
简介面向深度学习与机器学习初学者这是一份基于Keras的Python项目实战教程聚焦波士顿房价预测这一经典回归问题。资源文件打包为1个PDF文档大小约366KB内容集中便于配套学习。目前已有1348人学习浏览是入门回归建模的实用参考。教程从回归问题描述入手详细解析波士顿房价数据集中14个特征的含义演示数据标准化StandardScaler、搭建单隐藏层13个神经元ReLU激活的Keras神经网络并通过KerasRegressor配合K折交叉验证评估基线模型再借助GridSearchCV进行超参数搜索优化。读者可按步骤复现从构建基准模型到降低均方误差的完整过程理解回归问题的建模思路与调参方法为类似趋势预测任务提供可迁移的实践范式。1. 为什么拿波士顿房价练手一个 13 维特征的小数据集足以跑通 Keras 全流程如果你手里只有一两天时间想从零把“深度学习”这个词落地成一次能跑的 Python 项目波士顿房价预测绝对是最合适的第一站。这个项目用 Keras 搭一个回归网络输入 13 个房屋特征输出一个连续的房价数值。它不涉及图像、不涉及序列数据量只有 506 条几秒钟就能训练完。正因为小你能把数据预处理、模型搭建、编译训练、评估预测这一整条链路看清楚之后再上图像分类或文本任务无非是换数据和换网络结构。这份教程的受众很明确已经会写基础 Python、知道 numpy 和 pandas 是什么但还没真正写完一个深度学习项目的人。你不需要懂高等数学只需要照着步骤复制代码再看着注释理解每一行在干什么。跑通之后你会得到一个能预测房价的模型更重要的是你对 Keras 的 API 有了体感——什么样的数据能喂进去、训练时报错该看哪里、模型效果不行第一步查什么。下面我按照做这个项目最常见的落地路径把从环境到调参的完整过程拆开讲。2. 先把环境立起来Python、Keras 与 TensorFlow 后端的装法与版本陷阱动手写模型之前最劝退新手的一步其实是环境配置。波士顿房价预测本身用不到 GPU一台普通笔记本就能跑但 Python 版本、Keras 版本、TensorFlow 版本之间的组合不对代码还没开始写就先被报错淹没了。我一般建议用虚拟环境把项目隔离起来而不是直接装到系统 Python 里后面你就会知道这个习惯能省多少后悔药。2.1 用虚拟环境隔离项目依赖很多人图省事直接pip install keras结果系统里同时存在旧版 TensorFlow 和新版 Keras互相覆盖依赖最后 import 都报错。常见做法是先用python -m venv建一个干净环境之后再往里装东西。这样就算把环境搞坏了删掉重建也只需要两分钟。python -m venv boston_env source boston_env/bin/activate # Windows 下执行 boston_env\Scripts\activate pip install --upgrade pip setuptools wheel这三条命令做的事情是创建一个名为boston_env的虚拟环境激活它然后把 pip 本身升级到较新版本。之后所有安装都发生在这个环境里不会污染系统自带的 Python。注意source是 macOS 和 Linux 的写法Windows 用户要切换到Scripts\activate。这一步跑通后命令行提示符前面会出现(boston_env)说明环境已经激活。2.2 Keras 2.x 与 TensorFlow 2.x 的安装参数Keras 从 2.3 版本开始并入了 TensorFlow 2现在你只需要安装 TensorFlow 就能用from tensorflow import keras。但网上很多旧教程还在教pip install keras单独装然后keras.backend报错多半就是版本混搭造成的。我建议统一走 TensorFlow 的 Keras API不要单独安装 keras 包。pip install tensorflow2.15.0这里的版本号你可以根据自己的 Python 版本微调。TensorFlow 2.15 要求 Python 3.9 到 3.11如果你用的是 Python 3.12建议装 2.16 或更新的版本。装完以后验证一下python -c import tensorflow as tf; print(tf.__version__); print(tf.keras.__version__)这条命令会打印 TensorFlow 版本和附加的 Keras 版本。如果输出正常说明环境已经没有问题。常见的坑是只装了tensorflow-cpu或装成了tensorflow-gpu这两个接口在导入时没有区别但 GPU 版还需要 CUDA 和 cuDNN 环境波士顿房价这种小模型用 CPU 版反而更省心。2.3 验证 Keras 是否真的可用跑一个最小 MLP环境装完之后我习惯先跑一个十行代码的“冒烟测试”确认网络能前向传播、能反向传播而不是一上来就写完整项目。这个习惯能帮你区分是环境问题还是代码逻辑问题。from tensorflow import keras from tensorflow.keras import layers import numpy as np x np.random.rand(64, 13).astype(float32) y np.random.rand(64, 1).astype(float32) model keras.Sequential([ layers.Dense(16, activationrelu, input_shape(13,)), layers.Dense(1) ]) model.compile(optimizeradam, lossmse) model.fit(x, y, epochs1, batch_size16, verbose0) print(Keras 冒烟测试通过)这里的input_shape(13,)要和波士顿房价数据的特征数对齐后面正式训练时同样是 13。layers.Dense(16)表示第一层有 16 个神经元activationrelu是激活函数最后一层Dense(1)是输出层因为回归任务输出一个标量。编译时用mse作为损失函数adam是优化器。如果你的环境没问题运行后应该直接打印“通过”。如果报错说缺 DLL 或者 libstdc那基本是 TensorFlow 安装时缺了系统依赖回到上一步重新检查 Python 版本和 TensorFlow 版本匹配关系。3. 读懂波士顿房价数据13 个特征的含义与预处理边界环境就绪之后真正的工作是从数据开始的。波士顿房价数据集是 1978 年美国波士顿郊区房屋价格数据包含 506 条样本。每条样本有 13 个特征对应城镇犯罪率、房间数、房龄、到就业中心距离等指标。Keras 自带的keras.datasets.boston_housing可以直接加载但你要理解每个特征的范围差异有多大——最小的是几个小数值最大的是几百这种数量级差异如果不做处理神经网络很难正常训练。3.1 数据从哪里拿长什么样在 Keras 2.x 里数据加载一行就够了from tensorflow.keras.datasets import boston_housing (train_data, train_targets), (test_data, test_targets) boston_housing.load_data() print(训练集形状:, train_data.shape) print(测试集形状:, test_data.shape) print(特征示例:, train_data[0]) print(对应房价:, train_targets[0])train_data是 (404, 13) 的二维数组404 条训练样本每条 13 个特征test_data是 (102, 13)。train_targets是 (404,) 的一维数组每个值是该样本的房价中位数单位是千美元比如 24 表示 24000 美元。打印出来的特征示例会是一串数字从犯罪率到房龄都有数量级差异很大比如有的特征在 0 到 1 之间有的在 300 以上。这直接决定了你必须做归一化。3.2 归一化为什么是必须项而不是可选项神经网络对输入尺度非常敏感。如果某些特征在 0 到 1 之间另一些在 100 到 500 之间梯度更新会被大数值特征主导小数值特征几乎学不到东西。更糟的是激活函数在输入绝对值很大时容易进入饱和区梯度变成 0训练就停滞了。所以归一化不是“锦上添花”是“不做就训练不出来”。常见做法是用训练集的均值和标准差归一化然后把同样的统计量应用到测试集。注意不能把测试集混进来计算均值和标准差否则会造成数据泄露让评估结果虚高。代码如下mean train_data.mean(axis0) std train_data.std(axis0) train_data_norm (train_data - mean) / std test_data_norm (test_data - mean) / std print(归一化后训练集均值趋近 0:, train_data_norm.mean(axis0))关键点都在axis0也就是按特征列而不是按样本行做统计。每个特征都有自己的均值与标准差归一化后每个特征都变成均值为 0、标准差为 1 的分布。这样模型在梯度下降时对所有特征一视同仁。实际项目中如果你换了一批新预测数据也要用这个历史均值和标准差去归一化而不是重新算否则模型输入分布会变。3.3 训练集/测试集划分的两种做法与选择Keras 自带的数据集已经帮我们分好了 404 条训练、102 条测试但实操中经常要自己划分。常见的做法有两种一是用 scikit-learn 的train_test_split二是直接用keras.utils的切分接口。如果你用的是自带数据直接用训练集测试集的变量即可如果你自己收集了数据我建议用第一种from sklearn.model_selection import train_test_split X_train, X_temp, y_train, y_temp train_test_split( train_data, train_targets, test_size0.2, random_state42 ) X_val, X_test, y_val, y_test train_test_split( X_temp, y_temp, test_size0.5, random_state42 )这里先切出 20% 作为临时集再把临时集对半分分别得到验证集和测试集。random_state42固定随机种子保证每次运行切分结果一样否则你换一次运行模型评测的基准就变了。波士顿数据量小切分时会损失训练样本所以 Keras 自带的 404/102 划分已经够用自己在做大型项目时再考虑更多重交叉验证。4. 用 Keras 搭一个回归网络从 Sequential 到模型训练数据准备好之后就到了核心环节用 Keras 搭建和训练模型。回归任务和分类任务最大的区别在于输出层没有激活函数神经元数量是 1损失函数用均方误差。很多人套用分类模型的写法最后一层加上 softmax直接报错或损失永远不下降。这一章我把网络结构、编译参数、训练循环每个环节的参数都讲清楚。4.1 网络结构设计隐藏层数与神经元数的取舍对于 13 个特征、506 条样本的数据量网络不能太深。常见做法是两层隐藏层第一层 64 个神经元第二层 64 个神经元或者更保守的 16-16。神经元越多模型容量越大但也越容易过拟合。我的经验是从小到大试先试一层 16 个神经元看验证 loss 是否下降再逐步加深加宽。from tensorflow import keras from tensorflow.keras import layers model keras.Sequential([ layers.Dense(64, activationrelu, input_shape(13,)), layers.Dense(64, activationrelu), layers.Dense(1) # 回归输出不带激活函数 ])input_shape(13,)告诉模型输入是 13 维向量。layers.Dense(64, activationrelu)表示这一层有 64 个神经元输出经过 ReLU 激活变成非线性。中间的隐藏层越多模型能学到的组合特征越复杂但在小数据集上很容易把训练集的噪声也背下来。最后一层Dense(1)不带激活函数因为房价预测是回归输出可以是任意实数如果加了 sigmoid 或 relu 反而限制了输出的范围。4.2 编译参数loss、optimizer 与 metrics 怎么设编译是模型训练前的配置步骤这里要决定优化器、损失函数和衡量指标。对回归问题来说mse均方误差是最常用的损失函数优化器选adam基本不用调参就能收敛。衡量指标我习惯加一个mae平均绝对误差因为 MAE 的单位和房价一致比如mae3说明平均预测偏差 3000 美元比 MSE 更直观。model.compile( optimizeradam, lossmse, metrics[mae] )optimizer参数可以只传字符串名字Keras 会自动用默认学习率。如果你想微调学习率可以换成keras.optimizers.Adam(learning_rate0.001)。注意学习率 0.001 是 Adam 的默认值小数据集上通常不需要改。metrics列表可以传多个指标这里我们只需要 MAE。如果你用accuracy运行时会报错或一直为 0因为回归任务的输出是连续值用准确率没有意义。4.3 训练循环与验证曲线epochs 和 batch_size 怎么调训练过程用fit方法传入训练数据、验证数据、迭代轮数和批次大小。这里最容易犯的错是 epochs 设太大导致过拟合或者设太小还没收敛。我建议先设 100同时看训练集和验证集的 loss 曲线再调整。history model.fit( train_data_norm, train_targets, validation_data(test_data_norm, test_targets), epochs100, batch_size16, verbose1 )epochs100表示把整个数据集从头到尾训练 100 遍。batch_size16表示每次从训练集取 16 个样本计算一次梯度。batch_size 越小梯度更新越频繁训练波动越大越大训练越平滑但需要更多显存。波士顿数据集只有 404 条batch_size16在每轮会产生 25 次更新几秒钟就跑完。validation_data传入的是归一化后的测试集和未归一化的房价标签注意验证集的特征必须用训练集的统计量归一化。跑完 100 轮之后你可以用history.history画出训练 loss 和验证 loss 的曲线。如果训练 loss 持续下降但验证 loss 在某个 epoch 后开始上升那就是过拟合了需要在后面加早停或正则化。import matplotlib.pyplot as plt plt.plot(history.history[loss], labeltrain_loss) plt.plot(history.history[val_loss], labelval_loss) plt.legend() plt.xlabel(epochs) plt.ylabel(loss) plt.show()这张图上如果两条曲线越分越开说明模型开始背诵训练集了。波士顿数据量小过拟合是常态不要追求训练 loss 降到 0只要验证 loss 足够低并且不再明显下降就能接受。5. 避坑/常见问题波士顿房价预测里的 5 个实战踩坑记录这个项目看起来简单真正自己写过一遍的人基本都踩过下面这些坑。每个坑我都按“现象 → 原因 → 解决”的顺序来写下次你遇到可以直接对照排查。5.1 现象训练 loss 正常下降测试 MAE 却高得离谱原因很可能是在加载数据后没有做归一化就直接训练。数值大的特征主导了梯度模型学到了“只看犯罪率加权平均”这种假规律测试集上一旦数值分布稍变预测就完全跑偏。解决方法是按第 3.2 节的方式用训练集的均值和标准差归一化注意测试集也用同一组统计量。另一个原因是数据集划分不均匀有可能测试集里恰好有几条极端房价样本MAE 被拉高。这种时候用交叉验证看整体表现不要纠结单次划分。5.2 现象Keras 报错 ValueError: Shape mismatch报错信息里会提示Input shape和Dense层期望的形状不一致。最常见的来源是input_shape(13,)写成了(13,1)。前者表示 13 个特征的一维向量后者表示 13 行 1 列的二维矩阵。如果你的训练数据是 (404, 13)那必须用(13,)。另一个原因是自己导入 CSV 时把特征列数读错了比如数据里混入了序号列。解决方法是训练前打印train_data.shape确认第二维是 13如果不是检查原始数据文件是否包含多余列。5.3 现象归一化后预测值变成负数评估指标失效归一化本身不会让房价变负但如果你加载了原始数据直接预测而训练时用了归一化后的数据输入分布不对模型输出的数值范围自然就错了。更隐蔽的情况是你把标签也归一化了导致预测值在 0 附近再反归一化时公式写错。建议只对特征做归一化标签保持原样。如果你确实对标签做了归一化记得预测后乘标准差加均值。写在代码里就是predicted model.predict(test_data_norm) predicted_in_original predicted * target_std target_mean这里的target_std和target_mean是训练标签的统计量来自train_targets.std()和train_targets.mean()。不要把它们跟特征归一化混在一起。5.4 现象无法下载数据集代码卡在加载数据boston_housing.load_data()在首次运行时会从网上下载数据到本地缓存目录。如果网络受限或者下载地址被墙代码会一直卡在连接或者超时。解决方法是手动下载数据文件放到~/.keras/datasets/目录Windows 下是C:\Users\你的用户名\.keras\datasets\。从其他镜像下载后重命名为boston_housing.npz放进去就能加载。另外注意 Keras 2.15 之后的版本可能已经不能直接下载建议装旧版本或从本地路径读取。这属于环境边界问题不是你的代码问题。5.5 现象模型训练重复运行结果不一致即使同样的数据、同样的网络结构fit多次运行结果也会有浮动。原因有两个一是初始化权重是随机的二是fit内部的数据打乱顺序随机。这个浮动在波士顿这类小数据集上尤其明显有时 MAE 差 0.5 就会影响你的调参判断。解决方法是在代码开头固定随机种子import random import numpy as np from tensorflow import keras random.seed(42) np.random.seed(42) keras.utils.set_random_seed(42)keras.utils.set_random_seed(42)会同时固定 TensorFlow 和 Keras 的随机状态。注意即使固定了种子某些 GPU 操作仍然有非确定性但 CPU 上基本可以复现。做实验时固定随机种子才能对比不同网络结构之间的优劣否则你以为自己调参有效其实是随机噪声。6. 让预测结果可解释回归指标解读与模型改进技巧模型训练完不是终点你要能说清楚“预测得怎么样”以及“还能怎么让它更好”。这一章我讲三个最实用的步骤解读回归指标、保存模型供以后使用、以及用小技巧让模型更稳。6.1 用 MAE、RMSE 与 R2 理解模型到底准不准回归任务最常用的三个指标MAE 平均绝对误差、RMSE 均方根误差、R2 决定系数。MAE 的意义是平均每个预测量偏差多少千美元比如 2.8 表示平均偏差 2800 美元。RMSE 和 MAE 的差距能反映预测误差的分布如果 RMSE 比 MAE 大很多说明存在少数极端误差很大的样本。R2 越接近 1 越好0 表示模型和直接用平均值预测的效果一样。你可以用 scikit-learn 快速计算from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score pred model.predict(test_data_norm).flatten() mae mean_absolute_error(test_targets, pred) rmse mean_squared_error(test_targets, pred, squaredFalse) r2 r2_score(test_targets, pred) print(fMAE: {mae:.2f}, RMSE: {rmse:.2f}, R2: {r2:.2f})model.predict返回的形状是 (102, 1)所以用.flatten()压成一维再和测试标签做比较。r2_score在测试集上是 0.7 左右就能算一个合格的回归模型波士顿历届常见结果在 0.6 到 0.8 之间如果低于 0.4 说明预处理或网络结构有问题。6.2 保存与加载模型h5 格式与后续部署训练好之后把模型保存成文件下次直接加载不用重新训练。Keras 的model.save会保存网络结构和权重加载后用predict就能做推理。model.save(boston_model.h5) loaded_model keras.models.load_model(boston_model.h5) new_pred loaded_model.predict(test_data_norm[:5])model.save支持 h5 格式文件里包含结构、权重、优化器状态和编译配置。加载时注意必须和保存时的 Keras 版本兼容跨大版本加载有时会报错。如果你只想部署不想要优化器状态可以用model.save_weights(boston_weights.h5)只存权重加载时需要先重新构建模型结构再load_weights。实际项目中我一般保存完整模型省得每次重建结构。6.3 一个实用技巧用早停与正则化拿到更稳的模型最后一个改进技巧是早停。训练时如果验证 loss 不再下降继续训练只会过拟合。用 Keras 的EarlyStopping回调可以在验证 loss 连续 N 轮没有改善时自动停止训练同时保存最佳权重from tensorflow.keras.callbacks import EarlyStopping callbacks [ EarlyStopping( monitorval_loss, patience10, restore_best_weightsTrue, verbose1 ) ] model.fit( train_data_norm, train_targets, validation_data(test_data_norm, test_targets), epochs200, batch_size16, callbackscallbacks, verbose0 )monitorval_loss表示监控验证集的 losspatience10表示连续 10 轮没有下降就停restore_best_weightsTrue让模型恢复到验证 loss 最低时的权重。这是我最常用的一个参数组合小数据集上非常管用。加早停后你不再需要手动调 epochs 精确到 100 还是 150只要设一个大上限模型自己会找到合适的停止点。我自己的习惯是每次跑完这个项目都会把归一化用的均值和标准差存成一个 JSON 文件再把模型存成 h5这样以后对任意新房源预测时先用 JSON 里的参数归一化再喂给模型。可能有人觉得波士顿房价预测太简单但正是这份简单让我养成了“数据统计量不落地不训练”的习惯。如果你跑完这个项目希望也能收获这种对数据尺度敏感的感觉而不是只得到一个漂亮的 loss 数字。希望帮到你。本文还有配套的精品资源点击获取