一、实验任务与数据简介

  • 任务:根据房屋的79个特征(如面积、地段、建筑年份等)预测房价(SalePrice)。

  • 数据集:来自Kaggle的房价预测竞赛,包含训练集(train.csv)和测试集(test.csv)。

  • 评价指标:通常使用均方根对数误差(RMSLE),但实验中我们使用均方误差(MSE)作为损失函数。


二、数据预处理流程(核心)

1. 标签预处理:取对数

  • 对目标变量 SalePrice 取对数:y_train = np.log(train_data['SalePrice'])

  • 原因:房价分布通常右偏(长尾),取对数使其接近正态分布,利于模型训练;且对数误差与相对误差相关,更合理。

2. 合并训练集和测试集

  • 为统一进行特征工程,将训练集(不含标签)和测试集按行合并。

  • 好处:对缺失值填充、编码等操作一致,避免测试集单独处理时出错。

3. 处理缺失值

  • 数值型特征:用中位数填充(median()),因为中位数对异常值更稳健。

  • 类别型特征:用字符串 'None' 填充,表示缺失为一类。

4. 处理类别特征:独热编码(One-Hot Encoding)

  • 使用 pd.get_dummies(data, dummy_na=True)

  • 作用:将类别变量转换为0/1数值,使模型能使用。

  • dummy_na=True:为缺失值也创建一个虚拟列,避免信息丢失。

5. 标准化(Z-score标准化)

  • 公式:X_std = (X - mean) / std

  • 注意:用训练集的均值与标准差标准化训练集、验证集和测试集(不能重新计算测试集的统计量,否则分布不一致)。

  • 标准化让所有特征在同一量级,加快梯度下降收敛。


三、数据集划分

  • 训练集:用于训练模型参数。

  • 验证集:从训练集中划分出一部分(如20%),用于调参和早停,不用于训练。

  • 测试集:原始提供的 test.csv,用于最终提交(无标签)。

  • 区别:验证集有标签,可计算损失评估模型;测试集无标签,仅供预测。


四、模型设计(MLP)

  • 使用 nn.Module 自定义模型,结构可配置:input_dim → 多个隐藏层(如256→128→64)→ 输出层(1个神经元)。

  • 每个隐藏层后跟:

    • 激活函数(如 ReLU

    • Dropout层(随机丢弃一部分神经元,防止过拟合)

  • Dropoutdropout_rate 表示神经元被丢弃的概率。训练时启用,验证/测试时自动关闭(需 model.eval())。


五、损失函数与优化器

  • 损失函数:回归任务用均方误差 nn.MSELoss()

  • 优化器:Adam(自适应学习率),常用参数 lr(学习率)和 weight_decay(L2正则化系数)。

  • weight_decay:对参数施加L2惩罚,使权重趋向小值,防止过拟合。


六、训练技巧

1. 学习率调度器 ReduceLROnPlateau

  • 当验证损失连续 patience 轮不再下降时,将学习率乘以 factor

  • 作用:自动降低学习率,帮助模型跳出局部最优或平稳期。

2. 早停(Early Stopping)

  • 当验证损失连续 patience 轮没有下降时,停止训练,防止过拟合。

  • 同时保存最佳模型(best_val_loss 对应的权重)。

3. 设备管理(device

  • 将模型和数据移动到 GPU(cuda)或 CPU。

  • 预测时,结果需用 .cpu() 移回CPU才能转为NumPy。


七、模型评估与可视化

  • 损失曲线:训练损失和验证损失随epoch变化。若验证损失上升而训练损失下降 → 过拟合;两者都高且不降 → 欠拟合。

  • 真实值vs预测值散点图:点应大致落在 y=x 对角线附近,偏离说明预测偏差大。


八、预测与提交

  • 加载最佳模型,对测试集进行预测,注意:

    • 模型输出的是对数价格,需用 np.exp() 转换回原始价格。

  • 生成提交文件:Id 和 SalePrice 两列。

附加

正则化手段:权重衰减(L2正则化)与暂退法(Dropout)—— 解决过拟合

一、过拟合与欠拟合

1.1 概念定义

现象 定义 训练误差 验证/测试误差
欠拟合 模型过于简单,未能捕捉数据中的规律
过拟合 模型过于复杂,死记硬背训练数据,泛化能力差 很低
正常拟合 模型复杂度适中,既能学习规律又能泛化 较低 较低

1.2 图像呈现状态

假设我们用一个多项式拟合一些散点:

  • 欠拟合(例如用一次函数拟合抛物线分布):

    • 图像:一条直线穿不过大部分点,预测曲线平滑但偏离真实趋势。

    • 特点:模型太简单,偏差高

  • 过拟合(例如用高次多项式拟合少量点):

    • 图像:曲线剧烈震荡,精确穿过每一个训练点,但形状极不规则。

    • 特点:模型太复杂,方差高,对噪声也学习了。

  • 正常拟合(例如用二次函数拟合抛物线分布):

    • 图像:平滑曲线,基本贴合点分布趋势,且没有剧烈波动。

手绘图描述(考试时可用文字说明):

  • 欠拟合:直线穿过散点,大部分点远离直线。

  • 过拟合:锯齿状曲线,每个点都被准确经过,但预测新点时会偏离很远。


二、两种正则化手段详解

2.1 权重衰减(Weight Decay,即 L2 正则化)

原理

在损失函数中添加一个惩罚项:

作用:惩罚大的权重,迫使权重尽量小,从而降低模型复杂度,防止过拟合。

用法(PyTorch)

optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=0.001)
# 或 Adam
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=0.001)
参数 weight_decay 的含义
  • 即公式中的 λ(lambda),控制正则化强度。

  • 越大,对权重的惩罚越重,模型越简单(可能欠拟合)。

  • 越小,正则化作用越弱,接近无正则化。

  • 常用值:1e-41e-50.001 等。

为什么叫“权重衰减”?

因为梯度下降更新时,相当于先把权重乘以 (1 - ηλ) 再减去梯度项,即权重被衰减了。


2.2 暂退法(Dropout)

原理

训练时,以概率 p 随机将某些神经元的输出置为0(“丢弃”或“暂退”),并且为了保持期望不变,保留的神经元输出除以 (1-p)

作用:强制网络学习冗余表示,避免神经元之间过强的协同适应(co-adaptation),提高泛化能力。

用法(PyTorch)
import torch.nn as nn

class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 256)
        self.dropout1 = nn.Dropout(p=0.5)   # 暂退概率 0.5
        self.fc2 = nn.Linear(256, 128)
        self.dropout2 = nn.Dropout(p=0.5)
        self.fc3 = nn.Linear(128, 10)
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = torch.relu(self.fc1(x))
        x = self.dropout1(x)      # 训练时随机丢弃,测试时自动关闭
        x = torch.relu(self.fc2(x))
        x = self.dropout2(x)
        x = self.fc3(x)
        return x
参数 p 的含义(Dropout rate)
  • 每个神经元被丢弃的概率(即输出置0的概率)。

  • p=0.5:一半神经元随机失活(常用值)。

  • p=0.2:20%失活,正则化较弱。

  • p=0.9:90%失活,模型可能欠拟合。

  • 注意:测试时 Dropout 层会自动关闭(不丢弃神经元),且不需要缩放。


三、对比总结

方法 核心思想 参数 参数越大 → 训练/测试行为
权重衰减 限制权重大小 weight_decay (λ) 模型越简单 训练和测试时都生效
Dropout 随机丢弃神经元 p 丢弃越多 → 正则化越强 训练时随机丢弃,测试时不丢弃

四、例题

例题1(概念判断)

题目:判断下列现象属于欠拟合还是过拟合。
(1) 训练损失 0.01,验证损失 0.85。
(2) 训练损失 0.45,验证损失 0.46。
(3) 训练损失 0.80,验证损失 0.81。

答案
(1) 过拟合(训练很好,验证很差)
(2) 正常拟合(两者相近且较低)
(3) 欠拟合(两者都高)


例题2(原理简述)

题目:简述权重衰减为什么能防止过拟合。

参考答案
权重衰减在损失函数中加入权重的平方和,使模型在优化时不仅最小化原始损失,还要尽量保持权重较小。小权重意味着模型对输入变化不敏感,决策边界更平滑,从而降低了过拟合风险。


例题3(Dropout 参数设置)

题目:在训练一个深度网络时,发现验证集准确率远低于训练集,你怀疑是过拟合。你想在模型中增加 Dropout 层,现有两个候选参数 p=0.2 和 p=0.8。应该选哪个?为什么?

答案
应选 p=0.8(丢弃80%的神经元)。因为过拟合严重时,需要更强的正则化,更大的 p 意味着更多神经元被随机丢弃,模型被迫学习更鲁棒的特征。当然 p 过大可能导致欠拟合,需要调参。


例题4(代码填空)

题目:补全以下代码,添加 Dropout 层和权重衰减。

class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 256)
        self.dropout = nn.______(p=0.5)   # 填空1
        self.fc2 = nn.Linear(256, 10)
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = torch.relu(self.fc1(x))
        x = self.______(x)                # 填空2
        x = self.fc2(x)
        return x

model = MLP()
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=______)  # 填空3

答案
填空1:Dropout
填空2:dropout(实例名)
填空3:0.001(或其他数值,如 1e-4)


例题5(数值理解)


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

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

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

  1. 对房价标签 SalePrice 取对数的原因是( )
    A. 使标签变为整数
    B. 让标签分布更接近正态分布,利于模型训练
    C. 减少特征数量
    D. 方便可视化

  2. 填充数值特征的缺失值时,实验中使用的是( )
    A. 均值
    B. 众数
    C. 中位数
    D. 直接删除

  3. 以下哪个操作可以防止模型过拟合?( )
    A. 增加学习率
    B. 使用 Dropout
    C. 减少训练数据
    D. 不使用激活函数

  4. 标准化测试集时,应该使用( )
    A. 测试集的均值和标准差
    B. 训练集的均值和标准差
    C. 验证集的均值和标准差
    D. 全数据集的均值和标准差

  5. 在早停机制中,patience 参数的含义是( )
    A. 训练的总轮数
    B. 学习率下降的等待轮数
    C. 验证损失连续不下降的最大轮数,超过则停止训练
    D. 每轮训练的批次数量


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

  1. 对类别特征进行独热编码应使用 pandas 的 pd.______() 函数,参数 dummy_na=True 的作用是 ______。

  2. 模型定义中,Dropout层的参数 dropout_rate=0.2 表示 ______。训练时 Dropout 生效,验证时需调用 model.______() 来禁用 Dropout。

  3. 学习率调度器 ReduceLROnPlateau 中,mode='min' 表示监控指标 ______ 时降低学习率,factor=0.5 表示学习率 ______。

  4. 在训练循环中,梯度清零使用 optimizer.______(),参数更新使用 optimizer.______()

  5. 模型预测后,输出的 SalePrice 是 ______(填“原始价格”或“对数价格”),需要用 np.______() 转换回原始价格。


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

  1. ( )训练集和测试集应该分别进行标准化,各自计算均值和标准差。

  2. ( )Dropout层在验证阶段也会随机丢弃神经元,以保持一致性。

  3. ( )早停机制中,当验证损失连续10轮不下降时,应停止训练并保存最佳模型。

  4. ( )独热编码会增加特征的维度。

  5. ( )均方误差(MSE)是分类问题的常用损失函数。


四、简答题(将原实验中的思考题整合,共35分)

简答题1(4分,来自实验一)

device 变量的作用是什么?如果电脑有GPU,device 会是什么?

简答题2(4分,来自实验二)

训练集和测试集分别有多少个样本?目标变量(预测值)是哪一列?

简答题3(4分,来自实验3.1)

为什么要对 SalePrice 取对数?如果不取对数会怎样?

简答题4(4分,来自实验3.3)

为什么需要对类别特征进行独热编码?dummy_na=True 的作用是什么?

简答题5(4分,来自实验3.5)

为什么要用训练集的均值和标准差来标准化测试集,而不是重新计算?

简答题6(4分,来自实验四)

验证集和测试集的区别是什么?为什么需要验证集?

简答题7(4分,来自实验四)

模型训练时,代码中计算的 train_loss 和 val_loss 分别是哪个集的结果?它们各自的作用是什么?

简答题8(4分,来自实验五)

Dropout层放在什么位置?它的参数 dropout_rate 代表什么?如果将 dropout_rate 从 0.2 改为 0.5,会发生什么?

简答题9(3分,来自实验五)

模型定义中,self.net = nn.Sequential(*layers) 的作用是什么?


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

请根据上下文填写正确的代码。

# 处理缺失值
numeric_cols = all_data.select_dtypes(include=[np.number]).columns
for col in numeric_cols:
    if all_data[col].isnull().any():
        median_val = all_data[col].______()   # 空1
        all_data[col].fillna(median_val, inplace=True)

# 独热编码
all_data = pd.______(all_data, dummy_na=True)   # 空2

# 标准化
train_means = X_train.______()   # 空3
train_stds = X_train.______()    # 空4

# 创建 DataLoader
train_dataset = TensorDataset(______, ______)   # 空5, 空6
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=______)   # 空7

# 模型定义中的激活函数和 Dropout
layers.append(nn.______())          # 空8
layers.append(nn.______(dropout_rate))  # 空9

# 损失函数
criterion = nn.______()   # 空10


参考答案与超详细解析

一、单选题

  1. B
    解析:房价分布通常右偏(长尾),取对数后接近正态分布,利于模型学习;同时预测对数价格再指数还原,得到的误差更接近相对误差,符合竞赛评价指标RMSLE。

  2. C
    解析:实验中使用中位数填充。中位数对异常值不敏感,比均值更稳健;尤其房价数据中可能存在极端值(豪宅),中位数更合适。

  3. B
    解析:Dropout随机丢弃神经元,迫使网络学习冗余表示,防止过拟合。增加学习率可能使训练不稳定;减少数据反而容易过拟合;无激活函数无法学习非线性。

  4. B
    解析:标准化必须使用训练集的统计量,因为测试集是模拟“未见数据”,我们不知道其分布。若使用测试集的均值和标准差,相当于“偷看”了测试集,会破坏评估的公正性。

  5. C
    解析patience 表示验证损失连续不下降的轮数上限。当连续 patience 轮验证损失都没有改善时,停止训练,防止过拟合。


二、填空题

  1. 答案get_dummies;为缺失值单独创建一个虚拟列
    解析pd.get_dummies 将类别转换为0/1列。dummy_na=True 会对原本缺失的值生成一列,例如 col_NaN 标记为1,保留缺失信息。

  2. 答案:每个神经元有20%的概率被丢弃(或随机失活概率0.2);eval()
    解析dropout_rate 是神经元被暂时移除的概率。训练时启用,验证时需用 model.eval() 关闭Dropout,让所有神经元参与计算。

  3. 答案:不再下降(或达到最小值);乘以0.5(即缩小一半)
    解析mode='min' 表示监控指标(如验证损失)达到最小值时触发;factor=0.5 表示将学习率乘以0.5,降低一半。

  4. 答案zero_grad()step()
    解析:标准三步:清零梯度(zero_grad)→ 反向传播(backward)→ 更新参数(step)。

  5. 答案:对数价格;exp
    解析:模型训练时对 SalePrice 取了对数,所以输出的是对数价格。提交时需要还原为原始价格,用 np.exp()


三、判断题

  1. ×
    解析:测试集必须使用训练集的均值和标准差,不能独立计算,否则导致分布不一致。

  2. ×
    解析:Dropout仅在训练阶段启用,验证和测试阶段自动关闭(需调用 model.eval()),否则会导致预测结果随机。


  3. 解析:早停机制正是这样:连续 patience 轮验证损失未改善则停止,并回滚到最佳模型。


  4. 解析:每个类别值会生成一个新列,因此特征维度增加(如性别有男、女,则变成两列)。

  5. ×
    解析:MSE 是回归任务的损失函数,分类任务通常用交叉熵。


四、简答题(详细解析)

简答题1

作用device 变量指定模型和数据运行的硬件(CPU或GPU)。
有GPU时device = torch.device('cuda')
解析:GPU并行计算可大幅加速训练。代码中通过 torch.cuda.is_available() 自动判断,避免手动修改。

简答题2

训练集样本数:根据 train_data.shape,一般为1460(Kaggle房价数据集)。
测试集样本数:1459。
目标变量列'SalePrice'

简答题3

取对数原因

  • 房价分布右偏,对数变换后接近正态分布,满足线性回归假设。

  • 使用对数损失(RMSLE)对异常值不敏感,且预测误差与相对误差相关。
    不取对数的后果

  • 模型可能受高价房影响大,低价房预测不准;

  • 损失值巨大,训练不稳定;

  • 提交的RMSLE得分会较差。

简答题4

独热编码原因:机器学习模型只能处理数值,类别特征(如地段、材质)需要转换为0/1特征。
dummy_na=True:为缺失值单独生成一列(如 col_NaN),保留缺失信息,避免简单删除导致信息丢失。

简答题5

标准化测试集使用训练集统计量

  • 测试集模拟真实未见数据,我们不知道其均值和标准差。

  • 若使用测试集自己的统计量,相当于引入了未来信息,评估结果不可靠。

  • 保证训练和测试数据处于同一量纲,模型才能正确预测。

简答题6

验证集:从训练集中划分,有标签,用于调参、早停、选择最佳模型。
测试集:无标签(竞赛提供),用于最终评估或提交。
为什么需要验证集:防止模型在测试集上过拟合(不能反复使用测试集调参),验证集作为“模拟考试”来调整超参数。

简答题7

  • train_loss:训练集上的平均损失,反映模型拟合训练数据的能力。

  • val_loss:验证集上的平均损失,反映模型泛化能力。
    作用:比较两者可判断欠拟合(两者都高)、过拟合(train_loss低,val_loss高)或正常。

简答题8

Dropout位置:通常放在每个隐藏层之后、激活函数之后(或之前均可,但常见于激活后)。
dropout_rate:每个神经元被随机丢弃的概率,0.2表示20%的神经元在每次前向传播时临时移除。
改为0.5:更强的正则化,可能提升泛化能力,但若模型容量不足,可能导致欠拟合;训练速度变慢(因为有效参数减少)。
改为0:关闭Dropout,容易过拟合。

简答题9

nn.Sequential(*layers) 将 layers 列表中的所有层(Linear、ReLU、Dropout等)按顺序封装成一个序列网络。调用 forward 时自动依次执行。这样代码简洁,不需要手动写每层的前向传播。


五、代码填空题答案

空1median
空2get_dummies
空3mean
空4std
空5X_train_tensor
空6y_train_tensor
空7True
空8ReLU(或其他激活函数如 LeakyReLU,但实验使用ReLU)
空9Dropout
空10MSELoss

Logo

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

更多推荐