深度学习基础
一、代码练习
1. 张量
张量是深度学习模型训练的基本数据类型,之后的样本,训练模型都基于该数据结构进行计算,一维张量称为向量,二位张量是矩阵
定义向量基本操作:使用torch.tensor1
2
3
4
5
6
7import torch
x = torch.tensor(666) # 一维张量
y = torch.tensor([1, 2]) # 向量
z = torch.ones(2, 3) # 矩阵
normal = torch.ones(2, 3, 4) # 可以是任意维度的矩阵
创建基本方法1
2
3
4
5
6
7
8
9
10
11
12
13
14import torch
x = torch.ones(2, 3) # 全一
y = torch.zeros(2, 3) # 全0
z = torch.eye(2, 3) # 创建单位矩阵
# 按照规律创建
f = torch.arange(0, 10, 2) # arrange(start, end, step) 从start开始到end,每步间隔step
p = torch.linspace(0, 1, 5) # 在区间内均匀取点:[0, 0.25, 0.500, 0.7500, 1.000]
r = torch.rand(2, 3) # 每个元素来源[0, 1) 随机生成矩阵
o = torch.randn(2, 3) # 标准正态分布
h = torch.normal(mean=0, std=1, size=(2, 3)) # 指定不同的均值和标准差,正态分布
k = torch.randperm(5) # 0 - 4随机排列
运算:
- 基本运算,加减乘除,求幂运算
- 布尔运算、大于小于、最大最小
- 线性运算、矩阵乘法、求模、求行列式
基本运算包括:abs/sqrt/div/exp/fmod/pow,以及一些三角函数cos/sin/asin/atan2/cosh, 及ceil/round/floor/trunc等
布尔运算:gt/lt/ge/le/eq/ne,topk, sort,max,min
线性计算:trace,diag,mm/bmm,t,dot/cross,inverse,svd等
2. 旋转矩阵分类
初始化参数
![[{A6344C9E-BC08-4314-8431-6631AC183DF1}.png]]
1 | import random |
几何意义:
t = linspace(0,1,N):从中心(半径 0)到边缘(半径 1)逐渐变大的半径。inner_var:角度。从(2π/C)*c开始,转大约 两圈(到(2π/C)*(2+c)),再加一点高斯噪声randn*0.2,让点不在完美曲线上,更真实。(sin(θ), cos(θ)):单位圆上的方向。t * (sin, cos):把点沿这个方向从 0 拉伸到 1,形成螺旋臂。- 每个 c 生成一条螺旋,3 类一共 3 条螺旋臂,彼此交错。
![[{34ACE4C4-7CBA-43C0-A729-C407B6B93B68}.png]]在二维平面上生成了 3 条交错的螺旋线,每条 1000 个点,共 3000 个点,标签分别是 0、1、2
线性模型分类
1 | import random |
![[{2A5D4743-1185-44DC-B67D-1E4B41B58D8B}.png]]
现在模型相当于线性变换,将3000个样本全部喂到模型里,训练梯度并累计之后,准确率来到50%,由于全线性,比较难以拟合螺旋数据,所以准确率难以提高
两层神经网络(加Relu版本)
在线性两层网络基础上加入Relu,使得训练曲线可以弯曲,在原来两层神经网络中,
有 一层: W = w1 @ X1 + b1 + w2 @ X2 + b2 … -> 两层W = (w1 @ X1 + b1 + w2 @ X2 + b2 ..) @ X1 + b1 依旧是线性的,加入激活函数后使得原来的训练曲线可以变成折现
1 | import random |
![[{E25A7979-08BB-4BF6-A201-B3F58391B436}.png]]
准确率来到99%
二、知识回答
1、AlexNet有哪些特点?为什么可以比LeNet取得更好的性能?
AlexNet 的核心特点:
- 结构:8层
- 激活:ReLU
- 池化:重叠最大池化
- 正则:Dropout, 数据增强, weight decay, LRN
- 训练:双GPU分组卷积,SGD momentum,学习率衰减,模型集成…
- 输入输出:227x227x3,1000类。
与LeNet对比:
LeNet:浅、小、灰度32x32、sigmoid/tanh、平均池化、无Dropout/数据增强、约60k参数。
AlexNet:深、大、彩色高分辨率、ReLU、最大池化、Dropout/数据增强、约60M参数。
为什么更好:
- 数据和任务:ImageNet大规模复杂,LeNet MNIST简单。
- 容量和深度:更多层学层次特征。
- ReLU:缓解梯度消失,训练快。
- 正则化:Dropout+数据增强+权重衰减+LRN,防过拟合。
- 池化:重叠最大池化保留信息。
- GPU:使大模型训练可行,双GPU分组卷积。
- 训练策略:学习率衰减、动量、模型集成。
所以AlexNet在ImageNet上top-5错误率16.4%,远超第二名。它不是LeNet简单放大,而是适应大数据/复杂图像的现代CNN开端。
2、激活函数有哪些作⽤?
假设你有一堆数据点,它们大致排成一条优美的曲线。但你手里只有一把直尺,只能画直线。无论怎么调整角度和位置,直线都无法贴合那条曲线——这就是线性模型的困境。
神经网络最初也面临同样的问题。但有了激活函数,它才从“只会画直线”进化成“能画任意曲线”的强大工具。
最简单的模型是线性回归:
y=wx+by=wx+b
其中 ww 是权重,bb 是偏置。给它一组数据,它找到一条直线,让预测值尽量接近真实值。
如果堆叠多层线性变换呢?
y=W2(W1x+b1)+b2y=W2(W1x+b1)+b2
展开后仍然是:
y=Wx+by=Wx+b
也就是说,多层线性网络等价于单层线性网络。无论叠多少层,它依然只能拟合直线(或高维空间中的平面)。这显然无法处理图像、语音、自然语言等复杂任务。
拟合曲线:需要非线性
要让网络拟合曲线,必须在层与层之间加入非线性变换。这个变换就是激活函数。
激活函数通常作用在神经元的线性输出之后:
a=f(Wx+b)a=f(Wx+b)
其中 ff 就是激活函数。有了它,多层网络就不再等价于单层线性模型,而是可以逼近任意复杂的非线性函数——这就是通用逼近定理的直观含义。
可以说:线性层负责“画线”,激活函数负责“把线掰弯”。多层非线性组合起来,就能拼出任意曲线。
1. Sigmoid
σ(x)=11+e−xσ(x)=1+e−x1
它的输出范围是 (0,1)(0,1),形状像一条平滑的 S 形曲线。
优点:
- 输出可解释为概率,适合二分类输出层。
- 平滑可导,便于反向传播。
缺点:
- 当输入很大或很小时,导数接近 0,导致梯度消失。
- 输出不是零中心,可能让训练不稳定。
- 计算涉及指数,相对较慢。
2. Tanh
tanh(x)=ex−e−xex+e−xtanh(x)=ex+e−xex−e−x
输出范围是 (−1,1)(−1,1),也是 S 形曲线,但零中心。
优点:
- 零中心,通常比 Sigmoid 收敛更快。
- 同样平滑可导。
缺点: - 两端依然饱和,梯度消失问题仍然存在。
- 计算量也不小。
3. ReLU(Rectified Linear Unit)
ReLU(x)=max(0,x)ReLU(x)=max(0,x)
它非常简单:正数原样输出,负数直接置零。
优点:
- 正区间导数恒为 1,有效缓解梯度消失。
- 计算极快,只需比较和取最大值。
- 负区间输出为 0,产生稀疏激活,有时能提升泛化。
缺点: - 负区间导数为 0,可能导致“神经元死亡”——某些神经元永远不再激活。
- 输出不是零中心。
为了解决神经元死亡,后续又出现了 Leaky ReLU、ELU、GELU、Swish 等变体,但 ReLU 依然是很多网络的基础。3、梯度消失现象是什么?
梯度消失(vanishing gradient) 是指在深层神经网络训练时,反向传播的梯度从输出层向输入层逐层传播,由于链式法则中多个局部导数相乘,梯度幅度逐层衰减,导致靠近输入层的参数几乎得不到有效更新。
反向传播时,每一层都要把梯度“乘上”本层的导数再往前传。如果每一层的导数都小于 1,那么乘很多次后,梯度就会指数级变小:
0.25×0.25×0.25×⋯≈00.25×0.25×0.25×⋯≈0
例如 sigmoid 函数的导数最大只有 0.25:
σ′(z)=σ(z)(1−σ(z))≤0.25σ′(z)=σ(z)(1−σ(z))≤0.25
所以一个 10 层网络反向传播时,梯度可能变成 0.2510≈10−60.2510≈10−6,到浅层时几乎为零。
主要表现
- 靠近输入层的参数更新非常慢,甚至几乎不更新。
- 浅层学不到有效特征,底层特征质量差。
- 网络越深,训练越困难,损失下降慢或效果差。
- 靠近输出层的梯度可能还正常,但传到前面就消失了。
4、神经网络是更宽好还是更深好?
深度更好原因
- 层次化特征表达
深层网络可以逐层组合:边缘 → 纹理 → 部件 → 物体。
对图像、语音、自然语言等复杂任务,这种层次抽象非常关键。 - 参数效率更高
某些复杂函数,浅而宽的网络可能需要指数级神经元,深层网络用少得多的参数就能表示。
也就是说,深度可以带来表达能力的“指数级增益”。 - 现代主流架构以深为主
AlexNet、VGG、ResNet、DenseNet、Transformer 都通过增加深度来提升性能。
尤其是 ResNet 用残差连接解决了“更深反而退化”的问题。
代价:
- 容易梯度消失/爆炸。
- 训练慢,收敛难。
- 需要 BN、残差连接、合适初始化等技巧。
- 太深会出现退化问题:训练误差反而上升。
宽度更好原因
- 单层容量大
宽度增加每层的神经元/通道数,能同时学习更多特征。 - 更容易优化和并行
宽网络梯度路径多,训练通常更稳定,GPU 并行效率也较高。 - 浅层宽网络也能逼近复杂函数
通用逼近定理说:单隐层只要足够宽,可以逼近任意连续函数。
代价:
- 参数爆炸,内存和计算成本高。
- 泛化不一定更好,容易过拟合。
- 难以学习深层组合特征。
- 对某些任务,宽度收益边际递减很快。
经验规律
| 情况 | 更推荐 |
|---|---|
| 复杂图像、语音、NLP | 加深,配合残差/BN |
| 简单任务、小数据 | 浅而宽或浅而窄即可 |
| 训练困难、梯度消失 | 加宽、加残差、换 ReLU |
| 欠拟合 | 先加深,再增宽 |
| 过拟合 | 不要盲目加宽或加深,先加正则化 |
| 计算预算有限 | 深度优先,宽度辅助 |
5、为什么要使⽤Softmax?
多分类网络的原始输出只是一组任意实数(logits),不能直接当作概率;Softmax 把它们变成“非负、和为 1”的概率分布,并且可导,便于用交叉熵损失和梯度下降训练。
6、SGD 和 Adam 哪个更有效?
SGD
$θt+1=θt−ηgtθt+1=θt−ηgt$
带动量时:
$vt=βvt−1+gt,θt+1=θt−ηvtvt=βvt−1+gt,θt+1=θt−ηvt$
- 所有参数共用一个学习率。
- 对学习率、调度策略非常敏感。
- 梯度噪声大,但有时这种噪声有助于泛化。
Adam
$mt=β1mt−1+(1−β1)gtmt=β1mt−1+(1−β1)gtvt=β2vt−1+(1−β2)gt2vt=β2vt−1+(1−β2)gt2$
再做偏差校正,更新:
$θt+1=θt−ηm^tv^t+ϵθt+1=θt−ηv^t+ϵm^t$
- 为每个参数自适应调整学习率。
- 初期收敛快,对学习率不那么敏感。
- 需要保存一阶矩和二阶矩,内存开销更大。
| 维度 | SGD + Momentum | Adam / AdamW |
|---|---|---|
| 收敛速度 | 初期慢,需调 LR | 初期快 |
| 超参敏感度 | 对 LR 很敏感 | 对 LR 较鲁棒 |
| 最终泛化 | 常更好,尤其 CV | 可能稍差,AdamW 改善明显 |
| 内存 | 低 | 高,需存 m、v |
| 稀疏梯度 | 差 | 好 |
| 常见场景 | ResNet、经典 CV | Transformer、NLP、稀疏特征 |
| 训练稳定性 | 依赖调参 | 通常更稳 |
