神经网络的数学基础

神经网络的数学基础

1、初识神经网络

  • 接下来的工作流程如下:
    1. 首先,将训练数据( train_images 和 train_labels)输入神经网络;
    2. 其次, 网络学习将图像和标签关联在一起;
    3. 最后,网络对 test_images 生成预测,而我们将验证这些预测与 test_labels 中的标签是否匹配。
  • 神经网络的核心组件是( layer),它是一种数据处理模块,你可以将它看成数据过滤器。进去一些数据,出来的数据变得更加有用。具体来说,层从输入数据中提取表示——我们期望这种表示有助于解决手头的问题。大多数深度学习都是将简单的层链接起来,从而实现渐进式的数据蒸馏( data distillation)。深度学习模型就像是数据处理的筛子,包含一系列越来越精细的数据过滤器(即层)。
  • 要想训练网络,我们还需要选择编译( compile)步骤的三个参数:
    1. 损失函数( loss function):网络如何衡量在训练数据上的性能,即网络如何朝着正确的方向前进;
    2. 优化器( optimizer):基于训练数据和损失函数来更新网络的机制;
    3. 在训练和测试过程中需要监控的指标( metric):本例只关心精度,即正确分类的图像所占的比例。
  • 将对数据进行预处理,将其变换为网络要求的形状,并缩放到所有值都在 [0, 1] 区间;
  • 对标签进行分类编码
  • 开始训练网络,在 Keras 中这一步是通过调用网络的 fit 方法来完成
  • 检查一下模型在测试集上的性能

2、神经网络的数据表示

  • 当前所有机器学习系统都使用张量作为基本数据结构。

    张量这一概念的核心在于,它是一个数据容器。它包含的数据几乎总是数值数据,因此它是数字的容器。

  • 标量(0D 张量)

    仅包含一个数字的张量叫作标量(scalar,也叫标量张量、零维张量、 0D 张量)。在 Numpy 中,一个 float32 或 float64 的数字就是一个标量张量(或标量数组)。

    你可以用 ndim 属性来查看一个 Numpy 张量的轴的个数,张量轴的个数也叫作( rank)

    在这里插入图片描述

  • 向量(1D 张量)

    数字组成的数组叫作向量(vector)或一维张量(1D 张量)。一维张量只有一个轴

    在这里插入图片描述

    这个向量有 5 个元素,所以被称为 5D 向量。不要把 5D 向量和 5D 张量弄混! 5D 向量只有一个轴,沿着轴有 5 个维度,而 5D 张量有 5 个轴(沿着每个轴可能有任意个维度)。 维度( dimensionality)可以表示沿着某个轴上的元素个数(比如 5D 向量),也可以表示张量中轴的个数(比如 5D 张量),这有时会令人感到混乱。对于后一种情况,技术上更准确的说法是 5 阶张量(张量的阶数即轴的个数),但 5D 张量这种模糊的写法更常见。

  • 矩阵(2D 张量)

    向量组成的数组叫作矩阵( matrix)或二维张量( 2D 张量)。矩阵有 2 个轴(通常叫作

    在这里插入图片描述

  • 3D 张量与更高维张量

    将多个矩阵组合成一个新的数组,可以得到一个 3D 张量。

    在这里插入图片描述

    将多个 3D 张量组合成一个数组,可以创建一个 4D 张量,以此类推。深度学习处理的一般是 0D 到 4D 的张量,但处理视频数据时可能会遇到 5D 张量。

  • 关键属性

    1. 轴的个数(阶)。例如, 3D 张量有 3 个轴,矩阵有 2 个轴。这在 Numpy 等 Python 库中也叫张量的 ndim
    2. 形状这是一个整数元组,表示张量沿每个轴的维度大小(元素个数)。例如,前面矩阵示例的形状为 (3, 5), 3D 张量示例的形状为 (3, 3, 5)。向量的形状只包含一个元素,比如 (5,),而标量的形状为空,即 ()。
    3. 数据类型(在 Python 库中通常叫作 dtype)。这是张量中所包含数据的类型,例如,张量的类型可以是 float32、 uint8、 float64 等。
  • 在 Numpy 中操作张量

    我们使用语法 train_images[i] 来选择沿着第一个轴的特定数字。选择张量的特定元素叫作张量切片( tensor slicing)

  • 数据批量

    通常来说,深度学习中所有数据张量的第一个轴( 0 轴,因为索引从 0 开始)都是样本轴( samples axis,有时也叫样本维度

    深度学习模型不会同时处理整个数据集,而是将数据拆分成小批量

    对于这种批量张量,第一个轴( 0 轴)叫作批量轴( batch axis)或批量维度( batch dimension)。

  • 现实世界中的数据张量

    1. 向量数据:2D 张量,形状为 (samples, features)

      对于这种数据集,每个数据点都被编码为一个向量,因此一个数据批量就被编码为 2D 张量(即向量组成的数组),其中第一个轴是样本轴,第二个轴是特征轴

    2. 时间序列数据或序列数据: 3D 张量,形状为 (samples, timesteps, features)

      当时间(或序列顺序)对于数据很重要时,应该将数据存储在带有时间轴的 3D 张量中。每个样本可以被编码为一个向量序列(即 2D 张量),因此一个数据批量就被编码为一个 3D 张量。

    3. 图像: 4D 张量,形状为 (samples, height, width, channels) 或 (samples, channels, height, width)

      图像通常具有三个维度:高度、宽度和颜色深度。虽然灰度图像(比如 MNIST 数字图像)只有一个颜色通道,因此可以保存在 2D 张量中,但按照惯例,图像张量始终都是 3D 张量,灰度图像的彩色通道只有一维。因此,如果图像大小为 256× 256,那么 128 张灰度图像组成的批量可以保存在一个形状为 (128, 256, 256, 1) 的张量中,而 128 张彩色图像组成的批量则可以保存在一个形状为 (128, 256, 256, 3) 的张量中。

      图像张量的形状有两种约定: 通道在后( channels-last)的约定(在 TensorFlow 中使用)和通道在前( channels-first)的约定。

    4. 视频: 5D 张量,形状为 (samples, frames, height, width, channels) 或 (samples,frames, channels, height, width)


3、神经网络的 “齿轮”:张量运算

  • 逐元素运算

    relu 运算和加法都是逐元素(element-wise)的运算,即该运算独立地应用于张量中的每个元素

  • 广播

    如果将两个形状不同的张量相加,会发生什么?

    如果没有歧义的话,较小的张量会被广播( broadcast),以匹配较大张量的形状。广播包含以下两步:

    1. 向较小的张量添加轴(叫作广播轴),使其 ndim 与较大的张量相同;
    2. 将较小的张量沿着新轴重复,使其形状与较大的张量相同。
  • 张量点积

    点积运算,也叫张量积与逐元素的运算不同,它将输入张量的元素合并在一起

    1. 两个向量之间的点积是一个标量,而且只有元素个数相同的向量之间才能做点积
    2. 一个矩阵 x 和一个向量 y 做点积,返回值是一个向量,其中每个元素是 y 和 x 的每一行之间的点积
    3. 两个矩阵之间的点积:对于两个矩阵 x 和 y,当且仅当 x.shape[1] == y.shape[0] 时,你才可以对它们做点积( dot(x, y))。得到的结果是一个形状为 (x.shape[0], y.shape[1]) 的矩阵,其元素为 x 的行与 y 的列之间的点积
  • 张量变形

    第三个重要的张量运算是张量变形( tensor reshaping),张量变形是指改变张量的行和列,以得到想要的形状。变形后的张量的元素总个数与初始张量相同。

    经常遇到的一种特殊的张量变形是转置( transposition)。对矩阵做转置是指将行和列互换,使 x[i, :] 变为 x[:, i]。


4、神经网络的 “引擎”:基于梯度的优化

  • 每个神经层都用下述方法对输入数据进行变换:
    o u t p u t = r e l u ( d o t ( W , i n p u t ) + b ) output = relu(dot(\mathbf{W}, input) + \mathbf{b}) output=relu(dot(W,input)+b)
    在这个表达式中, W 和 b 都是张量,均为该层的属性。它们被称为该层的权重( weight)或可训练参数( trainable parameter),分别对应 kernel 和 bias 属性。这些权重包含网络从观察训练数据中学到的信息。

    一开始,这些权重矩阵取较小的随机值,这一步叫作随机初始化( random initialization)。当然, W 和 b 都是随机的, relu(dot(W, input) + b) 肯定不会得到任何有用的表示。虽然得到的表示是没有意义的,但这是一个起点。下一步则是根据反馈信号逐渐调节这些权重。这个逐渐调节的过程叫作训练也就是机器学习中的学习

    上述过程发生在一个训练循环( training loop)内,其具体过程如下。必要时一直重复这些步骤:

    1. 抽取训练样本 x 和对应目标 y 组成的数据批量;
    2. 在 x 上运行网络[这一步叫作前向传播( forward pass)],得到预测值 y_pred;
    3. 计算网络在这批数据上的损失,用于衡量 y_pred 和 y 之间的距离;
    4. 更新网络的所有权重,使网络在这批数据上的损失略微下降。

    第一步看起来非常简单,只是输入 / 输出( I/O)的代码。第二步和第三步仅仅是一些张量运算的应用,所以你完全可以利用上一节学到的知识来实现这两步。难点在于第四步:更新网络的权重。考虑网络中某个权重系数,你怎么知道这个系数应该增大还是减小,以及变化多少?

    一种简单的解决方案是,保持网络中其他权重不变,只考虑某个标量系数,让其尝试不同的取值。假设这个系数的初始值为 0.3。对一批数据做完前向传播后,网络在这批数据上的损失是 0.5。如果你将这个系数的值改为 0.35 并重新运行前向传播,损失会增大到 0.6。但如果你将这个系数减小到 0.25,损失会减小到 0.4。在这个例子中,将这个系数减小 0.05 似乎有助于使损失最小化。对于网络中的所有系数都要重复这一过程。

    但这种方法是非常低效的,因为对每个系数(系数很多,通常有上千个,有时甚至多达上百万个)都需要计算两次前向传播(计算代价很大)。

    一种更好的方法是利用网络中所有运算都是可微( differentiable)的这一事实,计算损失相对于网络系数的梯度( gradient),然后向梯度的反方向改变系数,从而使损失降低

  • 随机梯度下降

    给定一个可微函数,理论上可以用解析法找到它的最小值:函数的最小值是导数为 0 的点,因此你只需找到所有导数为 0 的点,然后计算函数在其中哪个点具有最小值。

    将这一方法应用于神经网络,就是用解析法求出最小损失函数对应的所有权重值。但对于实际的神经网络是无法求解的,因为参数的个数不会少于几千个,而且经常有上千万个。

    相反,你可以使用开头总结的四步算法:基于当前在随机数据批量上的损失,一点一点地对参数进行调节。由于处理的是一个可微函数,你可以计算出它的梯度,从而有效地实现第四步。沿着梯度的反方向更新权重,损失每次都会变小一点:

    1. 抽取训练样本 x 和对应目标 y 组成的数据批量;
    2. 在 x 上运行网络,得到预测值 y_pred;
    3. 计算网络在这批数据上的损失,用于衡量 y_pred 和 y 之间的距离;
    4. 计算损失相对于网络参数的梯度[一次反向传播( backward pass)];
    5. 将参数沿着梯度的反方向移动一点,比如 W -= step * gradient,从而使这批数据上的损失减小一点。

    刚刚描述的方法叫作小批量随机梯度下降( mini-batch stochastic gradient descent,又称为小批量 SGD)。术语随机( stochastic)是指每批数据都是随机抽取的

    在这里插入图片描述

    为 step 因子选取合适的值是很重要的。如果取值太小,则沿着曲线的下降需要很多次迭代,而且可能会陷入局部极小点。如果取值太大,则更新权重值之后可能会出现在曲线上完全随机的位置。

    SGD 还有多种变体,其区别在于计算下一次权重更新时还要考虑上一次权重更新,而不是仅仅考虑当前梯度值,这些变体被称为优化方法( optimization method)或优化器( optimizer)。

  • 链式求导:反向传播算法

    在实践中,神经网络函数包含许多连接在一起的张量运算,每个运算都有简单的、已知的导数。例如,下面这个网络 f 包含 3 个张量运算 a、 b 和 c,还有 3 个权重矩阵 W1、 W2 和 W3。
    f ( W 1 , W 2 , W 3 ) = a ( W 1 , b ( W 2 , c ( W 3 ) ) ) f(W1, W2, W3) = a(W1, b(W2, c(W3))) f(W1,W2,W3)=a(W1,b(W2,c(W3)))
    根据微积分的知识,这种函数链可以利用下面这个恒等式进行求导,它称为链式法则( chain rule):

    (f(g(x)))’ = f’(g(x)) * g’(x)。

    将链式法则应用于神经网络梯度值的计算,得到的算法叫作反向传播( backpropagation,有时也叫反式微分, reverse-mode differentiation)。反向传播从最终损失值开始,从最顶层反向作用至最底层,利用链式法则计算每个参数对损失值的贡献大小


5、一个实例

  • 输入数据

    (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
    
    train_images = train_images.reshape((60000, 28 * 28))
    train_images = train_images.astype('float32') / 255
    
    test_images = test_images.reshape((10000, 28 * 28))
    test_images = test_images.astype('float32') / 255
    

    输入图像保存在 float32 格式的 Numpy 张量中,形状分别为 (60000, 784)(训练数据)和 (10000, 784)(测试数据)

  • 构建网络

    network = models.Sequential()
    network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
    network.add(layers.Dense(10, activation='softmax'))
    

    这个网络包含两个 Dense 层,每层都对输入数据进行一些简单的张量运算,这些运算都包含权重张量。权重张量是该层的属性,里面保存了网络所学到的知识(knowledge)。

  • 网络的编译

    network.compile(optimizer='rmsprop',
                    loss='categorical_crossentropy',
                    metrics=['accuracy'])
    

    categorical_crossentropy 是损失函数,是用于学习权重张量的反馈信号,在训练阶段应使它最小化;

    减小损失是通过小批量随机梯度下降来实现的。梯度下降的具体方法由第一个参数给定,即 rmsprop 优化器。

  • 训练数据

    network.fit(train_images, train_labels, epochs=5, batch_size=128)
    

    在调用 fit 时发生了什么:网络开始在训练数据上进行迭代(每个小批量包含 128 个样本),共迭代 5 次[在所有训练数据上迭代一次叫作一个轮次(epoch)]。在每次迭代过程中,网络会计算批量损失相对于权重的梯度,并相应地更新权重。 5轮之后,网络进行了 2345 次梯度更新(每轮 469 次),网络损失值将变得足够小,使得网络能够以很高的精度对手写数字进行分类。


6、总结

  • 学习是指找到一组模型参数,使得在给定的训练数据样本和对应目标值上的损失函数最小化
  • 学习的过程:随机选取包含数据样本及其目标值的批量,并计算批量损失相对于网络参数的梯度。随后将网络参数沿着梯度的反方向稍稍移动(移动距离由学习率指定
  • 整个学习过程之所以能够实现,是因为神经网络是一系列可微分的张量运算因此可以利用求导的链式法则来得到梯度函数,这个函数将当前参数和当前数据批量映射为一个梯度值;
  • 损失优化器。将数据输入网络之前,你需要先定义这二者:
    • 损失在训练过程中需要最小化的量,因此,它应该能够衡量当前任务是否已成功解决;
    • 优化器使用损失梯度更新参数的具体方式,比如 RMSProp 优化器、带动量的随机梯度下降(SGD)等。
  • 3
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值