
人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载本篇指南以《动手学深度学习》d2l-zh多层级感知机章节的 Kaggle 房价预测实战为核心完整讲解如何从零参与 Kaggle 房价预测竞赛House Prices: Advanced Regression Techniques包括带缓存与 SHA-1 校验的数据集下载工具、基于pandas的数值/类别特征预处理流水线、线性基线模型与对数 RMSE 评估指标、Adam 优化器训练流程、K 折交叉验证的模型选择方法以及最终生成submission.csv并提交到 Kaggle 的完整链路。读完本文你将掌握一套可复用到任意表格类回归竞赛的标准化实战方案。竞赛背景与数据集概况Kaggle 房价预测比赛是一个非常适合入门深度学习的竞赛起点。该数据集由 Bart de Cock 于 2011 年收集覆盖 2006–2010 年间美国爱荷华州埃姆斯市Ames, IA的房价记录相比经典的波士顿房价数据集它在样本数量和特征数量上都更为庞大。它属于通用表格数据不包含音频、视频等需要专门模型的奇异结构因此是练习数据预处理、模型设计与超参数选择的理想载体。在原始章节中作者通过这一实战项目展示了真实数据科学任务的完整形态数据缺失、多种数据类型混杂、官方评测指标特殊、需要本地划分验证集而只能通过平台评测测试集。下载与缓存数据集全书中的数据集都通过一套统一的工具函数下载。核心机制是维护一个全局字典DATA_HUB将数据集名称映射为包含URL 与 SHA-1 哈希的二元组所有数据集托管在DATA_URL指定的站点import os import requests import zipfile import tarfile import hashlib DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/download函数负责实际下载并将数据集缓存到本地目录默认../data。它先检查本地缓存若文件已存在且其 SHA-1 与DATA_HUB中记录一致则直接复用缓存文件避免重复下载def download(name, cache_diros.path.join(.., data)): 下载一个DATA_HUB中的文件返回本地文件名 assert name in DATA_HUB, f{name} 不存在于 {DATA_HUB} url, sha1_hash DATA_HUB[name] os.makedirs(cache_dir, exist_okTrue) fname os.path.join(cache_dir, url.split(/)[-1]) if os.path.exists(fname): sha1 hashlib.sha1() with open(fname, rb) as f: while True: data f.read(1048576) if not data: break sha1.update(data) if sha1.hexdigest() sha1_hash: return fname # 命中缓存 print(f正在从{url}下载{fname}...) r requests.get(url, streamTrue, verifyTrue) with open(fname, wb) as f: f.write(r.content) return fname另有两个配套工具download_extract用于下载并解压 zip/tar 压缩包download_all则遍历DATA_HUB把书中用到的全部数据集一次性拉取到缓存目录。这套工具已经沉淀进 d2l 工具库中例如 d2l/paddle.py 中同样注册了本次比赛的数据集条目DATA_HUB[kaggle_house_train] ( DATA_URL kaggle_house_pred_train.csv, 585e9cc93e70b39160e7921475f9bcd7d31219ce) DATA_HUB[kaggle_house_test] ( DATA_URL kaggle_house_pred_test.csv, fa19780a7b011d9b009e8bff8e99922a8ee2eb90)Kaggle 平台与竞赛页面Kaggle 是当今流行的机器学习竞赛平台每场比赛围绕至少一个数据集展开许多比赛由赞助方提供奖金。平台通过论坛与共享代码促进协作与竞争排行榜提供了各方案之间直接的定量比较代码共享则让每个人都能学习哪些方法有效、哪些无效。参与比赛前需要先注册账户。本次房价预测竞赛的页面地址为https://www.kaggle.com/c/house-prices-advanced-regression-techniques。在竞赛页面的Data 选项卡下可以找到数据集、提交预测并查看排名访问与读取数据集竞赛数据分为训练集和测试集。每条记录包含房屋属性值如街道类型、施工年份、屋顶类型、地下室状况等与房屋价格标签特征由多种数据类型构成——施工年份是整数、屋顶类型是离散类别、其余特征多为浮点数。现实数据的复杂性在这里显现部分样本存在整体缺失缺失值被标记为 NA。房屋价格只出现在训练集中毕竟是竞赛。我们只能自行划分训练集创建验证集而官方测试集的评估只能在上传预测后由平台完成。读取数据使用pandas参见 pandas 章节。若环境未安装可在 Jupyter 中直接!pip install pandas。随后按框架导入工具库例如 PyTorch 版%matplotlib inline from d2l import torch as d2l import torch from torch import nn import pandas as pd import numpy as npMXNet、TensorFlow、Paddle 版本的导入方式对应为from d2l import mxnet/tensorflow/paddle as d2l。利用前述下载工具缓存比赛数据后用pandas分别载入训练与测试 CSVtrain_data pd.read_csv(download(kaggle_house_train)) test_data pd.read_csv(download(kaggle_house_test)) print(train_data.shape) # (1460, 81)1460 个样本、80 个特征 1 个标签 print(test_data.shape) # (1459, 80)1459 个样本、80 个特征查看前 4 个样本的前 4 个与最后 2 个特征以及标签SalePriceprint(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])可以看到每个样本的第一个特征是Id它只用于识别样本、不携带任何预测信息因此送入模型前要将其剔除。训练集与测试集按列拼接得到统一的特征矩阵all_features pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))数据预处理真实数据往往混合多种类型建模前必须预处理。流程分三步1. 数值特征均值填充 标准化首先将所有缺失值替换为对应特征的均值然后将特征重新缩放到零均值、单位方差$$x \leftarrow \frac{x - \mu}{\sigma},$$其中 $\mu$、$\sigma$ 分别是特征的均值与标准差。标准化后 $E[\frac{x-\mu}{\sigma}]0$ 且 $E[(x-\mu)^2]\sigma^2$特征满足零均值、单位方差。标准化的意义有二一是方便优化收敛二是因为我们事先不知道哪些特征相关不希望惩罚分配给某个特征的系数超过其他特征否则会引入不公平的先验偏置。# 选出所有非 object数值型特征 numeric_features all_features.dtypes[all_features.dtypes ! object].index all_features[numeric_features] all_features[numeric_features].apply( lambda x: (x - x.mean()) / (x.std())) # 标准化后均值消失缺失值可以直接填 0 all_features[numeric_features] all_features[numeric_features].fillna(0)一个小技巧标准化之后缺失值等价于该特征取均值因此直接填充 0 即可无需单独记录均值。2. 类别特征独热编码对 MSZoning 这类离散特征使用独热编码one-hot替换——这与多分类标签转向量是同一思想。例如 MSZoning 取值 RL 与 RM去掉原特征后生成两个指示特征MSZoning_RL、MSZoning_RM原始值为 RL 时前者为 1、后者为 0。pandas的get_dummies自动完成这一切其中关键参数是dummy_naTrue——它把 NA缺失值也当作一种合法取值并为其单独创建指示特征all_features pd.get_dummies(all_features, dummy_naTrue) all_features.shape # 特征数从 79 增至 331这一转换使特征总数从 79 增加到 331。最后通过values属性把pandas数据转为 NumPy再转成张量供训练使用n_train train_data.shape[0] train_features d2l.tensor(all_features[:n_train].values, dtyped2l.float32) test_features d2l.tensor(all_features[n_train:].values, dtyped2l.float32) train_labels d2l.tensor( train_data.SalePrice.values.reshape(-1, 1), dtyped2l.float32)训练线性基线模型与对数 RMSE首先训练一个带平方损失MSE的线性模型。线性模型固然难以夺冠但它提供了宝贵的健全性检查sanity check若连它都做不优于随机猜测则说明大概率存在数据处理 bug若一切正常它又成为基线帮助我们估计更复杂模型的提升空间。loss nn.MSELoss() in_features train_features.shape[1] def get_net(): net nn.Sequential(nn.Linear(in_features, 1)) return net相对误差与对数 RMSE房价与股票类似我们更关心相对误差$\frac{y-\hat{y}}{y}$ 而非绝对误差。例如在俄亥俄州农村典型房价 12.5 万美元偏差 10 万美元是灾难性的而在加州豪宅区房价中位数超 400 万美元同样的偏差却是优秀预测。解决办法是对价格的对数衡量差异——这恰恰也是竞赛官方的评测指标$|\log y - \log \hat{y}| \le \delta$ 等价于 $e^{-\delta} \le \frac{\hat{y}}{y} \le e^\delta$。由此定义预测价格对数与标签价格对数之间的均方根误差$$\sqrt{\frac{1}{n}\sum_{i1}^n\left(\log y_i -\log \hat{y}_i\right)^2}.$$实现上为防止对小于 1 的预测取对数产生负值或溢出先把预测值裁剪到不小于 1def log_rmse(net, features, labels): # 为在取对数时稳定数值将小于 1 的值设置为 1 clipped_preds torch.clamp(net(features), 1, float(inf)) rmse torch.sqrt(loss(torch.log(clipped_preds), torch.log(labels))) return rmse.item()训练函数与 Adam 优化器与前面章节不同本节训练使用Adam 优化器后续章节会详述。其核心吸引力在于对初始学习率不那么敏感即便在无限超参调优资源下未必优于别的优化器实际使用中人们普遍发现它显著省心。训练函数在每个 epoch 结束后记录训练集及可选的验证集的log_rmsedef train(net, train_features, train_labels, test_features, test_labels, num_epochs, learning_rate, weight_decay, batch_size): train_ls, test_ls [], [] train_iter d2l.load_array((train_features, train_labels), batch_size) # 使用Adam优化算法 optimizer torch.optim.Adam(net.parameters(), lrlearning_rate, weight_decayweight_decay) for epoch in range(num_epochs): for X, y in train_iter: optimizer.zero_grad() l loss(net(X), y) l.backward() optimizer.step() train_ls.append(log_rmse(net, train_features, train_labels)) if test_labels is not None: test_ls.append(log_rmse(net, test_features, test_labels)) return train_ls, test_ls这里的d2l.load_array在 d2l/torch.py 中实现为TensorDatasetDataLoaderis_trainTrue时打乱数据weight_decay参数直接对接 Adam 的 L2 正则。TensorFlow 版使用tf.keras.losses.MeanSquaredError与tf.keras.optimizers.Adam并借助tf.GradientTape手动计算梯度应用更新Paddle 版使用paddle.optimizer.Adam训练后调用optimizer.clear_grad()清空梯度。K 折交叉验证模型选择与超参数调整依靠 模型选择章节 引入的 K 折交叉验证。首先实现取第 $i$ 折的函数把数据切分为 K 段第 $i$ 段作为验证集其余拼接为训练集。数据集规模不大这种简单切分方式足够def get_k_fold_data(k, i, X, y): assert k 1 fold_size X.shape[0] // k X_train, y_train None, None for j in range(k): idx slice(j * fold_size, (j 1) * fold_size) X_part, y_part X[idx, :], y[idx] if j i: X_valid, y_valid X_part, y_part elif X_train is None: X_train, y_train X_part, y_part else: X_train d2l.concat([X_train, X_part], 0) y_train d2l.concat([y_train, y_part], 0) return X_train, y_train, X_valid, y_valid然后执行 K 次训练返回训练与验证误差的平均值并在第一折时绘制训练/验证 log rmse 随 epoch 变化的曲线纵轴为对数刻度def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay, batch_size): train_l_sum, valid_l_sum 0, 0 for i in range(k): data get_k_fold_data(k, i, X_train, y_train) net get_net() train_ls, valid_ls train(net, *data, num_epochs, learning_rate, weight_decay, batch_size) train_l_sum train_ls[-1] valid_l_sum valid_ls[-1] if i 0: d2l.plot(list(range(1, num_epochs 1)), [train_ls, valid_ls], xlabelepoch, ylabelrmse, xlim[1, num_epochs], legend[train, valid], yscalelog) print(f折{i 1}训练log rmse{float(train_ls[-1]):f}, f验证log rmse{float(valid_ls[-1]):f}) return train_l_sum / k, valid_l_sum / k模型选择与过拟合监控本节提供一组未调优的默认超参数把进一步优化留给读者k, num_epochs, lr, weight_decay, batch_size 5, 100, 5, 0, 64 train_l, valid_l k_fold(k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size) print(f{k}-折验证: 平均训练log rmse: {float(train_l):f}, f平均验证log rmse: {float(valid_l):f})这里lr5线性模型配合标准化特征可承受较大的学习率、weight_decay0暂不施加权重衰减、batch_size64、训练 100 轮。训练中应同时监控训练误差与验证误差两个数字训练误差极低而验证误差显著更高 →过拟合可引入正则化权重衰减、dropout或减少模型容量过拟合轻微 → 数据或许能支撑更强的模型。注意K 折交叉验证在数据集足够大、超参数组合合理时对多重检验相当稳健但如果尝试的组合过多可能碰巧取得优异的验证表现而该表现不再代表真实泛化误差。提交预测到 Kaggle确定超参数后改用全部训练数据重新训练而非仅交叉验证使用的 $1-1/K$ 比例再对测试集做预测并整理成 Kaggle 要求的submission.csv仅含Id与SalePrice两列def train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size): net get_net() train_ls, _ train(net, train_features, train_labels, None, None, num_epochs, lr, weight_decay, batch_size) d2l.plot(np.arange(1, num_epochs 1), [train_ls], xlabelepoch, ylabellog rmse, xlim[1, num_epochs], yscalelog) print(f训练log rmse{float(train_ls[-1]):f}) # 将网络应用于测试集 preds d2l.numpy(net(test_features)) # 重新格式化以导出到Kaggle test_data[SalePrice] pd.Series(preds.reshape(1, -1)[0]) submission pd.concat([test_data[Id], test_data[SalePrice]], axis1) submission.to_csv(submission.csv, indexFalse) train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)一个实用的健全性检查是确认测试集上的预测表现与 K 折交叉验证的结果大致吻合若一致即可放心上传。提交步骤非常简单登录 Kaggle进入房价预测竞赛页面点击 Submit Predictions 或 Late Submission 按钮位于页面右侧点击页面底部虚线框中的 Upload Submission File 按钮选择要上传的预测文件点击页面底部的 Make Submission 按钮查看结果。小结与进阶练习本节沉淀的可复用经验真实数据通常混合多种数据类型必须预处理将实值数据重缩放为零均值、单位方差并用均值填充缺失值是良好的默认做法把类别特征转换为指示独热特征可将其当作独热向量处理用 K 折交叉验证选择模型并调整超参数对数变换对相对误差类问题价格、股价非常有效。若想继续提升成绩可围绕以下方向练习将本节预测提交到 Kaggle观察分数直接最小化价格的对数即把log(SalePrice)作为标签能否改进模型预测价格对数而非价格会发生什么用均值填充缺失值是否总是好主意提示能否构造缺失并非随机的情形通过 K 折交叉验证调优超参数提升得分改进模型结构增加层数、权重衰减、dropout若不对连续数值特征做标准化会发生什么上述完整流程对应的可执行中文代码与逐框架MXNet/PyTorch/TensorFlow/Paddle实现可在 chapter_multilayer-perceptrons/kaggle-house-price.md 中查看相关工具函数load_array、plot、DATA_HUB等沉淀于 d2l/torch.py、d2l/paddle.py、d2l/tensorflow.py 与 d2l/mxnet.py可直接import d2l复用。赞分享人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载相关推荐突破Kaggle房价预测瓶颈GluonK折交叉验证实战指南突破Kaggle房价预测瓶颈GluonK折交叉验证实战指南 在数据科学竞赛中房价预测是一个经典的回归问题而Kaggle平台上的房价预测竞赛更是检验机器学MXNet Gluon 实战基于 K 折交叉验证的 Kaggle 房价预测回归任务House PricesMXNet Gluon 实战基于 K 折交叉验证的 Kaggle 房价预测回归任务House Prices 本篇指南以仓库中的 example/gluon深度学习人工智能机器学习分布式训练基于 Apache MXNet Gluon 的 Kaggle House Prices 房价预测实战从数据预处理到 K 折交叉验证的完整回归管线基于 Apache MXNet Gluon 的 Kaggle House Prices 房价预测实战从数据预处理到 K 折交叉验证的完整回归管线 导读 本文围人工智能深度学习机器学习上一篇Dialog输入对话框完全指南密码验证与文本限制的5种实现下一篇gsd-core 计划收敛Plan Convergence门控覆盖机制/gsd-autonomous --converge 深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考