写点什么

AI 入门之深度学习:基本概念篇

  • 2024-08-08
    北京
  • 本文字数:5708 字

    阅读完需:约 19 分钟

1、什么是深度学习

1.1、机器学习


图 1:计算机有效工作的常用方法:程序员编写规则(程序),计算机遵循这些规则将输入数据转换为适当的答案。这一方法被称为符号主义人工智能,适合用来解决定义明确的逻辑问题,比如早期的 PC 小游戏:五子棋等,但是像图像分类、语音识别或自然语言翻译等更复杂、更模糊的任务,难以给出明确的规则。


图 2:机器学习把这个过程反了过来:机器读取输入数据和相应的答案,然后找出应有的规则。机器学习系统是训练出来的,而不是明确的用程序编写出来。举个例子,如果你想为度假照片添加标签,并希望将这项任务自动化,那么你可以将许多人工打好标签的照片输人机器学习系统,系统将学会把特定照片与特定标签联系在一起的统计规则。


定义:机器学习就是在预定义的可能性空间中,利用反馈信号的指引,在输入数据中寻找有用的表示和规则。


1.2、深度学习

深度学习是机器学习的一个分支领域,强调从一系列连续的表示层中学习。现代的深度学习模型通常包含数十个甚至上百个连续的表示层,它们都是从训练数据中自动学习而来。与之对应,机器学习有时也被称为浅层学习。


在深度学习中,这些分层表示是通过叫作神经网络的模型学习得到的。深度神经网络可以看作多级信息蒸馏过程:信息穿过连续的过滤器,其纯度越来越高。


技术定义:一种多层的学习数据表示的方法。


1.3、深度学习工作原理

a. 对神经网络的权重(有时也被称为该层的参数)进行随机赋值


b. 经过一系列随机变换,得到预测值 Y'


c. 通过损失函数(有时也被称为目标函数或代价函数),得到预测值 Y'与真实值 Y 之间的损失值


d. 将损失值作为反馈信号,通过优化器来对权重值进行微调,以降低当前示例对应的损失值


e. 循环重复足够做的次数(b-d),得到具有最小损失值的神经网络,就是一个训练好的神经网络


2、神经网络数学基础

2.1、神经网络的数据表示

目前所有机器学习系统都使用张量(tensor)作为基本数据结构,张量对这个领域非常重要,TensorFlow 就是以它来命名。


张量这一概念的核心在于,它是一个数据容器。它包含的数据通常是数值数据,因此它是一个数字容器。你可能对矩阵很熟悉,它是 2 阶张量。张量是矩阵向任意维度的推广,张量的维度通常叫做轴。


张量是由以下 3 个关键属性来定义的。


:轴的个数


形状:表示张量沿每个轴的维度大小(元素个数)


数据类型(dtype):数据的类型,可以是 float16、float32、float64、unit8、string 等

2.1.1、标量(0 阶张量)

仅包含一个数字的张量叫做标量(SCALAR),也叫 0 阶张量或 0 维张量。


下面是一个 NumPy 标量


import numpy as npx = np.array(3)x.ndim // 轴:0, 形状:()
复制代码
2.1.2、向量(1 阶张量)

数字组成的数组叫做向量(VECTOR),也叫 1 阶张量或 1 维张量。


下面是一个 NumPy 向量


x = np.array([4, 1, 5])x.ndim // 轴:1, 形状:(3,)
复制代码


这个向量包含 3 个元素,所以也叫 3 维向量。不要把 3 维向量和 3 维张量混为一谈,3 维向量只有一个轴,沿着这个轴有 3 个维度。

2.1.3、矩阵(2 阶张量)

向量组成的数组叫做矩阵(MATRIX),也 2 阶张量或 2 维张量。矩阵有 2 个轴:行和列。


下面是一个 NumPy 矩阵


x = np.array([    [4, 6, 7],    [7, 3, 9],    [1, 2, 5]])x.ndim // 轴:2, 形状:(3, 3)
复制代码


现实世界中的向量实例:


向量数据:形状为(samples, features)的 2 阶张量,每个样本都是一个数值(特征)向量,向量数据库存储的基本单位。

2.1.4、3 阶张量与更高阶的张量

将多个矩阵打包成一个新的数组,就可以得到一个 3 阶张量(或 3 维张量)


下面是一个 3 阶 NumPy 张量


x = np.array([    [[4, 6, 7],    [7, 3, 9],    [1, 2, 5]],    [[5, 7, 1],    [9, 4, 3],    [3, 5, 2]]])x.ndim // 轴:3, 形状:(2, 3, 3)
复制代码


将多个 3 阶张量打包成一个数组,就可以创建一个 4 阶张量。


现实世界中的实例:


时间序列数据或序列数据:形状为(samples, timesteps, features)的 3 阶张量,每个样本都是特征向量组成的序列(序列长度为 timesteps)


图像数据:形状为(samples, height, width, channels)的 4 阶张量,每个样本都是一个二维像素网格,每个像素则由一个“通道”(channel)向量表示。


视频数据:形状为(samples, frames, height, width, channels)的 5 阶张量,每个样本都是由图像组成的序列(序列长度为 frames)。


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

所有计算机程序最终都可以简化为对二进制输入的一些二进制运算,与此类似,深度神经网络学到的所有变换也都可以简化为对数值数据张量的一些张量运算或张量函数。

2.2.1、逐元素运算

逐元素运算,即该运算分别应用于张量的每个元素。参与运算的张量的形状必须相同。


import numpy as npz = x + y // 逐元素加法z = x - y // 逐元素加法z = x * y // 逐元素乘积z = x / y // 逐元素除法z = np.maximum(z, 0.) //逐元素relu,大于0输出等于输入,小于0则输出为0
复制代码


rule 运算是一种常用的激活函数,rule(x)就是 max(x, 0):如果输入 x 大于 0,则输出等于输入值;如果输入 x 小于等于 0,则输出为 0。

2.2.2、张量积

张量积或点积是最常见且最有用的张量运算之一。注意,不要将其与逐元素乘积弄混。


在 NumPy 中使用 np.dot 函数来实现张量积:z = np.dot(x, y)


数学符号中的(·)表示点积运算:z = x · y


•两个向量的点积是一个标量,而且只有元素个数相同的向量才能进行点积运算。


•一个矩阵 x 和一个向量 y 做点积运算,其返回值是一个向量,其中每个元素是 y 和 x 每一行的点积。


•对于矩阵 x 和 y,当且仅当 x.shape[1] == y.shape[0]时,才可以计算点积,其结果是一个形状为(x.shape[0], y.shape[1])的矩阵,其元素是 x 的行与 y 的列之间的向量点积。


2.2.3、张量变形

张量变形是指重新排列张量的行和列,以得到想要的形状。变形后,张量的元素个数与初始张量相同。


import numpy as npx = np.array([[0, 1],              [2, 3]              [4, 5]])x.shape //(3, 2)x = x.reshape((6, 1))>>> x array([[0],       [1],       [2],       [3],       [4],       [5]])x = x.reshape(2, 3)>>> xarray([[0, 1, 2],       [3, 4, 5]])
复制代码


常见的一种特殊的张量变形是转置。矩阵转置是指将矩阵的行和列互换,即 x[i, :]变为 x[:, i]


x = np.zeros((300, 20)) //创建一个形状为(300, 20)的零矩阵x = np.transpose(x)>>> x.shape(20, 300)
复制代码
2.2.4、张量运算的几何解释

平移、旋转、缩放、倾斜等基本的几何操作都可以表示为张量运算。



线性变换:与任意矩阵做点积运算,都可以实现一次线性变换。缩放和旋转,都属于线性变换。


仿射变换:一次线性变换与一次平移的组合。


•带有 rule 激活函数的仿射变换:多次仿射变换相当于一次仿射变换,因此一个完全没有激活函数的多层神经网络等同于一层,这种“深度”神经网络其实就是一个线性模型。


2.2.5、深度学习的几何解释

神经网络完全由一系列张量运算组成,而这些张量运算只是输入数据的简单几何变换。因此,你可以将神经网络解释为高维空间中非常复杂的几何变换,这种变换通过一系列简单步骤来实现。


机器学习的目的:为高维空间中复杂、高度折叠的数据流行(一个连续的表面)找到简洁的表示。深度学习可以将复杂的几何变换逐步分解为一系列基本变换。

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

回顾 1.3 章节【深度学习工作原理】,步骤 a 看起来很简单,只是输入/输出(I/O)的代码。步骤 b、c 仅仅是应用了一些张量运算。难点在于步骤 d:更新模型权重。对于模型的某个权重系数,你怎么知道这个系数应该增大还是减小,以及变化多少?


一种简单的解决方案是,保持模型的其他权重不变,只考虑一个标量系数,让其尝试不同的取值。对于模型的所有系数都要重复这一过程。但这种方法非常低效,因为系数有很多(通常有上千个,甚至多达百万个)。幸运的是,有一种更好的方法:梯度下降法。

2.3.1、导数

假设有一个光滑连续的函数 f(x) = y,由于函数是连续的,因此 x 的微小变化只会导致 y 的微小变化。因此在某个点 p 附近,如果 x 变化足够小,就可以将 f 近似看作斜率为 a 的线性函数。


斜率 a 被称为 f 在 p 点的导数。如果 a < 0,说明 x 在 p 点附近的微增将导致 f(x)减小;如果 a > 0,那么 x 在 p 点附近的微增将导致 f(x)增大;


2.3.2、梯度

导数这一概念可以应用于任何函数,只要函数所对应的表面是连续且光滑的。张量运算的导数叫做梯度。对于一个标量函数来说,导数是表示函数曲线的局部斜率,张量函数的梯度表示该函数所对应多维表面的曲率。


举例来说,物体位置相对于时间的梯度是这个物体的速度,二阶梯度则是它的加速度。

2.3.3、随机梯度下降

步骤 d 中更新模型权重,假设我们要处理的是一个可微函数,可以计算出它的梯度,沿着梯度的反方向更新权重,每次损失都会减小一点。


(1)抽取训练样本 x 和对应目标 y_true 组成的一个数据批量


(2)在 x 上运行模型,得到预测值 y_pred(前向传播)


(3)计算模型在这批数据上的损失值


(4)计算损失相对于模型参数的梯度(反向传播)


(5)将参数沿着梯度的反方向移动一小步,从而减小损失值


这个方法叫做小批量随机梯度下降(SGD),随机是指每批数据都是随机抽取的;如果每次迭代都在所有数据上运行,这叫做批量梯度下降,但是计算成本高得多,折中办法是选择合理的小批量大小。


神经网络的每一个权重系数都是空间中的一个自由维度,为了对损失表面有更直观的认识,可以将沿着二维损失表面的梯度下降可视化,但你不可能将神经网络的真实训练过程可视化,因为无法用人类可以理解的方式来可视化 1 000 000 维空间。这些低维表示中建立的直觉,实践中不一定总是准确的。


2.3.4、链式求导:反向传播

在前面的算法中,我们假设函数是可微(可以被求导)的,所以很容易计算其梯度。但是在实践中如何计算复杂表达式的梯度?这时就需要用到反向传播算法。


(1)链式法则


利用简单运算(如加法、rule 或张量积)的导数,可以轻松计算出这些基本运算的任意复杂组合的梯度。链式法则规定:grad(y, x) == grad(y, x1) * grad(x1, x),因此只要知道 f 和 g 的导数,就可以求出 fg 的导数。如果添加更多的中间函数,看起来就像是一条链。将链式法则应用于神经网络梯度值的计算,就得到了一种叫做反向传播的算法。


(2)用计算图进行自动微分


思考反向传播的一种有用方法是利用计算图。计算图是 TensorFlow 和深度学习革命的核心数据结构。它是一种由运算构成的有向无环图。如今,现代框架比如 TensorFlow,支持基于计算图的自动微分,可以计算任意可维张量运算组合的梯度,只需写出前向传播,而无需做任何额外工作。


GradientTape 是一个 API,让你可以充分利用 TensorFlow 强大的自动微分能力。它是一个 Python 作用域,能够以计算图(tape)的形式记录在其中运行的张量运算。

3、实践:使用 Python 的 Kears 库识别手写数字

在这个例子中,我们要解决的问题是,将手写数字的灰度图像(28 像素 * 28 像素)划分到 10 个类别(从 0 到 9)中,我们将使用 MNIST 数据集,它是机器学习领域的一个经典数据集。你可以将解决 MNIST 问题看作深度学习的“Hello World”。

3.1 加载 Kears 中的 MNIST 数据集

from tensorflow.keras.datasets import mnist(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
复制代码


train_images, train_labels 组成了训练集,模型将从这些数据中进行学习。我们会在测试集 test_images, test_labels 上对模型进行测试。


查看数据集形状:


>>> train_images.shape(60000, 28, 28) //训练集为60000张图片,每张图片中28*28像素点数据>>> test_images.shape(10000, 28, 28) //测试集为10000张图片,每张图片中28*28像素点数据
复制代码

3.2 神经网络架构模型

from tensorflow import kerasfrom tensorflow.keras import layersmodel = keras.Sequential([    layers.Dense(512, activation="relu"),    layers.Dense(10, activation="softmax")])
复制代码


神经网络的核心组件是层(layer),大多数深度学习工作设计将简单的层链接起来,从而实现渐进式的数据蒸馏,从输入数据中提取表示。


本例中的模型包含 2 个 Dense 层,每层都对输入数据做一些简单的张量运算(relu、softmax),这些运算都涉及权重张量,权重张量是该层的属性或参数,里面保存了模型所学到的知识。

3.3 模型编译

model.compile(    optimizer="rmsprop",    loss="sparse_categorical_crossentropy",    metrics=["accuracy"])
复制代码


这里指定了编译的 3 个步骤:优化器、损失函数以及监控的指标。其中 sparse_categorical_crossentropy 是损失函数,用于学习权重张量的反馈信号;使用 rmsprop 优化器,通过小批量随机梯度下降(SGD)降低损失值。

3.4 准备图像数据

train_images = train_images.reshape((60000, 28*28))train_images = train_images.astype("float32") / 255test_images = test_images.reshape((10000, 28*28))test_images = test_images.astype("float32") / 255
复制代码


在开始训练之前,我们先对数据进行预处理,将其变化为模型要求的形状,并缩放到所有值都在[0, 1]区间。

3.5 拟合模型

model.fit(train_images, train_labels, epochs=5, batch_size=128)
复制代码


在 Keras 中通过调用模型的 fit 方法来完成训练数据上的拟合模型:模型开始在训练数据上进行迭代(每个小批量包含 128 个样本),共迭代 5 轮。对于每批数据,模型会计算损失相对于权重的梯度,并将权重沿着减小该批量对应损失值的方向移动,5 轮迭代后训练精度到达了 98.9%。

3.6 利用模型预测

>>> test_digits = test_images[0:10]>>> predictions = model.predict(test_digits)>>> predictions[0]//为了方面阅读,以下数据均为示例array([1.07, 1.69, 6.13, 8.41, 2.99, 3.03, 8.36, 9.99, 2.66, 3.81], dtype=float32)
复制代码


这个数组中的每个值,为对应数字图像 test_digits[0]属于 0-9 类别的概率,可以看到第 7 个概率最大,因此这个数字一定是 7。检查测试标签是否与之一致:


>>> test_lables[0]7
复制代码

3.7 在新数据上评估模型

>>> test_loss, test_acc = model.evaluate(test_images, test_lables)>>> print(f"test_acc: {test_acc}")test_acc: 0.9785
复制代码


测试精度约为 97.8%,比训练精度 98.9%低不少。训练精度和测试精度之间的这种差距是过拟合造成的。

4、参考资料

图书:Python 深度学习(第 2 版)


作者:[美]弗朗索瓦·肖莱 著 张亮 译


链接:https://item.jd.com/13378515.html

发布于: 刚刚阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
AI入门之深度学习:基本概念篇_京东科技开发者_InfoQ写作社区