学习笔记第三章第二部分: 深度学习入门:基于 Python 的理论与实现

chapter3 第二部分神经网络

3.1 三层神经网络的实现

我们将以 numpy 数组完成一个三层神经网络, 下面的介绍围绕下图展开.
ps: 3层神经网络:输入层(第0层)有2个神经元,第1个隐藏层(第1层)有3个神经元,第2个隐藏层(第2层)有2个神经元,输出层(第3层)有2个神经元.


三层神经网络.png

3.1.1 关于符号的识别

关于符号
\mathbf{w}_{12} ^{(1)} , \mathbf{a}_{1} ^{(1)}
权重和隐藏层的神经元的右上角有一个“(1)”,它表示权重和神经元的层号(即第1层的权重、第1层的神经元)。此外,权重的右下角有两个数字,它们是后一层的神经元和前一层的神经元的索引号。比如,\mathbf{w}_{12} ^{(1)}
表示前一层的第2个神经元x2到后一层的第1个神经元
\mathbf{a}_{1} ^{(1)}
的权重。权重右下角按照“后一层的索引号、前一层的索引号”的顺序排列。如图所示:

符号确认.png

3.1.2 各层传递的实现

下从输入层到第1层的第1个神经元的信号传递过程


输入层到第一层

使用公式进行计算:


第一层计算公式

使用numpy 简化计算公式为:
numpy矩阵简化

用代码实现

X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])
print(W1.shape) # (2, 3)
print(X.shape) # (2,)
print(B1.shape) # (3,)
A1 = np.dot(X, W1) + B1

Z1 = sigmoid(A1)   # 使用sigmoid 激活函数
print(A1) # [0.3, 0.7, 1.1]
print(Z1) # [0.57444252, 0.66818777, 0.75026011]

代码过程如图所示:

矩阵运算完使用激活函数.png

在这之后第一层到第二层也以此类推,而在第二层到第三层输出层的时候.输出层的实现也和之前的实现基本相同。不过,最后的激活函数和之前的隐藏层有所不同.

def identity_function(x):
   return x
W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)   # 或者Y = A3 ,保持风格跟之前一致

输出层的激活函数用σ()表示,不同于隐藏层的激活函数h()(σ读作sigma)

至此,将全部代码整理为一个类中:

import numpy as np


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def identity_function(x):
    return x


def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    return network


def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)
    return y


network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)  # [ 0.31682708 0.69627909]

这里定义了init_network()和forward()函数。init_network()函数会进行权重和偏置的初始化,并将它们保存在字典变量network中。这个字典变量network中保存了每一层所需的参数(权重和偏置)。forward()函数中则封装了将输入信号转换为输出信号的处理过程。
另外,这里出现了forward(前向)一词,它表示的是从输入到输出方向的传递处理。后面在进行神经网络的训练时,我们将介绍后(backward,从输出到输入方向)的处理。
至此,神经网络的前向处理的实现就完成了。通过巧妙地使用NumPy多维数组,我们高效地实现了神经网络。

3.2 输出层设计

机器学习的问题大致可以分为分类问题和回归问题。分类问题是数据属于哪一个类别的问题。比如,区分图像中的人是男性还是女性的问题就是分类问题。而回归问题是根据某个输入预测一个(连续的)数值的问题。比如,根据一个人的图像预测这个人的体重的问题就是回归问题(类似“57.4kg”这样的预测)。

神经网络可以用在分类问题和回归问题上,不过需要根据情况改变输出层的激活函数。一般而言,回归问题用恒等函数,分类问题用softmax函数。

3.2.1 恒等函数与softmax函数

恒等函数就是原样不动直接输出. 而soft则使用下图公式:


softmax.png

该图表示假设输出层共有n个神经元,计算第k个神经元的输出yk.如图所示,softmax函数的分子是输入信号ak的指数函数,分母是所有输入信号的指数函数的和。

使用python 解释器, 实现softmax(), 并查看每一步的结果.


softmax()-python解析器.png

代码为:

import numpy as np

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y
  • 注意事项
    由于e的n次方,为指数函数,所以通常会超过int类型最大的取值范围,这就是softmax函数的缺陷,可以通过数学简化运算,避免出现这个问题,推导过程入下图:


    推导过程.png

    在进行softmax的指数函数的运算时,加上(或者减去)某个常数并不会改变运算的结果。这里的C可以使用任何值,但是为了防止溢出,一般会使用输入信号中的最大值。


    增加常数C.png

改进后的代码如下:

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  # 溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

3.3 本章所学内容

  • 神经网络中的激活函数使用平滑变化的sigmoid函数或ReLU函数。
  • 通过巧妙地使用NumPy多维数组,可以高效地实现神经网络。
  • 机器学习的问题大体上可以分为回归问题和分类问题。
  • 关于输出层的激活函数,回归问题中一般用恒等函数,分类问题中
    一般用softmax函数。
  • 分类问题中,输出层的神经元的数量设置为要分类的类别数。
  • 输入数据的集合称为批。通过以批为单位进行推理处理,能够实现
    高速的运算。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。