一、深度学习概述
1. 什么是深度学习
人工智能、机器学习和深度学习之间的关系:
机器学习是实现人工智能的一种途径,深度学习是机器学习的子集,区别如下:
传统机器学习算法依赖人工设计特征、提取特征,而深度学习依赖算法自动提取特征。深度学习模仿人类大脑的运行方式,从大量数据中学习特征,这也是深度学习被看做黑盒子、可解释性差的原因。
随着算力的提升,深度学习可以处理图像,文本,音频,视频等各种内容,主要应用领域有:
- 图像处理:分类、目标检测、图像分割(语义分割)
- 自然语言处理:LLM、NLP、Transformer
- 语音识别:对话机器人、智能客服(语音+NLP)
- 自动驾驶:语义分割(行人、车辆、实线等)
- LLM:大Large语言Language模型Model
- 机器人:非常火的行业
有了大模型的加持,AI+各行各业。
2. 深度学习发展历史
深度学习其实并不是新的事物,深度学习所需要的神经网络技术起源于20世纪50年代,叫做感知机。当时使用单层感知机,因为只能学习线性可分函数,连简单的异或(XOR)等线性不可分问题都无能为力,1969年Marvin Minsky写了一本叫做《Perceptrons》的书,他提出了著名的两个观点:1.单层感知机没用,我们需要多层感知机来解决复杂问题 2.没有有效的训练算法。
20世纪80年代末期,用于人工神经网络的反向传播算法(也叫Back Propagation算法或者BP算法)的发明,给机器学习带来了希望,掀起了基于统计模型的机器学习热潮。这个热潮一直持续到今天。人们发现,利用BP算法可以让一个人工神经网络模型从大量训练样本中学习统计规律,从而对未知事件做预测。这种基于统计的机器学习方法比起过去基于人工规则的系统,在很多方面显出优越性。这个时候的人工神经网络,虽也被称作多层感知机(Multi-layer Perceptron),但实际是种只含有一层隐层节点的浅层模型。
2006年,杰弗里·辛顿以及他的学生鲁斯兰·萨拉赫丁诺夫正式提出了深度学习的概念。
2012年,在著名的ImageNet图像识别大赛中,杰弗里·辛顿领导的小组采用深度学习模型AlexNet一举夺冠。AlexNet采用ReLU激活函数,从根本上解决了梯度消失问题,并采用GPU极大的提高了模型的运算速度。
同年,吴恩达教授和Jeff Dean主导的深度神经网络DNN技术在ImageNet评测中把错误率从26%降低到15%,再一次吸引了学术界和工业界对于深度学习领域的关注。
2016年,随着谷歌公司基于深度学习开发的AlphaGo以4:1的比分战胜了国际顶尖围棋高手李世石,深度学习的热度一时无两。后来,AlphaGo又接连和众多世界级围棋高手过招,均取得了完胜。这也证明了在围棋界,基于深度学习技术的机器人已经超越了人类。
2017年,基于强化学习算法的AlphaGo升级版AlphaGo Zero横空出世。其采用“从零开始”、“无师自通”的学习模式,以100:0的比分轻而易举打败了之前的AlphaGo。除了围棋,它还精通国际象棋等其它棋类游戏,可以说是真正的棋类“天才”。此外在这一年,深度学习的相关算法在医疗、金融、艺术、无人驾驶等多个领域均取得了显著的成果。所以,也有专家把2017年看作是深度学习甚至是人工智能发展最为突飞猛进的一年。
2019年,基于Transformer 的自然语言模型的持续增长和扩散,这是一种语言建模神经网络模型,可以在几乎所有任务上提高NLP的质量。Google甚至将其用作相关性的主要信号之一,这是多年来最重要的更新。
2020年,深度学习扩展到更多的应用场景,比如积水识别,路面塌陷等,而且疫情期间,在智能外呼系统,人群测温系统,口罩人脸识别等都有深度学习的应用。
2024年的诺贝尔物理学奖授予了深度学习领域的两位杰出人物:物理学家约翰·霍普菲尔德(John Hopfield)与“AI教父”杰弗里·辛顿(Geoffrey Hinton)。这个决定反映了深度学习在科学和技术领域日益增长的重要性,值得注意的是,诺贝尔奖通常不会直接授予计算机科学领域,因为它有自己的奖项,比如图灵奖,被认为是计算机科学领域的最高荣誉。然而,由于深度学习对物理现象的理解和模拟具有重要意义,因此授予物理学奖也是合理的。这一决定也突显了跨学科研究(也就是我们常说的:AI+)的重要性及其对科学进步的推动作用。
3. 深度学习的优势
二、神经网络
我们要学习的深度学习(Deep Learning)是神经网络的一个子领域,主要关注更深层次的神经网络结构,也就是深层神经网络(Deep Neural Networks,DNNs)。所以,我们需要先搞清楚什么是神经网络!
1. 感知神经网络
神经网络(Neural Networks)是一种模拟人脑神经元网络结构的计算模型,用于处理复杂的模式识别、分类和预测等任务。生物神经元如下图:
生物学:
人脑可以看做是一个生物神经网络,由众多的神经元连接而成
- 树突:从其他神经元接收信息的分支
- 细胞核:处理从树突接收到的信息
- 轴突:被神经元用来传递信息的生物电缆
- 突触:轴突和其他神经元树突之间的连接
人脑神经元处理信息的过程:
- 多个信号到达树突,然后整合到细胞体的细胞核中
- 当积累的信号超过某个阈值,细胞就会被激活
- 产生一个输出信号,由轴突传递。
神经网络由多个互相连接的节点(即人工神经元)组成。
2. 人工神经元
人工神经元(Artificial Neuron)是神经网络的基本构建单元,模仿了生物神经元的工作原理。其核心功能是接收输入信号,经过加权求和和非线性激活函数处理后,输出结果。
2.1 构建人工神经元
人工神经元接受多个输入信息,对它们进行加权求和,再经过激活函数处理,最后将这个结果输出。
2.2 组成部分
- 输入(Inputs): 代表输入数据,通常用向量表示,每个输入值对应一个权重。
- 权重(Weights): 每个输入数据都有一个权重,表示该输入对最终结果的重要性。
- 偏置(Bias): 一个额外的可调参数,作用类似于线性方程中的截距,帮助调整模型的输出。
- 加权求和: 神经元将输入乘以对应的权重后求和,再加上偏置。
- 激活函数(Activation Function): 用于将加权求和后的结果转换为输出结果,引入非线性特性,使神经网络能够处理复杂的任务。常见的激活函数有Sigmoid、ReLU(Rectified Linear Unit)、Tanh等。
2.3 数学表示
如果有 n 个输入 x 1 , x 2 , … , x n x_1, x_2, \ldots, x_n x1,x2,…,xn,权重分别为 w 1 , w 2 , … , w n w_1, w_2, \ldots, w_n w1,w2,…,wn,偏置为 b b b,则神经元的输出 y y y 表示为:
z = ∑ i = 1 n w i ⋅ x i + b y = σ ( z ) z=\sum_{i=1}^nw_i\cdot x_i+b \\ y=\sigma(z) z=i=1∑nwi⋅xi+by=σ(z)
其中, σ ( z ) \sigma(z) σ(z) 是激活函数。
2.4 对比生物神经元
人工神经元和生物神经元对比如下表:
生物神经元 | 人工神经元 |
---|---|
细胞核 | 节点 (加权求和 + 激活函数) |
树突 | 输入 |
轴突 | 带权重的连接 |
突触 | 输出 |
3. 深入神经网络
神经网络是由大量人工神经元按层次结构连接而成的计算模型。每一层神经元的输出作为下一层的输入,最终得到网络的输出。
3.1 基本结构
神经网络有下面三个基础层(Layer)构建而成:
-
输入层(Input): 神经网络的第一层,负责接收外部数据,不进行计算。
-
隐藏层(Hidden): 位于输入层和输出层之间,进行特征提取和转换。隐藏层一般有多层,每一层有多个神经元。
-
输出层(Output): 网络的最后一层,产生最终的预测结果或分类结果
3.2 网络构建
我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个权重,经典如下:
注意:同一层的各个神经元之间是没有连接的。
3.3 全连接神经网络
全连接(Fully Connected,FC)神经网络是前馈神经网络的一种,每一层的神经元与上一层的所有神经元全连接,常用于图像分类、文本分类等任务。
3.3.1 特点
- 全连接层: 层与层之间的每个神经元都与前一层的所有神经元相连。
- 权重数量: 由于全连接的特点,权重数量较大,容易导致计算量大、模型复杂度高。
- 学习能力: 能够学习输入数据的全局特征,但对于高维数据却不擅长捕捉局部特征(如图像就需要CNN)。
3.3.2 计算步骤
- 数据传递: 输入数据经过每一层的计算,逐层传递到输出层。
- 激活函数: 每一层的输出通过激活函数处理。
- 损失计算: 在输出层计算预测值与真实值之间的差距,即损失函数值。
- 反向传播(Back Propagation): 通过反向传播算法计算损失函数对每个权重的梯度,并更新权重以最小化损失。
三、数据处理
数据和加载器
-
Ecxel表格的数据;
-
图片是数据;
-
文本信息是数据;
-
官方数据集是数据;
-
make_regression模拟的也是数据;
四、参数初始化
神经网络的参数初始化是训练深度学习模型的关键步骤之一。初始化参数(通常是权重和偏置)会对模型的训练速度、收敛性以及最终的性能产生重要影响。下面是关于神经网络参数初始化的一些常见方法及其相关知识点。
官方文档参考:https://pytorch.org/docs/stable/nn.init.html
1. 固定值初始化
固定值初始化是指在神经网络训练开始时,将所有权重或偏置初始化为一个特定的常数值。这种初始化方法虽然简单,但在实际深度学习应用中通常并不推荐。
1.1 全零初始化
将神经网络中的所有权重参数初始化为0。
方法:将所有权重初始化为零。
缺点:导致对称性破坏,每个神经元在每一层中都会执行相同的计算,模型无法学习。
应用场景:通常不用来初始化权重,但可以用来初始化偏置。
代码演示:
import torch
import torch.nn as nndef test004():# 3. 全0参数初始化linear = nn.Linear(in_features=6, out_features=4)# 初始化权重参数nn.init.zeros_(linear.weight)# 打印权重参数print(linear.weight)if __name__ == "__main__":test004()
打印结果:
Parameter containing:
tensor([[0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0.]], requires_grad=True)
1.2 全1初始化
全1初始化会导致网络中每个神经元接收到相同的输入信号,进而输出相同的值,这就无法进行学习和收敛。所以全1初始化只是一个理论上的初始化方法,但在实际神经网络的训练中并不适用。
代码演示:
import torch
import torch.nn as nndef test003():# 3. 全1参数初始化linear = nn.Linear(in_features=6, out_features=4)# 初始化权重参数nn.init.ones_(linear.weight)# 打印权重参数print(linear.weight)if __name__ == "__main__":test003()
输出结果:
Parameter containing:
tensor([[1., 1., 1., 1., 1., 1.],[1., 1., 1., 1., 1., 1.],[1., 1., 1., 1., 1., 1.],[1., 1., 1., 1., 1., 1.]], requires_grad=True)
1.3 任意常数初始化
将所有参数初始化为某个非零的常数(如 0.1,-1 等)。虽然不同于全0和全1,但这种方法依然不能避免对称性破坏的问题。
import torch
import torch.nn as nndef test002():# 2. 固定值参数初始化linear = nn.Linear(in_features=6, out_features=4)# 初始化权重参数nn.init.constant_(linear.weight, 0.63)# 打印权重参数print(linear.weight)passif __name__ == "__main__":test002()
输出结果:
Parameter containing:
tensor([[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300]], requires_grad=True)
参考2:
import torch
import torch.nn as nndef test002():net = nn.Linear(2, 2, bias=True)# 假设一个数值x = torch.tensor([[0.1, 0.95]])# 初始化权重参数net.weight.data = torch.tensor([[0.1, 0.2], [0.3, 0.4]])# 输出什么:权重参数会转置output = net(x)print(output, net.bias)passif __name__ == "__main__":test002()
2. 随机初始化
方法:将权重初始化为随机的小值,通常从正态分布或均匀分布中采样。
应用场景:这是最基本的初始化方法,通过随机初始化避免对称性破坏。
代码演示:随机分布之均匀初始化
import torch
import torch.nn as nndef test001():# 1. 均匀分布随机初始化linear = nn.Linear(in_features=6, out_features=4)# 初始化权重参数nn.init.uniform_(linear.weight)# 打印权重参数print(linear.weight)if __name__ == "__main__":test001()
打印结果:
Parameter containing:
tensor([[0.4080, 0.7444, 0.7616, 0.0565, 0.2589, 0.0562],[0.1485, 0.9544, 0.3323, 0.9802, 0.1847, 0.6254],[0.6256, 0.2047, 0.5049, 0.3547, 0.9279, 0.8045],[0.1994, 0.7670, 0.8306, 0.1364, 0.4395, 0.0412]], requires_grad=True)
代码演示:正态分布初始化
import torch
import torch.nn as nndef test005():# 5. 正太分布初始化linear = nn.Linear(in_features=6, out_features=4)# 初始化权重参数nn.init.normal_(linear.weight, mean=0, std=1)# 打印权重参数print(linear.weight)if __name__ == "__main__":test005()
打印结果:
Parameter containing:
tensor([[ 1.5321, 0.2394, 0.0622, 0.4482, 0.0757, -0.6056],[ 1.0632, 1.8069, 1.1189, 0.2448, 0.8095, -0.3486],[-0.8975, 1.8253, -0.9931, 0.7488, 0.2736, -1.3892],[-0.3752, 0.0500, -0.1723, -0.4370, -1.5334, -0.5393]],requires_grad=True)
3. Xavier 初始化
也叫做Glorot初始化。
方法:根据输入和输出神经元的数量来选择权重的初始值。权重从以下分布中采样:
W ∼ U ( − 6 n i n + n o u t , 6 n i n + n o u t ) W\sim\mathrm{U}\left(-\frac{\sqrt{6}}{\sqrt{n_\mathrm{in}+n_\mathrm{out}}},\frac{\sqrt{6}}{\sqrt{n_\mathrm{in}+n_\mathrm{out}}}\right) W∼U(−nin+nout6,nin+nout6)
或者
W ∼ N ( 0 , 2 n i n + n o u t ) W\sim\mathrm{N}\left(0,\frac{2}{n_\mathrm{in}+n_\mathrm{out}}\right) W∼N(0,nin+nout2)
N ( 0 , std 2 ) N ( 0 , std 2 ) \mathcal{N}(0, \text{std}^2)\mathcal{N}(0, \text{std}^2) N(0,std2)N(0,std2)
其中 n in n_{\text{in}} nin 是当前层的输入神经元数量, n out n_{\text{out}} nout是输出神经元数量。
优点:平衡了输入和输出的方差,适合 S i g m o i d Sigmoid Sigmoid 和 T a n h Tanh Tanh 激活函数。
应用场景:常用于浅层网络或使用 S i g m o i d Sigmoid Sigmoid 、 T a n h Tanh Tanh 激活函数的网络。
代码演示:
import torch
import torch.nn as nndef test007():# Xavier初始化:正态分布linear = nn.Linear(in_features=6, out_features=4)nn.init.xavier_normal_(linear.weight)print(linear.weight)# Xavier初始化:均匀分布linear = nn.Linear(in_features=6, out_features=4)nn.init.xavier_uniform_(linear.weight)print(linear.weight)if __name__ == "__main__":test007()
打印结果:
Parameter containing:
tensor([[-0.4838, 0.4121, -0.3171, -0.2214, -0.8666, -0.4340],[ 0.1059, 0.6740, -0.1025, -0.1006, 0.5757, -0.1117],[ 0.7467, -0.0554, -0.5593, -0.1513, -0.5867, -0.1564],[-0.1058, 0.5266, 0.0243, -0.5646, -0.4982, -0.1844]],requires_grad=True)
Parameter containing:
tensor([[-0.5263, 0.3455, 0.6449, 0.2807, -0.3698, -0.6890],[ 0.1578, -0.3161, -0.1910, -0.4318, -0.5760, 0.3746],[ 0.2017, -0.6320, -0.4060, 0.3903, 0.3103, -0.5881],[ 0.6212, 0.3077, 0.0783, -0.6187, 0.3109, -0.6060]],requires_grad=True)
4. He初始化
也叫kaiming 初始化。
方法:专门为 ReLU 激活函数设计。权重从以下分布中采样:
W ∼ N ( 0 , 2 n i n ) W\sim\mathrm{N}\left(0,\frac{2}{n_\mathrm{in}}\right) W∼N(0,nin2)
其中 n in n_{\text{in}} nin 是当前层的输入神经元数量。
优点:适用于 R e L U ReLU ReLU 和 L e a k y R e L U Leaky ReLU LeakyReLU 激活函数。
应用场景:深度网络,尤其是使用 ReLU 激活函数时。
代码演示:
import torch
import torch.nn as nndef test006():# He初始化:正态分布linear = nn.Linear(in_features=6, out_features=4)nn.init.kaiming_normal_(linear.weight, nonlinearity="relu")print(linear.weight)# He初始化:均匀分布linear = nn.Linear(in_features=6, out_features=4)nn.init.kaiming_uniform_(linear.weight, nonlinearity="relu")print(linear.weight)if __name__ == "__main__":test006()
输出结果:
Parameter containing:
tensor([[ 1.4020, 0.2030, 0.3585, -0.7419, 0.6077, 0.0178],[-0.2860, -1.2135, 0.0773, -0.3750, -0.5725, 0.9756],[ 0.2938, -0.6159, -1.1721, 0.2093, 0.4212, 0.9079],[ 0.2050, 0.3866, -0.3129, -0.3009, -0.6659, -0.2261]],requires_grad=True)Parameter containing:
tensor([[-0.1924, -0.6155, -0.7438, -0.2796, -0.1671, -0.2979],[ 0.7609, 0.9836, -0.0961, 0.7139, -0.8044, -0.3827],[ 0.1416, 0.6636, 0.9539, 0.4735, -0.2384, -0.1330],[ 0.7254, -0.4056, -0.7621, -0.6139, -0.6093, -0.2577]],requires_grad=True)
5. 总结
在使用Torch构建网络模型时,每个网络层的参数都有默认的初始化方法,同时还可以通过以上方法来对网络参数进行初始化。