这一行代码:
delta3[range(num_examples), y] -= 1
是计算softmax损失函数梯度的一部分。我建议您查看这个链接,了解更多关于该损失函数的公式和直觉背后的原理:
http://peterroelants.github.io/posts/neural_network_implementation_intermezzo02/。
此外,我还建议您看一下Mathematics Stack Exchange上的这篇文章,了解如何导出softmax损失的梯度:
https://math.stackexchange.com/questions/945871/derivative-of-softmax-loss-function。第一篇文章可以深入了解,而第二篇则是第一篇文章的简短概括。
softmax损失函数的梯度是输出层的梯度,需要将其向后传播到输出层前的层中,以继续反向传播算法。
总结上面的文章,如果您为一个训练样例计算softmax损失的梯度,则对于每个类别,该损失的梯度就是该类别的softmax值。您还需要将实际训练样例所属类别的损失值减去1。请记住,类别
i 的样例的梯度等于
p_i - y_i ,其中
p_i 是该样例的类别
i 的softmax分数,
y_i 使用一位有效编码方案进行分类标签。如果
i 不是样例的真实类别,则
y_i = 0 ,否则为
y_i = 1 。
delta3
包含您小批量训练中每个样例的softmax损失函数梯度。具体而言,它是一个2D矩阵,其中总行数等于训练样例的数量或,而列数是类的总数。
首先,我们为每个训练样例和每个类别计算softmax值。接下来,对于每个梯度的行,我们确定对应于样本所属的真实类别的列位置,并将分数减去1。
range(num_examples)
将生成一个列表,从
0
到
num_examples-1
,而
y
包含每个样例的真实类别标签。因此,对于每对
range(num_examples)
和
y
,这会访问正确的行和列位置,以最终确定损失函数梯度。
现在在数学堆栈交换帖子以及您的理解中,梯度是
delta3 = probs - y
。这假设
y
是一个
独热编码矩阵,这意味着
y
与
probs
具有相同的大小,并且对于
y
的每一行,除包含正确类别的列索引设置为1外,所有零都为0。因此,如果您正确考虑,如果生成一个矩阵
y
,其中每行的列都为零,除了该示例所属的类号之外,它等效于仅访问每行的正确列并将得分减1。
在MATLAB中,实际上需要创建线性索引以便进行此减法。具体来说,您需要使用
sub2ind
将这些行和列位置转换为线性索引,然后我们可以访问梯度矩阵并将值减1。
因此:
ind = sub2ind(size(delta3), 1 : num_examples, y + 1);
delta3(ind) = delta3(ind) - 1;
在您提供的Python教程中,假设类标签从
0
到
N-1
,其中N是总类数。但在MATLAB中,我们从
1
开始索引数组,因此我已经在上面的代码中添加了
1
到
y
,以确保标签从
1
而不是
0
开始。
ind
包含需要访问的行和列位置的线性索引,因此我们使用这些索引完成减法运算。
如果您要利用您的编辑所获得的知识进行公式化,您应该执行以下操作:
ymatrix = full(sparse(1 : num_examples, y + 1, 1, size(delta3, 1), size(delta3, 2));
delta3 = probs - ymatrix;
ymatrix
包含了我所说的矩阵,其中每一行对应一个示例,所有元素都是零,除了与示例所属类别相关的列,该列的值为1。你可能之前没见过
sparse
和
full
函数。
sparse
允许你创建一个零矩阵,并且你可以指定非零元素的行和列位置以及这些位置的值。在这种情况下,我正好每行访问一个元素,并使用示例的类别 ID 访问列,并将这些位置的值设置为1。同时请记住,我会加1,因为我假设你的类别 ID 从0开始。由于这是一个
sparse
矩阵,我将其转换为
full
,以便用数字矩阵表示,而不是使用
sparse
形式。因此,这段代码的操作与我之前展示的代码片段等效。但是,第一种方法更有效率,因为你不需要创建额外的矩阵来促进梯度计算。你直接在原地修改梯度。
顺带一提,
sklearn
是 Python 机器学习包
scikit-learn,而
NameError
是指你没有安装实际的包。要安装它,请使用
pip
或
easy_install
将 Python 包安装到计算机上...所以在命令行中,只需简单输入:
pip install sklearn
或者:
easy_install sklearn
然而,运行上述减法代码并不需要scikit-learn。但是,您确实需要安装
NumPy 包。对于
pip
:
pip install numpy
...以及easy_install
:
easy_install numpy
delta3
?NameError
表示找不到sklearn
,因此您可能没有正确地进行import
。 - A. Sokol