网站通栏图片代码,域名如何解析别人网站,修改wordpress语言,房地产销售基础知识新手必看建议点赞收藏关注#xff01;持续更新至pytorch大部分内容更完。 本文已达到10w字#xff0c;故按模块拆开#xff0c;详见目录导航。
整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 损失函数创建损失函数 #xff08;共18个#xff09;nn.CrossEnt…建议点赞收藏关注持续更新至pytorch大部分内容更完。 本文已达到10w字故按模块拆开详见目录导航。
整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 损失函数创建损失函数 共18个nn.CrossEntropyLossnn.NLLLossBCE LossBCEwithLogitsLossnn.L1Lossnn.MSELossnn.SmoothL1Lossnn.PoissonNLLLossnn.KLDivLossnn.MarginRankingLossnn.MultiLabelMarginLossnn.SoftMarginLossnn.MultiLabelSoftMarginLossnn.MultiMarginLossnn.TripletMarginLossnn.HingeEmbeddingLossnn.CosineEmbeddingLossnn.CTCLoss 设置损失函数超参数选择损失函数 优化器(共10个)optim.SGD 随机梯度下降法torch.optim.ASGD 随机平均梯度下降torch.optim.Rprop 弹性反向传播torch.optim.Adagrad 自适应学习率梯度下降法torch.optim.AdadeltaAdagrad的改进torch.optim.RMSpropAdagrad的改进torch.optim.Adam(AMSGrad)RMSprop结合Momentumtorch.optim.Adamax: Adam增加学习率上限torch.optim.SparseAdam稀疏版Adamtorch.optim.LBFGS:BFGS的改进 优化算法梯度下降法管理模型参数管理多个参数组实现不同学习率调整学习率 迭代训练观察训练效果绘制loss/accuracy曲线用TensorBoard分析 模型应用图像分类图像分割目标检测对抗生成循环网络 损失函数
损失函数loss代价函数cost目标函数objective 交叉熵信息熵相对熵 (1)熵用来描述一个事件的不确定性不确定性越大则熵越大. (2)信息熵是自信息的期望自信息用于衡量单个输出单个事件的不确定性. (3)相对熵又叫做KL散度用于衡量两个分布之间的差异即两个分布之间的距离但不是距离的函数不具备对称性。 下图公式中都是P是真实的分布Q是模型输出的分布Q需要逼近、拟合P的分布. (4)交叉熵用于衡量两个分布之间的相似度. (5)P是真实的分布即训练集中样本的分布。由于训练集是固定的概率分布也是固定的H§是个常数.故优化交叉熵等价于优化相对熵。 上图是一个伯努利分布可以发现当概率是0.5时熵最大为0.690.69这个数字经常会碰到模型训练坏了、模型的训练第一个iteration此时不具备判断能力因为对于任何输出判别的概率都是1/2。
创建损失函数 共18个
nn.CrossEntropyLoss
nn.CrossEntropyLoss(weightNone, ignore_index- 100, reductionmean )size_averageNone, reduceNone,这俩个参数已废弃
weight:各类别loss设置权值
ignore_index:忽略某个类别而不计算它的loss
reduction:计算模式可为none/sum/mean
none 逐个元素计算这么多个loss
sum 所有元素求和返回标量
mean 加权平均返回标量交叉熵这里的不是按照书中公式所计算的这里其实是nn.LogSoftmax()与nn.NLLLoss()结合进行计算的。它采用softmax对数据进行了归一化把数据值归一化到概率输出的形式。交叉熵损失函数常常用于分类任务中。交叉熵是衡量两个概率分布之间的差异交叉熵值越低表示两个概率分布越近。 运用softmax可以将输出值转换归一化到01之间作为概率。 首先上图 这里x是输出的一个概率值class是一个类别值。 第二式中的(分式)就是softmax的公式对比第一式即交叉熵公式可知 这个xi是已经取到的所以p(xi)1并且第二式只是计算其中一个的交叉熵故也没有N项求和符号。 当调用这个方法时传入了weight参数则计算公式为第三式
# fake data
#二分类任务输出神经元2个batchsize是3即三个样本[1,2] [1,3] [1,3]
inputs torch.tensor([[1, 2], [1, 3], [1, 3]], dtypetorch.float)
#dtype必须是long有多少个样本tensor1D就有多长。而且这里的类别label也是从0开始标号的
target torch.tensor([0, 1, 1], dtypetorch.long)# ----------------------------------- CrossEntropy loss: reduction -----------------------------------
flag 0
# flag 1
if flag:# def loss functionloss_f_none nn.CrossEntropyLoss(weightNone, reductionnone)loss_f_sum nn.CrossEntropyLoss(weightNone, reductionsum)loss_f_mean nn.CrossEntropyLoss(weightNone, reductionmean)# forwardloss_none loss_f_none(inputs, target)loss_sum loss_f_sum(inputs, target)loss_mean loss_f_mean(inputs, target)# viewprint(Cross Entropy Loss:\n , loss_none, loss_sum, loss_mean)#输出为[1.3133, 0.1269, 0.1269] 1.5671 0.5224# --------------------------------- compute by hand
flag 0
# flag 1
if flag:idx 0input_1 inputs.detach().numpy()[idx] # [1, 2]两个神经元target_1 target.numpy()[idx] # [0]# 第一项x_class input_1[target_1]# 第二项 map指对其每一个神经元进行运算sigma_exp_x np.sum(list(map(np.exp, input_1)))log_sigma_exp_x np.log(sigma_exp_x)# 输出lossloss_1 -x_class log_sigma_exp_xprint(第一个样本loss为: , loss_1)# ----------------------------------- weight -----------------------------------
flag 0
# flag 1
if flag:# def loss function有多少个类别weights这个向量就要设置多长
每一个类别都必须设置weight
如果不想关注这个weight就将其设置为1就不会变的。如果类别是mean则每个weight数值多大不重要重要在于他们之间的比例。结果可以看出来原先得到的loss基础上如果数据label0则用weight[0]1倍故与之前相等。而label1的后两个数据的loss变成了之前的2倍(因为weight2)在sum模式下weight2也代表label1的这一个数据就占两份1在分母中在本例中为 三个数据loss之和/(122)
weights torch.tensor([1, 2], dtypetorch.float)# weights torch.tensor([0.7, 0.3], dtypetorch.float)loss_f_none_w nn.CrossEntropyLoss(weightweights, reductionnone)loss_f_sum nn.CrossEntropyLoss(weightweights, reductionsum)loss_f_mean nn.CrossEntropyLoss(weightweights, reductionmean)# forwardloss_none_w loss_f_none_w(inputs, target)loss_sum loss_f_sum(inputs, target)loss_mean loss_f_mean(inputs, target)# viewprint(\nweights: , weights)print(loss_none_w, loss_sum, loss_mean)#权值为[1,2],则输出[1.3133, 0.2539, 0.2539] 1.8210 0.3642# target[0,1,1]所以对应0的需要乘以权值1对应1的需要乘以权值2.# 1.3133是1.3133*11.31330.2530是0.1269*20.25390.2530是0.1269*20.2539.#0.3642是1.8210/(122)0.3642分母是权值的份数5.# --------------------------------- compute by hand 手动计算
flag 0
# flag 1
if flag:weights torch.tensor([1, 2], dtypetorch.float)#weights_all5 计算sum公式中除掉的分母份数weights_all np.sum(list(map(lambda x: weights.numpy()[x], target.numpy()))) # [0, 1, 1] --- # [1 2 2]mean 0loss_sep loss_none.detach().numpy()for i in range(target.shape[0]):
#输出每一个样本在这平均值loss中贡献的数目x_class target.numpy()[i]tmp loss_sep[i] * (weights.numpy()[x_class] / weights_all)mean tmpprint(mean)
nn.NLLLoss
nn.NLLLoss(weightNone, size_averageNone, ignore_index- 100, reduceNone, reductionmean)实现负对数似然函数中的负号功能简单来说就是取负号
# fake data
#二分类任务输出神经元2个batchsize是3即三个样本[1,2] [1,3] [1,3]
inputs torch.tensor([[1, 2], [1, 3], [1, 3]], dtypetorch.float)
#dtype必须是long有多少个样本tensor1D就有多长。
target torch.tensor([0, 1, 1], dtypetorch.long)# ----------------------------------- 2 NLLLoss -----------------------------------
flag 0
# flag 1
if flag:weights torch.tensor([1, 1], dtypetorch.float)loss_f_none_w nn.NLLLoss(weightweights, reductionnone)loss_f_sum nn.NLLLoss(weightweights, reductionsum)loss_f_mean nn.NLLLoss(weightweights, reductionmean)# forwardloss_none_w loss_f_none_w(inputs, target)loss_sum loss_f_sum(inputs, target)loss_mean loss_f_mean(inputs, target)# viewprint(NLL Loss, loss_none_w, loss_sum, loss_mean)#输出[-1,-3,-3] -7 -2.3333# target[0, 1, 1]#-1是因为第一个样本[1,2]是第0类因此只对第一个神经元输出操作-1*1。#-3是因为第二个样本[1,3]是第1类因此只对第二个神经元输出操作-1*3。#-3是因为第三个样本[1,3]是第1类因此只对第二个神经元输出操作-1*3。#求mean时的分母是权重weight的和。
BCE Loss
xn是模型输出的概率取值yn是标签二分类中对应0或1。
nn.BCELoss(weightNone, size_averageNone, reduceNone, reductionmean)二分类交叉熵损失函数
注意输入值取值在[0,1]利用sigmoid函数可实现
# ----------------------------------- 3 BCE Loss -----------------------------------
flag 0
# flag 1
if flag:
#同样是二分类每个样本有两个神经元inputs torch.tensor([[1, 2], [2, 2], [3, 4], [4, 5]], dtypetorch.float) #4个样本target torch.tensor([[1, 0], [1, 0], [0, 1], [0, 1]], dtypetorch.float) #float类型每个神经元一一对应去计算loss而不是之前是整个向量去计算losstarget_bce target#一定要加上sigmoid将输入值取值在[0,1]区间inputs torch.sigmoid(inputs)weights torch.tensor([1, 1], dtypetorch.float)loss_f_none_w nn.BCELoss(weightweights, reductionnone)loss_f_sum nn.BCELoss(weightweights, reductionsum)loss_f_mean nn.BCELoss(weightweights, reductionmean)# forwardloss_none_w loss_f_none_w(inputs, target_bce)loss_sum loss_f_sum(inputs, target_bce)loss_mean loss_f_mean(inputs, target_bce)# viewprint(\nweights: , weights)print(BCE Loss, loss_none_w, loss_sum, loss_mean)#输出[[0.3133, 2.1269], [0.1269, 2.1269], [3.0486, 0.0181], [4.0181, 0.0067]] 11.7856 1.4732#每个神经元一一对应去计算loss,因此loss个数是2*48个# --------------------------------- compute by hand
flag 0
# flag 1
if flag:idx 0x_i inputs.detach().numpy()[idx, idx]y_i target.numpy()[idx, idx] ## loss# l_i -[ y_i * np.log(x_i) (1-y_i) * np.log(1-y_i) ] # np.log(0) nanl_i -y_i * np.log(x_i) if y_i else -(1-y_i) * np.log(1-x_i)# 输出lossprint(BCE inputs: , inputs)print(第一个loss为: , l_i) #0.3133
BCEwithLogitsLoss σ是sigmoid函数
nn.BCEWithLogitsLoss(weightNone, size_averageNone, reduceNone, reductionmean, pos_weightNone)结合sigmoid与二分类交叉熵
注意网络最后不要加sigmoid函数再加这个值就不准确了这个损失函数存在的原因有的时候不希望模型里有sigmoid在最后一层。多了一个参数pos_weight 正样本权值
1pos_weight用于均衡正负样本正样本的loss需要乘以pos_weight。
比如正样本100个负样本300个此时可以将pos_weight设置为3就可以实现正负样本均衡。
2pos_weight里是一个tensor列表需要和标签个数相同比如现在有一个多标签分类类别有200个那么 pos_weight 就是为每个类别赋予的权重值长度为200
3如果现在是二分类只需要将正样本loss的权重写上即可比如我们有正负两类样本正样本数量为100个负样本为400个我们想要对正负样本的loss进行加权处理将正样本的loss权重放大4倍通过这样的方式缓解样本不均衡问题
criterion nn.BCEWithLogitsLoss(pos_weighttorch.tensor([4]))# ----------------------------------- 4 BCE with Logis Loss -----------------------------------
# flag 0
flag 1
if flag:inputs torch.tensor([[1, 2], [2, 2], [3, 4], [4, 5]], dtypetorch.float)target torch.tensor([[1, 0], [1, 0], [0, 1], [0, 1]], dtypetorch.float)target_bce target# inputs torch.sigmoid(inputs) 不能加sigmoidweights torch.tensor([1, 1], dtypetorch.float)loss_f_none_w nn.BCEWithLogitsLoss(weightweights, reductionnone)loss_f_sum nn.BCEWithLogitsLoss(weightweights, reductionsum)loss_f_mean nn.BCEWithLogitsLoss(weightweights, reductionmean)# forwardloss_none_w loss_f_none_w(inputs, target_bce)loss_sum loss_f_sum(inputs, target_bce)loss_mean loss_f_mean(inputs, target_bce)# viewprint(\nweights: , weights)print(loss_none_w, loss_sum, loss_mean)#输出[[0.3133, 2.1269], [0.1269, 2.1269], [3.0486, 0.0181], [4.0181, 0.0067]] 11.7856 1.4732# --------------------------------- pos weight# flag 0
flag 1
if flag:inputs torch.tensor([[1, 2], [2, 2], [3, 4], [4, 5]], dtypetorch.float)target torch.tensor([[1, 0], [1, 0], [0, 1], [0, 1]], dtypetorch.float)target_bce target# itarget# inputs torch.sigmoid(inputs)weights torch.tensor([1], dtypetorch.float)#pos_w torch.tensor([1], dtypetorch.float) #设置为1时loss输出与原先一致。pos_w torch.tensor([3], dtypetorch.float) # 3#设置为3时会对正样本的loss乘以3即标签是1对应的loss。#输出[[0.3133*3, 2.1269], [0.1269*3, 2.1269], [3.0486, 0.0181*3], [4.0181, 0.0067*3]]loss_f_none_w nn.BCEWithLogitsLoss(weightweights, reductionnone, pos_weightpos_w)loss_f_sum nn.BCEWithLogitsLoss(weightweights, reductionsum, pos_weightpos_w)loss_f_mean nn.BCEWithLogitsLoss(weightweights, reductionmean, pos_weightpos_w)# forwardloss_none_w loss_f_none_w(inputs, target_bce)loss_sum loss_f_sum(inputs, target_bce)loss_mean loss_f_mean(inputs, target_bce)# viewprint(\npos_weights: , pos_w)print(loss_none_w, loss_sum, loss_mean)
nn.L1Loss
计算Inputs与target之差的绝对值
nn.MSELoss
计算差的平方
# ------------------------------------------------- 5 L1 loss ----------------------------------------------
flag 0
# flag 1
if flag:inputs torch.ones((2, 2)) #2*2数值为1target torch.ones((2, 2)) * 3 #2*2数值为3loss_f nn.L1Loss(reductionnone)loss loss_f(inputs, target)print(input:{}\ntarget:{}\nL1 loss:{}.format(inputs, target, loss))#输出为[[2,2],[2,2]]# ------------------------------------------------- 6 MSE loss ----------------------------------------------loss_f_mse nn.MSELoss(reductionnone)loss_mse loss_f_mse(inputs, target)print(MSE loss:{}.format(loss_mse))#输出为[[4,4],[4,4]]
nn.SmoothL1Loss
平滑的L1 loss看图就知道为什么要这样设置函数了可以减轻离群点带来的影响。
# ------------------------------------------------- 7 Smooth L1 loss ----------------------------------------------
flag 0
# flag 1
if flag:inputs torch.linspace(-3, 3, steps500) #-3到3区间取500个数据点target torch.zeros_like(inputs) #数值为0维度与inputs一致loss_f nn.SmoothL1Loss(reductionnone)loss_smooth loss_f(inputs, target)loss_l1 np.abs(inputs.numpy()-target.numpy())plt.plot(inputs.numpy(), loss_smooth.numpy(), labelSmooth L1 Loss)plt.plot(inputs.numpy(), loss_l1, labelL1 loss)plt.xlabel(x_i - y_i)plt.ylabel(loss value)plt.legend()plt.grid()plt.show()#画出的图像就是上图所示nn.PoissonNLLLoss
泊松分布的负对数似然损失函数
nn.PoissonNLLLoss(log_inputTrue, fullFalse, size_averageNone, eps1e-08, reduceNone, reductionmean)log_input:输入是否是对数形式决定计算公式使用上图哪一个
full计算所有loss,默认为False
eps修正项避免log(input)为nan即避免输入取0时# ------------------------------------------------- 8 Poisson NLL Loss ----------------------------------------------
flag 0
# flag 1
if flag:inputs torch.randn((2, 2)) #2*2标准正态分布target torch.randn((2, 2)) #2*2标准正态分布loss_f nn.PoissonNLLLoss(log_inputTrue, fullFalse, reductionnone)loss loss_f(inputs, target)print(input:{}\ntarget:{}\nPoisson NLL loss:{}.format(inputs, target, loss))# --------------------------------- compute by hand
flag 0
# flag 1
if flag:idx 0loss_1 torch.exp(inputs[idx, idx]) - target[idx, idx]*inputs[idx, idx] #计算第一个元素即inputs[0,0]print(第一个元素loss:, loss_1)
nn.KLDivLoss KL散度衡量两个分布的相似性或者“距离” P:样本在真实分布的概率 即标签 Q:尽可能拟合逼近P的分布即模型输出的分布 Q(xi)指其中xi样本的概率
第二个公式ln 是pytorch 的这个计算公式xn是输入的数据yn是标签 有一些区别区别在于xn而非logQ(xi)即log(xn)这样就是下面提到的需要提前计算输入的log-probabilities
nn.KLDivLoss(size_averageNone, reduceNone, reductionmean, log_targetFalse)计算KLD即KL散度,相对熵
需提前将输入计算log-probablities如通过nn.logsoftmax()softmax生成probabilities 然后对其logbatchmeanbatchsize维度求平均值也就是说求平均值除以的分母不再是元素个数而是batchsize# ------------------------------------------------- 9 KL Divergence Loss ----------------------------------------------
flag 0
# flag 1
if flag:# 3个神经元第一批样本中第一个神经元输出为0.5第二个0.3第三个0.2# 第二批样本中第一个0.2第二个0.3第三个0.5inputs torch.tensor([[0.5, 0.3, 0.2], [0.2, 0.3, 0.5]]) #2*32批样本3个神经元 已经是概率值了不需要再softmaxinputs_log torch.log(inputs)target torch.tensor([[0.9, 0.05, 0.05], [0.1, 0.7, 0.2]], dtypetorch.float)loss_f_none nn.KLDivLoss(reductionnone)loss_f_mean nn.KLDivLoss(reductionmean)loss_f_bs_mean nn.KLDivLoss(reductionbatchmean)loss_none loss_f_none(inputs, target)loss_mean loss_f_mean(inputs, target) #所有元素相加/66是所有元素的个数loss_bs_mean loss_f_bs_mean(inputs, target) #所有元素相加/22是batchsize一共是两批次即两批样本print(loss_none:\n{}\nloss_mean:\n{}\nloss_bs_mean:\n{}.format(loss_none, loss_mean, loss_bs_mean))# --------------------------------- compute by hand
flag 0
# flag 1
if flag:idx 0loss_1 target[idx, idx] * (torch.log(target[idx, idx]) - inputs[idx, idx])print(第一个元素loss:, loss_1)
nn.MarginRankingLoss 计算公式如上y-1 或 1 当y-1时希望x2x1那么就不产生loss 当y 1 时希望x1x2那么就不产生loss
nn.MarginRankingLoss(margin0.0, size_averageNone, reduceNone, reductionmean)计算两个向量之间相似度用于排序任务该方法计算两组数据之间的差异返回n*n的一个loss矩阵margin:边界值x1与x2之间的差异值# ---------------------------------------------- 10 Margin Ranking Loss --------------------------------------------
flag 0
# flag 1
if flag:x1 torch.tensor([[1], [2], [3]], dtypetorch.float) #3*1x2 torch.tensor([[2], [2], [2]], dtypetorch.float) #3*1target torch.tensor([1, 1, -1], dtypetorch.float) #向量也是1*3loss_f_none nn.MarginRankingLoss(margin0, reductionnone)loss loss_f_none(x1, x2, target)print(loss) #输出为[[1,1,0], [0,0,0], [0,0,1]]# loss中第一行第一列的元素1是用x1的第1个元素[1]与x2的第1个元素[2]比较此时y1loss1# loss中第一行第二列的元素1是用x1的第1个元素[2]与x2的第2个元素[2]比较此时y1loss1# loss中第一行第三列的元素0是用x1的第1个元素[3]与x2的第3个元素[2]比较此时y-1loss0# loss中第二行第一列的元素0是用x1的第2个元素[2]与x2的第1个元素[2]比较此时y1loss0当两个值相等时不论y是多少loss0# 后面计算同理y的值与x2是第几个有关比如x2取第1个值则y取第一个值x2取第3个值则y取第三个值。
nn.MultiLabelMarginLoss 1分母是神经元的个数。 2x[y[j]]-x[i]标签所在的神经元的值-不是标签所在的神经元的值。 目的是为了使标签所在的神经元的输出比非标签所在的神经元的输出越来越大这样loss才会等于0。
nn.MultiLabelMarginLoss(size_averageNone, reduceNone, reductionmean)多标签边界损失函数注意是多标签 不是多分类比如 4分类任务样本x属于0类和3类则标签为[0,3,-1-1] 而非[1,0,0,1]
# ---------------------------------------------- 11 Multi Label Margin Loss -----------------------------------------
flag 0
# flag 1
if flag:x torch.tensor([[0.1, 0.2, 0.4, 0.8]]) #1*41是一批样本四分类分别对应第0类、第1类、第2类、第3类y torch.tensor([[0, 3, -1, -1]], dtypetorch.long) #标签设置第0类第3类不足的地方用-1填充占位注意类型必须是longloss_f nn.MultiLabelMarginLoss(reductionnone)loss loss_f(x, y)print(loss) # 输出0.8500# --------------------------------- compute by hand
flag 0
# flag 1
if flag:#标签所在的神经元是第0类和第3类所以要计算第0类神经元的loss和第3类神经元的loss需要各自减去不是标签的神经元x x[0] #取出第1批样本#第0类神经元需要减去第1类、第2类神经元item_1 (1-(x[0] - x[1])) (1 - (x[0] - x[2])) # [0]#第3类神经元需要减去第1类、第2类神经元item_2 (1-(x[3] - x[1])) (1 - (x[3] - x[2])) # [3]loss_h (item_1 item_2) / x.shape[0] #x.shape[0]4print(loss_h)
nn.SoftMarginLoss 分母是样本数nelement() 统计 tensor (张量) 中元素的个数。 y可取1 或-1
nn.SoftMarginLoss(size_averageNone, reduceNone, reductionmean)计算二分类的logistic 损失
# ---------------------------------------------- 12 SoftMargin Loss -----------------------------------------
flag 0
# flag 1
if flag:inputs torch.tensor([[0.3, 0.7], [0.5, 0.5]]) # 2*2#2个样本每个样本里2个神经元target torch.tensor([[-1, 1], [1, -1]], dtypetorch.float) # 2*2loss_f nn.SoftMarginLoss(reductionnone)loss loss_f(inputs, target)print(SoftMargin: , loss) # 2*2# --------------------------------- compute by hand
flag 0
# flag 1
if flag:idx 0inputs_i inputs[idx, idx]target_i target[idx, idx]loss_h np.log(1 np.exp(-target_i * inputs_i))print(loss_h)
nn.MultiLabelSoftMarginLoss 1C是样本个数取平均。i是神经元个数。 2标签y[i]只能是01。 3当i是标签神经元时y[i]1只需要计算前一项因为后一项1-y[i]0。反之当i不是标签神经元时y[i]0只需要计算后一项因为前一项为0。
nn.MultiLabelSoftMarginLoss(weightNone, size_averageNone, reduceNone, reductionmean)softMarginLoss多标签版本weight:各类别loss设置权值# ---------------------------------------------- 13 MultiLabel SoftMargin Loss -----------------------------------------
flag 0
# flag 1
if flag:inputs torch.tensor([[0.3, 0.7, 0.8]]) #三分类任务target torch.tensor([[0, 1, 1]], dtypetorch.float)#即属于1类也属于2类不属于0类loss_f nn.MultiLabelSoftMarginLoss(reductionnone)loss loss_f(inputs, target)print(MultiLabel SoftMargin: , loss) #输出0.5429# --------------------------------- compute by hand
flag 0
# flag 1
if flag:#第1个元素的标签为0只需要计算后一项。i_0 torch.log(torch.exp(-inputs[0, 0]) / (1 torch.exp(-inputs[0, 0])))#第2个元素的标签为1只需要计算前一项。i_1 torch.log(1 / (1 torch.exp(-inputs[0, 1])))#第3个元素的标签为1只需要计算前一项。i_2 torch.log(1 / (1 torch.exp(-inputs[0, 2])))loss_h (i_0 i_1 i_2) / -3print(loss_h) #输出0.5429
nn.MultiMarginLoss x[y]是标签所在神经元的输出值x[i]是非标签所在神经元的输出值。
nn.MultiMarginLoss(p1, margin1.0, weightNone, size_averageNone, reduceNone, reductionmean)计算多分类折页损失p可选1或2
margin 边界值
weight 各类别设置loss权值# ---------------------------------------------- 14 Multi Margin Loss -----------------------------------------
flag 0
# flag 1
if flag:x torch.tensor([[0.1, 0.2, 0.7], [0.2, 0.5, 0.3]])#在本损失函数的公式设定中#第一个标签1对应x中第一个样本第1个元素从第0个元素开始数0.2#第二个标签2对应x中第二个样本第2个元素从第0个元素开始数0.3y torch.tensor([1, 2], dtypetorch.long) loss_f nn.MultiMarginLoss(reductionnone)loss loss_f(x, y)print(Multi Margin Loss: , loss) #输出[0.8000, 0.7000]# --------------------------------- compute by hand
flag 0
# flag 1
if flag:x x[0] #取出第一个样本 所以后面减去的神经元不能是x[1]margin 1i_0 margin - (x[1] - x[0])# i_1 margin - (x[1] - x[1])i_2 margin - (x[1] - x[2])loss_h (i_0 i_2) / x.shape[0] #shape类别数3print(loss_h) #输出0.8000
nn.TripletMarginLoss
三元组定义为 希望通过学习之后使得anchor与positive的距离比anchor到negative的距离小这里放在人脸识别中则anchor是当前样本positive 这个样本真实对应的人脸negative其他人脸 第二个公式指的是用p范数默认用2范数
nn.TripletMarginLoss(margin1.0, p2.0, eps1e-06, swapFalse, size_averageNone, reduceNone, reductionmean)计算三元组损失常用于人脸验证p范数的阶默认2
margin边界值# ---------------------------------------------- 15 Triplet Margin Loss -----------------------------------------
flag 0
# flag 1
if flag:anchor torch.tensor([[1.]])pos torch.tensor([[2.]])neg torch.tensor([[0.5]])loss_f nn.TripletMarginLoss(margin1.0, p1)loss loss_f(anchor, pos, neg)print(Triplet Margin Loss, loss) #2-1-1-0.51 1.5#输出1.5000# --------------------------------- compute by hand
flag 0
# flag 1
if flag:margin 1a, p, n anchor[0], pos[0], neg[0]d_ap torch.abs(a-p)d_an torch.abs(a-n)loss d_ap - d_an marginprint(loss)
nn.HingeEmbeddingLoss ▲表示margin。
nn.HingeEmbeddingLoss(margin1.0, size_averageNone, reduceNone, reductionmean)计算两个输入的相似性常用于非线性embedding和半监督学习输入x应为两个输入之差的绝对值# ---------------------------------------------- 16 Hinge Embedding Loss -----------------------------------------
flag 0
# flag 1
if flag:inputs torch.tensor([[1., 0.8, 0.5]])target torch.tensor([[1, 1, -1]])loss_f nn.HingeEmbeddingLoss(margin1, reductionnone)loss loss_f(inputs, target)print(Hinge Embedding Loss, loss)#输出[1.0000, 0.8000, 0.5000]# --------------------------------- compute by hand
flag 0
# flag 1
if flag:margin 1.loss max(0, margin - inputs.numpy()[0, 2])print(loss)
nn.CosineEmbeddingLoss nn.CosineEmbeddingLoss(margin0.0, size_averageNone, reduceNone, reductionmean)利用余弦相似度计算两个输入相似性利用cos是关注方向上的差异
margin 取值范围[-1,1] 推荐为[0,0.5]# ---------------------------------------------- 17 Cosine Embedding Loss -----------------------------------------
flag 0
# flag 1
if flag:x1 torch.tensor([[0.3, 0.5, 0.7], [0.3, 0.5, 0.7]])x2 torch.tensor([[0.1, 0.3, 0.5], [0.1, 0.3, 0.5]])target torch.tensor([[1, -1]], dtypetorch.float)loss_f nn.CosineEmbeddingLoss(margin0., reductionnone)loss loss_f(x1, x2, target)print(Cosine Embedding Loss, loss)# 输出[0.0167, 0.9833]# --------------------------------- compute by hand
flag 0
# flag 1
if flag:margin 0.def cosine(a, b):numerator torch.dot(a, b) # 分子是点积denominator torch.norm(a, 2) * torch.norm(b, 2) #分母是模长相乘return float(numerator/denominator)l_1 1 - (cosine(x1[0], x2[0]))l_2 max(0, cosine(x1[1], x2[1]))print(l_1, l_2)# 输出0.0167 0.9833
nn.CTCLoss
原理后续补充。
nn.CTCLoss(blank0, reductionmean, zero_infinityFalse)计算CTC损失解决时序类数据的分类 connectionist temporal classification
blank:blank label
zero_infinity:无穷大的值或梯度置0例如OCR中输入输出不确定的情况怎么计算分类就要用到这个# ---------------------------------------------- 18 CTC Loss -----------------------------------------
# flag 0
flag 1
if flag:T 50 # Input sequence lengthC 20 # Number of classes (including blank)N 16 # Batch sizeS 30 # Target sequence length of longest target in batchS_min 10 # Minimum target length, for demonstration purposes# Initialize random batch of input vectors, for *size (T,N,C)inputs torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()# Initialize random batch of targets (0 blank, 1:C classes)target torch.randint(low1, highC, size(N, S), dtypetorch.long)input_lengths torch.full(size(N,), fill_valueT, dtypetorch.long)target_lengths torch.randint(lowS_min, highS, size(N,), dtypetorch.long)ctc_loss nn.CTCLoss()loss ctc_loss(inputs, target, input_lengths, target_lengths)print(CTC loss: , loss) #输出7.5385
设置损失函数超参数
选择损失函数
优化器(共10个)
由损失函数得到loss经由模型参数自动求导得到梯度优化器根据优化策略根据梯度更新模型中可学习参数的值使得loss往下降的方向走即使模型输出接近真实标签。
梯度是一个向量方向为方向导数取得最大值的方向。故沿着梯度方向是增长最快的那么沿着梯度负方向是下降最快的。
学习率控制学习更新步伐防止梯度爆炸【通常设置学习率为0.01】
动量momentum结合当前梯度和上一次更新信息用于当前更新可以看成一个惯性减少迭代次数加速迭代收敛。利用指数加权平均时间序列中离得越近的参数参考性越大权重越大。 指数加权平均v_tp*v_t-1 (1-p)*θt beta类似于记忆周期beta越小记忆周期越短。比如beta0.8到第20天左右就记不住了而beta0.98可以记忆到80天左右。 上述图中蓝色图像明显先达到了minimum但又不断迂回缓冲这是因为 momentum较大而且受到之前迭代的大梯度值的影响。 合适的动量之一可以发现蓝色早于黄色先收敛到最小值。
# -*- coding:utf-8 -*-file name : momentum.py
brief : 梯度下降的动量 momentumimport torch
import numpy as np
import torch.optim as optim
import matplotlib.pyplot as plt
torch.manual_seed(1)def exp_w_func(beta, time_list):return [(1 - beta) * np.power(beta, exp) for exp in time_list]
# np.power(beta, exp) 即 beta**expbeta 0.9
num_point 100
time_list np.arange(num_point).tolist() #创建time list# ------------------------------ exponential weight ------------------------------
flag 0
# flag 1
if flag:weights exp_w_func(beta, time_list)plt.plot(time_list, weights, -ro, labelBeta: {}\ny B^t * (1-B).format(beta))plt.xlabel(time)plt.ylabel(weight)plt.legend()plt.title(exponentially weighted average)plt.show()print(np.sum(weights))# ------------------------------ multi weights ------------------------------
flag 0
# flag 1
if flag:beta_list [0.98, 0.95, 0.9, 0.8]w_list [exp_w_func(beta, time_list) for beta in beta_list]for i, w in enumerate(w_list):plt.plot(time_list, w, labelBeta: {}.format(beta_list[i]))plt.xlabel(time)plt.ylabel(weight)plt.legend()plt.show()# ------------------------------ SGD momentum ------------------------------
# flag 0
flag 1
if flag:def func(x):return torch.pow(2*x, 2) # y (2x)^2 4*x^2 dy/dx 8xiteration 100m 0.9 # .9 .63 可以修改不同的momentum去看效果图lr_list [0.01, 0.03]momentum_list list()loss_rec [[] for l in range(len(lr_list))]iter_rec list()for i, lr in enumerate(lr_list):x torch.tensor([2.], requires_gradTrue)momentum 0. if lr 0.03 else mmomentum_list.append(momentum)optimizer optim.SGD([x], lrlr, momentummomentum)for iter in range(iteration):y func(x)y.backward()optimizer.step()optimizer.zero_grad()loss_rec[i].append(y.item())for i, loss_r in enumerate(loss_rec):plt.plot(range(len(loss_r)), loss_r, labelLR: {} M:{}.format(lr_list[i], momentum_list[i]))plt.legend()plt.xlabel(Iterations)plt.ylabel(Loss value)plt.show()
class Optimizer(object):def __init__(self,params,defaults):self.defaultsdefaults self.statedefaultdict(dict)self.param_groups[]...param_groups[{params:param_groups}]defaults:优化器超参数
state:参数缓存如momentum缓存
param_groups:管理的参数组是一个list其中是dict键值对value才是参数内容
_step_count:记录更新次数学习率调整中使用优化器最基本的5个方法
zero_grad()#清空所管理参数的梯度
#pytorch中张量梯度不会自动清零每次反向传播时计算的梯度是叠加的
step() #执行一次更新反向传播后根据优化方法更新参数
add_param_group()#添加参数组在优化器中可以不同阶段设置不同参数组如设置不同的学习率
state_dict()#获取优化器当前状态信息字典
load_state_dict()#加载状态信息字典 可以用于重新从一个state_dict状态开始训练# -*- coding: utf-8 -*-# file name : optimizer_methods.py
# brief : optimizers methodsimport os
BASE_DIR os.path.dirname(os.path.abspath(__file__))
import torch
import torch.optim as optim
from tools.common_tools import set_seedset_seed(1) # 设置随机种子weight torch.randn((2, 2), requires_gradTrue) # 创建2*2的weight
weight.grad torch.ones((2, 2)) # 权值梯度设为1optimizer optim.SGD([weight], lr0.1)# ----------------------------------- step -----------------------------------
flag 0
# flag 1
if flag:print(weight before step:{}.format(weight.data))#输出[[0.6614, 0.2669], [0.0617, 0.6213]]optimizer.step() print(weight after step:{}.format(weight.data)) #输出[[0.5614, 0.1669], [-0.0383, 0.5213]]#0.5614 0.6614 - weight.grad (1) * lr (0.1)0.6614-0.1其余同理减去0.1# ----------------------------------- zero_grad -----------------------------------
flag 0
# flag 1
if flag:print(weight before step:{}.format(weight.data))optimizer.step() # 修改lr1 0.1观察结果print(weight after step:{}.format(weight.data))print(weight in optimizer:{}\nweight in weight:{}\n.format(id(optimizer.param_groups[0][params][0]), id(weight))) #输出一致#优化器中管理参数的内存地址和weight的内存地址一致节省内存空间print(weight.grad is {}\n.format(weight.grad)) #输出[[1., 1.], [1., 1.]]optimizer.zero_grad()print(after optimizer.zero_grad(), weight.grad is\n{}.format(weight.grad)) #输出[[0., 0.], [0., 0.]]# ----------------------------------- add_param_group -----------------------------------
flag 0
# flag 1
if flag:print(optimizer.param_groups is\n{}.format(optimizer.param_groups))w2 torch.randn((3, 3), requires_gradTrue)optimizer.add_param_group({params: w2, lr: 0.0001}) #添加一组超参数print(optimizer.param_groups is\n{}.format(optimizer.param_groups)) #有两组超参数# ----------------------------------- state_dict -----------------------------------
flag 0
# flag 1
if flag:optimizer optim.SGD([weight], lr0.1, momentum0.9)opt_state_dict optimizer.state_dict()print(state_dict before step:\n, opt_state_dict)for i in range(10):optimizer.step()print(state_dict after step:\n, optimizer.state_dict())#打印可以发现state中的key就是这个param的id地址torch.save(optimizer.state_dict(), os.path.join(BASE_DIR, optimizer_state_dict.pkl))#保存这个状态# -----------------------------------load state_dict -----------------------------------
flag 0
# flag 1
if flag:
#使用场景比如说之前已经训练了100次接着它的结果继续训练optimizer optim.SGD([weight], lr0.1, momentum0.9)state_dict torch.load(os.path.join(BASE_DIR, optimizer_state_dict.pkl))print(state_dict before load state:\n, optimizer.state_dict())optimizer.load_state_dict(state_dict)print(state_dict after load state:\n, optimizer.state_dict())
optim.SGD 随机梯度下降法
注意事项 pytroch中使用SGD十分需要注意的是更新公式与其他框架略有不同 pytorch中是这样的 vρ∗vg pp−lr∗v p - lr∗ρ∗v - lr∗g 其他框架 vρ∗vlr∗g pp−v p - ρ∗v - lr∗g ρ是动量v是速率g是梯度p是参数其实差别就是在ρ∗v这一项pytorch中将此项也乘了一个学习率。
torch.optim.SGD(params, lrrequired parameter, momentum0, dampening0, weight_decay0, nesterovFalse)params必须参数: 这是一个包含了需要优化的参数张量的迭代器例如模型的参数 model.parameters()。lr必须参数: 学习率learning rate。它是一个正数控制每次参数更新的步长。较小的学习率会导致收敛较慢较大的学习率可能导致震荡或无法收敛。momentum默认值为 0: 动量momentum是一个用于加速 SGD 收敛的参数。它引入了上一步梯度的指数加权平均。通常设置在 0 到 1 之间。当 momentum 大于 0 时算法在更新时会考虑之前的梯度有助于加速收敛。weight_decay默认值为 0: 权重衰减也称为 L2 正则化项。它用于控制参数的幅度以防止过拟合。通常设置为一个小的正数。nesterov默认值为 False: 是否采用NAG。Nesterov 动量。当设置为 True 时采用 Nesterov 动量更新规则。Nesterov 动量在梯度更新之前先进行一次预测然后在计算梯度更新时使用这个预测。torch.optim.ASGD 随机平均梯度下降
torch.optim.ASGD(params, lr0.01, lambd0.0001, alpha0.75, t01000000.0, weight_decay0)功能
ASGD也成为SAG均表示随机平均梯度下降(Averaged Stochastic Gradient Descent)简单地说ASGD就是用空间换时间的一种SGD详细可参看论文http://riejohnson.com/rie/stograd_nips.pdf
参数:
params(iterable)- 参数组(参数组的概念请查看 3.1 优化器基类Optimizer)优化器要优化的那些参数。
lr(float)- 初始学习率可按需随着训练过程不断调整学习率。
lambd(float)- 衰减项默认值1e-4。
alpha(float)- power for eta update 默认值0.75。
t0(float)- point at which to start averaging默认值1e6。
weight_decay(float)- 权值衰减系数也就是L2正则项的系数。torch.optim.Rprop 弹性反向传播
torch.optim.Rprop(params, lr0.01, etas(0.5, 1.2), step_sizes(1e-06, 50))功能
实现Rprop优化方法(弹性反向传播)优化方法原文《Martin Riedmiller und Heinrich Braun: Rprop - A Fast Adaptive Learning Algorithm. Proceedings of the International Symposium on Computer and Information Science VII, 1992》
该优化方法适用于full-batch不适用于mini-batch因而在min-batch大行其道的时代里很少见到。torch.optim.Adagrad 自适应学习率梯度下降法
torch.optim.Adagrad(params, lr0.01, lr_decay0, weight_decay0, initial_accumulator_value0)功能
实现Adagrad优化方法(Adaptive Gradient)Adagrad是一种自适应优化方法是自适应的为各个参数分配不同的学习率。这个学习率的变化会受到梯度的大小和迭代次数的影响。梯度越大学习率越小梯度越小学习率越大。缺点是训练后期学习率过小因为Adagrad累加之前所有的梯度平方作为分母。
详细公式请阅读Adaptive Subgradient Methods for Online Learning and Stochastic Optimization
John Duchi, Elad Hazan, Yoram Singer; 12(Jul):2121−2159, 2011.(http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)torch.optim.AdadeltaAdagrad的改进
torch.optim.Adadelta(params, lr1.0, rho0.9, eps1e-06, weight_decay0)功能
实现Adadelta优化方法。Adadelta是Adagrad的改进。Adadelta分母中采用距离当前时间点比较近的累计项这可以避免在训练后期学习率过小。
详细公式请阅读:https://arxiv.org/pdf/1212.5701.pdftorch.optim.RMSpropAdagrad的改进
torch.optim.RMSprop(params, lr0.01, alpha0.99, eps1e-08, weight_decay0, momentum0, centeredFalse)功能
实现RMSprop优化方法Hinton提出RMS是均方根root meam square的意思。RMSprop和Adadelta一样也是对Adagrad的一种改进。RMSprop采用均方根作为分母可缓解Adagrad学习率下降较快的问题。并且引入均方根可以减少摆动详细了解可读http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdftorch.optim.Adam(AMSGrad)RMSprop结合Momentum
torch.optim.Adam(params, lr0.001, betas(0.9, 0.999), eps1e-08, weight_decay0, amsgradFalse)功能
实现Adam(Adaptive Moment Estimation))优化方法。Adam是一种自适应学习率的优化方法Adam利用梯度的一阶矩估计和二阶矩估计动态的调整学习率。吴老师课上说过Adam是结合了Momentum和RMSprop并进行了偏差修正。
参数
amsgrad- 是否采用AMSGrad优化方法asmgrad优化方法是针对Adam的改进通过添加额外的约束使学习率始终为正值。(AMSGradICLR-2018 Best-Pper之一《On the convergence of Adam and Beyond》)。
详细了解Adam可阅读,Adam: A Method for Stochastic Optimization(https://arxiv.org/abs/1412.6980)。torch.optim.Adamax: Adam增加学习率上限
torch.optim.Adamax(params, lr0.002, betas(0.9, 0.999), eps1e-08, weight_decay0)功能
实现Adamax优化方法。Adamax是对Adam增加了一个学习率上限的概念所以也称之为Adamax。
详细了解可阅读Adam: A Method for Stochastic Optimization(https://arxiv.org/abs/1412.6980)(没错就是Adam论文中提出了Adamax)。torch.optim.SparseAdam稀疏版Adam
torch.optim.SparseAdam(params, lr0.001, betas(0.9, 0.999), eps1e-08)功能
针对稀疏张量的一种“阉割版”Adam优化方法。
only moments that show up in the gradient get updated, and only those portions of the gradient get applied to the parameterstorch.optim.LBFGS:BFGS的改进
torch.optim.LBFGS(params, lr1, max_iter20, max_evalNone, tolerance_grad1e-05, tolerance_change1e-09, history_size100, line_search_fnNone)功能
实现L-BFGSLimited-memory Broyden–Fletcher–Goldfarb–Shanno优化方法。L-BFGS属于拟牛顿算法。L-BFGS是对BFGS的改进特点就是节省内存。
使用注意事项
1.This optimizer doesn’t support per-parameter options and parameter groups (there can be only one).
Right now all parameters have to be on a single device. This will be improved in the future.(2018-10-07)优化算法
对于几种优化算法具体选择原则 经验先Adam自适应训练更快但精度不一定比SGD高,SGD最多
梯度下降法
当学习率learning rate1时 w_i1w_i -g(w_i) w_i指第i次迭代时的参数g(w_i)指的是它所对应的梯度。
下面的代码展示了如何发生梯度爆炸。 所以这就是引入学习率的重要性此时LR可以控制更新步伐 梯度下降公式扩展成 w_i1w_i -LR*g(w_i)【通常设置学习率为0.01】
当LR设置成0.2时明显发现loss是逐渐下降的。
# -*- coding:utf-8 -*-file name : learning_rate.py
brief : 梯度下降的学习率演示import torch
import numpy as np
import matplotlib.pyplot as plt
torch.manual_seed(1)def func(x_t):y (2x)^2 4*x^2 dy/dx 8xreturn torch.pow(2*x_t, 2)# init
x torch.tensor([2.], requires_gradTrue)# ------------------------------ plot data ------------------------------
flag 0
# flag 1
if flag:
#画出func所示的笛卡尔坐标系x-y 曲线图x_t torch.linspace(-3, 3, 100)y func(x_t)plt.plot(x_t.numpy(), y.numpy(), labely 4*x^2)plt.grid()plt.xlabel(x)plt.ylabel(y)plt.legend()plt.show()# ------------------------------ gradient descent ------------------------------
flag 0
# flag 1
if flag:iter_rec, loss_rec, x_rec list(), list(), list()lr 0.01 # /1. /.5 /.2 /.1 /.125max_iteration 20 # /1. 4 /.5 4 /.2 20 200for i in range(max_iteration):y func(x)y.backward()#求取到x的梯度print(Iter:{}, X:{:8}, X.grad:{:8}, loss:{:10}.format(i, x.detach().numpy()[0], x.grad.detach().numpy()[0], y.item()))x_rec.append(x.item())x.data.sub_(lr * x.grad) # x - lr * x.grad 数学表达式意义: x x - lr * x.grad # x是一个张量0.5 0.2 0.1 0.125x.grad.zero_()#清0 防止累加iter_rec.append(i)loss_rec.append(y)plt.subplot(121).plot(iter_rec, loss_rec, -ro)plt.xlabel(Iteration)plt.ylabel(Loss value)x_t torch.linspace(-3, 3, 100)y func(x_t)plt.subplot(122).plot(x_t.numpy(), y.numpy(), labely 4*x^2)plt.grid()y_rec [func(torch.tensor(i)).item() for i in x_rec]plt.subplot(122).plot(x_rec, y_rec, -ro)plt.legend()plt.show()
#造成梯度爆炸# ------------------------------ multi learning rate ------------------------------# flag 0
flag 1
if flag:iteration 100num_lr 10lr_min, lr_max 0.01, 0.2 # .5 .3 .2lr_list np.linspace(lr_min, lr_max, numnum_lr).tolist()loss_rec [[] for l in range(len(lr_list))]iter_rec list()for i, lr in enumerate(lr_list):x torch.tensor([2.], requires_gradTrue)for iter in range(iteration):y func(x)y.backward()x.data.sub_(lr * x.grad) # x.data - x.gradx.grad.zero_()loss_rec[i].append(y.item())for i, loss_r in enumerate(loss_rec):plt.plot(range(len(loss_r)), loss_r, labelLR: {}.format(lr_list[i]))plt.legend()plt.xlabel(Iterations)plt.ylabel(Loss value)plt.show()
管理模型参数
管理多个参数组实现不同学习率
调整学习率
迭代训练
观察训练效果
绘制loss/accuracy曲线
用TensorBoard分析
模型应用
图像分类
图像分割
目标检测
对抗生成
循环网络