求助:使用Keras在2D数据上演示过拟合无法复现问题
嘿,作为经常帮同行搞定教学演示的人,我太懂你这种想完美复现Ng那套过拟合演示的心情了——毕竟直观的可视化比讲十遍理论都管用。你没复现成功大概率是在数据集、模型梯度或者训练设置上没踩准点,给你梳理几个关键步骤,亲测有效:
1. 先把演示用的2D数据集调对
Andrew Ng课程里的演示之所以效果明显,核心是用了少量带噪声的非线性分布数据——比如月牙形、环形散点。如果你的数据集太规整、样本量太大,就算模型再复杂也难出明显过拟合:
- 用
sklearn生成标准演示数据就行,记得加噪声、控样本量:from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split # 生成300个带噪声的月牙形数据 X, y = make_moons(n_samples=300, noise=0.2, random_state=42) # 按7:3拆分训练/验证集(必须拆,过拟合的核心是训练/验证表现差异) X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3, random_state=42)
2. 设计“复杂度梯度明确”的模型链
要给学生展示从欠拟合→拟合合适→过拟合的完整过程,模型的复杂度差异必须拉够:
- 欠拟合模型:用最简单的单层逻辑回归,连激活函数都不用太复杂:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense def build_simple_model(): model = Sequential([ Dense(1, activation='sigmoid', input_shape=(2,)) ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model - 拟合合适模型:2-3层全连接,每层10-20个神经元,刚好能捕捉数据规律但不会记噪声:
def build_medium_model(): model = Sequential([ Dense(16, activation='relu', input_shape=(2,)), Dense(8, activation='relu'), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model - 过拟合模型:堆5层以上全连接,每层50+神经元,完全不加正则化(故意让它“死记硬背”训练集):
def build_overfit_model(): model = Sequential([ Dense(100, activation='relu', input_shape=(2,)), Dense(100, activation='relu'), Dense(100, activation='relu'), Dense(100, activation='relu'), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model
3. 训练时的关键细节
- 训练轮数要够多:别只训10轮,至少训150-200轮,才能看到验证集准确率从上升到下降的完整曲线
- 一定要记录训练历史:用
history = model.fit(...)保存训练/验证的准确率、损失,然后画图对比——这是给学生看的核心可视化:import matplotlib.pyplot as plt def plot_overfit_comparison(hist_simple, hist_medium, hist_overfit): plt.figure(figsize=(15,5)) # 子图1:简单模型 plt.subplot(1,3,1) plt.plot(hist_simple.history['accuracy'], label='Train') plt.plot(hist_simple.history['val_accuracy'], label='Val') plt.title('Underfitting Model') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() # 子图2:中等模型 plt.subplot(1,3,2) plt.plot(hist_medium.history['accuracy'], label='Train') plt.plot(hist_medium.history['val_accuracy'], label='Val') plt.title('Well-Fitted Model') plt.xlabel('Epochs') plt.legend() # 子图3:过拟合模型 plt.subplot(1,3,3) plt.plot(hist_overfit.history['accuracy'], label='Train') plt.plot(hist_overfit.history['val_accuracy'], label='Val') plt.title('Overfitting Model') plt.xlabel('Epochs') plt.legend() plt.show() - 暂时关掉所有正则化(Dropout、L2约束):这些是用来抑制过拟合的,演示阶段先不加,才能让过拟合效果更明显
4. 避坑提醒
- 别用数据增强:如果给2D数据加了随机翻转、平移,模型泛化能力会变强,反而看不到过拟合
- 优化器用默认
adam就行:别随便调学习率,太高会导致模型震荡,看不到清晰的过拟合曲线 - 确保训练/验证集分布一致:用
train_test_split拆分时别打乱分布,否则验证集的表现会失真
把三个模型的训练曲线放在一起展示,学生一眼就能看懂:简单模型训练/验证准确率都低(欠拟合),中等模型两者都高且接近(拟合合适),复杂模型训练准确率直奔100%但验证准确率先升后降(过拟合)——完全贴合Ng课程里的演示效果。
内容的提问来源于stack exchange,提问作者Baptiste
相关产品推荐
相关产品推荐

