第一部分:线性回归

1. 模拟数据生成

  • 使用 torch.randn 生成符合正态分布的特征矩阵 X

  • 真实模型:y = X·w + b + 噪声,噪声用于模拟真实数据中的随机误差,防止模型完全过拟合。

  • 噪声通常为均值为0的正态分布随机数。

2. 数据集划分

  • 训练集:用于训练模型参数(通常占80%)。

  • 测试集:用于评估模型泛化能力(通常占20%)。

  • 划分目的:检测模型是否过拟合,评估在未见数据上的表现。

3. 模型定义(继承 nn.Module

  • 线性层:nn.Linear(in_features, out_features)

  • 前向传播:forward(self, x) 中调用线性层。

  • 线性回归输出维度为 1(连续值预测)。

4. 损失函数与优化器

  • 损失函数:均方误差(MSE)—— nn.MSELoss()

  • 优化器:随机梯度下降(SGD)—— optim.SGD(model.parameters(), lr=learning_rate)

  • 学习率控制参数更新步长,太大易震荡/发散,太小收敛慢。

5. 训练流程(关键步骤)

  • 前向传播:pred = model(batch_X)

  • 计算损失:loss = criterion(pred, batch_y)

  • 梯度清零:optimizer.zero_grad()

  • 反向传播:loss.backward()

  • 参数更新:optimizer.step()

  • 使用 DataLoader 批量训练,shuffle=True 打乱数据。

6. 评估与可视化

  • model.eval() 切换到评估模式(影响 Dropout/BatchNorm)。

  • with torch.no_grad(): 关闭梯度跟踪,节省内存。

  • 绘制损失曲线,对比学习到的权重/偏置与真实值。

7. 超参数调优

  • 学习率、训练轮数(epoch)、批大小(batch size)。

  • 过大 batch size 可能降低泛化能力,过小则梯度噪声大。


第二部分:softmax回归(多分类)

1. 数据集:Fashion-MNIST

  • 10个类别:T恤、裤子、套衫、裙子、外套、凉鞋、衬衫、运动鞋、包、踝靴。

  • 图像尺寸:28×28 灰度图 → 输入特征维度 784

  • 使用 torchvision.datasets.FashionMNIST 加载。

  • 预处理:ToTensor() 归一化到 [0,1],可选 Normalize((0.5,), (0.5,)) 到 [-1,1]。

2. 模型定义

  • 线性层:nn.Linear(784, 10),输出10个类别的得分(logits)。

  • 需要展平图像:x = x.view(x.size(0), -1) 或 x = x.flatten(1)

3. 损失函数

  • 交叉熵损失:nn.CrossEntropyLoss()

  • 内部实现:LogSoftmax + NLLLoss,数值稳定性好。

  • 适用于多分类,能有效区分概率分布。

4. 评估指标

  • 准确率(Accuracy)= 正确预测数 / 总样本数。

  • torch.max(outputs, 1) 获取预测类别索引。

5. 训练过程(与线性回归类似)

  • 相同的前向、损失、反向、更新步骤。

  • 增加准确率计算。

6. 可视化预测结果

  • 显示图像及其真实/预测标签,绿色正确、红色错误。

  • 帮助直观理解模型表现。

7. 探索性实验

  • 调整学习率、批大小、训练轮数。

  • 增加隐藏层(多层感知机)提升性能。

均方误差(MSE)的用途与实现

用途:均方误差是回归任务中常用的损失函数,衡量模型预测值与真实值之间的平方差的平均值。它对异常值敏感,适用于需要惩罚较大误差的场景。

Python实现

import numpy as np

def mean_squared_error(y_true, y_pred):
    return np.mean((y_true - y_pred) ** 2)

# 示例
y_true = np.array([1, 2, 3])
y_pred = np.array([1.1, 1.9, 3.2])
print(mean_squared_error(y_true, y_pred))  # 输出: 0.02

数学公式
给定真实值 $y$ 和预测值 $\hat{y}$,MSE 计算公式为:
{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2


交叉熵(Cross-Entropy)的用途与实现

用途:交叉熵常用于分类任务,尤其是二分类或多分类问题。它衡量预测概率分布与真实分布的差异,值越小表示预测越准确。

Python实现

import numpy as np

def cross_entropy(y_true, y_pred, epsilon=1e-15):
    y_pred = np.clip(y_pred, epsilon, 1 - epsilon)  # 避免log(0)
    return -np.sum(y_true * np.log(y_pred)) / len(y_true)

# 示例(二分类)
y_true = np.array([1, 0, 1])  # 真实标签
y_pred = np.array([0.9, 0.1, 0.8])  # 预测概率
print(cross_entropy(y_true, y_pred))  # 输出: 0.076

数学公式
[ \text{CE} = -\frac{1}{n} \sum_{i=1}^{n} \sum_{c=1}^{C} y_{i,c} \log(\hat{y}_{i,c}) ]


关键区别

  • 任务类型:MSE适用于回归,交叉熵适用于分类。
  • 梯度特性:交叉熵在分类任务中梯度更新更高效,避免MSE可能导致的训练停滞。

核心概念对比

特性 线性回归 softmax回归
任务类型 回归(连续值) 分类(离散类别)
输出层 1个神经元 C个神经元(C=类别数)
激活函数 无(恒等) softmax(隐含在损失中)
损失函数 均方误差(MSE) 交叉熵(CrossEntropyLoss)
评估指标 MSE, MAE, R² 准确率、混淆矩阵

实验总结

请简要回答以下问题:

  1. 线性回归部分

    • 损失函数:通常采用均方误差(MSE)作为损失函数,公式为:
      J(\theta) = \frac{1}{2n} \sum_{i=1}^{n} (h_{\theta}(x^{(i)}) - y^{(i)})^2
      其中 $n$是样本数量, $h_{\theta}(x)$是模型预测值,$y$是真实值,$\theta$ 是模型参数。

    • 模型收敛判断:主要通过以下方式判断:

      • 训练损失值趋于稳定不再显著下降;
      • 验证集上的性能改善饱和;
      • 设损失变化阈值(如 $|\Delta J| < \epsilon$)控制训练停止。
  2. softmax回归部分

    • 适用于多分类的原因:softmax回归通过softmax函数($ \hat{y}_k = \frac{e^{z_k}}{\sum{c=1}^{K} e^{z_c}} $)将输入特征$x$映射为所有类别的概率分布$\hat{\mathbf{y}} \in \mathbb{R}^{K}$。这确保输出满足$\sum_{k=1}^{K} \hat{y}_k = 1$,因此适合多分类问题,因为它能直接输出每一类的预测概率。

    • 交叉熵损失函数的作用:用于衡量预测概率分布 $\hat{\mathbf{y}}$与真实类别分布$y$ 的差异。公式为:
      J(\theta) = - \sum_{i=1}^{n} \sum_{c=1}^{K} y_{i,c} \log \hat{y}_{i,c}
      其中 $y_{i,c}$ 是真实标签的one-hot编码(当 $c$为真实类时为1,否则为0), $\hat{y}_{i,c}$ 是模型预测的第$c$类的概率。它引导模型优化概率预测。

  3. 对比分析

    • 主要区别:线性回归和softmax回归的核心区别在以下几点:
      • 问题类型:线性回归用于回归任务(预测连续值),softmax回归用于分类任务(多为多类别离散值)。
      • 输出维度:线性回归输出一个实数 $\hat{y}$,softmax回归输出一个 $K$维概率向量 $\hat{\mathbf{y}}$
      • 损失函数:线性回归多用均方误差损失,softmax回归用交叉熵损失。

《人工智能概论》实验2 考试题

(总分100分,建议完成时间80分钟)

一、单选题(每题3分,共18分)

  1. 在线性回归实验中,生成模拟数据的公式为 y = X @ true_w + true_b + noise。其中 noise 的作用是( )
    A. 增加训练集大小
    B. 模拟真实数据中的随机误差,防止模型过拟合
    C. 使特征之间产生共线性
    D. 使标签变成离散值

  2. 以下哪个损失函数最适合用于线性回归任务?( )
    A. nn.CrossEntropyLoss()
    B. nn.NLLLoss()
    C. nn.MSELoss()
    D. nn.BCELoss()

  3. 关于 DataLoader 的参数 shuffle=True,下列说法正确的是( )
    A. 每个 epoch 都会打乱数据顺序,有助于提高模型泛化能力
    B. 每个 batch 内的样本顺序随机
    C. 打乱特征与标签的对应关系
    D. 只在训练集上打乱,测试集自动也为 True

  4. 对于 Fashion-MNIST 数据集,图像张量的形状是 (batch, 1, 28, 28)。在使用 nn.Linear 之前,需要将图像展平,正确的展平操作是( )
    A. x = x.view(x.size(0), -1)
    B. x = x.view(-1, 28*28)
    C. x = x.flatten(1)
    D. A 和 C 均可

  5. 在 softmax 回归中,损失函数 nn.CrossEntropyLoss() 内部包含了( )操作。
    A. softmax + 均方误差
    B. sigmoid + 二值交叉熵
    C. softmax + 负对数似然
    D. log-softmax + NLLLoss

  6. 模型训练过程中,正确的操作顺序是( )
    A. loss.backward() → optimizer.zero_grad() → optimizer.step()
    B. optimizer.zero_grad() → loss.backward() → optimizer.step()
    C. optimizer.step() → loss.backward() → optimizer.zero_grad()
    D. loss.backward() → optimizer.step() → optimizer.zero_grad()


二、填空题(每空2分,共20分)

  1. 在线性回归实验中,真实权重为 [2.0, -3.0, 0.5],偏置为 4.0。生成的数据集有 1000 个样本,每个样本有 ______ 个特征。训练集和测试集的划分比例通常为 ______ : ______

  2. 定义线性回归模型的类需要继承自 torch.nn.______,其中线性层使用 nn.Linear(______, ______),输出维度为 1。

  3. 在训练循环中,调用 optimizer.zero_grad() 的作用是 ______;调用 loss.backward() 的作用是 ______

  4. Fashion-MNIST 数据集共有 ______ 个类别,图像尺寸为 28×28 像素,输入神经网络的维度为 ______


三、判断题(正确打“√”,错误打“×”,每题2分,共10分)

  1. ( )在线性回归中,如果学习率设置过大,损失值可能会先快速下降,然后剧烈震荡甚至发散。

  2. ( )model.eval() 和 with torch.no_grad(): 的作用完全相同,可以互换使用。

  3. ( )交叉熵损失函数可以直接用于多分类问题,不需要在模型输出层额外添加 softmax。

  4. ( )对于线性回归任务,使用 DataLoader 时 batch_size 越大,模型收敛速度一定越快。

  5. ( )在测试集上评估模型时,需要调用 model.train() 来保持与训练时一致的行为。


四、简答题(共32分)

说明:以下题目均来自实验指导书中的“思考题”。

简答题1(6分,来自实验 3.2 思考题)

(1)为什么要将数据集划分为训练集和测试集?
(2)如果不划分,直接用全部数据训练会有什么问题?

简答题2(6分,来自实验 3.3 及 3.4 思考题)

(1)nn.Linear(in_features, out_features) 中的两个参数分别代表什么?
(2)为什么线性回归的输出维度是1?
(3)线性回归中为什么使用均方误差(MSE)作为损失函数?

简答题3(6分,来自实验 4.3 思考题)

(1)为什么 softmax 回归使用交叉熵损失而不是均方误差?
(2)nn.CrossEntropyLoss 和组合 softmax + nn.NLLLoss 有什么关系?

简答题4(8分,来自实验 3.7、4.6 及综合思考)

(1)model.eval() 和 with torch.no_grad(): 的作用分别是什么?它们必须同时使用吗?
(2)训练集准确率和测试集准确率哪个通常更高?为什么?
(3)在线性回归的最后,我们对比了学习到的权重和真实权重。为什么它们不可能完全相等?

简答题5(6分,来自实验 3.8 调参实验及 4.8 探索性实验)

(1)在调参实验中,学习率过大会导致什么现象?学习率过小会有什么问题?
(2)增大批大小(batch size)对训练速度和模型性能可能产生什么影响?
(3)在 Fashion-MNIST 实验中,如果增加一个隐藏层(如 128 个神经元),你认为准确率会如何变化?为什么?


五、代码填空题(每空2分,共20分)

代码填空1(线性回归部分,共6空)

# 定义模型
class LinearRegressionModel(nn.Module):
    def __init__(self, n_features):
        super().__init__()
        self.linear = nn.Linear(______, 1)   # 空1

    def forward(self, x):
        return self.linear(x)

# 创建模型、损失函数和优化器
model = LinearRegressionModel(n_features)
criterion = nn.MSELoss()                     # 损失函数已定义
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练循环
for epoch in range(num_epochs):
    for batch_X, batch_y in dataloader:
        # 前向传播
        pred = ______(batch_X)               # 空2(调用模型)
        # 计算损失
        loss = ______(pred.squeeze(), batch_y)  # 空3(使用criterion)
        # 反向传播三步
        optimizer.______()                   # 空4
        loss.______()                        # 空5
        optimizer.______()                   # 空6

代码填空2(softmax回归部分,共4空)

# 定义模型
class SoftmaxModel(nn.Module):
    def __init__(self, input_dim, num_classes):
        super().__init__()
        self.linear = nn.Linear(input_dim, num_classes)  # input_dim=784, num_classes=10

    def forward(self, x):
        x = x.view(x.size(0), -1)   # 展平
        return self.linear(x)

# 创建模型、损失函数和优化器
model = SoftmaxModel(784, 10)
criterion = nn.______()                      # 空7
optimizer = optim.______(model.parameters(), lr=0.01)  # 空8

# 训练时计算准确率(片段)
outputs = model(images)
_, predicted = torch.max(outputs, ______)    # 空9

# 训练轮数循环
for epoch in range(______):                  # 空10
    # 训练代码...


参考答案与解析

一、单选题(每题3分,共18分)

1. 在线性回归实验中,生成模拟数据的公式为 y = X @ true_w + true_b + noise。其中 noise 的作用是( )
A. 增加训练集大小
B. 模拟真实数据中的随机误差,防止模型过拟合
C. 使特征之间产生共线性
D. 使标签变成离散值

✅ 答案:B

💡 详细解析(小白必读)

  • 在真实世界中,我们测量或收集的数据总会包含一些随机误差(比如测量仪器误差、环境干扰等)。

  • 如果生成的 y 完全由 X·w + b 决定(没有噪声),那么模型只要学到精确的 w 和 b 就能完美预测。但这样的模型面对真实带噪声的数据时就会表现很差——这叫过拟合

  • 加入噪声后,模型无法100%拟合所有点,必须学会抓住“主要规律”,这就提升了模型的泛化能力

  • 所以 noise 的作用就是模拟真实误差,防止模型死记硬背。


2. 以下哪个损失函数最适合用于线性回归任务?( )
A. nn.CrossEntropyLoss()
B. nn.NLLLoss()
C. nn.MSELoss()
D. nn.BCELoss()

✅ 答案:C

💡 详细解析

  • 线性回归要预测一个连续的数值(如房价、温度)。

  • MSELoss(均方误差)计算预测值与真实值差的平方,然后取平均。这个函数是凸函数,便于梯度下降找到全局最优;而且它对大误差惩罚更重,促使模型尽量贴近真实值。

  • 其他选项:

    • CrossEntropyLoss 和 NLLLoss 用于分类任务(输出概率分布)。

    • BCELoss 用于二分类(输出0~1之间的概率)。

  • 所以回归任务首选 MSELoss


3. 关于 DataLoader 的参数 shuffle=True,下列说法正确的是( )
A. 每个 epoch 都会打乱数据顺序,有助于提高模型泛化能力
B. 每个 batch 内的样本顺序随机
C. 打乱特征与标签的对应关系
D. 只在训练集上打乱,测试集自动也为 True

✅ 答案:A

💡 详细解析

  • shuffle=True 会在每个 epoch 开始前将所有样本的顺序打乱(重新排列),然后把打乱后的样本逐个 batch 取出。

  • 为什么有用?

    • 如果数据有某种顺序(比如前500个是A类,后500个是B类),不打乱的话,模型可能会先长时间只见到A类,再只见到B类,导致训练不稳定,收敛变慢。

    • 打乱后,每个 batch 里各类样本混合,梯度估计更稳定,模型学到的规律更通用(泛化能力更好)。

  • B 错:打乱的是整个数据集的顺序,不是 batch 内部。

  • C 错:打乱时特征和标签会一起重新排列,不会破坏配对关系。

  • D 错:测试集通常设置 shuffle=False,以保持顺序便于评估。


4. 对于 Fashion-MNIST 数据集,图像张量的形状是 (batch, 1, 28, 28)。在使用 nn.Linear 之前,需要将图像展平,正确的展平操作是( )
A. x = x.view(x.size(0), -1)
B. x = x.view(-1, 28*28)
C. x = x.flatten(1)
D. A 和 C 均可

✅ 答案:D

💡 详细解析

  • nn.Linear 期望输入是一个二维矩阵:[样本数, 特征数]。而原始图像是四维:[batch, 通道, 高, 宽]

  • 我们需要保留 batch 维度不变,把剩下的三个维度(通道=1,高=28,宽=28)“拉直”成一个长向量:1×28×28 = 784

  • 方法1:x.view(x.size(0), -1)

    • x.size(0) 就是 batch 大小,-1 表示自动计算剩余维度的大小(这里就是 784)。

  • 方法2:x.flatten(1)

    • flatten(1) 表示从第1维开始展平(第0维是 batch),结果也是 [batch, 784]

  • 方法B x.view(-1, 28*28) 会把 batch 和通道、高、宽全部混在一起展平,结果可能变成 [batch*28, 28] 之类的错误形状,所以不正确。


5. 在 softmax 回归中,损失函数 nn.CrossEntropyLoss() 内部包含了( )操作。
A. softmax + 均方误差
B. sigmoid + 二值交叉熵
C. softmax + 负对数似然
D. log-softmax + NLLLoss

✅ 答案:D

💡 详细解析(重点)

  • 多分类问题的标准流程是:

    1. 模型输出每个类别的“得分”(logits)。

    2. 用 softmax 将得分转换为概率分布(所有类别概率之和=1)。

    3. 对正确类别的概率取负对数(-log(概率)),得到损失。

  • 理论上可以写成:loss = -log(softmax(logits)[正确类别])

  • 但是直接计算 softmax 再取 log 可能遇到数值不稳定的问题(比如指数爆炸或下溢)。

  • PyTorch 的 CrossEntropyLoss 实际做的是:先对 logits 做 log_softmax(数值上更稳定),然后调用 NLLLoss(负对数似然损失)。

  • 因此它等价于 LogSoftmax + NLLLoss,而不是简单的 softmax + NLLLoss

  • 选项 C 是理论上的等价描述,但选项 D 是 PyTorch 的真实实现方式,更准确。


6. 模型训练过程中,正确的操作顺序是( )
A. loss.backward() → optimizer.zero_grad() → optimizer.step()
B. optimizer.zero_grad() → loss.backward() → optimizer.step()
C. optimizer.step() → loss.backward() → optimizer.zero_grad()
D. loss.backward() → optimizer.step() → optimizer.zero_grad()

✅ 答案:B

💡 详细解析(非常关键)

  • 每一步训练的正确流程是:

    1. 梯度清零:因为梯度默认会累加(.grad 会不断叠加),不清零的话,新的梯度会加在旧的上面,导致更新方向错误。

    2. 反向传播:计算当前 batch 的损失对每个参数的梯度,存入 .grad

    3. 参数更新:优化器根据 .grad 和学习率更新参数。

  • 顺序绝对不能颠倒。如果先 backward 再 zero_grad,那么 backward 时旧梯度还没清除,会累加,然后 zero_grad 又把刚刚计算的新梯度清除了,等于白做。

  • 记住口诀:清零 → 反向 → 更新


二、填空题(每空2分,共20分)

7. 真实权重为 [2.0, -3.0, 0.5],每个样本有 ______ 个特征。训练集和测试集的划分比例通常为 ______ : ______。

✅ 答案:3;80;20(或 4:1)

💡 详细解析

  • 权重向量有3个数,每个数对应一个特征的系数 → 特征数量 = 3。

  • 实验代码中 split_idx = int(0.8 * n_samples),表示 80% 训练,20% 测试。

  • 这是机器学习的基本惯例:训练集用来学习参数,测试集用来评估模型在从未见过的数据上的表现。


8. 定义线性回归模型的类需要继承自 torch.nn.______,其中线性层使用 nn.Linear(______, ______),输出维度为 1。

✅ 答案:Module;n_features;1

💡 详细解析

  • 在 PyTorch 中,所有自定义的网络层/模型都要继承 nn.Module 父类,这样才能使用参数管理、梯度等功能。

  • nn.Linear(in_features, out_features) 中:

    • in_features:输入数据的特征维度。这里就是特征数 n_features

    • out_features:输出维度。线性回归输出一个标量(预测值),所以是 1。


9. 调用 optimizer.zero_grad() 的作用是 ______;调用 loss.backward() 的作用是 ______。

✅ 答案:将模型参数的梯度清零(避免累积);计算损失关于参数的梯度并累加到 .grad 中

💡 详细解析

  • 梯度累积特性:每次调用 backward(),新梯度会加到原来的 .grad 上,而不是替换。

  • 如果不清零,多个 batch 的梯度会一直叠加,参数更新就会错乱。

  • zero_grad() 把每个参数的 .grad 设置为 0(或 None)。

  • backward() 通过自动微分机制,从损失开始反向传播,计算每个参数对损失的导数,存到该参数的 .grad 属性中。


10. Fashion-MNIST 数据集共有 ______ 个类别,图像尺寸为 28×28 像素,输入神经网络的维度为 ______。

✅ 答案:10;784

💡 详细解析

  • Fashion-MNIST 包含 10 类服饰(T恤、裤子、套衫、裙子、外套、凉鞋、衬衫、运动鞋、包、踝靴)。

  • 每张图是 28 行 × 28 列 的灰度图,展平后就是 28×28 = 784 个像素值。

  • 所以输入层的神经元数量就是 784。


三、判断题(每题2分,共10分)

11. 在线性回归中,如果学习率设置过大,损失值可能会先快速下降,然后剧烈震荡甚至发散。

✅ 正确(√)

💡 详细解析

  • 学习率太大了,参数更新步长过大,可能直接“跨过”最低点,跑到对面更高的地方。下一次又跨回来,如此反复形成震荡。

  • 如果学习率更大,损失会不断增大(发散),最终变成 NaN。

  • 可以把学习率想象成下山时的步长:步长太大可能会跨过山谷,反而爬到另一座山上。


12. model.eval() 和 with torch.no_grad(): 的作用完全相同,可以互换使用。

✅ 错误(×)

💡 详细解析

  • model.eval():切换模型的“模式”。影响 Dropout 层(训练时随机丢弃神经元,评估时不丢弃)、BatchNorm 层(训练时用 batch 统计量,评估时用全局统计量)。

  • torch.no_grad():一个上下文管理器,告诉 PyTorch 不要跟踪计算图,不记录梯度。可以节省内存和计算,不影响 Dropout 等层的行为。

  • 评估时通常同时使用 model.eval() 和 with torch.no_grad():,但它们各司其职,不能互相替代。


13. 交叉熵损失函数可以直接用于多分类问题,不需要在模型输出层额外添加 softmax。

✅ 正确(√)

💡 详细解析

  • nn.CrossEntropyLoss 内部已经自动对模型输出的 logits 应用了 softmax(准确说是 log-softmax),然后计算损失。

  • 你只需要让模型输出10个原始分数(logits),不需要自己加 softmax 层。

  • 如果自己加了 softmax 再传入 CrossEntropyLoss,相当于做了两次 softmax,结果会错误。


14. 对于线性回归任务,使用 DataLoader 时 batch_size 越大,模型收敛速度一定越快。

✅ 错误(×)

💡 详细解析

  • batch size 增大,每个 batch 的梯度估计更精确(因为样本多),但计算一次梯度的时间更长。

  • 更大的 batch size 可能导致收敛到更差的局部极小值(泛化能力下降)。

  • 收敛速度要看“达到相同精度所需的时间”,不一定更快。实际工程中需要调参。

  • 所以“一定越快”是错误的。


15. 在测试集上评估模型时,需要调用 model.train() 来保持与训练时一致的行为。

✅ 错误(×)

💡 详细解析

  • 训练时调用 model.train() 会让 Dropout、BatchNorm 等层工作在“训练模式”。

  • 评估时应该调用 model.eval() 切换到“评估模式”,这样 Dropout 不会随机丢弃神经元,BatchNorm 使用固定的统计量。

  • 如果用 train() 模式去评估,结果会不稳定且不准确。

四、简答题
 

简答题1(6分)
(1)为什么要将数据集划分为训练集和测试集?
(2)如果不划分,直接用全部数据训练会有什么问题?

(1)训练集用于学习参数,测试集用于评估泛化能力,防止过拟合。用来判断模型是否真正学到规律
(2)无法知道模型对新样本的预测能力;模型可能过拟合训练数据,实际应用性能差。可能会发生数据泄露;评估结果会过于乐观。

简答题2(6分)
(1)nn.Linear(in_features, out_features) 中的两个参数分别代表什么?
(2)为什么线性回归的输出维度是1?
(3)线性回归中为什么使用均方误差(MSE)作为损失函数?

(1)in_features 为输入特征数,out_features 为输出特征数。
(2)线性回归预测一个连续的标量值(如房价),所以输出维度为1。(每个样本只需要一个预测值)
(3)MSE 是可导的凸函数,便于梯度下降;且对较大误差惩罚更强,适合回归任务。

简答题3(6分)
(1)为什么 softmax 回归使用交叉熵损失而不是均方误差?
(2)nn.CrossEntropyLoss 和组合 softmax + nn.NLLLoss 有什么关系?

(1)交叉熵直接衡量概率分布差异,分类任务中梯度更有效;MSE 对概率不敏感,且梯度易饱和。
(2)nn.CrossEntropyLoss 等价于 LogSoftmax + NLLLoss,实际实现采用 log-softmax 保证数值稳定性。

简答题4(8分)
(1)model.eval() 和 with torch.no_grad(): 的作用分别是什么?它们必须同时使用吗?
(2)训练集准确率和测试集准确率哪个通常更高?为什么?
(3)在线性回归的最后,我们对比了学习到的权重和真实权重。为什么它们不可能完全相等?

(1)model.eval() 切换模型模式(影响 Dropout、BN),使用的是训练好的统计量;no_grad() 禁用梯度计算。不必须同时使用,但评估时通常一起用,节省内容,加速计算
(2)训练集准确率更高,因为模型已“见过”训练数据并可能过拟合。
(3)数据含随机噪声,且模型从有限样本学习,梯度下降收敛到受噪声影响的近似解,不会恰好等于真实值。

简答题5(6分)
(1)学习率过大会导致什么现象?学习率过小会有什么问题?
(2)增大批大小对训练速度和模型性能可能产生什么影响?
(3)在 Fashion-MNIST 实验中,如果增加一个隐藏层,你认为准确率会如何变化?为什么?

(1)学习率过大:损失震荡或发散;过小:收敛缓慢,可能陷入局部极小。
(2)增大 batch size:训练速度可能加快(并行),但泛化能力可能下降(梯度平滑,易陷尖锐极小),内存需求增加。
(3)准确率通常会提高,因为增加隐藏层引入非线性,模型表达能力更强;但可能过拟合,需正则化。

五、代码填空题

空1n_features(或具体数字 3
空2model
空3criterion
空4zero_grad()
空5backward()
空6step()
空7CrossEntropyLoss
空81
空9SGD(或其他合理优化器如 Adam,但按实验原代码为 SGD
空10num_epochs

代码填空解析

  • 空1n_features 或 3

    • 线性层的输入维度必须等于每个样本的特征数量。

    • 实验中特征数 = 3,但更推荐用变量 n_features 以保持通用性。

  • 空2model

    • 我们之前创建了模型实例 model = LinearRegressionModel(n_features)

    • 用 model(batch_X) 执行前向传播,相当于调用 model.forward(batch_X)

  • 空3criterion

    • 之前定义了 criterion = nn.MSELoss()

    • 注意:模型输出 pred 形状是 [batch, 1],而 batch_y 形状是 [batch]

    • 用 pred.squeeze() 去掉维度1(变成 [batch]),使形状匹配,才能计算 MSE。

  • 空4zero_grad() —— 清零所有参数的梯度,防止累加。

  • 空5backward() —— 反向传播,计算当前损失的梯度。

  • 空6step() —— 根据梯度和学习率更新参数。

  • 这三步的顺序是固定的,不能颠倒。

  • 空7CrossEntropyLoss

    • 多分类问题必须用交叉熵损失。

    • PyTorch 中就是 nn.CrossEntropyLoss()

  • 空8SGD(或 Adam

    • 实验原代码使用的是 SGD(随机梯度下降)。

    • SGD 是最基础的优化器,学习率固定。

    • 如果写 Adam 也可以,但考试建议按照实验原样填 SGD

  • 空91

    • outputs 的形状是 [batch, 10],其中第1维(索引1)是类别维度。

    • torch.max(outputs, 1) 会在第1维上找最大值,返回 (最大值, 最大值索引)

    • predicted 就是每个样本预测的类别索引(0~9)。

  • 空10num_epochs

    • 循环的次数由变量 num_epochs 控制,实验中通常设为 20 或更多。

    • 这里填变量名而不是具体数字,因为代码前面会有定义。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐