第3章 神经网络
上一章(感知机)学习的感知机可以表示很多复杂的函数,但是其涉及的输入与输出的权重是由人工进行的,即根据真值表人工决定权重。
神经网络解决的问题:自动从数据中学习到合适的权重参数(权重、偏置)
3.1 参数
基本参数与感知机一样。
-
w:输入权重,用于控制各个输入信号的重要性
-
b:激活偏置,用于控制神经元被激活的容易程度
加权信号的总和为:y = b+w1x1 + … + wnxn。如果总和超过0,则输出1,否则输出0,这是一种分情况的操作,可以有很多种操作
为了简化,将所有操作用一个函数表示,即h(x),那么 y = h(b+w1x1 + … + wnxn)
输入信号的综合会被函数h(x)转换,转换后的值就是输出y。
3.2 激活函数
激活函数作用:加入非线性因素,非线性变换让网络储存信息大大增加,神经网络才能具备分层的非线性映射学习能力。(线性表达能力有限,经过多层网络叠加最后仍然可变换为线性,与1层线性网络无差别,对于增加网络深度无意义)
a=w1x1+w2x2+b,输出A=f(a) (神经网络运算可以作为矩阵运算打包进行)
阶跃函数f(a):两种取值,a>0,f(a)=1, 被激活; a<0,f(a)=0, 不激活。
其他激活函数f(a):f(a)的取值由激活函数而定。(激活是感知机里的概念,神经网络中的激活函数只是引用了名称,输出是一个数值,流动的是连续的实数值信号,决定输出值输入值如何变换)
感知机与神经网络信号关联:感知机中神经元之间流动的是0 或 1的二元信号,而神经网络中流动的是连续的实数值信号。
激活函数关联:
不同点:平滑性上有差异。
相同点:输入信号越重要,输出的值越大; 输出信号的值都在0到1之间; 且二者均为非线性函数。
sigmoid函数:
sigmoid函数是一条平滑的曲线,输出随着输入发生连续性的变化
sigmoid函数的平滑性对神经网络的学习具有重要意义
sigmoid函数可以返回 0.731…、0.880 … 等实数(这一点和刚才的平滑性有关)
softmax函数特征:输出值为0~1之间的实数,总和为1,因此输出可看做为概率。
一般神经网络只把输出值最大神经元所对应的类别作为识别结果,使用softmax函数后不会改变最大神经元的判断,且指数函数运算计算量大,因此神经网络进行分类一般忽略输出层的softmax函数(推理阶段)。
求解机器学习问题分为学习和推理:
学习(训练):算法从已知的数据学习模型,调整合适的参数
推理(分类):学习得到的模型对未知数据进行推理
最终推理可舍掉softmax函数,但学习时需用到softmax函数。
ReLU函数:
输入大于0,直接输出该值;输入小于等于0,输出0。
输出层所用激活函数:一般情况,回归问题(恒等函数、将输入原样输出)、二元分类(sigmoid函数)、多元分类(softmax函数)。
分类问题:数据属于哪一个类别(区分图像是男/女) 回归问题:根据某个输入预测一个(连续的)数值问题(根据一个人的图像预测体重)
阶跃函数:
def step_function(x):
return np.array(x > 0, dtype=np.int) # 大于0则1 小于0则0
sigmoid函数:
def sigmoid(x):
return 1 / (1 + np.exp(-x)) # 一直都在0~1范围内,输入越大输出越大
relu函数:
def relu(x):
return np.maximum(0, x) # 输入大于0,直接输出该值;输入小于等于0,输出0
3.3 神经网络的计算
多维数组运算:
矩阵的乘积:np.dot(A, B)
A和B必须保持在对应维度的元素个数一致
A[x,a] · B[a,y] => C[x,y]
神经网络的内积、传播:
使用 Y=np.dot(A, B) 矩阵的乘积可以一次性完成 Y 的计算,不需单独计算 Y 的每一个元素,这种实现十分重要。
输入 -> 第1层神经元
输入写入矩阵 X (x1,x2,x3…),权重写入矩阵 W1(w1,w2,w3…),偏置写入矩阵 B1(b1,b2,b3…)。
则第1层的加权和矩阵 A1= XW1+ B1,假设使用激活函数为sigmoid函数,被激活函数转换后的信号用 Z1 表示。
A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)
第1层神经元 -> 第2层神经元
将转换后的信号Z1(z1,z2,z3…)作为新的输入。
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
将输入神经元到输出神经元的过程中,对应的权重 W 作为将输入 X 作为另一个矩阵。
第2层神经元 -> 输出层(激活函数假设用恒等函数identify_function)
A3 = np.dot(Z2, W3) + B3
Y = identify_function(A3)
输出层的神经元数量:
对于分类问题:输出层神经元数量一般设置为类别的数量。例如识别数字(10分类)问题,神经元数量设置为10个。某个神经元 y 输出值最大,则表明神经网络预测的是 y 对应的类别。
3.4 手写数字识别
使用神经网络解决问题 和 求解机器学习问题的步骤一样,即 有 训练阶段 和 预测阶段两个步骤。
-
训练阶段即 使用训练数据进行 权重参数的学习
-
预测阶段即 使用训练阶段学习到的参数,对输入数据进行预测。
(1) 数据介绍
-
数据集:Mnist手写数字图像集,由0到9的数字图像构成,训练集:6万张,测试集:1万张
-
图像数据:28pt x 28pt 的灰度图像(1通道),各像素取值:0~255,都有正确的数字标签
**Pickle模块:**可以将程序运行中的对象保存为文件。如果加载保存过的pickle文件(.pkl),可以立刻复原之前程序运行中的对象。其实pickle文件就是保存的字典对象。在模型训练完后,可以利用pickle将模型参数保存为pickle文件,然后在测试阶段,再使用pickle加载这个模型参数文件,就可以立刻得到原本训练好的模型。
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
# load_mnist是用来读取minist数据的函数,返回了训练数据 和 测试数据;有三个参数:
# normalize:是否将输入图像的像素数据正规化为0.0 ~ 1.0的值
# flatten:是否将输入图像展开为一维数组(False就是1x28x28的三维数组,True就是784的一维数组)
# one_hot_label:是否将 标签 保存为 one-hot表示 数组
数据读取结果:
x_test:10000 x 784 的二维数组
t_test:10000 x 1 的二维数组(或者说一维数组?)
(2)神经网络的推理过程
一个图片一个图片进行测试,一个图片数据是784维的一维数组,所以输入层有784个神经元,由于数字标签有0~9十种类别,所以输出层有10个神经元。此外,这个神经网络有2个隐藏层,分别有50个、100个神经元(这个数字可以自己设置)
三个步骤:
-
获取测试数据:get_data
-
利用已经训练好的模型参数 来 初始化 网络模型的参数:init_network
-
利用模型对测试数据 进行 预测:predict
init_network中,会读入保存在pickle文件sample_weight.pkl中学习到的权重参数,这个pkl文件 以 字典变量的形式保存了 权重和偏置参数。
在该例子中,load_mnist函数的参数normalize参数设置为True,在读取数据时,函数内部会进行转换,将图像的各个像素值 除以255,使得数据的值 在0.0~1.0的范围内。
这种把数据限定到某个范围内的处理叫做 正规化;
对神经网络的输入数据进行 某种既定的转换 叫做 预处理;
这里,对输入图像进行正规化 就是 一种预处理。
预处理在神经网络(深度学习)中非常实用,可以提高识别性能 和 学习效率;
很多预处理都会 考虑到数据的整体分布;比如,利用数据整体的均值 或 标准差 来 移动数据,使数据整体以0为中心分布;或者进行正规化,把数据的延展控制在一定范围内 等等…
(3)批处理(batch)
批处理可以加快计算机的运算速度,批处理一次性计算大型数据 要 比 分开逐步计算各个小型数组 的 速度更快。
当打包多张图片数据时,比如打包一百张图片一起来预测。 则输入为 100x784
在预测阶段的数据处理过程为:
100x784 * 784x50 * 50x100 * 100x10 -> 100x10 :100个元素个数为10的数组,是一个二维数组
每次输入100张图片数据,输出是100组预测得分,这种打包式的输入数据成为 批(batch)
批处理只是改变了输入数据,在预测阶段predict的完全不需要改变的,因为np.array数组完全适应各种维度的计算过程
只预测一个图片时:
y = predict(network, x[i])
批处理预测图片时:(batch_size为批处理大小,用于设置一次性处理的图片数量)
x_batch = x[i:i+batch_size]
y_batch = predict(network, x_batch) (batch_size x 10)
计算预测正确的数量时的代码也要变:
p = np.argmax(y_batch, axis=1) # (100,) 从第二个维度对应的数字集合(10个)里面找到最大值对应的索引
tmp = np.argmax(y_batch, axis=0) # (10,) 从第一个维度对应的数字集合(100个)里面找到最大值对应的索引
accuracy_cnt += np.sum(p == t[i:i+batch_size])
如果您觉得有收获的话可以点个赞支持一下(#^ ○ ^#) 谢谢!