47.2_softmax函数
47.2 softmax函数
当使用神经网络进行多分类时,我们可以直接使用之前在线性回归中使用的神经网络。此前在MLP类中实现了神经网络,这意味着我们可以直接使用它。例如,对于输入数据的维度是2,需要将数据分为3类的问题,我们可以写出以下代码。
steps/step47.pyfromdezero.modelsimportMLP model $=$ MLP((10,3))上面的代码通过MLP((10, 3))创建了一个2层的全连接网络。第1个全连接层的输出大小为10,第2个全连接层的输出大小为3。由此得到的model会把输入数据变换为三维向量(有3个元素的向量)。输入一组数据后,代码如下所示。
steps/step47.py$\mathbf{x} = \mathbf{np}$ .array([0.2,-0.4])
y $=$ model(x)
print(y)运行结果
variable([[-0.6150578 -0.42790162 0.31733288]])上面代码中的 的形状是 (1, 2)。该形状表示 1 个样本数据中有 2 个元素 (=二维向量)。神经网络的输出的形状是 (1, 3),它意味着 1 个样本数据会变换为 3 个元素 (=三维向量)。这个三维向量的每个元素都对应一个类别,元素值最大的索引就是模型分类的类别。在上面的例子中,(在第 0 个、第 1 个和第 2 个元素中) 第 2 个元素的值最大,为 0.31733288,这表示模型将数据分到了第 2 个类中。

虽然上面的示例代码中只有一个输入数据,但模型也支持一次性处理多个数据。如果 ,那么4个输入数据将被合并为一组数据, 会一次性处理4个输入数据。具体来说,y.shape为(4,3),其中第i个输入数据是 ,相应的输出是 。
这里展示的代码示例中,神经网络的输出是数值。这个数值也能够转换为概率。进行这种转换的是softmax函数。softmax函数的式子如下所示。
假设向softmax函数输入的数据 共有 个(这个 是类的数量)。式子47.1是求第 个输出 的式子。softmax函数的分子是输入 的指数函数,分母是所有输入的指数函数之和,因此有 和 换言之, 可以解释为一种概率。
下面在DeZero中实现softmax函数。首先实现输入数据只有一个(一个样本数据)时的softmax函数。代码如下所示。
steps/step47.py
fromdezeroimportVariable,as_variable
importdezero-functionsasF
defsoftmaxld(x): $\mathrm{x} =$ as_variable(x) $\mathbf{y} = \mathbf{F}\cdot \exp (\mathbf{x})$ sum_y $=$ F-sum(y) return y/sum_y函数内部的实现仅仅是使用DeZero函数对式子47.1进行编码(假定DeZero的Exp类和exp函数已经添加到functions.py中)。第一行的 确保ndarray实例x被转换为Variable实例。

在上面代码y/sum_y的计算中,由于y和sum_y的形状不同,所以通过广播使二者形状匹配。我们已经在DeZero中支持了广播。因此,在使用广播的情况下,反向传播也会正确进行。
下面我们来实际使用一下softmax1d函数。
steps/step47.py$\mathbf{x} =$ Variable(np.array([[0.2, -0.4]]))
y $=$ model(x)
p $=$ softmax1d(y)
print(y)
print(p)运行结果
variable([[-0.61505778 -0.42790161 0.31733289]])
variable([[0.21068638 0.25404893 0.53526469]])结果 的每个元素都是 0 和 1 之间的值,它们的总和是 1。这样就成功地将神经网络的输出变换为概率了。

由于softmax函数的计算中有指数函数的计算,其值容易变大(或变小),所以,在实现softmax函数时,我们通常会采取防止溢出的措施。本书不对这部分内容进行介绍。关于如何更好地实现softmax函数,可以参阅《深度学习入门:基于Python的理论与实现》的3.5.2节。
下面对softmax函数进行扩展,使其能够批量处理数据,比如图47-2中的将softmax函数应用于每个样本数据的情况。
[-0.615,-0.427,0.317]
[-0.763,-0.249,0.185]
[-0.520,-0.962,0.578]
[-0.942,-0.503,0.175]
图47-2 对二维数据应用softmax函数的例子
[ \begin{bmatrix} [0.210, 0.254, 0.535] \\ [0.190, 0.318, 0.491] \\ [0.215, 0.138, 0.646] \\ [0.178, 0.276, 0.545] \end{bmatrix} ]我们要实现上图这种能应用于批量数据的softmax函数,其实现如下所示①。
dezero/functions.py
def softmaxsimple(x,axis=1): x = as_variable(x) y $=$ exp(x) sum_y $=$ sum(y,axis $\equiv$ axis,keepdims=True) return y / sum_y假设参数 为二维数据,参数axis指定了softmax函数应用于哪个轴。如果 ,则像图47-2那样使用softmax函数。求和时的参数keepdims=True,这意味着对每一行都执行式子47.1的除法运算。
这里实现的softmax.simple函数只使用了DeZero函数。虽然它能输出正确的结果,但也有可改进的地方。更好的实现方式是实现继承Function类的Softmax类,然后实现softmax函数,这里不再赘述。代码在dezero/functions.py中,感兴趣的读者可以参考。