我们使用损失函数(Loss Function)(有时也叫代价函数Cost Function或目标函数Objective)来衡量我们对结果的不满意程度。直观地讲,当评分函数输出结果与真实结果之间差异越大,损失函数输出越大,反之越小。
多类支持向量机损失(Multiclass Support Vector Machine Loss) 想要SVM在正确分类上的得分始终比不正确分类上的得分高出一个边界值 Δ \Delta Δ。
第 i i i 个数据中包含图像 x i x_i xi 的像素和代表正确类别的标签 y i y_i yi。评分函数输入像素数据,然后通过公式 f ( x i , W ) f(x_i, W) f(xi,W) 来计算不同分类类别的分值。这里我们将分值简写为 s s s。针对第 j j j 个类别的得分就是第 j j j 个元素: s j = f ( x i , W ) j s_j = f(x_i, W)_j sj=f(xi,W)j。针对第 i i i 个数据的多类SVM的损失函数定义如下: L i = ∑ j ̸ = y i m a x ( 0 , s j − s y i + Δ ) L_i = \sum_{j\not= y_i} max(0, s_j - s_{y_i} + \Delta) Li=j̸=yi∑max(0,sj−syi+Δ)
折叶损失(hinge loss):关于0的阀值: m a x ( 0 , − ) max(0, -) max(0,−) 函数,它常被称为折叶损失。平方折叶损失SVM(即L2-SVM),它使用的是 m a x ( 0 , − ) 2 max(0, -)^2 max(0,−)2,更强烈(平方地而不是线性地)地惩罚过界的边界值。不使用平方是更标准的版本,但是在某些数据集中,平方折叶损失会工作得更好。可以通过交叉验证来决定到底使用哪个。
Δ \Delta Δ设置:在绝大多数情况下设为 Δ = 1 \Delta = 1 Δ=1 是安全的。超参数 Δ \Delta Δ 和 λ \lambda λ 看起来是两个不同的超参数,但实际上他们一起控制同一个权衡:即损失函数中的数据损失和正则化损失之间的权衡。
权重 W W W 的大小对于分类分值有直接影响:当我们将 W W W 中值缩小,分类分值之间的差异也变小,反之亦然。因此,不同分类分值之间的边界的具体值(比如 Δ = 1 \Delta = 1 Δ=1 或 Δ = 10 \Delta = 10 Δ=10)从某些角度来看是没意义的,因为权重自己就可以控制差异变大和缩小。也就是说,真正的权衡是我们允许权重能够变大到何种程度(通过正则化强度 λ \lambda λ 来控制)。
无正则化的多类支持向量机损失Python遇到的问题:假设有一个数据集和一个权重集 W W W 能够正确地分类每个数据,即所有的边界都满足,对于所有的 i i i 都有 L i = 0 L_i = 0 Li=0。问题在于这个 W W W 并不唯一:可能有很多相似的 W W W 都能正确地分类所有的数据。一个简单的例子:如果 W W W 能够正确分类所有数据,即对于每个数据,损失值都是 0 0 0。那么当 λ > 0 \lambda > 0 λ>0 时,任何数乘 λ W \lambda W λW 都能使得损失值为 0 0 0。
消除模糊性:我们希望能向某些特定的权重 W W W 添加一些偏好,对其他权重则不添加,以此来消除模糊性。方法是向损失函数增加一个正则化惩罚(regularization penalty) R ( W ) R(W) R(W) 部分。最常用的正则化惩罚是L2范式,L2范式通过对所有参数进行逐元素的平方惩罚来抑制大数值的权重: R ( W ) = ∑ k ∑ l W k , l 2 R(W) = \sum_k \sum_l W_{k, l}^2 R(W)=k∑l∑Wk,l2
完整的多类SVM损失函数:它由两个部分组成:数据损失(data loss),即所有样例的的平均损失 L i L_i Li,以及正则化损失(regularization loss)。完整公式如下所示: L = 1 N ∑ i L i + λ R ( W ) L = \frac{1}{N} \sum_i L_i + \lambda R(W) L=N1i∑Li+λR(W)
其完整的展开式为: L = 1 N ∑ i ∑ j ̸ = y i [ m a x ( 0 , f ( x i ; W ) j − f ( x i ; W ) y i + Δ ) ] + λ ∑ k ∑ l W k , l 2 L= \frac{1}{N} \sum_i \sum_{j \not= y_i} [max(0, f(x_i; W)_j - f(x_i; W)_{y_i} + \Delta)] + \lambda \sum_k \sum_l W_{k, l}^2 L=N1i∑j̸=yi∑[max(0,f(xi;W)j−f(xi;W)yi+Δ)]+λk∑l∑Wk,l2
N N N 是训练集的数据量。用超参数 λ \lambda λ 来计算正则化惩罚的权重。该超参数无法简单确定,需要通过交叉验证来获取。与SVM不同,Softmax的输出,归一化的分类概率更加直观。在Softmax分类器中,函数映射 f ( x i ; W ) = W x i f(x_i; W) = Wx_i f(xi;W)=Wxi保持不变,但将这些评分值视为每个分类的未归一化的对数概率,并且将折叶损失(hinge loss)替换为交叉熵损失(cross-entropy loss)。公示如下: L i = − log ( e f y i ∑ j e f j ) L_i = - \log(\frac{e^{f_{y_i}}}{\sum_j e^{f_j}}) Li=−log(∑jefjefyi)
f j f_j fj 来表示分类评分向量 f f f 中的第 j j j 个元素。整个数据集的损失值是数据集中所有样本数据的损失值 L i L_i Li 的均值与正则化损失 R(W) 之和。 f j ( z ) = e z j ∑ k e z k f_j(z) = \frac{e^{z_j}}{\sum_k e^{z_k}} fj(z)=∑kezkezj被称作softmax 函数。其输入值是一个向量,向量中元素为任意实数的评分值( z z z 中的),函数对其进行压缩,输出一个向量,其中每个元素值在0到1之间,且所有元素之和为1。下图所示为两种分类器的工作过程:
多类别SVM损失函数:当得分超过某个阈值边放弃优化。Softmax损失函数:不断将概率质量向正确类别聚集。梯度总是指向函数增长速度最快的方向。所以我们损失函数应沿负梯度方向进行更新。
梯度计算
多元函数梯度计算: ∇ f ( x , y ) = ( ∂ f ∂ x , ∂ f ∂ y ) \nabla f(x, y) = (\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}) ∇f(x,y)=(∂x∂f,∂y∂f)根绝偏导数的定义, f ( x , y ) f(x, y) f(x,y) 在点 ( a , b ) (a, b) (a,b) 关于 x x x 的偏导数为: ∂ f ∂ x = lim h → 0 f ( a + h , b ) − f ( a , b ) h \frac{\partial f}{\partial x} = \lim_{h \to 0} \frac{f(a + h, b) - f(a, b)}{h} ∂x∂f=limh→0hf(a+h,b)−f(a,b)计算梯度有两种方法:
数值梯度法:利用有限差值计算梯度。 def eval_numerical_gradient(f, x): """ 一个f在x处的数值梯度法的简单实现 - f是只有一个参数的函数 - x是计算梯度的点 """ fx = f(x) # 在原点计算函数值 grad = np.zeros(x.shape) h = 0.00001 # 对x中所有的索引进行迭代 it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) while not it.finished: # 计算x+h处的函数值 ix = it.multi_index old_value = x[ix] x[ix] = old_value + h # 增加h fxh = f(x) # 计算f(x + h) x[ix] = old_value # 存到前一个值中 (非常重要) # 计算偏导数 grad[ix] = (fxh - fx) / h # 坡度 it.iternext() # 到下个维度 return grad 分析梯度法:由相应公式直接求得梯度表达式。【注】:常常使用第一个方法作为第二个方法的测试单元。
对于损失函数: L ( W ) = 1 N ∑ i L i ( x i , y i ; W ) + λ R ( W ) L(W) = \frac{1}{N} \sum_i L_i(x_i, y_i;W) + \lambda R(W) L(W)=N1i∑Li(xi,yi;W)+λR(W)
其梯度为: ∇ W L ( W ) = 1 N ∑ i ∇ W L i ( x i , y i ; W ) + λ ∇ W R ( W ) \nabla_W L(W) = \frac{1}{N} \sum_i \nabla_WL_i(x_i, y_i;W) + \lambda \nabla_W R(W) ∇WL(W)=N1i∑∇WLi(xi,yi;W)+λ∇WR(W)
普通梯度下降:程序重复地计算梯度然后对参数进行更新。
# 普通的梯度下降 while True: weights_grad = evaluate_gradient(loss_fun, data, weights) weights += - step_size * weights_grad # 进行梯度更新小批量数据梯度下降:在大规模的应用中,训练数据可以达到百万级量级。如果像这样计算整个训练集,来获得仅仅一个参数的更新就太浪费了。一个常用的方法是计算训练集中的小批量(batches)数据。
# 普通的小批量数据梯度下降 while True: data_batch = sample_training_data(data, 256) # 256个数据 weights_grad = evaluate_gradient(loss_fun, data_batch, weights) weights += - step_size * weights_grad # 参数更新随机梯度下降:小批量数据策略有个极端情况,那就是每个批量中只有1个数据样本,这种策略被称为随机梯度下降(Stochastic Gradient Descent 简称SGD),有时候也被称为在线梯度下降。
思想:特征空间的转换。
常用方法:
色彩直方图图像的方向梯度词袋模型