从本章开始,会接触到一些深度学习理论框架的知识,为以后实现算法打好基础。 本章新接触的概念有:
- 神经网络
- 激活函数(step, sigmoid, ReLU, softmax)
- 矩阵与矩阵运算
- 训练集(train),测试集(test)
- 正规化(normalization),预处理(pre-processing)
- 批处理(batch)
从感知机到神经网络
图:感知机的图形表达
图:感知机的算式表达
首先复习一下感知机的结构,它由输入
、输出
、权重
、偏置
几个元素组成,单层感知机是线性的,通过组合多个单层感知机可以得到多层感知机,用于表达非线性空间。但是,其中的难点在于如何确定每个输入的权重,也就是调参
。设定权重的工作依赖于人工进行,而神经网络则是一种可以自动从数据中学习从而得到参数的技术。
在感知机的算式表达中,θ
表示神经元被激活的难易程度,可以把它从不等式右侧移到左侧,从而得到偏置b
,它的权重是1
。
图:明确表示出偏置
此时引入激活函数(activation function
)的概念,根据算式结果决定输出是0还是1。
图:激活函数的算式表达
图像表达如下:
图:激活函数的图像表达
激活函数
常见的激活函数有
- 阶跃函数
- sigmoid函数
- ReLU函数
阶跃函数
以0为界的跳变,<=0
输出0,>0
输出1,呈阶梯状
变化,故称为阶跃函数。
py
# 阶跃函数
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x>0, dtype=np.int64) # 将boolean转换为int
x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()
输出:

sigmoid函数
利用到了自然对数e=2.7182
,能够在保留原始大小关系的基础上,将输出局限在-1~1
之间。
图:sigmoid函数算式
py
def sigmoid(x):
return 1/(1+np.exp(-x))

线性函数(y=cx)的问题在于,不管如何加深层数,总是存在一个与之等价的单层感知机,无法发挥多层网络带来的优势。因此激活函数必须选择非线性函数。
ReLU
Rectified Linear Unit 修正线性单元,修正
指的是对于负数和0返回0。
图:ReLU的算式表达
py
def relu(x):
return np.maximum(0, x)

多维数组与矩阵
[[1,2], [3,4], [5,6]]
是一个3*2
的矩阵,即3行2列。从最外层的中括号开始向内算起,第一级的组数即行数,每一组内的元素数即列数。

矩阵乘法(内积),行与列交叉相乘,相加作为结果矩阵的元素。因此矩阵的行列数在相乘过程中需要前后衔接。


用矩阵乘法表示神经元的信号传递过程
对于权重w
而言
- 上标:表示当前计算的是第几层(输出)的权重(从0开始计数)
- 下标-左侧:指向输出层第几个神经元(从1开始计数)
- 下标-右侧:来自输入层第几个神经元(从1开始计数)

神经元从1开始计数,但(输出)层数从0开始计数,这样做的原因是偏置b其实可以作为第0个神经元
一个三层神经网络可以描述为下图:

机器学习问题:分类与回归
机器学习主要研究两类问题:
- 分类 :数据属于哪一类别,如根据照片判断男人还是女人
- 二元分类问题可以使用sigmoid函数
- 多元分类问题使用softmax函数
- 回归 :预测一个连续的数值,如预测明天的气温
- 回归问题使用恒等函数
图:恒等函数与softmax函数
图:softmax函数的算式表达
由算式可知,softmax输出层各元素总和是1。
py
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
softmax函数会面临溢出问题,可以减去输入中的最大值来避免
py
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
实践:手写数字识别
神经网络确定权重的过程,可分为学习和推理两个步骤:
- 学习:使用训练数据进行权重参数学习
- 推理 :也称为前向传播(
forward propagation
),使用刚才学习到的参数对输入数据进行分类
MNIST数据集,是一个手写数字图像集,训练集6w,测试集1w。每张图片都是28*28像素的灰度图像,像素灰度值[0, 255]

首先需要下载数据集,这部分已经封装进了load_mnist
函数中,数据集会被下载到../dataset/
目录下,需要注意单张图片(28*28)在读入时是经过flatten
的,已经被拉平成一维数组,在显示时需要reshape
还原。
py
# mnist_show.py
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 把父目录及其全部子目录和文件加入到python检索路径中(默认只检索当前目录)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
img = x_train[0]
label = t_train[0]
print(label) # 5
print(img.shape) # (784,)
img = img.reshape(28, 28) # 把图像的形状变为原来的尺寸
print(img.shape) # (28, 28)
img_show(img)

这里先跳过训练部分,直接使用训练完成的参数,在测试集上进行验证。
py
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
# 返回测试集的数据和标签
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
return x_test, t_test
# 之前训练完成的权重&偏置
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
def predict(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 = softmax(a3)
return y
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p = np.argmax(y) # 获取概率最高的元素的索引
if p == t[i]:
accuracy_cnt += 1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
输出识别精度accuracy
:
bash
λ python neuralnet_mnist.py
Accuracy:0.9352
正规化与预处理
- 正规化(normalization) :把数据限定到某个范围内的处理,如把输入图片像素色值除255,得到
0~1
之间的色值 - 预处理(pre-processing):对神经网络的输入数据进行转换,正规化是预处理的一种
批处理(batch)
节约数据读入时间,克服数据传输的瓶颈,利用数值计算库的大型数组运算优化功能。
例:100个每批
py
batch_size = 100 # 批数量
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
x_batch = x[i:i+batch_size]
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i+batch_size])
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))