pytorch 权值初始化与损失函数
梯度爆炸和梯度消失
为什么会产生以上问题
若,
每一次传递就会变为原来的N倍,batch_size的大小,梯度爆炸,要避免这个问题
增加激活函数后,权重越来越小,会出现梯度消失的问题
方差一致性:保持数据尺度维持在恰当范围,通常方差为1
饱和函数,如sigmod ,Tanh
通常采用均匀分布,~
得出
对于非饱和函数 ,等变种
变种,在负半轴有斜率的
tanh_gain = nn.init.calculate_gain('tanh')
nn.init.xavier_uniform_(m.weight.data, gain=tanh_gain)
# 以上方法只适应于饱和激活函数,并不适合reLU
# relu 等变种激活函数
nn.init.kaiming_normal_(m.weight.data)
损失函数
单个样本叫损失,一般用这个
计算整个样本集损失平均值
目标函数,正则项
pytorch中的损失继承nn.Module 主要是redaction none :每个神经元进行操作,sum average
1.nn.CrossEntropyLoss()
交叉熵损失函数
这个是nn.LogSoftmax() nn.NLLLoss()两个函数计算的
衡量两个概率分布的差异,信息熵,相对熵
交叉熵 = 信息熵 + 相对熵 (熵表示一个信息的不确定性)
自信息
熵:
相对熵: 散度
交叉熵:
所以越小越好
inputs = torch.tensor([[1, 2], [1, 3], [1, 3]], dtype=torch.float)
target = torch.tensor([0, 1, 1], dtype=torch.long)
# 同target = torch.tensor([[1,0],[0,1],[0,1]], dtype=torch.float)
# 样本3个 标签0 标签从0开始 其实每一个标签都是和样本维度一样输入[x1,x2,x3,x4] 标签[0,1,0,0] 这就是标签是1
# loss函数作为神经网络的最后一层算是,举得例子就是类似最后一层的输出和真实标签的差距,所以target是long类型的,
# 类似与索引
weights = torch.tensor([1, 2], dtype=torch.float) # 负样本权重1 正样本权重2 label1 的样本权重1 label2 的样本权重2# weights = torch.tensor([0.7, 0.3], dtype=torch.float)
loss_f_none_w = nn.CrossEntropyLoss(weight=weights, reduction='none')
loss_f_sum = nn.CrossEntropyLoss(weight=weights, reduction='sum')
loss_f_mean = nn.CrossEntropyLoss(weight=weights, reduction='mean')
#forward
loss_none_w = loss_f_none_w(inputs, target)
loss_sum = loss_f_sum(inputs, target)
loss_mean = loss_f_mean(inputs, target)
#'none':就是每个神经元都进行一对一计算
#'sum':计算出来每个神经元进行相加
#'average':求平均,如果设置了weight,相当于把相应的样本进行拷贝,此例子中就是label1是1个,label2相应的样本增多两个,在计算weight时,把weight加起来
# 输出
tensor([1.3133, 0.2539, 0.2539]) tensor(1.8210) tensor(0.3642)
2.nn.NLLLoss()
取反损失函数
target位置取反
inputs = torch.tensor([[1, 2], [1, 3], [1, 3]], dtype=torch.float)
target = torch.tensor([0, 1, 1], dtype=torch.long)
weights = torch.tensor([1, 1], dtype=torch.float)
loss_f_none_w = nn.NLLLoss(weight=weights, reduction='none')
loss_f_sum = nn.NLLLoss(weight=weights, reduction='sum')
loss_f_mean = nn.NLLLoss(weight=weights, reduction='mean')
# forward
loss_none_w = loss_f_none_w(inputs, target)
#输出:
tensor([-1., -3., -3.]) tensor(-7.) tensor(-2.3333)
3.nn.BCELoss()
二分类交叉熵函数
输入的target与为型
输入样本的各个属性值必须在[0,1],需要使用 sigmod()进行转换
inputs = torch.tensor([[1, 2], [2, 2], [3, 4], [4, 5]], dtype=torch.float)
target = torch.tensor([[1, 0], [1, 0], [0, 1], [0, 1]], dtype=torch.float)
# 每个神经元一一对应计算loss
target_bce = target
# itarget
inputs = torch.sigmoid(inputs)
weights = torch.tensor([1, 1], dtype=torch.float)
loss_f_none_w = nn.BCELoss(weight=weights, reduction='none')
loss_f_sum = nn.BCELoss(weight=weights, reduction='sum')
loss_f_mean = nn.BCELoss(weight=weights, reduction='mean')
#forward 同上
# 输出:
BCE Loss tensor([[0.3133, 2.1269],
[0.1269, 2.1269],
[3.0486, 0.0181],
[4.0181, 0.0067]])
tensor(11.7856) tensor(1.4732)
4.nn.BCEWithLogitsLoss()
结合Sigmod与二分类交叉熵
网络最后不能加sigmod函数,自己带有sigmod的功能
inputs = torch.tensor([[1, 2], [2, 2], [3, 4], [4, 5]], dtype=torch.float)
target = torch.tensor([[1, 0], [1, 0], [0, 1], [0, 1]], dtype=torch.float)
target_bce = target
# itarget
# inputs = torch.sigmoid(inputs)
weights = torch.tensor([1], dtype=torch.float)
pos_w = torch.tensor([3], dtype=torch.float) # 3 正样本*3
# 参数:pos_weight:正样本[0,1]类权值 weight 各类别loss设置权重
loss_f_none_w = nn.BCEWithLogitsLoss(weight=weights, reduction='none', pos_weight=pos_w)
loss_f_sum = nn.BCEWithLogitsLoss(weight=weights, reduction='sum', pos_weight=pos_w)
loss_f_mean = nn.BCEWithLogitsLoss(weight=weights, reduction='mean', pos_weight=pos_w)
# forward
loss_none_w = loss_f_none_w(inputs, target_bce)
#输出
weights: tensor([1., 1.])
BCE Loss tensor([[0.3133, 2.1269],
[0.1269, 2.1269],
[3.0486, 0.0181],
[4.0181, 0.0067]]) tensor(11.7856) tensor(1.4732)
pos_weights: tensor([3.])
tensor([[0.9398, 2.1269],
[0.3808, 2.1269],
[3.0486, 0.0544],
[4.0181, 0.0201]]) tensor(12.7158) tensor(1.5895)
5.nn.L1Loss ()
计算inputs和target之差的绝对值
inputs = torch.ones((2, 2))
target = torch.ones((2, 2)) * 3
loss_f = nn.L1Loss(reduction='none')
loss = loss_f(inputs, target)
#输出:
input:tensor([[1., 1.],
[1., 1.]])
target:tensor([[3., 3.],
[3., 3.]])
L1 loss:tensor([[2., 2.],
[2., 2.]])
6.nn.MSELoss()
计算inputs与target之差的平方
reduction:计算模式,可为none/sum/mean
inputs = torch.ones((2, 2))
target = torch.ones((2, 2)) * 3
loss_f_mse = nn.MSELoss(reduction='none')
loss_mse = loss_f_mse(inputs, target)
MSE loss:tensor([[4., 4.],[4., 4.]])
7.nn.SmoothL1Loss()
平滑的L1Loss,
在底端更加平滑
inputs = torch.linspace(-3, 3, steps=500)
target = torch.zeros_like(inputs)
loss_f = nn.SmoothL1Loss(reduction='none')
loss_smooth = loss_f(inputs, target)
loss_l1 = np.abs(inputs.numpy())
8.nn.PoissonNLLLoss()
泊松分布(二项分布)的负数对数似然损失函数
log_input:输入是否为对数形式,决定计算公式
full:计算所有loss,默认false
eps:修正项,避免
inputs = torch.randn((2, 2))
target = torch.randn((2, 2))
loss_f = nn.PoissonNLLLoss(log_input=True, full=False, reduction='none')
loss = loss_f(inputs, target)
print("input:{}\ntarget:{}\nPoisson NLL loss:{}".format(inputs, target, loss))
#输出:
input:tensor([[0.6614, 0.2669],[0.0617, 0.6213]])
target:tensor([[-0.4519, -0.1661],[-1.5228, 0.3817]])
Poisson NLL loss:tensor([[2.2363, 1.3503],[1.1575, 1.6242]])
idx = 0
loss_1 = torch.exp(inputs[idx, idx]) - target[idx, idx]*inputs[idx, idx]
9.nn.KLDivLoss()
KL散度,相对熵,计算两个分布的相似度
此函数中计算
这个时候的已经是概率分布了(目标概率分布),就是 是第一类的概率为0.9 第二类0.0. 第三类0.05,[0.9,0.05,0.05],是经过多层神经元输出的一个概率分布[0.8,0.1,0.1]
上公式解释:对一个样本计算去掉,需要先计算一个,或使用nn.logsoftmax(),处理多分类时的概率分布
batchmean:batchsize维度求平均值
inputs = torch.tensor([[0.5, 0.3, 0.2], [0.2, 0.3, 0.5]]) ##这是个分布
inputs_log = torch.log(inputs)
target = torch.tensor([[0.9, 0.05, 0.05], [0.1, 0.7, 0.2]], dtype=torch.float)
loss_f_none = nn.KLDivLoss(reduction='none')
loss_f_mean = nn.KLDivLoss(reduction='mean')
loss_f_bs_mean = nn.KLDivLoss(reduction='batchmean')
loss_none = loss_f_none(inputs, target)
loss_mean = loss_f_mean(inputs, target)
loss_bs_mean = loss_f_bs_mean(inputs, target)
print("loss_none:\n{}\nloss_mean:\n{}\nloss_bs_mean:\n{}".format(loss_none, loss_mean, loss_bs_mean))
#输出:
loss_none:tensor([[-0.5448, -0.1648, -0.1598],[-0.2503, -0.4597, -0.4219]])
warnings.warn("reduction: 'mean' divides the total loss by both the batch size and the support size."
loss_mean:-0.3335360586643219
loss_bs_mean:-1.000608205795288
idx = 0
loss_1 = target[idx, idx] * (torch.log(target[idx, idx]) - inputs[idx, idx])
10.nn.MarginRankingLoss()
两个N维向量之间的相似度,用于排序任务,该方法计算两组数据之间的差异,返回一个的Loss矩阵
y=1,希望x1比x2大,当x1>x2时,不产生loss
y=-1,希望x1比x2小,当x2>x1时,不产生loss
margin :边界值
reduction:计算模式
x1 = torch.tensor([[1], [2], [3]], dtype=torch.float)
x2 = torch.tensor([[2], [2], [2]], dtype=torch.float)
target = torch.tensor([1, 1, -1], dtype=torch.float) #这是y
loss_f_none = nn.MarginRankingLoss(margin=0, reduction='none')
loss = loss_f_none(x1, x2, target)
# y=-1 x1[2]=3 3-2 3-2 3-2 1 1 -1 --->0 0 1
#输出:
loss:tensor([[1., 1., 0.],
[0., 0., 0.],
[0., 0., 1.]])
11.nn.MultiLabelMarginLoss()
多标签边界损失函数,多标签:一个样本有多个标签,比如一张图片对应多个类别
举例:四分类任务,样本x属于0类和3类,标签,不是
其中,
公式含义是标签所在神经元减去不是标签所在的神经元,
只有标签所在神经元大于不是标签所在的神经元的值小于1时,两类差越大越好,才有意义
x = torch.tensor([[0.1, 0.2, 0.4, 0.8]])
y = torch.tensor([[0, 3, -1, -1]], dtype=torch.long) #样本属于第0类和第3类,数据为long类型
loss_f = nn.MultiLabelMarginLoss(reduction='none')
loss = loss_f(x, y)
#输出:
tensor([0.8500])
# 计算步骤
x = x[0]
item_1 = (1-(x[0] - x[1])) + (1 - (x[0] - x[2])) # [0]
item_2 = (1-(x[3] - x[1])) + (1 - (x[3] - x[2])) # [3]
loss_h = (item_1 + item_2) / x.shape[0]
12.nn.SoftMarginLoss()
二分类logistic损失
是平均值,
inputs = torch.tensor([[0.3, 0.7], [0.5, 0.5]])
target = torch.tensor([[-1, 1], [1, -1]], dtype=torch.float)
loss_f = nn.SoftMarginLoss(reduction='none')
loss = loss_f(inputs, target)
#输出:
SoftMargin: tensor([[0.8544, 0.4032],[0.4741, 0.9741]])
idx = 0
inputs_i = inputs[idx, idx]
target_i = target[idx, idx]
loss_h = np.log(1 + np.exp(-target_i * inputs_i))
#输出:tensor(0.8544)
13.nn.MultiLabelSoftMarginLoss()
的多标签版本
是类别数量
假设4分类,取值,属于第1类和第4类,这个和多标签边界损失函数标签不一样
inputs = torch.tensor([[0.3, 0.7, 0.8]])
target = torch.tensor([[0, 1, 1]], dtype=torch.float) #标签是float型
loss_f = nn.MultiLabelSoftMarginLoss(reduction='none')
loss = loss_f(inputs, target)
#输出:MultiLabel SoftMargin: tensor([0.5429])
#手算
i_0 = torch.log(torch.exp(-inputs[0, 0]) / (1 + torch.exp(-inputs[0, 0])))
i_1 = torch.log(1 / (1 + torch.exp(-inputs[0, 1])))
i_2 = torch.log(1 / (1 + torch.exp(-inputs[0, 2])))
loss_h = (i_0 + i_1 + i_2) / -3
14.nn.MultiMarginLoss()
计算多分类的折页损失
y取值为类型,表示第1个样本为第1类,第2个样本为第2类,第3个样本为第1类
标签值减去非标签的值,不能等于标签所在项
主要参数:weight 各类别的loss设置权重,margin边界值,默认1,p:可选1或者2,默认1
x = torch.tensor([[0.1, 0.2, 0.7], [0.2, 0.5, 0.3]])
y = torch.tensor([1, 2], dtype=torch.long) #label类型为long
loss_f = nn.MultiMarginLoss(reduction='none')
loss = loss_f(x, y)
#输出:Multi Margin Loss: tensor([0.8000, 0.7000])
x = x[0]
margin = 1
i_0 = margin - (x[1] - x[0])
#i_1 = margin - (x[1] - x[1]) #0
i_2 = margin - (x[1] - x[2])
loss_h = (i_0 + i_2) / x.shape[0]
print(loss_h) #tensor(0.8000)
15.nn.TripletMarginLoss()
三元组损失,人脸识别中常用
计算点与点之间的距离,之间的距离要比之间的距离小,anchor是自己的头像,pos是自己的头像,neg是别人的头像
anchor = torch.tensor([[1.]])
pos = torch.tensor([[2.]])
neg = torch.tensor([[0.5]])
loss_f = nn.TripletMarginLoss(margin=1.0, p=1)
loss = loss_f(anchor, pos, neg)
#输出:Triplet Margin Loss tensor(1.5000)
margin = 1
a, 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 + margin
16.nn.HingeEmbeddingLoss()
计算两个输入的相似性,常用于非线性嵌入和半监督学习,输入x应该是两个输入之差的绝对值
inputs = torch.tensor([[1., 0.8, 0.5]])
target = torch.tensor([[1, 1, -1]]) #int型
loss_f = nn.HingeEmbeddingLoss(margin=1, reduction='none')
loss = loss_f(inputs, target)
# Hinge Embedding Loss tensor([[1.0000, 0.8000, 0.5000]])
margin = 1.
loss = max(0, margin - inputs.numpy()[0, 2])
print(loss) #0.5
17.nn.CosineEmbeddingLoss()
采用余弦相似度计算两个输入的相似性,embading中使用,计算方向上的差异
margin取值,推荐取值
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]], dtype=torch.float)
loss_f = nn.CosineEmbeddingLoss(margin=0., reduction='none')
loss = loss_f(x1, x2, target)
print("Cosine Embedding Loss", loss)
#Cosine Embedding Loss tensor([[0.0167, 0.9833]])
margin = 0.
def cosine(a, b):
numerator = torch.dot(a, b)
denominator = torch.norm(a, 2) * torch.norm(b, 2)
return float(numerator/denominator)
#norm 函数就是求范数,默认是2,就是求向量的模
l_1 = 1 - (cosine(x1[0], x2[0]))
l_2 = max(0, cosine(x1[0], x2[0]))
print(l_1, l_2)
18.nn.CTCLoss()
时序类数据分类