我正在跟踪nn和反向传播上的this tutorial。
我是python新手,我正在尝试将代码转换成matlab。
有人能解释一下下面的代码行吗(来自教程):
delta3[range(num_examples), y] -= 1
简而言之,如果我没有弄错的话,
delta3
和y
是向量,num_examples
是整数。我的理解是,
delta3=probs-y
和this math exchange entry一样(谢谢@rayryeng)。为什么和什么时候我应该减去1?否则,有谁能指引我到一个我可以简单运行并遵循代码的在线站点?我试图运行的所有地方(包括我的家用电脑)都出现错误:
“nameerror:未定义名称'sklearn'(可能缺少导入)
最佳答案
这一行:delta3[range(num_examples), y] -= 1
是计算softmax损耗函数梯度的一部分。我给你们介绍这个很好的链接,给你们更多的信息,关于这个损失函数是如何形成的,以及它背后的直觉:http://peterroelants.github.io/posts/neural_network_implementation_intermezzo02/。
另外,我给你介绍了数学堆栈交换的这篇文章,它向你展示了如何导出SoftMax损耗的梯度:https://math.stackexchange.com/questions/945871/derivative-of-softmax-loss-function。将第一个链接视为一个深潜水,而第二个链接是第一个链接的tl;dr
。
SoftMax损耗函数的梯度是输出层的梯度,您需要将其向后传播到输出层之前的层才能继续反向传播算法。
总结我在上面链接的帖子,如果你为一个训练示例计算softmax损失的梯度,那么对于每个类,损失的梯度就是为该类计算的softmax值对于实际训练示例所属的类,还需要将损失值减去1记住,类i
的示例的梯度等于p_i - y_i
,其中p_i
是该示例的类i
的softmax得分,y_i
是使用一个热编码方案的分类标签。具体来说,如果y_i = 0
不是示例的真正类,则为i
,如果是,则为y_i = 1
。delta3
包含小批量中每个示例的softmax loss函数的梯度。具体来说,它是一个2d矩阵,其中行的总数等于训练示例的数目,或者num_examples
,而列的数目是类的总数。
首先,我们计算每个训练示例和每个类的softmax分数。接下来,对于渐变的每一行,我们确定对应于示例所属的真实类的列位置,然后将分数减去1。range(num_examples)
将生成一个从0
到num_examples - 1
的列表,y
包含每个示例的真正类标签。因此,对于每一对range(num_examples)
和y
,它访问要减去1的右行和列位置,以确定损失函数的梯度。
现在在数学堆栈交换帖子以及你的理解中,梯度是delta3 = probs - y
。这假设y
是一个单热编码矩阵,这意味着y
的大小与probs
相同,并且对于y
的每一行,除了包含正确类的列索引(设置为1)之外,它都为零。因此,如果您考虑正确,如果您生成了一个矩阵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还要记住,假设类id从0开始,我将添加1。因为这是一个sparse
矩阵,所以我把它转换成full
来给你一个数值矩阵,而不是用sparse
的形式来表示它。因此,此代码在操作上与我显示的前一个代码段等效。但是,第一种方法更有效,因为不需要创建额外的矩阵来方便梯度计算而是就地修改渐变。另请注意,
sklearn
是python机器学习包,NameError
是指没有安装实际的包。要安装它,请使用scikit-learn或pip
将Python包安装到您的计算机所以在命令行中,它很简单:pip install sklearn
或:
easy_install sklearn
但是,运行上述减法代码不需要scikit learn。但您确实需要
easy_install
,因此请确保安装了该软件包。对于
pip
:pip install numpy
…对于
easy_install
:easy_install numpy
关于python - 反向传播的扩展,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41653482/