神经网络的学习

\quad\quad 在线性可分的与非门、或门的感知机模型中,我们可以根据真值表人工设定参数来实现,而此时的参数只有3个。然而,在实际的神经网络中,参数的数量成千上万,甚至上亿,很显然,人工设定参数是不可能的。从数据中学习就成了解决上面问题的关键。

  • “学习”就是指从训练数据中自动获取最优权重参数的过程
  • 为了能够进行学习,需要引入损失函数
  • 学习的目的:使损失函数达到最小值的权重参数
  • 学习过程可以使用梯度法

损失函数

\quad\quad 神经网络的学习需要通过某个指标来表现现在的状态,然后,以这个指标为基准,寻找最优权重参数。这个指标便是“损失函数”,这个损失函数可以死任意函数,但一般用均方误差和交叉熵误差。

损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。

  • 均方误差

E = 1 2 ∑ k ( y k − t k ) 2 E = \frac{1}{2}\sum_k(y_k - t_k)^2 E=21​k∑​(yk​−tk​)2

其中, y k y_k yk​ 表示神经网络的输出, t k t_k tk​ 表示监督数据(标签数据), k k k 表示数据的维度

# 均方误差损失函数
def mean_squared_error(y, t):return 0.5 * np.sum((y-t)**2)# 测试
# 假设数字"2"为正确解
t = [0,0,1,0,0,0,0,0,0,0]# 预测为"2"的概率最高
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]# 预测为"7"的概率最高
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]# 求均方误差
print(mean_squared_error(np.array(y1),np.array(t)))
print(mean_squared_error(np.array(y2),np.array(t)))
输出为:
0.09750000000000003
0.5975

结果我们发现, y 1 y1 y1 的损失函数的值更小,和监督数据之间的误差较小,也就是 y 1 y1 y1 的输出结果与监督数据更吻合。

  • 交叉熵误差
    E = − ∑ k t k l o g y k E = -\sum_kt_klog\ y_k E=−k∑​tk​log yk​

其中, y k y_k yk​ 表示神经网络的输出, t k t_k tk​ 表示正确解标签, k k k 表示数据的维度
t k t_k tk​ 中只有正确解标签的索引为1,其他为0(one-hot表示

# 交叉熵误差
def cross_entropy_error(y, t):delta = 1e-7return -np.sum(t * np.log(y + delta))
# 在计算log时,加上了一个微小值,防止出现计算np.log(0)变为负无穷大# 测试
# 设"2"为正确解
t = [0,0,1,0,0,0,0,0,0,0]# "2"的概率最高
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]# "7"的概率最高
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]# 求交叉熵误差
print(cross_entropy_error(np.array(y1),np.array(t)))
print(cross_entropy_error(np.array(y2),np.array(t)))
输出为:
0.510825457099338
2.302584092994546

此结果与前面均方误差讨论的内容一样

mini-batch学习(小批量学习)

\quad\quad 使用训练数据进行学习,就是针对训练数据计算损失函数的值,找到是该值尽可能小的参数,因此计算损失函数的值的时候必须将所有训练数据作为对象,也就是要把所有训练数据的损失函数值的总和作为学习的指标。

\quad\quad 前面提到的均方误差和交叉熵误差都是针对单个数据的损失函数,如果要求所有孙训练数据的损失函数的总和,这里仅以交叉熵误差为例,数学表达式可以写为:
E = − 1 N ∑ n ∑ k t n k l o g y n k E = - \frac{1}{N}\sum_n\sum_kt_{nk}log\ y_{nk} E=−N1​n∑​k∑​tnk​log ynk​

其中,假设数据有 N N N 个, t n k t_{nk} tnk​表示第n个数据的第k个元素的值,是监督数据, y n k y_{nk} ynk​ 是神经网络的输出

在数据量特别大的时候,如果我们以全部数据为对象来计算,计算过程需要花费很长的时间
因此,我们需要从全部数据中选出一部分,作为全部数据的“近似”
比如,从60000个训练数据中随机选择100个数据,再用这100个数据进行学习,这种学习方式就称为mini-batch学习

  • 如何选出小批量数据
import numpy as np
import mnist# load_mnist用于读入MNIST数据集函数
# 读入时设定one_hot_label=True,可以得到one-hot表示(即仅正确解标签为1,其他为0)
(X_train, T_train),(X_test, T_test) = mnist.load_mnist(normalize=False, one_hot_label=True)
print(X_train.shape)  # (60000, 784)print(T_train.shape)  # (60000, 10)train_size = X_train.shape[0]  # 训练数据的数量
batch_size = 10 # 设置批量数为10
# 使用np.random.choice()可以从指定数字中随机选择想要的数字
# 比如,np.random.choice(60000, 10)会从0-59999之间随机选择10个数字
batch_mask = np.random.choice(train_size, batch_size)
x_batch = X_train[batch_mask]
t_batch = T_train[batch_mask]
  • 同时处理单个数据和批量数据的交叉熵误差的实现
# 可以同时处理单个数据和批量数据
# 监督数据为非one-hot表示
def cross_entropy_error(y, t):# y为1维时,即if y.ndim == 1:t = t.reshape(1, t.size)y = y.reshape(1, y.size)# 监督数据是one-hot-vector的情况下,转换为正确解标签的索引if t.size == y.size:t = t.argmax(axis=1)batch_size = y.shape[0]return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

np.arange(5)表示生成一个NumPy数组[0, 1, 2, 3, 4],假设监督数据为[2, 7, 0, 9, 4]
y[np.arange(5), t]会生成[y[0, 2], y[1, 7], y[2, 0], y[3, 9], y[4, 4]]

导数、数值微分和偏导数

  • 导数数学表达式如下:
    d f ( x ) d x = lim ⁡ h → 0 f ( x + h ) − f ( x ) h \frac{df(x)}{dx} = \lim_{h\rightarrow 0} \frac{f(x+h) - f(x) }{h} dxdf(x)​=h→0lim​hf(x+h)−f(x)​

关于导数,可自行参考高等数学

  • 数值微分
def numerical_diff(f,x):h = 1e-4 # 0.0001return (f(x+h) - f(x-h)) / (2 * h)  # 这边使用的是中心差分

根据导数的定义,我们可以向h中赋入一个微小值,让h无限接近0,但是不能太小,太小可能会导致舍入误差(指因省略小数的精细部分的数值,小数点第8位以后的数值),导致最终结果的计算上的误差

  • 举例

y = 0.01 x 2 + 0.1 x y = 0.01x^2+0.1x y=0.01x2+0.1x

import numpy as np
import matplotlib.pylab as pltdef function_1(x):return 0.01*x**2 + 0.1*x x = np.arange(0.0, 20.0, 0.1)
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x, y)
plt.show()print(numerical_diff(function_1, 5)) # 0.1999999999990898
print(numerical_diff(function_1, 10)) # 0.2999999999986347

上面函数的导数为:
d f ( x ) d x = 0.02 x + 0.1 \frac{df(x)}{dx}= 0.02x + 0.1 dxdf(x)​=0.02x+0.1
在x=5和10处,“真的导数为”0.2和0.3,和上面的结果相比,误差很小。

  • 偏导数
    上面我们只是针对单一变量的函数的导数,如果有多个变量的函数的导数,我们称为偏导数。

用数学式表示为:

∂ f ∂ x 0 、 ∂ f ∂ x 1 \frac{\partial f}{\partial x_0}、\frac{\partial f}{\partial x_1} ∂x0​∂f​、∂x1​∂f​

对于多个变量的函数求导,我们可以取一个变量,然后固定其他变量来求偏导数,例如:
f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0,x_1) = x_0^2 + x_1^2 f(x0​,x1​)=x02​+x12​

def function_temp1(x0):return x0*x0 + 4.0**2print(numerical_diff(function_temp1, 3.0))  # 6.00000000000378

这里定义一个固定 x 1 = 4.0 x_1=4.0 x1​=4.0 的新函数,然后只有变量 x 0 x_0 x0​的函数应用了求数值微分的函数;
对 x 0 x_0 x0​的偏导数为:
∂ f ∂ x 0 = 2 x 0 \frac{\partial f}{\partial x_0} = 2x_0 ∂x0​∂f​=2x0​
x 0 = 3.0 , x 1 = 4.0 x_0 = 3.0,x_1 = 4.0 x0​=3.0,x1​=4.0 时,对 x 0 x_0 x0​的偏导数为6.0
我们可以发现,上面两个结果同样很接近

梯度

\quad\quad 对于多变量的函数,计算全部变量的偏导数汇总而成的向量就称为梯度。比如上面的两个变量的函数,梯度为:
( ∂ f ∂ x 0 , ∂ f ∂ x 1 ) (\frac{\partial f}{\partial x_0},\frac{\partial f}{\partial x_1}) (∂x0​∂f​,∂x1​∂f​)

  • python实现
# f(x0,x1) = x0^2 + x_1^2
def function_2(x):return x[0]**2 + x[1]**2# 梯度
def numerical_gradient(f, x):h = 1e-4 # 0.0001grad = np.zeros_like(x)  # 生成和x形状相同的0数组for idx in range(x.size):tmp_val = x[idx]# 计算f(x + h)x[idx] = tmp_val + hfxh1 = f(x)# 计算f(x - h)x[idx] = tmp_val - hfxh2 = f(x)grad[idx] = (fxh1 - fxh2) / (2*h)x[idx] = tmp_val # 还原值return grad# 测试
print(numerical_gradient(function_2, np.array([3.0, 4.0])))
print(numerical_gradient(function_2, np.array([0.0, 2.0])))
print(numerical_gradient(function_2, np.array([3.0, 0.0])))
输出为:
[6. 8.]
[0. 4.]
[6. 0.]

梯度法

\quad\quad 机器学习的主要任务是在学习时寻找最优参数。同样的,神经网络也必须在学习时找到最优参数(权重和偏置),这里所说的最优参数就是使损失函数取最小值时的参数。

\quad\quad 一般而言,损失函数很复杂,参数空间庞大,我们不知道它在何处能取最小值,但是我们可以通过巧妙地使用梯度来寻找函数的最小值(或者尽可能小的值),这种方法就称为梯度法。

梯度表示的是各点处的函数值减小最多的方向,因此,无法保证梯度所指的方向就是函数的最小值或者真正应该前进的方向。实际上,在复杂函数中,梯度指示的方向基本上都不是函数最小值处。
虽然梯度方向不一定指向函数最小值方向,但是沿着梯度方向能够最大限度地减小函数值,因此,在寻找函数最小值的位置任务中,要以梯度的信息为线索,决定前进的方向。

梯度法的数学表达式:

x 0 = x 0 − η ∂ f ∂ x 0 x 1 = x 1 − η ∂ f ∂ x 1 x_0 = x_0 - \eta \frac{\partial f}{ \partial x_0} \\ x_1 = x_1 - \eta \frac{\partial f}{ \partial x_1} x0​=x0​−η∂x0​∂f​x1​=x1​−η∂x1​∂f​

其中, η \eta η为学习率,决定在一次学习中,应该学习多少,以及在多大程度上更新参数。
上式表示一次更新,这个步骤会反复执行

  • python实现梯度下降法
# 梯度下降法(f为要进行最优化的函数, init_x为初始值,lr是学习率,step_num为梯度法的重复次数)
def gradient_descent(f, init_x, lr=0.01, step_num=100):x = init_xfor i in range(step_num):# 调用之前的numerical_gradient()函数求梯度grad = numerical_gradient(f, x)x -= lr * gradreturn x# 测试,用梯度下降法求函数f(x0,x1) = x0^2 + x_1^2最小值
# f(x0,x1) = x0^2 + x_1^2
def function_2(x):return x[0]**2 + x[1]**2init_x = np.array([-3.0, 4.0])  # 设置初始值为[-3.0, 4.0]
print(gradient_descent(function_2, init_x=init_x, lr=0.1, step_num=100))
输出为:
[-6.11110793e-10  8.14814391e-10]

结果非常接近(0,0),实际上,真实的最小值就是(0,0),所以说通过梯度法我们基本得到了正确的结果。

如果我们改变学习率,我们再来看看结果:

# 学习率过大
print(gradient_descent(function_2, init_x=init_x, lr=10.0, step_num=100))
# 结果为:[-2.58983747e+13 -1.29524862e+12]# 学习率过小
print(gradient_descent(function_2, init_x=init_x, lr=1e-10, step_num=100))
# 结果为:[-2.99999994  3.99999992]

由结果我们可以发现,学习率过大,会发散成一个很大的数;学习率过小,基本上没怎么更新就结束了
所以,设定合适的学习率是一个很重要的问题
学习率这样的参数称为超参数

  • 神经网络的梯度

假设我们有一个神经网络权重参数 W W W 如下:

W = ( w 11 w 12 w 13 w 21 w 22 w 23 ) W = \left( \begin{matrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \end{matrix} \right) W=(w11​w21​​w12​w22​​w13​w23​​)

梯度可以表示为:
∂ L ∂ W = ( ∂ L ∂ w 11 ∂ L ∂ w 12 ∂ L ∂ w 13 ∂ L ∂ w 21 ∂ L ∂ w 22 ∂ L ∂ w 23 ) \frac{\partial L}{\partial W} = \left( \begin{matrix} \frac{\partial L}{\partial w_{11}} & \frac{\partial L}{\partial w_{12}} & \frac{\partial L}{\partial w_{13}} \\ \\ \frac{\partial L}{\partial w_{21}} &\frac{\partial L}{\partial w_{22}} &\frac{\partial L}{\partial w_{23}} \end{matrix} \right) ∂W∂L​=⎝⎛​∂w11​∂L​∂w21​∂L​​∂w12​∂L​∂w22​∂L​​∂w13​∂L​∂w23​∂L​​⎠⎞​

  • python实现神经网络梯度
import numpy as np
# softmax函数
def softmax(x):if x.ndim == 2:x = x.Tx = x - np.max(x, axis=0)y = np.exp(x) / np.sum(np.exp(x), axis=0)return y.T x = x - np.max(x) # 溢出对策return np.exp(x) / np.sum(np.exp(x))# 交叉熵误差损失函数
def cross_entropy_error(y, t):if y.ndim == 1:t = t.reshape(1, t.size)y = y.reshape(1, y.size)# 监督数据是one-hot的情况下,转换为正确解标签的索引if t.size == y.size:t = t.argmax(axis=1)batch_size = y.shape[0]return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size# 梯度求解
def numerical_gradient(f, x):h = 1e-4 # 0.0001grad = np.zeros_like(x)it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])while not it.finished:idx = it.multi_indextmp_val = x[idx]x[idx] = float(tmp_val) + hfxh1 = f(x) # f(x+h)x[idx] = tmp_val - h fxh2 = f(x) # f(x-h)grad[idx] = (fxh1 - fxh2) / (2*h)x[idx] = tmp_val # 还原值it.iternext()   return grad    class simpleNet:def __init__(self):self.W = np.random.randn(2,3) # 用高斯分布进行初始化# 预测def predict(self, x):return np.dot(x, self.W)# 求损失函数值def loss(self, x, t): # x接收输入数据,t接收正确解标签z = self.predict(x)y = softmax(z)loss = cross_entropy_error(y, t)return loss# 测试
x = np.array([0.6, 0.9])
t = np.array([0, 0, 1])  # 正确解标签net = simpleNet()
print("权重参数:\n", net.W)f = lambda w: net.loss(x, t)
dW = numerical_gradient(f, net.W)print("梯度:\n", dW)
输出为:
权重参数:[[-0.76324663 -0.94168079 -0.10280071][-0.12308627 -0.0498545  -0.02240215]]
梯度:[[ 0.16727439  0.16053045 -0.32780484][ 0.25091159  0.24079568 -0.49170727]]

dW是一个2*3的二维数组,其中第一行第一列的数大约为0.167,这表明如果 w 11 w_{11} w11​增加h,那么损失函数的值就会增加0.167h;再如,第一行第三列的数大约为-0.328,这表明如果 w 13 w_{13} w13​增加h,那么损失函数的值将减小0.328h
因此,从减小损失函数值的观点来看, w 13 w_{13} w13​应该往正方向更新, w 11 w_{11} w11​应该往反方向更新

总结

  • 本篇主要介绍了神经网络的学习过程
  • 涉及到如何从整个训练数据中获取批量数据、损失函数、梯度法
  • 最后实现了一个简单的神经网络的权重参数的梯度求解
  • 求解出神经网络的梯度后,接下来只需要使用梯度法,更新参数即可,这将在下篇通过python实现

【深度学习】神经网络的学习过程相关推荐

  1. DL:深度学习(神经网络)的简介、基础知识(神经元/感知机、训练策略、预测原理)、算法分类、经典案例应用之详细攻略

    DL:深度学习(神经网络)的简介.基础知识(神经元/感知机.训练策略.预测原理).算法分类.经典案例应用之详细攻略 目录 深度学习(神经网络)的简介 1.深度学习浪潮兴起的三大因素 深度学习(神经网络 ...

  2. matlab在图像识别(深度学习神经网络)中的使用(转)

    前言: 1)图像识别用途甚广,解决的算法之一,是深度学习神经网络.matlab近几个版本,对这块的语法修改较多,总体而言,用户用起来更方便了: 2)这里以2018a版本为例,做一些粗略的说明. 1.概 ...

  3. MLP神经网络,GRNN神经网络,SVM神经网络以及深度学习神经网络对比识别人体健康非健康数据

    目录 一.理论基础 二.案例背景 1.问题描述 2.思路流程 三.部分MATLAB程序 四.仿真结论分析 五.参考文献 一.理论基础 MLP多层感知器神经网络(Multi-layer perceptr ...

  4. 利用python深度学习神经网络预测五年内糖尿病的发生(全代码)

    各位朋友大家好,今天我们做一个深度学习神经网络的项目,预测五年内糖尿病的发生.神经网络但凡入门数据科学的人都知道,我觉得叫神经网络是从仿生学角度的命名,从数据科学角度我更喜欢称它为多层感知机(mult ...

  5. 深度学习 神经网络(5)逻辑回归二分类-Pytorch实现乳腺癌预测

    深度学习 神经网络 逻辑回归二分类-乳腺癌预测 一.前言 二.代码实现 2.1 引入依赖库 2.2 加载并查看数据集 2.3 数据处理 2.4 数据分割 2.5 迭代训练 2.6 数据验证 一.前言 ...

  6. 深度学习——神经网络之DNN全连接神经网络、BP算法原理

    深度学习--神经网络之DNN全连接神经网络.BP算法原理 深度学习--神经网络之DNN全连接神经网络.BP算法原理 1.啥是人工神经网络 2.神经网络的应用 3.神经网络的组成 3.1.神经元 3.2 ...

  7. tx1开发板可以装linux,Nvidia推出Jetson TX1嵌入式开发板 针对深度学习神经网络设计...

    今天,Nvidia正式宣布基于Tegra X1打造的Jetson TX1登陆中国区市场.据介绍,该产品为Nvidia旗下首款针对深度学习神经网络而设计的嵌入式开发板,针对的开发方向为无人机.自主机器人 ...

  8. 从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具

    从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具 文章目录 1. 神经网络数据预处理 1.1 常规预测情景 1.2 文本预测场景 2.全连接神经网络 ...

  9. 第五章(1.1)深度学习——神经网络相关名词解释

    一.前言 很多人认为深度学习很枯燥,大部分情况是因为对深度学习的学术词语,特别是专有名词很困惑,即便对相关从业者,亦很难深入浅出地解释这些词语的含义. 人工智能,深度学习,机器学习-无论你在做什么,如 ...

  10. 深度学习神经网络入门案例详细解析-鸢尾花案例

    神经网络设计过程 案例: 鸢尾花分类 鸢尾花三种类别: 三种: 狗尾巴 杂草 小腹肌 通过搭建一个神经网络来对鸢尾花进行分类 收集花朵 的特征值: 四种 花萼长 花萼宽 花瓣长 花瓣宽 以及: 三种输 ...

最新文章

  1. ssl 和 https
  2. 技术图文:02 创建型设计模式(上)
  3. c++ 优先队列_std::priority_queue(优先队列)
  4. 数据中台推荐系统入门(三):推荐系统的评测指标
  5. mysql 设置宽松模式_mysql5.6 sql_mode设置为宽松模式
  6. ecs服务器数据迁移_某国际物流集团的云迁移解决方案
  7. Berkeley DB作用
  8. 没有bug队——加贝——Python 练习实例 19,20
  9. Mac便笺基本操作|便笺使用太鸡肋?那是你不知道这几个快捷键!
  10. linux镜像文件包括,关于镜像文件的详细介绍
  11. 二维otsu算法python_图像二值化与otsu算法介绍
  12. GUI GUIDER 应用笔记
  13. 图片分析——现代家居风水学[图文]居家必然之奇术
  14. Dockerfile指令详解镜像构建实例说明
  15. php自动获取节气对应的年月日_php如何通过日期获取农历、节日、节气?
  16. alpha 测试(α测试)与beta测试(β测试)的区别?
  17. NMEA1803协议3.0版本及以上说明
  18. 小学计算机走进魔力画室教案,山西经济出版社小学第一册三年级信息技术第三单元活动1-12教案教案2017年(37页)-原创力文档...
  19. android降噪算法,面向Android设备的音频降噪系统设计
  20. 通俗易懂!看完你就是半个天线专家了

热门文章

  1. xml与txt文件格式互换
  2. python的手机官方下载地址,手机python下载安装教程
  3. asp.net 打开服务器文件,aspnet打开服务器文件夹
  4. Windows10 邮箱批量导入联系人
  5. 贝叶斯算法 — 朴素贝叶斯分类器— 过滤垃圾邮件 — 流失用户 — 用户画像
  6. Mysql 事务的隔离性(隔离级别)
  7. ROS单线程与多线程处理
  8. Learning Standard C++ as a New Language ( By Bjarne Stroustrup )
  9. 战疫内外,京东智联云如此“一鸣惊人”!
  10. 软件生存周期、项目生命周期、产品生命周期区别