1.nn.Softmax(dim) çç解
2.pytorch算子的源码cuda实现——expand,where,softmax
3.基于pytorch的二分类、多分类、源码多标签等问题总结
4.请问用gumbel-softmax的源码时候,怎么让softmax输出的概率分布
5.一文看懂如何实现softmax分类器(内附完全代码)
6.DisenKGAT论文代码精读
nn.Softmax(dim) çç解
使ç¨pytorchæ¡æ¶è¿è¡ç¥ç»ç½ç»è®ç»æ¶ï¼æ¶åå°åç±»é®é¢ï¼å°±éè¦ä½¿ç¨softmaxå½æ°ï¼è¿é以äºå类为ä¾ï¼ä»ç»nn.Softmax()å½æ°ä¸ï¼åæ°çå«ä¹ã
1. æ°å»ºä¸ä¸ª2x2大å°çå¼ éï¼ä¸è¡ç解æä¸ä¸ªæ ·æ¬ç»è¿åé¢ç½ç»è®¡ç®åçè¾åºï¼1x2ï¼ï¼åbatch_sizeæ¯2ã
import numpy as np
import torch
import torch.nn as nn
a = np.array([[1.5, 6.7],[6.8, 3.4]])
b = torch.from_numpy(a)
2. ä¸é¢è°ç¨nn.Softmax(dim)ï¼dimåå«ä¸º0ï¼1ï¼ççç»ææ¯ä»ä¹æ ·å
f = nn.Softmax(dim = 0)
c = f(b)
ç»æï¼ tensor([[0., 0.], [0., 0.]], dtype=torch.float)
å¯ä»¥åç°ï¼æ¯æ¯ä¸åå为1.
f = nn.Softmax(dim = 1)
ç»æï¼tensor([[0., 0.], [0., 0.]], dtype=torch.float)
å¯ä»¥åç°æ¯æ¯ä¸è¡å为1
æ以ï¼å½nn.Softmaxçè¾å ¥æ¯ä¸ä¸ªäºç»´å¼ éæ¶ï¼å ¶åæ°dim = 0ï¼æ¯è®©åä¹å为1ï¼dim = 1ï¼æ¯è®©è¡ä¹å为1ã
è¥nn.Softmaxçè¾å ¥æ¯ä¸ç»´å¼ éæ¶ï¼dimçåå¼å°±åæäº0ï¼1ï¼2ï¼é£åæ¯ä»£è¡¨ä»ä¹ææå¢ï¼çä¸é¢çä¾åã
a = np.array([[[1.5, 6.7, 2.4],
[6.8, 3.4, 9.3]],
[[3.1, 6.5, 1.9],
[8.9, 1.2, 2.5]]])
æ们æaæ¢æä¸ä¸ªä¸ç»´æ°ç»ï¼å¤§å°æ¯2x2x3ï¼å¯ä»¥çææ¯2个2x3大å°çè¾å ¥ã
è¿æ¶ï¼æ们å®ä¹Softmaxå½æ°çdim为0ï¼åç»ææ¯ï¼
tensor([[[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.]]], dtype=torch.float)
å¯ä»¥åç°ï¼0.+0. = 1ï¼ 0.+0. = 1ï¼å³dim = 0ï¼æ¯è®©ä¸¤ä¸ª2x3æ°æ®ç对åºä½ç½®å为1.
使dim=1ï¼ç»ææ¯ï¼
tensor([[[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.]]], dtype=torch.float)
å¯ä»¥åç°ï¼0.+0. = 1ï¼0.+0. = 1ï¼å³dim = 1ï¼æ¯è®©å¼ éæ¯ä¸ª2x3æ°æ®èªå·±çåä¹å为1.
使dim=2ï¼å°±æ¯è®©å¼ éæ¯ä¸ª2x3æ°æ®èªå·±çè¡ä¹å为1.
pytorch算子的cuda实现——expand,where,softmax
算子的简单介绍 orch.Tensor.expand() 是 PyTorch 中 Tensor 类的一个方法,用于扩展张量的源码维度。输入:input 是源码要扩展的张量,size 是源码thdn指标源码一个元组,指定了要扩展的源码每个维度的大小。输出:返回一个新的源码张量,形状是源码 input 张量的形状扩展后的形状。例如,源码x 的源码形状假设为(2,1,5,1),x.expand(2,源码4,5,6) 表示希望将 x 扩展为(2,4,5,6)形状的数组,注意 expand 只能在原始形状扩张,源码并且是源码原始维度的长度为1的地方。 torch.where() 是源码 PyTorch 中的一个函数,用于根据给定的条件从两个张量中选择元素。输入:condition, inputx, inputy。注意 condition, inputx, inputy 不要求形状保持一致。例如,condition=[2,1,1,1],inputx=[1,3,4,1],inputy=[1,2,4,2],这都符合要求,此时输出的形状应该是[2,3,4,2],换句话说,where 应该支持广播运算。 一维情况的 expand 和 where 对于一维向量来说,使用 expand 和 where 实现非常简单。对于 expand,我们可以写出伪代码。对于 where,我们也可以写出伪代码。 高维数组的 expand 对于高维数组而言,expand 需要考虑在哪个维度扩张。假设输入向量 input 的形状为 [公式],其中至少存在一个 [公式](这是因为 expand 只能在某个维度的长度为1的地方扩张)。假设经过 expand 输出以后 output 的形状为 [公式]。由于计算机存储高维数组仍然需要将数组拉平,弄成一维数组存储,因此我们需要获得高维数组拉平后的长度以及全局索引。例如,input[inputIdx]: inputIdx =[公式]。output[outputIdx]: outputIdx =[公式]。由此我们就可以直接获得 expand 的公式。假设 [公式],即扩张的维度 dim=1,此时对于 output 的任意一个元素,假设索引为 [公式],那么这个元素对应的取值就应该是 input 中索引为 [公式] 的元素。 高维数组的 where 编程 有了 expand 的经验之后,where 的源码社区考试实现就相对容易理解了。在编写 expand 算子的过程中,核心内容是根据 outputIdx 反推得到 inputIdx。同样地,我们可以根据 outputIdx 计算出 inputxIdx, inputyIdx, conditionIdx,然后直接计算即可。 一维向量的 softmax 介绍 softmax 的实现相对复杂。这里本人暂时只能实现一维向量的 softmax。假设输入是 x,输出是 y,其中 [公式]。在处理过程中,为了避免指数变化导致溢出,首先需要计算出向量 x 的最大值 [公式],然后做一次变换 [公式],将变换以后的数组记录为 [公式],从而得到 [公式]。 softmax 的实现可以分解为三步:遍历向量 x,计算得到 M,也就是一个 max 规约操作。
更新向量 x,其中 [公式],计算 [公式],也就是一个 sum 规约。
得到向量 y,其中 [公式]。
向量的 sum 规约 softmax 涉及到两次规约,这里我们先介绍使用的规约策略。我们先用 sum 规约介绍,其实 max 规约几乎如出一辙。 交叉配对规约:reduce=0 向量长度是 size(假设 size 是 2 的幂次方),交叉配对的原理是不断将奇数位置的元素加到偶数位置,最终将所有元素的和存放在起始位置。 以代码举例说明,这里重点说明第 行的代码。定义了一个数组 tmp,其中 __shared__ 关键字表示这个数组放在共享内存中,以及 tmp 数组面对当前线程块中的所有线程都是共享的。对于每个线程块来说,tmp 存储的是该线程块每个线程对应的数据。__syncthreads() 在 GPU 端做一个同步,确保所有线程的数据都赋值到了 tmp。重点来看 行以后的代码。 以图为例,blockDim=(8,1,1), gridDim=(4,1,1),一共有 个线程,blockDim.x=8。考虑第 行这个循环。当 strip=1 时,threadIdx.x%2 == 0,则 threadIdx.x 有 0,魅宝源码2,4,6 满足条件。当 threadIdx.x=0 时, 行代码就是 tmp[0] += tmp[1],类似地,成功将数据从 8 个位置转移到了 4 个位置,然后继续修改 strip=2,4,最后将所有元素的和转移到 tmp[0] 即可。最后将 tmp[0] 的数据放到 result[blockIdx.x] 中,也就是说 result 的每个元素存储的都是对应某个线程块内所有元素的和。最终结果全在 result 数组中,那么我们就可以推断出 result 的长度应该是 ceil(num_rows / BLOCK_DIM),其中 ceil 表示向上取整,num_rows 是向量的长度。 交叉配对规约的特点是规约过程类似于一个二叉树,每次都把奇数位置的元素添加到偶数位置,架构很简单,但具体每一次规约的数据访问却是跳跃的。 交错配对规约:reduce=1 分析后面的规约代码,当 strip=4 时,threadIdx.x < 4,就有 threadIdx.x=0,1,2,3 满足条件。当 threadIdx.x=0 时,就有 tmp[0] += tmp[4],tmp[1] += tmp[5],tmp[2] += tmp[6],tmp[3] += tmp[7]。这种做法的好处是每次规约数组的访问都是连续的,可以减少访存开销。后面的数值实验也证明这种并行策略确实加速效果更好。 shuffle warp:reduce=2 这种做法的原理比较复杂,这里本人解释的不一定准确。首先声明了一个长度为 的共享内存数组 tmp,这个 实际上是线程的 warp,GPU 线程的设计是每 个线程为一组,称为一个线程簇 warp,我们的一维线程块的 BLOCK_DIM 每隔 个线程做一个切分。 现在我们进一步考虑线程块内部的线程,对于某个线程块里面的某一个 warp 而言,这里面的 data 其实是线程私有变量,但是 data += __shfl_down_sync(0xffffffff, data, ) 的意思表示不同线程之间的 data 其实可以通过某种特殊方式相互读取累加的。该 warp 有 个线程,第一次累加的原则是,第 0 个线程和第 个线程相加,...,第 个线程和第 个线程数据相加,这样就把 warp 内 个线程的数据全部累加到了前 个线程。后面几句代码也是类似的,最后把该 warp 的趋势斜率源码 个线程数据累加到第一个线程。所以当 threadIdx.x%==0 时,表示 threadIdx.x 这个线程存储了该 warp 中 个线程数据的累加和。所以 tmp[threadIdx.x/] 位置存储的就是每一个 warp 所有线程数据的和。 现在需要把 tmp 这 个数据类似原则累加,因此借助于 threadIdx.x 可以直接读取 tmp 的数据,但是 threadIdx.x 的范围太大,我们不要借助那么多所以需要做一个判断以免访问 tmp 越界。最后将 tmp 的数据做完规约以后得到的 data 就保存了当前线程块的所有线程数据的累加和。而我们线程块的总数是 gridDim.x,blockIdx.x 的范围就是 0 到 gridDim.x-1,所以 result 的长度还是 gridDim.x,每个元素保存了对应线程块所有数据的累加和。 对于某个 warp,为什么第一次规约是以 为距离累加呢?实际上,从线程的角度来看,比如我们考虑最前面的 个线程,也就是 block 中第一个 warp,0 号线程一直到 号线程做累加的时候读取的数据正好是相邻的 个元素,累加的时候读取的是后面 个元素。不管怎么累加,不同线程之间读取的数据总数相邻,这样就保证了数据的局部性,所以访问时间进一步缩短。 把这些并行策略封装在 pre_dot 以后,后面仍然是写一个 cuda_dot 函数将 result 的结果传回 CPU 的 host_z,然后再串行求 host_z 的元素和。特别注意的是此时调用需要使用 pre_dot<<>>(cuda_x, cuda_y, cuda_z, result),share_size 表示申请的共享内存大小,这里我一般使用 BLOCK_DIM×sizeof(double)。 向量的 max 规约 前面两种规约方式对于 max 来说是一样的,稍微有一点区别的是 reduce=2 这种抽牌规约策略。有兴趣的同学可以查看一下 __shfl_down_sync 函数的用法就知道这个是怎么回事了。 初级 softmax 有了上面的 sum 和 max 规约策略,我们可以给一个初级的 softmax 算法,步骤如下: 1:先对数组 input 做一个 max 规约,此时会得到一个 result 数组,这个数组的长度是 ceil(N/BLOCK_DIM),其中 N 是数组的长度,BLOCK_DIM 是线程块的大小。观察向量的 max 规约可以发现这个规约其实只是对向量做了切割,切割成了 ceil(N/BLOCK_DIM),每一份长度是 BLOCK_DIM。而这个向量 result 的长度正好是 ceil(N/BLOCK_DIM),其中 result 的每个元素存储的是对应的那份长度为 BLOCK_DIM 的数据的 max,但是这个不是全局 max,因此我们需要把向量 result 从 GPU 搬运到 CPU,然后通过一个串行 for 循环来遍历 result,由此来获得全局 max,假设是 M。 2:然后我们做一个更新向量 x,神秘买点源码其中 [公式],计算 [公式],此时这个做 sum 规约,仍然是把向量切割成了 ceil(N/BLOCK_DIM),每一份长度是 BLOCK_DIM,并且每份长度为 BLOCK_DIM 的数据的 sum 被存储到了 result 的对应位置(result 可以多次利用,不需要重新定义新的数组)。然后还是需要把向量 result 从 GPU 搬运到 CPU,然后通过一个串行 for 循环来遍历 result,由此来获得全局 sum,假设是 S。 3:得到向量 y,其中 [公式]。这个过程比较无聊,不赘述。 综合上面信息,我们发现这个初级的 softmax 的数据来来回回从 CPU 和 GPU 移动了好几次,效率不太高。 高级 softmax 我们回顾一下上面的步骤 1 和 2,我们发现生成的 result 需要从 GPU 移动到 CPU,然后还要串行遍历 result 计算全局结果,但我们可以类似在 GPU 端规约 result,依次来减少数据移动,增大速度。经过本人测试,这个想法完全可行,可以称之为二次规约: 观察上面这段代码,本人定义了一个 girdmax 函数来实现 result 的规约,这个过程和 reduce=1 的规约策略一模一样,经过这样规约以后,全局的 max 将会被存储到 result[0],也就是 result 向量的开头元素。 类似地,我们继续这么做,这个 gridsum 会将 result 的所有元素都加载到 index=0,也就是开头位置,这样就得到了我们的高级 softmax。 高维数组的 softmax 目前还没调节好代码,有兴趣的同学可以自己试一试,完整代码参考本人博客。 本人在下一篇博客给出了一个 softmax 算子融合的介绍,有兴趣可以参考。基于pytorch的二分类、多分类、多标签等问题总结
基本照搬 Honda:基于pytorch的二分类、多分类、多标签等问题总结;其中加了一些自己看的时候的思考。
1. Sigmoid函数和Softmax函数
1.1 Sigmoid
Sigmoid函数常用于多标签分类问题,即存在多个正确答案的情况,如胸部X光检查、住院等。在构建分类器时,使用Sigmoid函数处理各个原始输出值,以解决存在多个正确答案的问题。
1.2 Softmax
Softmax函数适用于多类别分类问题,即只有一个正确答案的情况,如手写数字、鸢尾花等。在构建分类器时,使用Softmax函数处理各个原始输出值,以解决只有唯一正确答案的问题。
2. Pytorch中的nn.sigmoid和nn.softmax
2.1 nn.Softmax
Softmax函数的表达式为:[公式]
nn.Softmax可以用于激活函数或多分类,其中分类模型如下:
2.2 nn.LogSoftmax
相对于nn.Softmax,nn.LogSoftmax对输出进行了log操作,公式如下:[公式]
2.3 nn.CrossEntropyLoss
nn.CrossEntropyLoss用于计算交叉熵,适用于二分类和多分类任务。
2.4 torch.nn.Sigmoid 和 BCELoss()
Sigmoid公式为:[公式]
BCELoss()用于二分类,计算方式如下:[公式]
对于多标签分类,将Sigmoid和BCELoss整合,即BCEWithLogitsLoss()。
3. 二分类中的nn.sigmoid和nn.softmax
3.1 区别
Sigmoid函数和Softmax函数在二分类问题上是等价的。Sigmoid函数将数值压缩到(0,1)之间,得到的结果可以理解为分类成目标类别的概率。Softmax函数本身针对多项分布,当类别数是2时,它退化为二项分布。
3.2 使用场景
在二分类问题时,二者可以互换使用。对于多类别分类任务,通常使用Softmax。对于多标签分类任务,通常使用Sigmoid。
4. 小思考
在二分类问题中,使用softmax和sigmoid的结果是相同的。对于多类别分类,sigmoid可以用于多分类,但使用softmax更为合理。在多标签分类中,将问题拆解成多个二分类问题,使用sigmoid进行分类。
请问用gumbel-softmax的时候,怎么让softmax输出的概率分布
在探讨使用gumbel-softmax时如何让softmax输出概率分布,可以参考pytorch中torch.nn.functional.gumbel_softmax的实现。
具体操作中,当参数hard设置为True时,返回的结果是one-hot向量。其中,y_soft表示采样得到的概率分布,y_hard是基于此概率分布计算得出的one-hot向量。这里的detach()方法实际上将一个张量从计算图中移除,使其成为常量,以确保在反向传播时不会计算它的梯度。
综上所述,gumbel-softmax通过构造一个数值上等同于one-hot向量的张量,但在反向传播过程中梯度沿y_soft返回,实现了一种在概率分布与one-hot向量间平滑过渡的方式。这种方式在处理离散概率分布时具有优势,能够提供更好的灵活性和稳定性。
一文看懂如何实现softmax分类器(内附完全代码)
首先导入需要的包。
设置小批量数目为,转换类型并生成迭代器,与线性回归的读取数据方法相似。
初始化模型参数:每个图像有个特征值,网络输出为个类别,因此存在*个权重参数和个偏差参数。
实现softmax运算,将其转换为非负数,每行元素之和为1。
回顾tensor的按维度操作,定义softmax运算公式。
将权重和偏差参数与输入数据相乘,得到输出结果。
定义损失函数,使用torch.gather函数提取真实标签对应的预测概率。
根据交叉熵函数公式计算损失值。
计算分类准确率,从预测概率中找出最大概率对应的索引,与真实标签比较,计算准确率。
优化算法选择小批量随机梯度下降。
训练模型,调节迭代周期数和学习率获得分类更准确的模型。
预测模型效果,训练五次后,损失值从0.减少到0.,准确率从0.提升到0.。
完整程序包含以上步骤,实现softmax分类器。
DisenKGAT论文代码精读
公式1:互信息
解释:该公式定义了随机变量x和z之间的互信息。
公式2:初始组件嵌入
公式解释:- h^0_{ u,k}:实体u在第k个潜在空间中的初始嵌入。- σ:激活函数(例如ReLU或Sigmoid)。- W_k:用于第k个潜在空间的投影矩阵。- x_u:实体u的特征向量。
对应代码文件:model.py文件:DisenLayer.py详细讲解总结
公式3和4:组件级别交互
公式解释:- m(v, k, r):从邻居v聚合的消息。- φ:组合操作符,可以是减法、乘法、交叉交互或循环相关。- h_{ v,k}:邻居v在第k个组件中的嵌入。- h_r:关系r的嵌入。- θ_r:关系r的投影矩阵。- W_r:关系r的投影矩阵。- diag(w_r):将向量w_r变成对角矩阵。
对应代码文件:DisenLayer.py详细讲解总结
如果您对某个具体部分有更详细的疑问或需要进一步的解释,请告诉我!
公式5:注意力得分
公式解释:- α_k(u, v, r):组件k中邻居v对于实体u的注意力得分,考虑关系r。- softmax:Softmax函数,用于归一化注意力得分。- (e^k_{ u,r})^T:实体u在关系r的第k个组件中的嵌入的转置。- e^k_{ v,r}:邻居v在关系r的第k个组件中的嵌入。
对应代码文件:DisenLayer.py详细讲解总结
公式6:组件聚合
公式解释:- h^{ l+1}{ u,k}:实体u在第k个组件中的第l+1层嵌入。- σ:激活函数。- ∑:求和符号,用于聚合邻居信息。- N(u):实体u的邻居集合。- α_k(u, v, r):组件k中邻居v对于实体u的注意力得分。- φ:组合操作符。- h^l{ v,k}:邻居v在第k个组件中的第l层嵌入。- h^l_r:关系r的第l层嵌入。- θ_r:关系r的投影矩阵。
对应代码文件:DisenLayer.py详细讲解
ReLU激活函数,对应公式中的点积部分 (e^k_{ u,r})^T · e^k_{ v,r}。-alpha = softmax(alpha, edge_index_i, num_nodes=self.p.num_ent):对alpha进行softmax归一化,对应公式中的softmax。
总结公式7:关系表示更新
公式解释:- h^{ l+1}r:关系r的第l+1层嵌入。- W^l{ rel}:第l层的线性变换矩阵。- h^l_r:关系r的第l层嵌入。
对应代码文件:DisenLayer.py详细讲解总结
公式8:互信息正则化
对应代码文件:model.py文件:model.py详细讲解
.Tanh())
总结公式9:KL散度
公式解释:- L(h_{ u,i}, h_{ u,j}):KL散度损失。- D_KL:KL散度。- p(h_{ u,i} | h_{ u,j}):真实条件概率分布。- q_θ (h_{ u,i} | h_{ u,j}):变分条件概率分布,参数为θ。
对应代码文件:model.py详细讲解总结
公式:组件级别预测
公式解释:- ψ_k(u, r, v):候选三元组(u, r, v)在第k个组件中的评分。- f:评分函数。- vec:向量化操作,将矩阵展平为向量。- h^L_{ u,k}:实体u在第k个组件中的第L层嵌入。- h^L_r:关系r的第L层嵌入。- star:卷积操作。- ω:卷积核。- W:线性变换矩阵。- h^L_{ v,k}:实体v在第k个组件中的第L层嵌入。
对应代码文件:model.py详细讲解
对应关系:-comb_emb:组合后的实体和关系嵌入,对应公式中的 f(h^L_{ u,k}; h^L_r)。- stack_inp:经过卷积操作的输入,对应公式中的 h^L_r star ω。- x:经过激活函数和线性变换后的嵌入,对应公式中的 f(vec(f(h^L_{ u,k}; h^L_r star ω)))W。
if self.p.score_order == 'before': x = torch.einsum('bk,bkn->bn', [attention, x]) pred = torch.sigmoid(x) elif self.p.score_order == 'after': x = torch.sigmoid(x) pred = torch.einsum('bk,bkn->bn', [attention, x]) pred = torch.clamp(pred, min=0., max=1.0) return pred, corr
总结公式:注意力评分
公式解释:- β_k(u, r):组件k在给定关系r中的重要性。- softmax:Softmax函数,用于归一化注意力得分。- (h^L_{ u,k} circ θ_r)^T:实体u在关系r的第k个组件中的嵌入与关系权重的元素级乘积的转置。- h^L_r:关系r的第L层嵌入。
对应代码文件:model.py详细讲解
x = x.view(-1, self.p.num_factors, self.p.gcn_dim)
总结
如果您对某个具体部分有更详细的疑问或需要进一步的解释,请告诉我!
公式:最终预测评分
公式解释:
对应代码文件:model.py详细讲解
f(h^L_{ u,k}; h^L_r star ω))W)。
if self.p.score_order == 'before': x = torch.einsum('bk,bkn->bn', [attention, x]) pred = torch.sigmoid(x) elif self.p.score_order == 'after': x = torch.sigmoid(x) pred = torch.einsum('bk,bkn->bn', [attention, x]) pred = torch.clamp(pred, min=0., max=1.0) return pred, corr
总结公式:总体目标
公式解释:- L:总损失函数。- B:批量大小。- N:知识图谱中的实体数量。- ∑_{ (u, r) ∈ batch}:对批次中的所有三元组(u, r)求和。- ∑_i:对所有候选实体i求和。- t_i:标签,表示三元组(u, r, v_i)是否为有效三元组。- log(ψ_{ final}(u, r, v_i)):最终预测评分的对数值。- λ:互信息正则化损失的权重。- L_mi:互信息正则化损失。
对应代码文件:run.py详细讲解总结
如果您对某个具体部分有更详细的疑问或需要进一步的解释,请告诉我!
NLP修炼系列之分类loss二分类、多分类与多标签分类loss损失函数
本文将探讨二分类、多分类与多标签分类的区别与损失函数,详细分析softmax、log_softmax、CrossEntropyLoss 和 NLLLoss 四个函数的应用与对比,以深入理解它们之间的差异和用法。 首先,我们需要了解基本概念: 二分类:任务有两个类别,每个样本属于其中的一个,如新闻分为体育与非体育。 多分类:任务有多个类别,每个样本属于一个类别,如新闻分类为体育、财经、其他。 多标签分类:任务有多个类别,每个样本可以属于多个类别,如新闻可能同时属于体育、财经、教育。 接下来,分析二分类任务:输出层仅有一个单元,使用sigmoid损失函数和二分类交叉熵损失。
torch中提供两种二分类损失函数:BCELoss 和 BCEWithLogitsLoss。
二者区别在于BCEWithLogitsLoss直接对最后的logits进行处理,不再需要sigmoid缩放。
使用sigmoid+BCELoss或softmax+交叉熵实现。
也可直接使用CrossEntropyLoss。
多分类任务的处理方式:输出层单元数为类别数量,使用softmax损失函数和多分类交叉熵损失。
标签转换为one-hot向量,表示每个类别的独热编码。
实现代码包括softmax+nll_loss或直接使用CrossEntropyLoss。
多标签分类任务:视为多个二分类任务,每个标签为独立的二分类问题。
使用sigmoid+BCELoss进行实现,对每个标签进行单独评分。
标签以one-hot编码形式表示,如[0,0,0,1,0,1,0,0,1]。
实现代码包括sigmoid+BCELoss或直接使用BCEWithLogitsLoss。
总结损失函数:激活函数将输出缩放到[0,1]。
求对数操作计算输出的对数。
累加求和计算损失。
softmax、log_softmax、CrossEntropyLoss 和 NLLLoss 的对比:softmax/sigmoid:对应激活函数操作。
log_softmax:完成激活函数与对数计算。
nll_loss:对应损失计算的最后一步。
CrossEntropyLoss:整合所有步骤。
多分类交叉熵损失实现方法:三步实现:softmax+log+nll_loss。
两步实现:log_softmax+nll_loss。
一步实现:crossEntropyLoss。
总结全文,本文详细介绍了二分类、多分类与多标签分类的区别,以及损失函数softmax、log_softmax、CrossEntropyLoss 和 NLLLoss 的对比,帮助读者理解这些函数在不同分类任务中的应用与区别。pytorch多分类任务输出层使用softmax,该选择什么损失函数
多分类任务中,通常在全连接层输出数据为batch_size*n_classes。此结构适配torch.nn.CrossEntropyLoss(),该函数内整合了softmax、log和NLLloss,故全连接层输出结果可直接接入此函数,实现交叉熵损失计算。函数中reduction参数有三种选择:'none'表示返回每个样本的交叉熵损失,'sum'表示返回每个样本损失的总和,'mean'表示返回平均交叉熵损失。
若全连接层输出结果上先应用了torch.softmax(),则不宜再直接使用torch.nn.CrossEntropyLoss()。此时,需在应用softmax后,进行log操作并取对应位置结果计算损失。具体公式为:loss = torch.log(torch.softmax(results_fc, dim=1))[torch.arange(len(target), target].sum()。
其中,results_fc为全连接层输出结果,target为真实标签。torch.softmax函数亦可用F.softmax替代。