深入浅出深度学习
- 深度学习的本质是通过多层神经网络对数据进行特征提取和转换,从而实现对数据的理解和预测。它的核心是神经网络,神经网络是一种模拟人脑神经元结构和功能的计算模型,它由大量的神经元(节点)和连接(权重)组成,通过对输入数据进行加权求和和非线性变换,实现对数据的表示和处理。
- 深度学习的优势在于它能够自动地从数据中学习特征,而不需要人工设计特征,这使得它在处理复杂数据(如图像、语音、文本等)时表现出色。它的应用范围非常广泛,包括计算机视觉、自然语言处理、语音识别、推荐系统等领域。
- 本文将对深度学习的基本原理进行介绍,并使用 进行构建和训练深度学习模型。
张量
几何代数中定义的张量是基于向量和矩阵的推广,比如可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量。
| 张量维度 | 代表含义 |
|---|---|
| 0维张量 | 代表的是标量(数字) |
| 1维张量 | 代表的是向量 |
| 2维张量 | 代表的是矩阵 |
| 3维张量 | 时间序列数据 股价 文本数据 单张彩色图片(RGB) |
张量是现代机器学习的基础。它的核心是一个数据容器,多数情况下,它包含数字,有时候它也包含字符串,但这种情况比较少。因此可以把它想象成一个数字的水桶。
这里有一些存储在各种类型张量的公用数据集类型:
- 3维 = 时间序列
- 4维 = 图像
- 5维 = 视频
创建张量
| 函数 | 功能 |
|---|---|
| Tensor(sizes) | 基础构造函数 |
| tensor(data) | 类似于np.array |
| ones(sizes) | 全1 |
| zeros(sizes) | 全0 |
| eye(sizes) | 对角为1,其余为0 |
| arange(s,e,step) | 从s到e,步长为step |
| linspace(s,e,steps) | 从s到e,均匀分成step份 |
| rand/randn(sizes) | rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布 |
| normal(mean,std) | 正态分布(均值为mean,标准差是std) |
| randperm(m) | 随机排列 |
操作张量
PyTorch中的 Tensor 支持超过一百种操作,包括转置、索引、切片、数学运算、线性代数、随机数等等,具体使用方法可参考官方文档。
神经网络
在 PyTorch 中,神经网络是通过继承 torch.nn.Module 类来定义的,自定义神经网络是,通常会创建一个继承自 nn.Module 的类,并在 __init__ 方法中定义网络的层,在 forward 方法中定义前向传播的计算过程。
__init(self)__: 构造函数,用于初始化网络的层(如卷积层、线性层等)、激活函数(如ReLU、Sigmoid等)以及其他需要的组件。forward(self, input_data): 前向传播函数,定义了输入数据如何通过__init__中定义的层进行计算,最终输出结果。这个方法会在调用网络实例时自动执行。接收一个或多个输入张量,并返回一个或多个输出张量。
网络结构
torch.nn 提供了很多不同类型的网络结构,它们可以在 nn.Module 子类中组合起来,以构建复杂的深度学习模型,其中线性层、卷积层、循环层代表了针对不同数据和任务的基本操作。
线性层(nn.Linear)
线性层(Linear Layer)也被称为全连接层(Fully Connected Layer),它是神经网络中最基本的层之一。线性层的主要功能是对输入数据进行线性变换,即通过权重矩阵和偏置向量将输入映射到输出空间。在数学上,线性层的计算可以表示为:,其中 是输入向量, 是权重矩阵, 是偏置向量, 是输出向量。
线性层是许多架构中的基本组成部分,包括简单的多层感知机(MLP),并且在像 CNN 和 RNN 这样更复杂的模型中,它们通常作为最终的分类或回归头部。
1 | import torch |
卷积层(nn.Conv2d)
卷积层是现代计算机视觉任务中最常用的层之一。它通过卷积操作提取输入数据(通常是图像)的局部特征。它的核心工作原理是在输入空间维度(高和宽)上滑动小型滤波器,对于每个位置计算局部区域的加权和,从而生成特征图(feature map)。这个过程可以帮助模型捕捉图像中的边缘、纹理、角点和其他重要特征。
1 | # 示例:处理一批 16 张图像,3 通道(RGB),32x32 像素 |
循环层(nn.RNN)
循环神经网络(RNN)是一类用于处理序列数据的神经网络。它们通过在时间步之间共享参数来捕捉序列中的时间依赖关系。RNN 的核心思想是使用隐藏状态(hidden state)来记忆先前时间步的信息,从而在处理当前时间步时能够参考过去的输入。比如文本、音频信号和时间序列等数据都可以使用 RNN 来建模。
1 | # 示例:处理一批 10 个序列,每个序列长 20 步,每步有 5 个特征。 |
虽然 nn.RNN 展示了基本思想,但简单的 RNN 通常因梯度消失而难以处理长序列。在实际应用中,通常更偏好 nn.LSTM(长短期记忆)和 nn.GRU(门控循环单元 (GRU))等更高级的循环层,因为它们包含门控机制,能更好地管理长距离依赖中的信息流。这些将在第 7 章再次提及。
激活函数
神经网络的表示能力很大程度上得益于在层之间引入非线性。如果只是简单地堆叠线性变换而没有任何介入函数,整个网络将简化为一个单一的等效线性变换。无论网络有多少层,它都只能学习输入与输出之间的线性关系。
激活函数是引入这些重要非线性的组成部分。它们逐元素应用于层的输出,在将值传递给下一层之前对其进行转换。PyTorch 在 torch.nn 模块中提供了各种各样的激活函数,通常通过将它们实例化为层在模型定义中使用,这里介绍最常见的三种:ReLU、Sigmoid 和 Tanh。
修正线性单元(ReLU)
含义:是一种非线性激活函数,它将输入小于零的值置为零,而将输入大于零的值保持不变。
优点:
- 计算简单,收敛速度快。
- 在正区间内具有线性特性,有助于缓解梯度消失问题。
- 由于负区间的输出为零,ReLU 具有稀疏激活的特性,有助于提高模型的表达能力。
缺点:
- 对于输入小于零的神经元,梯度为零,可能导致“死亡神经元”问题,即这些神经元在训练过程中可能永远不会被激活。
- 在某些情况下,ReLU 可能会导致梯度爆炸问题,尤其是在深层网络中。
- 输出范围为 ,可能导致输出值过大,需要注意梯度裁剪或归一化。
逻辑函数(Sigmoid)
含义:将任意实数平滑映射到 (0, 1) 的范围内,常用于二分类问题的输出层,输出代表一个概率值。
优点:
- 输出范围在 (0, 1) 之间,适合表示概率。
- 函数连续且可微,便于梯度计算。
缺点:
- 在输入值较大或较小时,梯度接近零,容易导致梯度消失问题,影响深层网络的训练。
- 输出不是零中心的,可能导致梯度更新方向不一致,影响收敛速度。
- 计算指数函数相对较慢,尤其在大规模网络中可能影响训练效率。
双曲正切函数(Tanh)
含义:将任意实数平滑映射到 (-1, 1) 的范围内,常用于隐藏层的激活函数。
优点:
- 输出范围在 (-1, 1) 之间,具有零中心特性,有助于梯度更新方向的一致性,有助于模型在训练过程中更快地收敛。
- 函数连续且可微,便于梯度计算。
缺点:
- 在输入值较大或较小时,梯度接近零,容易导致梯度消失问题,影响深层网络的训练。
- 计算指数函数相对较慢,尤其在大规模网络中可能影响训练效率。
损失函数
神经网络由堆叠的层和激活函数构建而成,每一层都可以看作是一个函数,它将输入映射到输出。神经网络的训练目标是通过调整网络的参数,使得网络的输出尽可能接近真实标签。为了衡量网络输出与真实标签之间的差距,引入了损失函数(Loss Function)。
损失函数接收网络的输出和真实标签作为输入,计算出一个标量值,表示网络预测的误差。这个误差值越小,说明网络的预测结果越接近真实标签。训练过程中,神经网络通过反向传播算法(Backpropagation)计算损失函数对网络参数的梯度,并使用优化算法(如梯度下降)更新参数,以最小化损失函数。
均方误差(MSE)
均方差误差(Mean Squared Error, MSE)是回归问题中最常用的损失函数之一。它计算预测值与真实值之间差异的平方的平均值。MSE 的公式如下:
其中 是样本数量, 是第 个样本的真实值, 是第 个样本的预测值。
平均绝对误差(MAE)
平均绝对误差(Mean Absolute Error, MAE)是回归问题中另一种常用的损失函数。它计算预测值与真实值之间差异的绝对值的平均值。MAE 的公式如下:
交叉熵损失(Cross-Entropy Loss)
交叉熵损失(Cross-Entropy Loss)是分类问题中最常用的损失函数之一。它衡量了预测概率分布与真实标签分布之间的差异。对于二分类问题,交叉熵损失的公式如下: