-
【本题 10 分】 请把离散的递归神经网络模型 x ( k + 1 ) = f ( w x ( k ) + b ) x(k+1) = f(wx(k) + b) x(k+1)=f(wx(k)+b) 化成连续型神经网络模型。
要将一个离散时间系统转换为连续时间系统,我们可以使用泰勒展开或直接假设一个小的时间步长 Δ t \Delta t Δt,然后利用差商近似导数。对于给定的离散模型 x ( k + 1 ) = f ( w x ( k ) + b ) x(k+1) = f(wx(k) + b) x(k+1)=f(wx(k)+b),可以将其视为在小时间间隔 Δ t \Delta t Δt 内的变化:
x ( t + Δ t ) − x ( t ) Δ t ≈ x ˙ ( t ) \frac{x(t+\Delta t) - x(t)}{\Delta t} \approx \dot{x}(t) Δtx(t+Δt)−x(t)≈x˙(t)
如果我们设 Δ t = 1 \Delta t = 1 Δt=1,则 k k k 对应于时间 t t t,那么我们可以写出:
x ˙ ( t ) = lim Δ t → 0 f ( w x ( t ) + b ) − x ( t ) Δ t \dot{x}(t) = \lim_{\Delta t \to 0} \frac{f(wx(t) + b) - x(t)}{\Delta t} x˙(t)=Δt→0limΔtf(wx(t)+b)−x(t)
这通常会简化为某种形式的微分方程,具体取决于激活函数 f f f 的选择。如果 f f f 是线性的,则可以直接得出结果;如果是非线性函数,则可能需要使用微分学的知识来求解。 -
【本题 10 分】 简述 PyTorch 框架中实现一个神经网络结构的方法,至少给出 2 种方法。
- 使用
torch.nn.Module
类:这是最常用的方式,通过继承nn.Module
类并定义forward
方法来构建网络。 - 使用
torch.nn.Sequential
构建简单的顺序模型:当模型是层的简单堆叠时,可以通过传递一系列层到Sequential
来快速创建模型。
- 使用
-
【本题 20 分】 请解释 LeNet5、AlexNet、ResNet 网络结构特点。
- LeNet5:由 Yann LeCun 提出,是最早的卷积神经网络之一,用于手写数字识别。它引入了卷积层、池化层和全连接层的概念。
- AlexNet:由 Alex Krizhevsky 等人提出,赢得了 ImageNet 2012 年挑战赛。它引入了 ReLU 激活函数、dropout 正则化以及更深层次的网络结构。
- ResNet(残差网络):由 Kaiming He 等人提出,解决了非常深的网络中的梯度消失问题。它通过引入残差块,使得信息可以直接从一层传到多层之后,从而允许训练更深的网络。
-
【本题 20 分】 为了防止过拟合,有哪些正则化方法?
- L2 正则化(权重衰减):向损失函数添加一个惩罚项,以限制参数的大小,从而减少复杂度。
- Dropout:随机丢弃一部分神经元,迫使网络学习更加鲁棒的特征表示。
- 数据增强:通过变换现有数据生成新的训练样本,增加数据多样性。
- 早停(Early Stopping):监控验证集上的性能,并在性能开始下降时停止训练。
-
【本题 20 分】 什么是 Dropout?Dropout 有什么作用?ReLU 激活函数相对于传统的 Sigmoid 激活函数有什么优势?
- Dropout 是一种正则化技术,其中在训练期间随机选择一部分神经元忽略(即设置为零)。这有助于防止复杂的共适应关系,从而提高泛化能力。
- ReLU (Rectified Linear Unit) 相较于 Sigmoid 的优势在于:
- 它不会造成梯度消失的问题,因为它的导数要么是 0 要么是 1。
- 计算效率更高,因为它只涉及阈值操作。
- 它能够缓解全负输入导致的“死亡神经元”问题,而 Sigmoid 在极端情况下可能会输出几乎恒定的值,导致后续梯度接近于零。
-
【本题 20 分】 请给出至少 3 种生成式 AI 模型的例子,并说明其用途。
- Variational Autoencoders (VAE):用于学习数据的概率分布,可以用来生成与训练数据相似的新样本,如图像、文本等。
- Generative Adversarial Networks (GAN):包含两个相互竞争的网络——生成器和判别器。广泛应用于图像合成、风格迁移等领域。
- Transformer-based Models(如 GPT 或 BERT):虽然主要是预训练语言模型,但它们也被用于生成任务,例如文本补全、对话系统和翻译等。
-
【本题 10 分】 简述 PyTorch 框架中梯度自动计算的步骤,并举一个例子说明。
PyTorch 中的梯度自动计算(
autograd
)是基于计算图的动态机制实现的。其主要步骤如下:- 定义模型参数:使用
torch.tensor
定义需要计算梯度的参数,并设置requires_grad=True
。 - 前向传播:通过模型计算输出值。
- 计算损失:根据输出值和目标值计算损失函数。
- 反向传播:调用
loss.backward()
计算损失相对于模型参数的梯度。 - 更新参数:使用优化器(如
torch.optim.SGD
)或手动更新参数。 - 清空梯度:在每次参数更新后,调用
optimizer.zero_grad()
或tensor.grad.zero_()
清空梯度。
以下是一个简单的线性回归示例:
import torch # 定义输入和输出数据 x_data = torch.tensor([[1.0], [2.0], [3.0]]) y_data = torch.tensor([[2.0], [4.0], [6.0]]) # 定义模型参数 w = torch.tensor(1.0, requires_grad=True) # 前向传播 def forward(x): return x * w # 定义损失函数 def loss(x, y): y_pred = forward(x) return (y_pred - y) ** 2 # 反向传播与参数更新 print("Before update: w =", w.item()) for x_val, y_val in zip(x_data, y_data): l = loss(x_val, y_val) l.backward() # 反向传播 print(f"\tx={x_val.item()}, y={y_val.item()}, loss={l.item():.2f}, grad={w.grad.item():.2f}") w.data = w.data - 0.01 * w.grad.data # 手动更新参数 w.grad.zero_() # 清空梯度 print("After update: w =", w.item())
- 定义模型参数:使用
-
【本题 10 分】 什么是梯度消失和梯度爆炸?有哪些解决梯度消失和梯度爆炸的方法?
- 梯度消失:在深度神经网络中,反向传播时梯度逐层减小,导致靠近输入层的参数几乎不更新,模型难以训练。
- 梯度爆炸:反向传播时梯度逐层增大,导致参数更新过大,模型训练不稳定甚至发散。
解决方法包括:
- 激活函数:使用 ReLU 或其变体(如 Leaky ReLU)避免梯度饱和。
- 权重初始化:采用 Xavier 或 He 初始化,确保初始梯度合理。
- 梯度裁剪:通过
torch.nn.utils.clip_grad_norm_
限制梯度的最大范数。 - 残差连接:在 ResNet 中引入跳跃连接,使梯度能够直接传递到浅层。
- 正则化:使用 L2 正则化或 Dropout 减少过拟合。
-
【本题 20 分】
(1) 求出下面递归神经网络模型的平衡点。
d x ( t ) d t = − 3 5 ln 2 x ( t ) + g ( x ( t ) ) , 其中 g ( x ) = e x − e − x e x + e − x \frac{dx(t)}{dt} = -\frac{3}{5 \ln 2} x(t) + g(x(t)), \quad \text{其中 } g(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} dtdx(t)=−5ln23x(t)+g(x(t)),其中 g(x)=ex+e−xex−e−x平衡点满足 d x ( t ) d t = 0 \frac{dx(t)}{dt} = 0 dtdx(t)=0,即:
− 3 5 ln 2 x ( t ) + g ( x ( t ) ) = 0 ⟹ 3 5 ln 2 x ( t ) = g ( x ( t ) ) -\frac{3}{5 \ln 2} x(t) + g(x(t)) = 0 \implies \frac{3}{5 \ln 2} x(t) = g(x(t)) −5ln23x(t)+g(x(t))=0⟹5ln23x(t)=g(x(t))
由于 g ( x ) = tanh ( x ) g(x) = \tanh(x) g(x)=tanh(x),且 tanh ( 0 ) = 0 \tanh(0) = 0 tanh(0)=0,因此 x ( t ) = 0 x(t) = 0 x(t)=0 是一个平衡点。由于 tanh ( x ) \tanh(x) tanh(x) 的取值范围为 ( − 1 , 1 ) (-1, 1) (−1,1),而左侧是线性函数,因此 x ( t ) = 0 x(t) = 0 x(t)=0 是唯一的实数解。(2) 构造能量函数判定其平衡点的稳定性。
构造能量函数 V ( x ) = 1 2 x 2 V(x) = \frac{1}{2} x^2 V(x)=21x2,它是正定的。计算其导数:
V ˙ ( x ) = x ⋅ x ˙ = x ( − 3 5 ln 2 x + tanh ( x ) ) \dot{V}(x) = x \cdot \dot{x} = x \left( -\frac{3}{5 \ln 2} x + \tanh(x) \right) V˙(x)=x⋅x˙=x(−5ln23x+tanh(x))
当 x ≠ 0 x \neq 0 x=0 时, V ˙ ( x ) < 0 \dot{V}(x) < 0 V˙(x)<0,因此 x = 0 x = 0 x=0 是一个稳定的平衡点。 -
【本题 20 分】 什么是 CNN?出现 CNN 的必要性是什么?CNN 的典型网络结构和 CNN 的特点是什么?
- 卷积神经网络(CNN):一种专门用于处理网格结构数据的深度学习模型,广泛应用于图像处理任务。
- 必要性:传统全连接网络参数过多,难以处理高维图像数据。CNN 通过卷积操作提取局部特征,减少参数数量,同时保持空间信息。
- 典型网络结构:包括卷积层、激活层(如 ReLU)、池化层(如最大池化)和全连接层。
- 特点:
- 局部连接:每个神经元只与输入数据的局部区域相连。
- 权值共享:卷积核的权重在整张图像上共享。
- 层次化特征提取:浅层提取边缘等低级特征,深层提取复杂的高级特征。
-
【本题 20 分】 什么是 GAN?GAN 的基本结构是什么?请列举至少 2 项你知道的 GAN 的改进模型。
- 生成对抗网络(GAN):由生成器和判别器组成的双网络模型。生成器生成假数据,判别器区分真假数据,两者通过对抗训练提升性能。
- 基本结构:
- 生成器:从随机噪声生成数据。
- 判别器:输入真实数据和生成数据,输出概率。
- 改进模型:
- Wasserstein GAN (WGAN):使用 Wasserstein 距离替代原始 GAN 的 JS 散度,解决训练不稳定问题。
- Conditional GAN (cGAN):在生成器和判别器中引入条件变量,控制生成数据的属性。
-
【本题 20 分】 请解释梯度下降、随机梯度下降、mini-batch 梯度下降算法,并说明其在 PyTorch 框架中的实现。
- 梯度下降(GD):使用整个训练集计算梯度,更新参数。计算精确但效率低。
- 随机梯度下降(SGD):每次迭代使用一个样本计算梯度,更新速度快但波动大。
- Mini-batch 梯度下降:每次迭代使用一小批样本计算梯度,结合了 GD 和 SGD 的优点。
在 PyTorch 中,可以通过
torch.optim
模块实现:import torch import torch.nn as nn import torch.optim as optim # 定义模型 model = nn.Linear(10, 1) # 定义损失函数和优化器 criterion = nn.MSELoss() optimizer = optim.SGD(model.parameters(), lr=0.01) # 训练过程 for epoch in range(100): for x_batch, y_batch in dataloader: # dataloader 提供 mini-batch 数据 optimizer.zero_grad() # 清空梯度 outputs = model(x_batch) # 前向传播 loss = criterion(outputs, y_batch) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 更新参数
1. 深度学习成功的因素及个人思考
深度学习成功的因素
- 大数据:深度学习模型需要大量数据进行训练,数据量的增加显著提升了模型的性能。
- 计算能力:GPU和TPU等硬件的发展使得训练大规模神经网络成为可能。
- 算法改进:如反向传播、激活函数、正则化技术、优化算法等的改进。
- 开源生态:TensorFlow、PyTorch等开源框架降低了深度学习的门槛。
- 理论支持:深度学习理论的不断完善,如深度学习的泛化能力、表示学习等。
个人思考
- 数据隐私:随着数据量的增加,数据隐私和安全问题日益突出,如何在保护隐私的前提下利用数据是一个重要课题。
- 模型解释性:深度学习模型通常被视为“黑盒”,提高模型的可解释性是未来的一个重要方向。
- 能源消耗:训练大规模模型需要大量能源,如何提高能源效率是一个挑战。
- 多模态学习:结合不同类型的数据(如图像、文本、音频)进行多模态学习是未来的一个趋势。
2. 神经网络常用激活函数、正则化手段、初始化方式、常用 loss 函数
常用激活函数
- ReLU (Rectified Linear Unit): f ( x ) = max ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)
- Leaky ReLU: f ( x ) = max ( 0.01 x , x ) f(x) = \max(0.01x, x) f(x)=max(0.01x,x)
- Sigmoid: f ( x ) = 1 1 + e − x f(x) = \frac{1}{1 + e^{-x}} f(x)=1+e−x1
- Tanh: f ( x ) = e x − e − x e x + e − x f(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} f(x)=ex+e−xex−e−x
- Softmax: f ( x i ) = e x i ∑ j e x j f(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}} f(xi)=∑jexjexi
常用正则化手段
- L1/L2 正则化:在损失函数中加入权重参数的L1或L2范数。
- Dropout:在训练过程中随机丢弃一部分神经元,防止过拟合。
- Batch Normalization:对每一层的输入进行归一化,加速训练。
常用初始化方式
- Xavier 初始化:适用于Sigmoid和Tanh激活函数,保持输入和输出的方差一致。
- He 初始化:适用于ReLU及其变体,保持输入和输出的方差一致。
- 随机初始化:随机初始化权重参数。
常用 loss 函数
- 均方误差 (MSE): L = 1 N ∑ i = 1 N ( y i − y ^ i ) 2 L = \frac{1}{N} \sum_{i=1}^N (y_i - \hat{y}_i)^2 L=N1∑i=1N(yi−y^i)2
- 交叉熵损失 (Cross-Entropy Loss): L = − ∑ i = 1 N y i log ( y ^ i ) L = -\sum_{i=1}^N y_i \log(\hat{y}_i) L=−∑i=1Nyilog(y^i)
- KL 散度 (Kullback-Leibler Divergence): L = ∑ i = 1 N p ( x i ) log p ( x i ) q ( x i ) L = \sum_{i=1}^N p(x_i) \log \frac{p(x_i)}{q(x_i)} L=∑i=1Np(xi)logq(xi)p(xi)
3. PyTorch 梯度自动计算的步骤和示例伪代码
步骤
- 定义模型和损失函数。
- 前向传播计算输出和损失。
- 反向传播计算梯度。
- 更新权重参数。
示例伪代码
# 步骤1: 定义张量,并设置 requires_grad=True
x = Tensor(value, requires_grad=True)
w = Tensor(weight, requires_grad=True)
b = Tensor(bias, requires_grad=True)
# 步骤2: 定义模型(例如简单的线性模型)
y = w * x + b # 前向传播:y = w * x + b
# 步骤3: 定义损失函数
loss = (y - target) ** 2 # 例如均方误差损失
# 步骤4: 计算梯度(反向传播)
loss.backward() # 计算每个张量的梯度
# 步骤5: 查看计算得到的梯度
print(w.grad) # 输出 w 的梯度
print(b.grad) # 输出 b 的梯度
# 步骤6: 使用优化器更新参数
optimizer = SGD([w, b], lr=0.01)
optimizer.step() # 根据梯度更新参数
4. 梯度下降类算法的公式、思想、优缺点
梯度下降 (GD)
- 公式: w t + 1 = w t − η ∇ L ( w t ) w_{t+1} = w_t - \eta \nabla L(w_t) wt+1=wt−η∇L(wt)
- 思想:沿着损失函数的负梯度方向更新参数,逐步逼近最优解。
- 优点:简单易实现。
- 缺点:收敛速度慢,容易陷入局部最优。
随机梯度下降 (SGD)
- 公式: w t + 1 = w t − η ∇ L i ( w t ) w_{t+1} = w_t - \eta \nabla L_i(w_t) wt+1=wt−η∇Li(wt)
- 思想:每次迭代只使用一个样本的梯度更新参数。
- 优点:收敛速度快,避免陷入局部最优。
- 缺点:噪声大,不稳定。
Momentum
- 公式: v t + 1 = γ v t + η ∇ L ( w t ) v_{t+1} = \gamma v_t + \eta \nabla L(w_t) vt+1=γvt+η∇L(wt), w t + 1 = w t − v t + 1 w_{t+1} = w_t - v_{t+1} wt+1=wt−vt+1
- 思想:引入动量项,加速收敛。
- 优点:加速收敛,减少震荡。
- 缺点:需要调整动量参数。
AdaGrad
- 公式: G t = G t − 1 + ( ∇ L ( w t ) ) 2 G_t = G_{t-1} + (\nabla L(w_t))^2 Gt=Gt−1+(∇L(wt))2, w t + 1 = w t − η G t + ϵ ∇ L ( w t ) w_{t+1} = w_t - \frac{\eta}{\sqrt{G_t + \epsilon}} \nabla L(w_t) wt+1=wt−Gt+ϵη∇L(wt)
- 思想:自适应调整学习率,对频繁更新的参数降低学习率。
- 优点:自适应学习率。
- 缺点:学习率可能过早衰减。
Adam
- 公式: m t = β 1 m t − 1 + ( 1 − β 1 ) ∇ L ( w t ) m_t = \beta_1 m_{t-1} + (1 - \beta_1) \nabla L(w_t) mt=β1mt−1+(1−β1)∇L(wt), v t = β 2 v t − 1 + ( 1 − β 2 ) ( ∇ L ( w t ) ) 2 v_t = \beta_2 v_{t-1} + (1 - \beta_2) (\nabla L(w_t))^2 vt=β2vt−1+(1−β2)(∇L(wt))2, w t + 1 = w t − η m t v t + ϵ w_{t+1} = w_t - \eta \frac{m_t}{\sqrt{v_t} + \epsilon} wt+1=wt−ηvt+ϵmt
- 思想:结合Momentum和AdaGrad的优点,自适应调整学习率。
- 优点:收敛速度快,稳定性好。
- 缺点:需要调整多个超参数。
1. 算法思想
梯度下降(Gradient Descent, GD)是一种用于优化问题的迭代算法。它通过计算损失函数关于模型参数的梯度(即偏导数),然后沿着梯度的反方向更新参数,以逐步逼近最优解。
- 梯度:指的是损失函数在某一点的导数,表示了损失函数的变化趋势。
- 更新规则:每次更新参数时,按照梯度的负方向进行调整。这样可以确保损失函数值逐渐减小。
2. 公式
在梯度下降算法中,参数的更新公式为:
θ
(
t
+
1
)
=
θ
(
t
)
−
η
∇
θ
J
(
θ
)
θ
(
t
+
1
)
=
θ
(
t
)
−
η
∇
θ
J
(
θ
)
θ(t+1)=θ(t)−η∇θJ(θ)\theta^{(t+1)} = \theta^{(t)} - \eta \nabla_{\theta} J(\theta)
θ(t+1)=θ(t)−η∇θJ(θ)θ(t+1)=θ(t)−η∇θJ(θ)
其中:
- θ ( t ) \theta^{(t)} θ(t) 是第 t t t次迭代的参数。
- η \eta η 是学习率(learning rate),一个超参数,控制每次更新的步长。
- ∇ θ J ( θ ) \nabla_{\theta} J(\theta) ∇θJ(θ) 是损失函数 J ( θ ) J(\theta) J(θ) 关于参数 θ \theta θ 的梯度。
3. 梯度下降的类型
- 批量梯度下降(Batch Gradient Descent, BGD):
- 每次更新时使用所有的训练数据。
- 优点:稳定收敛,最终能够找到全局最小值(假设损失函数是凸的)。
- 缺点:计算量大,尤其是数据集非常大的时候。
- 随机梯度下降(Stochastic Gradient Descent, SGD):
- 每次更新时仅使用一个样本的梯度。
- 优点:计算开销小,能处理大数据集,且每次更新都可以跳出局部最小值。
- 缺点:收敛速度较慢,且收敛过程可能较为波动。
- 小批量梯度下降(Mini-Batch Gradient Descent):
- 每次更新时使用一个小批量的数据。
- 优点:结合了批量和随机梯度下降的优点,收敛较为平稳,且计算效率较高。
- 缺点:需要选择适当的批量大小。
4. 优缺点
优点:
- 计算效率高:尤其是对于大规模数据集,随机梯度下降或小批量梯度下降能有效减少计算成本。
- 易于实现:梯度下降方法简单直观,可以应用于多种优化问题。
- 广泛适用:适用于各种机器学习模型,如线性回归、逻辑回归、神经网络等。
缺点:
- 可能陷入局部最小值:特别是在非凸函数中,梯度下降可能收敛到局部最小值,而非全局最小值。
- 选择合适的学习率困难:学习率过大可能导致更新过度,学习率过小可能导致收敛过慢。
- 收敛速度慢:尤其是对于非常复杂的损失函数,可能需要很多迭代才能收敛。
- 对初始值敏感:不同的初始化可能会影响收敛速度和结果。
总结
梯度下降是一个简单且强大的优化算法,适用于很多机器学习模型。它的核心思想是通过不断调整参数,沿着损失函数的最陡下降方向寻找最优解。虽然它有一些缺点(如可能陷入局部最小值、对学习率敏感等),但通过合理选择变种(如随机梯度下降、小批量梯度下降等)和调参,可以显著提高其性能。
5. Hopfield 神经网络相关的能量函数设计、计算,稳定性、平衡点判断
能量函数设计
- 公式: E = − 1 2 ∑ i , j w i j s i s j + ∑ i θ i s i E = -\frac{1}{2} \sum_{i,j} w_{ij} s_i s_j + \sum_i \theta_i s_i E=−21∑i,jwijsisj+∑iθisi
- 思想:能量函数用于描述网络的状态,能量越低,状态越稳定。
稳定性判断
- 公式: ∂ E ∂ s i = − ∑ j w i j s j + θ i \frac{\partial E}{\partial s_i} = - \sum_j w_{ij} s_j + \theta_i ∂si∂E=−∑jwijsj+θi
- 思想:当能量函数的梯度为零时,网络达到平衡点。
平衡点判断
- 公式: s i = sgn ( ∑ j w i j s j − θ i ) s_i = \text{sgn}(\sum_j w_{ij} s_j - \theta_i) si=sgn(∑jwijsj−θi)
- 思想:通过更新规则判断网络是否达到平衡点。
6. RNN/CNN 结构特点,出现的必要性,适合的应用场景
RNN (Recurrent Neural Network)
- 结构特点:具有循环连接,能够处理序列数据。
- 出现的必要性:处理时间序列数据,如语音、文本等。
- 适合的应用场景:语音识别、自然语言处理、时间序列预测。
CNN (Convolutional Neural Network)
- 结构特点:使用卷积核进行局部特征提取,具有平移不变性。
- 出现的必要性:处理图像数据,提取空间特征。
- 适合的应用场景:图像分类、目标检测、图像生成。
7. 典型 CNN 结构特点及 PyTorch 实现伪代码
Class CNN:
Initialize:
Conv -> ReLU -> Pooling
Conv -> ReLU -> Pooling
Fully Connected -> Dropout -> ReLU
Output Layer
Forward Pass:
For each Conv Layer:
Convolve -> Activate (ReLU) -> Pool
Flatten the feature map
Pass through Fully Connected Layers
Return Output
LeNet5
- 结构特点:卷积层、池化层、全连接层。
- PyTorch 伪代码:
import torch.nn as nn
class LeNet5(nn.Module):
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
self.fc1 = nn.Linear(16*4*4, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = nn.functional.relu(self.conv1(x))
x = nn.functional.max_pool2d(x, 2)
x = nn.functional.relu(self.conv2(x))
x = nn.functional.max_pool2d(x, 2)
x = x.view(-1, 16*4*4)
x = nn.functional.relu(self.fc1(x))
x = nn.functional.relu(self.fc2(x))
x = self.fc3(x)
return x
AlexNet
- 结构特点:多个卷积层和全连接层,使用ReLU激活函数和Dropout。
- PyTorch 伪代码:
import torch.nn as nn
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv1 = nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2)
self.conv2 = nn.Conv2d(96, 256, kernel_size=5, padding=2)
self.conv3 = nn.Conv2d(256, 384, kernel_size=3, padding=1)
self.conv4 = nn.Conv2d(384, 384, kernel_size=3, padding=1)
self.conv5 = nn.Conv2d(384, 256, kernel_size=3, padding=1)
self.fc1 = nn.Linear(256*6*6, 4096)
self.fc2 = nn.Linear(4096, 4096)
self.fc3 = nn.Linear(4096, 1000)
def forward(self, x):
x = nn.functional.relu(self.conv1(x))
x = nn.functional.max_pool2d(x, 3, 2)
x = nn.functional.relu(self.conv2(x))
x = nn.functional.max_pool2d(x, 3, 2)
x = nn.functional.relu(self.conv3(x))
x = nn.functional.relu(self.conv4(x))
x = nn.functional.relu(self.conv5(x))
x = nn.functional.max_pool2d(x, 3, 2)
x = x.view(-1, 256*6*6)
x = nn.functional.relu(self.fc1(x))
x = nn.functional.dropout(x, 0.5)
x = nn.functional.relu(self.fc2(x))
x = nn.functional.dropout(x, 0.5)
x = self.fc3(x)
return x
GoogleNet
- 结构特点:使用Inception模块,多个并行卷积核。
- PyTorch 伪代码:
import torch.nn as nn
class Inception(nn.Module):
def __init__(self, in_channels, out_1x1, red_3x3, out_3x3, red_5x5, out_5x5, out_pool):
super(Inception, self).__init__()
self.branch1 = nn.Conv2d(in_channels, out_1x1, kernel_size=1)
self.branch2 = nn.Sequential(
nn.Conv2d(in_channels, red_3x3, kernel_size=1),
nn.Conv2d(red_3x3, out_3x3, kernel_size=3, padding=1)
)
self.branch3 = nn.Sequential(
nn.Conv2d(in_channels, red_5x5, kernel_size=1),
nn.Conv2d(red_5x5, out_5x5, kernel_size=5, padding=2)
)
self.branch4 = nn.Sequential(
nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
nn.Conv2d(in_channels, out_pool, kernel_size=1)
)
def forward(self, x):
branch1 = self.branch1(x)
branch2 = self.branch2(x)
branch3 = self.branch3(x)
branch4 = self.branch4(x)
return torch.cat([branch1, branch2, branch3, branch4], 1)
class GoogleNet(nn.Module):
def __init__(self):
super(GoogleNet, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
self.conv2 = nn.Conv2d(64, 192, kernel_size=3, padding=1)
self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)
self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)
self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)
self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)
self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)
self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)
self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)
self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)
self.fc = nn.Linear(1024, 1000)
def forward(self, x):
x = nn.functional.relu(self.conv1(x))
x = nn.functional.max_pool2d(x, 3, 2, padding=1)
x = nn.functional.relu(self.conv2(x))
x = nn.functional.max_pool2d(x, 3, 2, padding=1)
x = self.inception3a(x)
x = self.inception3b(x)
x = nn.functional.max_pool2d(x, 3, 2, padding=1)
x = self.inception4a(x)
x = self.inception4b(x)
x = self.inception4c(x)
x = self.inception4d(x)
x = self.inception4e(x)
x = nn.functional.max_pool2d(x, 3, 2, padding=1)
x = self.inception5a(x)
x = self.inception5b(x)
x = nn.functional.avg_pool2d(x, 7)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x