机器学习中的各种损失函数解析:若博文有不妥之处,望加以指点,笔者一定及时修正。
损失函数:计算一个样本的误差;
代价函数:整个训练集上所有样本误差的平均;
目标函数:代价函数+正则化项
方差:衡量随机变量或者一组数据的离散程度。方差越大,数据越离散。
标准差:方差的算术平方根,反映组类个体之间的离散程度。
S o f t m a x Softmax Softmax :将特征图扁平化后的输出映射到(0,1)之间,给出每个类的概率。假设最后一层特征图尺度是: 5 ∗ 5 ∗ 1000 5*5*1000 5∗5∗1000 。再将这些特征输入给扁平化 为 [ N N N X 1 1 1] 个向量(这里的 N N N 是 5 ∗ 5 ∗ 1000 = 25000 5*5*1000=25000 5∗5∗1000=25000)。下面扁平化的 [ N N N X 1 1 1] 的向量进入全连接层,全连接层的参数权重是 W W W[ T T T X N N N](这里的 T T T 表示分类的类别数),经过全连接层处理就会得到一个 [ T T T x 1 1 1] 的向量,但是这个向量里面都每个数值的大小都没有限制,或许是无穷大,也有可能是无穷小,均有可能。因此多分类时候,往往在全连接层后面接个 S o f t m a x Softmax Softmax 层。这个层的输入是 [ T T T x 1 1 1] 的向量,输出也是 [ T T T x 1 1 1] 的向量。但是输出的每个向量都归一化到 [ 0 , 1 ] [0,1] [0,1] 之间。这里的 S o f t m a x Softmax Softmax 输出的向量是该样本属于每一类的概率。
S o f t m a x Softmax Softmax公式:
P j = e a j ∑ k = 1 T e a k P_j=\frac{e^{a_j}}{\sum_{k=1}^{T}{e}^{a_k}} Pj=∑k=1Teakeaj
上面公式中的 a j a_j aj 表示这 [ T T T x 1 1 1] 个向量中的第 j j j 个值,而下面分母表示所有值的求和。上式成功的把 P j P_j Pj 归一化到 ( 0 , 1 ) (0,1) (0,1) 之间。优化目标:属于正确标签的预测概率最高。
下面介绍 S o f t m a x L o s s Softmax \ Loss Softmax Loss:
L = − ∑ j = 1 T y i log p j L=-\sum_{j=1}^{T}{y_i} \ {\log{p_j}} L=−j=1∑Tyi logpj上式中的 p j p_j pj 表示 S o f t m a x Softmax Softmax 层输出的第 j j j 的概率值。 y y y 表示一个 [ 1 1 1 x T T T] 的向量,里面的 T T T 列中只有一个为1,其余为0(真实标签的那个为1,其余不是正确的为0)。这个公式有一个更简单的形式是:
L = − log p j L=-\log p_j L=−logpj其中的 j j j 是指当前样本的真实标签。 l o g log log函数是个递增的函数,你预测错的概率会比你预测对的概率要大,因为前面加了一个负号。
所以分类里面常用 S o f t m a x L o s s Softmax \ Loss Softmax Loss。
p ( x ) p(x) p(x) 为真实分布,根据真实分布 p ( x ) p(x) p(x) 来衡量识别一个样本的所需要的编码长度的期望(平均编码长度)为: H ( p ) = ∑ x p ( x ) log 1 p ( x ) H(p)=\sum_{x}{p(x) \log \frac{1}{p(x)}} H(p)=x∑p(x)logp(x)1 而交叉熵是使用预测的分布来表示来自真实分布的平均编码长度。也就是评估当前训练得到的概率分布与真实分布的差异情况,也就是使用错误分布来表示真实分布的平均编码程度。 H ( p , q ) = − ∑ x p ( x ) log 2 1 q ( x ) H(p,q)=-\sum_x{p(x) \log_2 \frac{1}{q(x)} } H(p,q)=−x∑p(x)log2q(x)1其中 p ( x ) p(x) p(x) 为真实分布, q ( x ) q(x) q(x) 是模型通过数据计算出来分布的概率。
减少交叉熵损失就是在提高模型的准确率。
预测的分布 q ( x ) q(x) q(x)得到的平均编码长度 H ( p , q ) H(p,q) H(p,q) > 真实分布 p ( x ) p(x) p(x)得到的平均编码长度 H ( p ) H(p) H(p)。
我们定义:由 q ( x ) q(x) q(x)得到的平均编码长度比由 p ( x ) p(x) p(x)得到的平均编码长度多出的部分称为 相对熵。
D K L ( p , q ) = H ( p , q ) − H ( p ) = ∑ x p ( x ) log p ( x ) q ( x ) D_{KL}(p,q)=H(p,q)-H(p)=\sum_{x}{p(x)} \log\frac{p(x)}{q(x)} DKL(p,q)=H(p,q)−H(p)=x∑p(x)logq(x)p(x)它表示两个函数或者概率分布的差异性:差异性越大则相对熵越大,反之,差异越小,相对熵越小。这个量来衡量近似分布相比原分布究竟损失了多少信息量,而不是两个分布在空间中的远近距离,所以散度不是距离, D K L ( p , q ) ≠ D K L ( q , p ) D_{KL}(p,q) \ne D_{KL}(q,p) DKL(p,q)̸=DKL(q,p)不具有交换性。
通过对真实值和预测值的差求平方,直接测量输出与输入之间的距离,这就是线性回归的损失函数,常常用于回归中。定义输入为 y i y_i yi,输出为 y ^ i \hat y_i y^i。那么平方损失函数定义为:(这边假设最终结果都服从于高斯分布)
L ( x ) = 1 N ∑ i = 1 N ( y i − y ^ i ) 2 L(x)=\frac{1}{N} \sum_{i=1}^N{ ( y_i - \hat y_i)^2} L(x)=N1i=1∑N(yi−y^i)2
均方误差用于多分类的时候,对每一类输出结果都很看重,交叉熵函数只对正确的分类结果看重。使用的一般原则:如果致力于解决的问题是回归问题的连续变量,使用均方误差比较合适;如果是分类问题的离散 O n e − h o t One-hot One−hot 向量,则交叉熵损失函数较合适。
举个例子,对于一个模型的输出为: ( x , y , z ) (x,y,z) (x,y,z),真实结果是 ( 0 , 1 , 0 ) (0,1,0) (0,1,0),那么这个损失函数可以描述为:
S o f t m a x L o s s : L S = − 0 ∗ l o g x − 1 ∗ l o g y − 0 ∗ l o g z = − l o g y Softmax \ Loss:L_S =-0*logx-1*logy-0*logz=-logy Softmax Loss:LS=−0∗logx−1∗logy−0∗logz=−logy M S E : L M S E = ( x − 0 ) 2 + ( y − 1 ) 2 + ( z − 0 ) 2 = x 2 + ( y − 1 ) 2 + z 2 MSE:L_{MSE}=(x-0)^2 +(y-1)^2+(z-0)^2=x^2+(y-1)^2+z^2 MSE:LMSE=(x−0)2+(y−1)2+(z−0)2=x2+(y−1)2+z2我们可以看出均方误差只是将正确的分类尽可能大,其余让错误分类变得更加平均。这对回归问题特别重要,对分类作用不大。
L ( x ) = 1 N ∑ i = 1 N ∣ y i − y ^ i ∣ L(x)=\frac{1}{N} \sum_{i=1}^N{ |y_i - \hat y_i|} L(x)=N1i=1∑N∣yi−y^i∣
绝对损失函数的意义与均方误差差不多,只不过没有取平方,而是取绝对值,差距不会被平方放大。利用均方误差更容易求解,但是平方值误差对于异常值更为稳健。
参考链接:https://blog.csdn.net/a529975125/article/details/81176029, 十分推荐!
MMD 是迁移学习,尤其是预适应 ( d o m a i n a d a p t a t i o n ) (domain \ adaptation) (domain adaptation)中应用广泛的一种损失函数。主要度量两个不同但相关的分布的距离。这两个分布的距离定义为:
M M D ( X , Y ) = ∣ ∣ 1 n ∑ i = 1 n ϕ ( x i ) − 1 m ∑ j = 1 m ϕ ( y j ) ∣ ∣ H 2 MMD(X,Y)=||\frac{1}{n}\sum_{i=1}^{n}\phi(x_i) - \frac{1}{m}\sum_{j=1}^{m}{\phi(y_j)}||_{H}^2 MMD(X,Y)=∣∣n1i=1∑nϕ(xi)−m1j=1∑mϕ(yj)∣∣H2这边的 H H H表示这个距离是由 ϕ ( ) \phi() ϕ() 将数据映射到再生希尔伯特空间 ( R K H S ) (RKHS) (RKHS)中进行度量的。
为什么要使用MMD?
域适应的目的:将源域中学到的知识可以应用到不同但相关的目标域。本质和关键上要找到一个变换函数,使变换后的源域数据与目标域数据的距离是最小的。那么如何度量两个域中数据分布差异的问题,因此也用到了 MMD。
MMD的理论推导:寻找一个变换函数,但是这个变换函数在不同的任务中都不是固定的。并且这个映射可能是高维空间中的映射,所以很难去选取和定义。 如果这个映射函数 ϕ ( ) \phi() ϕ() 未知,那 M M D MMD MMD 如何求取呢?
将 M M D MMD MMD 展开:
M M D ( X , Y ) = ∣ ∣ 1 n 2 ∑ i , i ′ n ϕ ( x i ) ϕ ( x i ′ ) − 2 n m ∑ i , j n ϕ ( x i ) ϕ ( y j ) + 1 m 2 ∑ j , j ′ n ϕ ( y i ) ϕ ( y i ′ ) ∣ ∣ H 2 MMD(X,Y)=||\frac{1}{n^2}\sum_{i,i^{'}}^{n}{\phi(x_i)\phi(x_{i^{'}})}-\frac{2}{nm}\sum_{i,j}^{n}\phi(x_i)\phi(y_j)+\frac{1}{m^2}\sum_{j,j_{'}}^{n}\phi({y_i})\phi({y_i}^{'})||^2_{H} MMD(X,Y)=∣∣n21i,i′∑nϕ(xi)ϕ(xi′)−nm2i,j∑nϕ(xi)ϕ(yj)+m21j,j′∑nϕ(yi)ϕ(yi′)∣∣H2展开后就出现 ϕ ( x i ) ϕ ( x i ′ ) \phi({x_i})\phi({x_i}^{'}) ϕ(xi)ϕ(xi′)的形式,这里面的 ϕ ( ) \phi() ϕ()就类似于 S V M SVM SVM 的核函数 k ( ∗ ) k(*) k(∗),就可以直接跳过 ϕ ( ) \phi() ϕ() 的部分,直接求 k ( x i ) k ( x i ′ ) k({x_i})k({x_i}^{'}) k(xi)k(xi′)。这里 M M D MMD MMD 又可以表示为:
M M D ( X , Y ) = ∣ ∣ 1 n 2 ∑ i , i ′ n k ( x i ) k ( x i ′ ) − 2 n m ∑ i , j n k ( x i ) k ( y j ) + 1 m 2 ∑ j , j ′ n k ( y i ) k ( y i ′ ) ∣ ∣ H 2 MMD(X,Y)=||\frac{1}{n^2}\sum_{i,i^{'}}^{n}{k(x_i)k(x_i^{'})}-\frac{2}{nm}\sum_{i,j}^{n}k(x_i)k(y_j)+\frac{1}{m^2}\sum_{j,j_{'}}^{n}k({y_i})k({y_i}^{'})||^2_{H} MMD(X,Y)=∣∣n21i,i′∑nk(xi)k(xi′)−nm2i,j∑nk(xi)k(yj)+m21j,j′∑nk(yi)k(yi′)∣∣H2
这里的核函数 k ( ∗ ) k(*) k(∗) 一般用高斯核函数 k ( u , v ) = e − ∣ ∣ u − v ∣ ∣ 2 σ k(u,v)=e^{\frac{-||u-v||^2}{\sigma}} k(u,v)=eσ−∣∣u−v∣∣2,因为使用高斯核函数可以映射到无穷维空间。
代码参考:https://blog.csdn.net/zkq_1986/article/details/86747841
我跑编码器实验的时候用的就是这个函数,亲证有效:
import torch
def guassian_kernel(source, target, kernel_mul=2.0, kernel_num=5, fix_sigma=None):
'''
将源域数据和目标域数据转化为核矩阵,即上文中的K
Params:
source: 源域数据(n * len(x))
target: 目标域数据(m * len(y))
kernel_mul:
kernel_num: 取不同高斯核的数量
fix_sigma: 不同高斯核的sigma值
Return:
sum(kernel_val): 多个核矩阵之和
'''
n_samples = int(source.size()[0])+int(target.size()[0])
# 求矩阵的行数,一般source和target的尺度是一样的,这样便于计算
total = torch.cat([source, target], dim=0)
#将source,target按列方向合并
#将total复制(n+m)份
total0 = total.unsqueeze(0).expand(int(total.size(0)), int(total.size(0)), int(total.size(1)))
#将total的每一行都复制成(n+m)行,即每个数据都扩展成(n+m)份
total1 = total.unsqueeze(1).expand(int(total.size(0)), int(total.size(0)), int(total.size(1)))
#求任意两个数据之间的和,得到的矩阵中坐标(i,j)代表total中第i行数据和第j行数据之间的l2 distance(i==j时为0)
L2_distance = ((total0-total1)**2).sum(2)
#调整高斯核函数的sigma值
if fix_sigma:
bandwidth = fix_sigma
else:
bandwidth = torch.sum(L2_distance.data) / (n_samples**2-n_samples)
#以fix_sigma为中值,以kernel_mul为倍数取kernel_num个bandwidth值(比如fix_sigma为1时,得到[0.25,0.5,1,2,4]
bandwidth /= kernel_mul ** (kernel_num // 2)
bandwidth_list = [bandwidth * (kernel_mul**i) for i in range(kernel_num)]
#高斯核函数的数学表达式
kernel_val = [torch.exp(-L2_distance / bandwidth_temp) for bandwidth_temp in bandwidth_list]
#得到最终的核矩阵
return sum(kernel_val)#/len(kernel_val)
def mmd_rbf(source, target, kernel_mul=2.0, kernel_num=5, fix_sigma=None):
'''
计算源域数据和目标域数据的MMD距离
Params:
source: 源域数据(n * len(x))
target: 目标域数据(m * len(y))
kernel_mul:
kernel_num: 取不同高斯核的数量
fix_sigma: 不同高斯核的sigma值
Return:
loss: MMD loss
'''
batch_size = int(source.size()[0])
#一般默认为源域和目标域的batchsize相同
kernels = guassian_kernel(source, target, kernel_mul=kernel_mul, kernel_num=kernel_num, fix_sigma=fix_sigma)
#根据式(3)将核矩阵分成4部分
XX = kernels[:batch_size, :batch_size]
YY = kernels[batch_size:, batch_size:]
XY = kernels[:batch_size, batch_size:]
YX = kernels[batch_size:, :batch_size]
loss = torch.mean(XX + YY - XY -YX)
return loss#因为一般都是n==m,所以L矩阵一般不加入计算
这几位的博客十分好,隆重推荐!