多分类交叉熵函数计算过程(包含numpy和pytorch代码实现) |
您所在的位置:网站首页 › 函数公式代码 › 多分类交叉熵函数计算过程(包含numpy和pytorch代码实现) |
文章目录
1.具体示例2.计算步骤2.1 numpy代码手动实现2.2 pytorch实现2.3 pytorch等价实现
3.sigmoid做多分类4. loss反向传播是本质
调库调用太久了
以至于把最基本的给忘了
连交叉熵的数学公式都记不清了,自己写代码验证还验证错误,就是因此公式记错了
所以重新记录一下,交叉熵的求解过程
当然,交叉熵的由来是一个最优化问题,在sigmoid函数相关最优化求解里会有相关的内容,而实际上原理就是求偏导后的,得的最小值等等,这里不概述。 仅给出计算公式以及手写代码和pytorch调库结果对比 1.具体示例下面的代码,实际上debug了很久才写出来的,注释已经很清楚了 2.1 numpy代码手动实现以一个shape:(3,4)的矩阵为例,计算 """ batch=3, nc = 4 """ import numpy as np target = np.array([ [-1.0606, 1.5613, 1.2007, -0.2481], [-1.9652, -0.4367, -0.0645, -0.5104], [0.1011, -0.5904, 0.0243, 0.1002] ]) label = np.array([0, 2, 1]) def np_softmax(arr): assert len(arr.shape) == 2 arr_exp = np.exp(arr) arr_sum = np.sum(arr_exp, axis=1) # (3,4) -->(3,) arr_sum = arr_sum[:, None] # 增加维度,才可以通过广播,进行矩阵除法。(3, )-->(3, 1) return arr_exp / arr_sum def np_onehot(nc, true_label): """ param nc: nc代表划分的类别数目 param true_label: 传入的标签 shape :(batch, ) return: 返回一个(batch, nc)形式的one_hot变量 """ tmp = np.arange(nc) tmp = tmp[None, :] # 增加行的维度,[0,1,2,3] -->[[0, 1, 2, 3]] 。后续才能广播,每一行都是0,1,2,3 true_label = true_label[:, None] # 增加列的维度,[0, 2, 1] -->[[0],[2],[1]] 。按照列广播 ans = tmp == true_label # 自动广播,返回(batch, nc)形式,为True或False return ans.astype(int) # bool --> int # 1.对预测结果softmax处理 target_soft = np_softmax(target) # 2. 取log对数 target_log = np.log(target_soft) # 3. one-hot变量 label_one = np_onehot(4, label) # 4. python矩阵乘法,按照元素相乘; 取负数 , 负对数 res = -target_log * label_one # 5. 按照列求和, 取均值 loss = np.mean(np.sum(res, axis=1)) print(loss)上面使用的是nn.CrossEntropyLoss()进行实现,但是也可以调用nn.LogSoftmax()结合nn.NLLLoss(),即,可以简单认为 nn.CrossEntropyLoss()等价于nn.LogSoftmax()加nn.NLLLoss() import torch import numpy as np import torch.nn as nn target = np.array([ [-1.0606, 1.5613, 1.2007, -0.2481], [-1.9652, -0.4367, -0.0645, -0.5104], [0.1011, -0.5904, 0.0243, 0.1002] ]) target = torch.tensor(target) label = torch.tensor([0, 2, 1]) # 先取softmax,再取log操作 m = nn.LogSoftmax(dim=1) # The negative log likelihood loss. It is useful to train a classification # problem with `C` classes loss = nn.NLLLoss() tmp = m(target) output = loss(tmp, label) print(output)解释如下:截图参考来源 注意BCELoss 和 BCELosswithLogit是有区别的 其实损失函数的相关计算,都是自己定义的 多分类中,使用sigmoid也是可以的。 即,每个类别的预测都是独立的、互不干扰,概率值的和也不为1 # loss_function = nn.CrossEntropyLoss() criterion = nn.BCELoss() for step, data in enumerate(train_bar): images, labels = data images = images.to(device) labels = labels.to(device) output = net(images.to(device)) # 对labels one-hot处理 labels = nn.functional.one_hot(labels, num_classes=5) # 对output sigmoid处理 output = torch.sigmoid(output) loss = criterion(output, labels.float()) optimizer.zero_grad() loss.backward() optimizer.step() 4. loss反向传播是本质loss是一个tensor,为啥它可以直接反向传播呢? 随便一个tensor都可以调用backward()么? 计算图存储了梯度计算公式的 根据链式法则对所有参数进行更新 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |