线性分类
损失函数
-
从图像像素值到所属类别的评分函数(score function)的参数是权重矩阵 W。
-
在函数中,数据 ( x i , y i ) (x_i,y_i) (xi,yi) 是给定的,不能修改。但是我们可以调整权重矩阵这个参数,使得评分函数的结果与训练数据集中图像的真实类别一致,即评分函数在正确的分类的位置应当得到最高的评分(score)。
-
我们将使用损失函数(Loss Function)(有时也叫代价函数 Cost Function 或目标函数 Objective)来衡量我们对结果的不满意程度。直观地讲,当评分函数输出结果与真实结果之间差异越大,损失函数输出越大,反之越小。
多类支持向量机损失
-
损失函数的具体形式多种多样。
- 首先,介绍常用的多类支持向量机(SVM)损失函数。
- SVM 的损失函数想要 SVM 在正确分类上的得分始终比不正确分类上的得分高出一个边界值 Δ \Delta Δ。
- 第 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 个元素: s j = f ( x i , W ) j s_j=f(x_i,W)_j sj=f(xi,W)j。
- 针对第 i 个数据的多类 SVM 的损失函数定义如下:
L i = ∑ j = ̸ y i max ( 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+Δ)
- 举例:用一个例子演示公式是如何计算的。
- 假设有3个分类,并且得到了分值 s = [ 13 , − 7 , 11 ] s=[13,-7,11] s=[13,−7,11]。
- 其中第一个类别是正确类别,即 y i = 0 y_i=0 yi=0。
- 同时假设 Δ \Delta Δ 是10。
- 上面的公式是将所有不正确分类
(
j
=
̸
y
i
)
(j = \not y_i)
(j≠yi) 加起来,所以我们得到两个部分:
L
i
=
max
(
0
,
−
7
−
13
+
10
)
+
max
(
0
,
11
−
13
+
10
)
L_i = \max(0, -7 - 13 + 10) + \max(0, 11 - 13 + 10)
Li=max(0,−7−13+10)+max(0,11−13+10)
- 可以看到第一个部分结果是0,这是因为 [-7-13+10] 得到的是负数,经过 m a x ( 0 , − ) max(0,-) max(0,−) 函数处理后得到0。
- 这一对类别分数和标签的损失值是0,这是因为正确分类的得分13与错误分类的得分-7的差为20,高于边界值10。而 SVM 只关心差距至少要大于10,更大的差值还是算作损失值为0。
- 第二个部分计算 [11-13+10] 得到8。虽然正确分类的得分比不正确分类的得分要高(13>11),但是比10的边界值还是小了,分差只有2,这就是为什么损失值等于8。
- 简而言之,SVM 的损失函数想要正确分类类别 y i y_i yi 的分数比不正确类别分数高,而且至少要高 Δ \Delta Δ 。如果不满足这点,就开始计算损失值。
- 在这次的模型中,我们面对的是线性评分函数
(
f
(
x
i
,
W
)
=
W
x
i
)
(f(x_i,W)=Wx_i)
(f(xi,W)=Wxi),所以我们可以将损失函数的公式稍微改写一下:
L i = ∑ j = ̸ y i max ( 0 , w j T x i − w y i T x i + Δ ) L_i = \sum_{j = \not y_i} \max(0, w_j^T x_i - w_{y_i}^T x_i + \Delta) Li=j≠yi∑max(0,wjTxi−wyiTxi+Δ)- 其中 w j w_j wj 是权重 W 的第 j 行,被变形为列向量。
- 然而,一旦开始考虑更复杂的评分函数 f 公式,这样做就不是必须的了。
- 首先,介绍常用的多类支持向量机(SVM)损失函数。
-
关于0的阀值: m a x ( 0 , − ) max(0,-) max(0,−) 函数,它常被称为折叶损失(hinge loss)。
- 平方折叶损失 SVM(即 L2-SVM)使用的是 m a x ( 0 , − ) 2 max(0,-)^2 max(0,−)2,将更强烈(平方地而不是线性地)地惩罚过界的边界值。
- 不使用平方是更标准的版本,但是在某些数据集中,平方折叶损失会工作得更好。
- 可以通过交叉验证来决定到底使用哪个。
我们对于预测训练集数据分类标签的情况总有一些不满意的,而损失函数就能将这些不满意的程度量化。
多类 SVM 想要正确类别的分类分数比其他不正确分类类别的分数要高,而且至少高出 Δ \Delta Δ 的边界值。如果其他分类分数进入了红色的区域,甚至更高,那么就开始计算损失。如果没有这些情况,损失值为0。我们的目标是找到一些权重,它们既能够让训练集中的数据样例满足这些限制,也能让总的损失值尽可能地低。
-
正则化(Regularization)
- 假设有一个数据集和一个权重集 W 能够正确地分类每个数据(即所有的边界都满足,对于所有的i都有 L i = 0 L_i=0 Li=0)。
- 问题在于这个 W 并不唯一:可能有很多相似的 W 都能正确地分类所有的数据。一个简单的例子:如果 W 能够正确分类所有数据,即对于每个数据,损失值都是0。那么当 λ > 1 \lambda>1 λ>1 时,任何数乘 λ W \lambda W λW 都能使得损失值为0,因为这个变化将所有分值的大小都均等地扩大了,所以它们之间的绝对差值也扩大了。
- 举个例子,如果一个正确分类的分值和举例它最近的错误分类的分值的差距是15,对 W 乘以2将使得差距变成30。
- 换句话说,我们希望能向某些特定的权重 W 添加一些偏好,对其他权重则不添加,以此来消除模糊性。这一点是能够实现的,方法是向损失函数增加一个正则化惩罚(regularization penalty)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 - 上面的表达式中,将 W 中所有元素平方后求和。注意正则化函数不是数据的函数,仅基于权重。
-
包含正则化惩罚后,就能够给出完整的多类 SVM 损失函数了,它由两个部分组成:数据损失(data loss),即所有样例的的平均损失 L i L_i Li,以及正则化损失(regularization loss)。
- 完整公式如下所示:
L = 1 N ∑ i L i ⎵ data loss + λ R ( W ) ⎵ regularization loss L=\underbrace{\frac{1}{N} \sum_{i} L_{i}}_{\text { data loss }}+\underbrace{\lambda R(W)}_{\text { regularization loss }} L= data loss N1i∑Li+ regularization loss λR(W) - 将其展开完整公式是:
L = 1 N ∑ i ∑ j = ̸ y i [ max ( 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}}\left[\max \left(0, f\left(x_{i} ; W\right)_{j}-f\left(x_{i} ; W\right)_{y_{i}}+\Delta\right)\right]+\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 是训练集的数据量。
- 现在正则化惩罚添加到了损失函数里面,并用超参数 λ \lambda λ 来计算其权重。该超参数无法简单确定,需要通过交叉验证来获取。
- 完整公式如下所示:
-
除了上述理由外,引入正则化惩罚还带来很多良好的性质:
- 比如引入了 L2 惩罚后,SVM 们就有了最大边界(max margin)这一良好性质。
- 其中最好的性质就是对大数值权重进行惩罚,可以提升其泛化能力,因为这就意味着没有哪个维度能够独自对于整体分值有过大的影响。
- 举个例子,假设输入向量 x = [ 1 , 1 , 1 , 1 ] x=[1,1,1,1] x=[1,1,1,1],两个权重向量 w 1 = [ 1 , 0 , 0 , 0 ] w_1=[1,0,0,0] w1=[1,0,0,0], w 2 = [ 0.25 , 0.25 , 0.25 , 0.25 ] w_2=[0.25,0.25,0.25,0.25] w2=[0.25,0.25,0.25,0.25]。
- 那么 w 1 T x = w 2 T = 1 w^T_1x=w^T_2=1 w1Tx=w2T=1,两个权重向量都得到同样的内积,但是 w 1 w_1 w1 的 L2 惩罚是1.0,而 w 2 w_2 w2 的 L2 惩罚是0.25。
- 因此,根据 L2 惩罚来看, w 2 w_2 w2 更好,因为它的正则化损失更小。
- 从直观上来看,这是因为 w 2 w_2 w2 的权重值更小且更分散。
- 既然 L2 惩罚倾向于更小更分散的权重向量,这就会鼓励分类器最终将所有维度上的特征都用起来,而不是强烈依赖其中少数几个维度。这一效果将会提升分类器的泛化能力,并避免过拟合。
-
需要注意的是,和权重不同,偏差没有这样的效果,因为它们并不控制输入维度上的影响强度。因此通常只对权重 W 正则化,而不正则化偏差 b。在实际操作中,可发现这一操作的影响可忽略不计。最后,因为正则化惩罚的存在,不可能在所有的例子中得到0的损失值,这是因为只有当 W = 0 W=0 W=0 的特殊情况下,才能得到损失值为0。
-
下面是一个无正则化部分的损失函数的 Python 实现,有非向量化和半向量化两个形式:
def L_i(x, y, W): """ unvectorized version. Compute the multiclass svm loss for a single example (x,y) - x is a column vector representing an image (e.g. 3073 x 1 in CIFAR-10) with an appended bias dimension in the 3073-rd position (i.e. bias trick) - y is an integer giving index of correct class (e.g. between 0 and 9 in CIFAR-10) - W is the weight matrix (e.g. 10 x 3073 in CIFAR-10) """ delta = 1.0 # see notes about delta later in this section scores = W.dot(x) # scores becomes of size 10 x 1, the scores for each class correct_class_score = scores[y] D = W.shape[0] # number of classes, e.g. 10 loss_i = 0.0 for j in xrange(D): # iterate over all wrong classes if j == y: # skip for the true class to only loop over incorrect classes continue # accumulate loss for the i-th example loss_i += max(0, scores[j] - correct_class_score + delta) return loss_i def L_i_vectorized(x, y, W): """ A faster half-vectorized implementation. half-vectorized refers to the fact that for a single example the implementation contains no for loops, but there is still one loop over the examples (outside this function) """ delta = 1.0 scores = W.dot(x) # compute the margins for all classes in one vector operation margins = np.maximum(0, scores - scores[y] + delta) # on y-th position scores[y] - scores[y] canceled and gave delta. We want # to ignore the y-th position and only consider margin on max wrong class margins[y] = 0 loss_i = np.sum(margins) return loss_i def L(X, y, W): """ fully-vectorized implementation : - X holds all the training examples as columns (e.g. 3073 x 50,000 in CIFAR-10) - y is array of integers specifying correct class (e.g. 50,000-D array) - W are weights (e.g. 10 x 3073) """ # evaluate loss over all examples in X without using any for loops # left as exercise to reader in the assignment
一定要记得 SVM 损失采取了一种特殊的方法,使得能够衡量对于训练数据预测分类和实际分类标签的一致性。还有,对训练集中数据做出准确分类预测和让损失值最小化这两件事是等价的。
-
实际考虑
- 设置 Delta:
- 现在看来,超参数 Δ \Delta Δ 在绝大多数情况下设为 Δ = 1.0 \Delta=1.0 Δ=1.0 都是安全的。
- 超参数 Δ \Delta Δ 和 λ \lambda λ 看起来是两个不同的超参数,但实际上他们一起控制同一个权衡:即损失函数中的数据损失和正则化损失之间的权衡。
- 理解这一点的关键是要知道,权重 W 的大小对于分类分值有直接影响(当然对他们的差异也有直接影响):当我们将 W 中值缩小,分类分值之间的差异也变小,反之亦然。
- 因此,不同分类分值之间的边界的具体值(比如 Δ = 1 \Delta=1 Δ=1 或 Δ = 100 \Delta=100 Δ=100)从某些角度来看是没意义的,因为权重自己就可以控制差异变大和缩小。
- 也就是说,真正的权衡是我们允许权重能够变大到何种程度(通过正则化强度 λ \lambda λ 来控制)。
- 与二元支持向量机(Binary Support Vector Machine)的关系
- 二元支持向量机对于第 i 个数据的损失计算公式是:
L i = Cmax ( 0 , 1 − y i w T x i ) + R ( W ) L_{i}=\operatorname{Cmax}\left(0,1-y_{i} w^{T} x_{i}\right)+R(W) Li=Cmax(0,1−yiwTxi)+R(W) - 其中, C C C 是一个超参数,并且 y i ∈ { − 1 , 1 } y_i\in\{-1,1\} yi∈{−1,1}。
- SVM 公式包含了上述公式,上述公式是多类支持向量机公式只有两个分类类别的特例。
- 这个公式中的 C C C 和多类 SVM 公式中的 λ \lambda λ 都控制着同样的权衡,而且它们之间的关系是 C ∝ 1 λ C\propto\frac{1}{\lambda} C∝λ1。
- 二元支持向量机对于第 i 个数据的损失计算公式是:
- 设置 Delta:
-
在初始形式中进行最优化。很多这些损失函数从技术上来说是不可微的(比如当 x=y 时,max(x, y) 函数就不可微分),但是在实际操作中并不存在问题,因为通常可以使用次梯度。
-
其他多类SVM公式。
- 另一种常用的公式是 One-Vs-All(OVA)SVM,它针对每个类和其他类训练一个独立的二元分类器。
- 还有另一种更少用的叫做 All-Vs-All(AVA)策略。
- 我们的公式比 OVA 性能更强(在构建有一个多类数据集的情况下,可以在损失值上取到0,而 OVA 就不行。
- 最后一个需要知道的公式是 Structured SVM,它将正确分类的分类分值和非正确分类中的最高分值的边界最大化。