每年毕业季都能看到一类非常典型的机器学习选题——各种“预测模型的设计与实现”。说实话,这类题目框架固定、套路成熟,但也最容易踩坑:要么死磕算法原理导致进度失控,要么代码全抄导致答辩一问三不知,要么忽略工程细节导致模型精度看似很高、实际换个时间段一测就崩。今天以“家庭用电预测模型的设计”为例,完整复盘一个基于sklearn+DNN、用Flask做Web展示的毕设项目应该怎么搭、怎么避坑、怎么在答辩时讲清楚。这个项目涵盖了时序数据处理、机器学习建模、深度学习网络设计和Web部署全链路,适合正在做大数据或深度学习方向毕设的同学参考。
我会尽量把每个环节做决策的理由讲透,而不是只贴代码。毕竟毕设答辩时老师最常问的就是“为什么选这个模型”“为什么做这个参数”“这个特征是怎么来的”。
1. 为什么选家庭用电预测这个方向
家庭用电预测在毕设选题里属于典型的“稳妥且有发挥空间”的方向。它的数据来源清晰、业务场景易懂、模型可复杂度可调节。往浅了做,可以用线性回归;往深了做,可以用LSTM或者Transformer。无论自身基础如何,都能做出一个完整且合理的项目。
1.1 电力负荷预测的本质是时间序列问题
家庭用电记录本质上是一串按时间排序的数值序列,预测的核心任务是“利用过去一段时间的历史负荷值,推算未来某个时刻或某个时间段的负荷值”。
你可能觉得这不就是一个回归问题吗?用sklearn里的随机森林、XGBoost一跑不就行了?确实可以。但严格来说它比普通回归多了一层约束——时间上的依赖关系。今天上午10点的用电量通常接近昨天上午10点的用电量,而不是接近今天凌晨3点的用电量。这意味着如果只是把所有样本随机打乱再训练,等于主动丢掉了最重要的时间顺序信息。这也是很多同学在做毕设时容易犯的错误。
1.2 题目技术栈组合的合理性
这个题目的关键词是sklearn、DNN和Flask,这个组合在毕设里很讨巧:
- sklearn负责做传统的机器学习基线模型,比如决策树、随机森林、梯度提升树、线性回归,保证项目“有对比”;
- DNN(深度神经网络)负责做深度学习模型,体现“大数据深度学习算法”这个方向;
- Flask负责把训练好的模型封装成Web服务,做一个小型的前端展示页面,体现“完整系统交付”能力。
从这个角度说,技术栈不是随便选的。sklearn刻画的是传统机器学习能力,DNN刻画的是深度学习能力,Flask刻画的是工程化能力。答辩时老师问“你觉得这个项目最大的亮点是什么”,你可以直接说:模型不是孤立存在的,它从数据处理到训练评估再到界面展示,形成了一条完整链路。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据准备:家庭用电数据从哪里来
做预测模型项目,数据是第一关。很多同学卡在这一步是因为根本找不到合适的公开数据集。这里推荐两类比较常用的数据来源。
2.1 常用数据集与字段结构
第一个是个人家庭用电数据集。比如UCI机器学习库中的“Individual Household Electric Power Consumption”数据集,包含2006年到2010年间某家庭每分钟的电力消耗记录,字段包括有功功率、无功功率、电压、电流以及厨房、洗衣房、空调等不同区域的子计量值,大约207万个记录。
第二个是建筑能耗数据集。这类数据在一些论文复现项目里很常见,通常按1分钟或1小时粒度记录整栋建筑的总用电量,附带温湿度、节假日等外部变量。
我个人建议新手选择字段相对简洁的数据集,重点关注两列:时间戳和用电量。先跑通全流程,再考虑要不要加入温度、湿度、节假日等外部特征来提升精度。
2.2 数据清洗与漏斗式异常过滤
拿到原始数据后最忌直接扔给模型。这类电器计量数据常见的问题有三类:
- 缺失值:时间戳有空缺,对应用电量为空。处理方式是按前向填充或者用前后均值补齐;
- 异常值:某时刻用电量突然飙到几千瓦,往往是电表抖动或瞬时大功率设备启动。这里需要设定合理的物理上下限;
- 重复值:同一时间戳出现多条记录,需要按时间戳去重。
建议做一个异常值统计表,清洗掉多少条、为何清洗,写清楚,这个在论文里也是加分项。比如下表是某个实际项目里的清洗记录:
| 清洗步骤 | 处理逻辑 | 预期记录变化 |
|---|---|---|
| 缺失时间戳检查 | 时间列升序后查重、查空隙 | 通常缺失率低于0.5% |
| 用电量小于0 | 负值删除或置0 | 极少数异常 |
| 用电量大于阈值 | 超过15kW的记录剔除 | 0.1%以内 |
| 节假日标记 | 新增是否为周末/节假日的布尔特征 | 不删数据 |
2.3 重采样:从分钟到小时的维度选择
原始的分钟级采样数据不一定直接适合建模。如果你的输入维度是“前24小时预测未来24小时”,那用小时级数据就够了,没必要用分钟级——分钟级会让序列长度变成1440,特征维度爆炸且训练极慢。
重采样一般用resample或pandas.DataFrame.groupby配合聚合函数实现:
python复制import pandas as pd
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp', inplace=True)
# 从分钟级聚合到小时级,取平均功率
hourly = df['power'].resample('1h').mean().reset_index()
重采样有几个细节值得注意:如果是预测用电量(千瓦时),应该用sum()。如果数据里包含“这一小时内多项记录的平均功率”,用mean()更合理。这个细节别看它小,选择错误会导致最终误差偏大。答辩的时候老师专门问过我这个细节,我是实际对比过才知道的。
2.4 构造监督学习样本:滑动窗口与滞后特征
处理完时序数据之后,不能直接喂给机器学习模型。模型并不知道“上一时刻”是什么意思,需要把序列数据转换成“特征X -> 标签y”的监督学习格式。这个转换通常采用滑动窗口。
假设用过去24小时的负荷值预测未来1小时的负荷值,那么每个样本的X是一个长度为24的向量,y是下个小时的用电量。实现方式可以用循环实现,也可以用自定义窗口函数:
python复制import numpy as np
def create_sequences(data, window_size=24, horizon=1):
X, y = [], []
for i in range(len(data) - window_size - horizon + 1):
X.append(data[i:i + window_size])
y.append(data[i + window_size + horizon - 1])
return np.array(X), np.array(y)
除了原始窗口值外,实际项目中还可以加上一些构造特征:比如当前时刻是星期几、是不是周末、一天中的第几个小时、历史滑动均值、历史滑动标准差。这些特征能大幅度提升sklearn系模型的效果。需要特别注意的是,用未来的数据构造特征是绝对禁止的,比如你要预测下午3点的用电量,就不能把下午3点的真实值拆进特征的均值里,这属于典型的数据泄漏。
3. 模型构建:从sklearn基线到DNN深度网络
模型部分是这个项目的核心。我推荐按“由浅入深、层层对比”的思路来做,先跑通sklearn的简单模型,再引入DNN深度学习模型。
3.1 设计合理的训练集、验证集和测试集
很多同学拿到数据就调用train_test_split随机切分,这个动作在时序预测中是一个严重的错误。
时序数据的序列关系决定了训练集和测试集必须按照时间顺序切分。如果用随机切分,模型“见过”后面的未来数据,测试集上的误差会严重失真。
正确做法是按照时间先后顺序切分,比如用前70%做训练集,再往后15%做验证集,最后15%做测试集:
python复制train_ratio = 0.7
valid_ratio = 0.15
test_ratio = 0.15
train_end = int(len(X) * train_ratio)
valid_end = int(len(X) * (train_ratio + valid_ratio))
X_train, y_train = X[:train_end], y[:train_end]
X_valid, y_valid = X[train_end:valid_end], y[train_end:valid_end]
X_test, y_test = X[valid_end:], y[valid_end:]
3.2 sklearn基线模型:随机森林与梯度提升树
在分类问题上随机森林很常用,在回归问题上同样可用。这里选择随机森林有两个理由:第一是它几乎不需要特征缩放,第二是它对非线性关系拟合能力强,本身具备特征重要性输出功能,方便答辩时展示特征分析。
python复制from sklearn.ensemble import RandomForestRegressor
rf_model = RandomForestRegressor(
n_estimators=200,
max_depth=10,
min_samples_leaf=2,
random_state=42,
n_jobs=-1
)
rf_model.fit(X_train, y_train)
用随机森林做这类负荷预测时有一个明显特征:预测值会偏向训练集均值,序列的“峰”往往预测不到位。这是因为回归树在叶子节点取均值,而样本分布集中在中低负荷区间,高峰值的样本量少,树难以精准覆盖。
梯度提升树,比如XGBoost的效果通常会强一些,但对超参数更敏感。实际项目中可以作为第二个对比模型出现。
3.3 DNN网络结构设计
DNN在这个项目里并不用做得太复杂。很多人一提到深度学习就上LSTM,但手指先别急着写。LSTM适合长序列依赖,而家庭用电预测如果只用24小时窗口,多层感知机往往就能取得不错的效果——还能更直观地展示正向传播、反向传播、过拟合这些基础知识。
我的设计思路是:
- 输入层:24个特征,即过去24小时的逐小时用电量;
- 第一个全连接层:128个神经元,激活函数用ReLU;
- 第二个全连接层:64个神经元,激活函数用ReLU;
- Dropout层:以0.2的比例随机丢弃,抑制过拟合;
- 第三个全连接层:32个神经元,激活函数ReLU;
- 输出层:1个神经元,激活函数用线性激活。
python复制from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.optimizers import Adam
def build_dnn(input_dim):
model = Sequential([
Dense(128, activation='relu', input_shape=(input_dim,)),
Dropout(0.2),
Dense(64, activation='relu'),
Dropout(0.2),
Dense(32, activation='relu'),
Dense(1, activation='linear')
])
model.compile(optimizer=Adam(learning_rate=0.001),
loss='mse',
metrics=['mae'])
return model
dnn_model = build_dnn(X_train.shape[1])
选择ReLU而不是tanh或sigmoid,核心原因是负荷数据经过归一化后虽然值域在0到1之间,但特征之间的线性关系比较强,ReLU收敛更快、梯度消失问题更轻。Dropout层直接放在全连接层之后,目的是让部分神经元随机失活,强制网络学习更鲁棒的特征表达。
3.4 数据归一化与逆变换:最容易出错的环节
DNN和某些激活函数对输入数据的尺度非常敏感。一般做法是用MinMaxScaler把训练集的负荷值压缩到0到1之间。
这里有一个极其关键、极其容易出错的坑:归一化参数只能用训练集计算,然后用同一套参数去transform验证集和测试集。什么意思?就是先fit训练集,得到最小值min和缩放范围max-min,然后分别对训练集、验证集、测试集执行transform。绝不能对完整数据集先归一化再切分,这是严重的数据泄漏,会导致验证集的结果虚高。
python复制from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(X_train.reshape(-1, 1))
X_train_scaled = scaler.transform(X_train.reshape(-1, 1)).reshape(X_train.shape)
X_valid_scaled = scaler.transform(X_valid.reshape(-1, 1)).reshape(X_valid.shape)
X_test_scaled = scaler.transform(X_test.reshape(-1, 1)).reshape(X_test.shape)
预测结束后需要把结果还原成真实的电力度数,这时scaler.inverse_transform(y_pred)是必须调用的逆变换。很多同学在部署阶段发现预测结果全是0到1之间的小数,就是因为漏了逆变换这一步。
4. 模型评估与调优:精准定义误差指标
模型训练完不是看一眼loss就算完的。在预测类毕设项目里,老师通常会用几个指标来衡量你对问题本身的理解深度。
4.1 指标选择的逻辑
回归问题里最常用的三个指标是MAE(平均绝对误差)、RMSE(均方根误差)和MAPE(平均绝对百分比误差)。它们各有分工:
- MAE:描述平均而言预测差多少千瓦,量纲直观,适合面向用户的展示;
- RMSE:放大较大误差的惩罚力度,适合探测是否存在个别极端预测失误;
- MAPE:描述误差相对于真实值的百分比,跨家庭对比时有意义。
实际测试下来,家庭用电数据里MAPE往往偏大。原因很简单:凌晨时段用电量极低,如果真实值是0.2千瓦,预测值是0.6千瓦,误差百分比就达到了200%,但绝对误差其实很小。所以我在最终展示时以MAE和RMSE为主,MAPE只作为参考。
模型对比结果:
| 模型 | MAE (kW) | RMSE (kW) | 训练时间 |
|---|---|---|---|
| 线性回归 | 0.41 | 0.78 | < 1s |
| 随机森林 | 0.25 | 0.53 | 5s |
| XGBoost | 0.21 | 0.45 | 12s |
| 自定义DNN | 0.19 | 0.41 | 120s |
从这个结果可以看出DNN的优势并不像想象中的“碾压级别”,但在误差指标上确实最优。实际项目里更合理的评价指标是:不仅看整体误差,还看高峰时段预测误差。因为电力负荷预测最有价值的部分就是峰值的提前预警。建议在项目里增加一段“峰时误差分析”,按一天中不同时段切分误差,这样报告内容会更饱满。
4.2 早停与模型保存
深度模型训练过程中,监控验证集的loss变化,发现若干轮没有下降时主动停止训练,省时间且防过拟合:
python复制from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True
)
history = dnn_model.fit(
X_train_scaled, y_train,
validation_data=(X_valid_scaled, y_valid),
epochs=100,
batch_size=64,
callbacks=[early_stop],
verbose=1
)
dnn_model.save('household_power_dnn.h5')
为什么不直接用model.fit默认设置?因为如果不设耐心值,100个epoch可能早就在第15轮就过拟合了,验证loss一路上扬,最后的模型反而很差。restore_best_weights=True会帮你自动回滚到验证集上表现最优的权重。
4.3 预测结果的时序可视化
评估阶段的最后一步,是取出测试集中连续一段时间的实际曲线与预测曲线叠加展示。这个图在毕设答辩中非常有力,比任何表格都有说服力。
用matplotlib做即可,但建议按周分块展示,因为家庭用电有非常明显的星期周期:
python复制import matplotlib.pyplot as plt
plt.figure(figsize=(14, 5))
plt.plot(actual_values[:168], label='Actual', linewidth=1.5)
plt.plot(predicted_values[:168], label='Predicted', linewidth=1.5, linestyle='--')
plt.xlabel('Hour')
plt.ylabel('Power (kW)')
plt.title('7-Day Household Power Consumption Prediction')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
第一次看到这张图会有直观的感觉:中间段拟合不错,但每天夜晚的波谷可能有些滞后,白天的峰值则被削平。这正是模型偏差的可视化,后续调优方向就是提升这些区域的拟合度。
5. Flask部署:把模型封装成可视化应用
到了这个阶段,你手上已经有一个训练好的模型和一个不错的验证结果。但毕设要求的是“系统”,不是“脚本”。Flask在这里的作用就是把模型包一层HTTP接口,同时渲染一个简洁的前端页面,做到Web端输入日期和历史数据、输出预测结果。
5.1 Flask应用的基础结构与模型加载
Flask的轻量是选它的最大理由。不需要额外搭建复杂的后端框架,一个Python文件加两个模板文件就能跑通全流程。项目结构可以是这样的:
text复制power_forecasting/
├── app.py
├── models/
│ └── household_power_dnn.h5
├── templates/
│ └── index.html
├── static/
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── main.js
└── data/
└── process_data.py
app.py的核心逻辑是加载模型、定义预测接口、渲染页面:
python复制from flask import Flask, request, jsonify, render_template
from tensorflow.keras.models import load_model
import numpy as np
from sklearn.preprocessing import MinMaxScaler
app = Flask(__name__)
model = load_model('models/household_power_dnn.h5')
@app.route('/')
def index():
return render_template('index.html')
@app.route('/predict', methods=['POST'])
def predict():
data = request.get_json()
input_seq = np.array(data['sequence']).reshape(1, -1)
# 注意:这里必须使用训练时保存的scaler参数做归一化
scaler = MinMaxScaler()
scaler.fit(input_seq) # 实际项目应加载训练时保存的scaler对象
input_scaled = scaler.transform(input_seq)
pred_scaled = model.predict(input_scaled)
pred = scaler.inverse_transform(pred_scaled)
return jsonify({'prediction': float(pred[0][0])})
if __name__ == '__main__':
app.run(debug=True, port=5000)
上面代码里“实际项目应加载训练时保存的scaler对象”这句很重要。不能在前端请求进来时重新fit一个scaler,因为新拟合的scaler参数和训练时的scaler参数不一定相同,预测结果会偏移。正确做法是在训练脚本里把scaler保存成文件(比如用joblib.dump),然后在Flask里加载。
python复制import joblib
scaler = joblib.load('models/scaler.pkl')
同理,输入端的特征构造过程也要保持与训练时完全一致。窗口长度是多少、特征顺序是什么,接口里就必须原样执行。
5.2 前后端联调的交互设计
部署不仅仅是一个接口。为了让系统显得完整,需要设计一个可操作的前端页面。
设计思路是:前端提供一个输入区域,让用户填入“过去24小时每小时的用电量”,点击预测按钮后,把24个数值以JSON格式POST到/predict,拿到预测值后显示在页面上。为了视觉效果更好,可以用Chart.js或ECharts把历史曲线和预测点画出来。
下面是前端接口调用的一段简化示例:
javascript复制async function handlePredict() {
const sequence = collectHourlyInput();
const response = await fetch('/predict', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({sequence: sequence})
});
const result = await response.json();
document.getElementById('result').innerText = `预测功率: ${result.prediction.toFixed(2)} kW`;
}
这个交互设计注意不要做得太重,比如不要在首页放一个复杂的图表组件库导致加载卡顿。毕设答辩现场网络环境不稳定,如果依赖CDN加载前端库会非常被动。建议把需要用到的JS库下载到本地static目录下,保证断网也能演示。
5.3 模型更新与再训练
答辩时经常被问到:“如果数据更新了,模型能持续学习吗?”
作为毕设项目,不必实现完整的在线学习,但可以做一个“重训练入口”。在Flask里增加一个接口,当用户上传新的历史数据CSV时,重新触发训练流程,训练结束更新模型文件。这个设计并不复杂,但能体现你对模型生命周期的理解:
python复制@app.route('/retrain', methods=['POST'])
def retrain():
upload_file = request.files['data']
if upload_file:
upload_file.save('data/new_data.csv')
# 调训练脚本,更新h5文件
from train import run_training
metrics = run_training()
return jsonify({'status': 'ok', 'metrics': metrics})
注意,如果训练耗时较长,前端会一直等待响应。一个可行的替代方案是异步任务或在线训练提示,但毕设没必要上Celery这么重的框架。只要说明“实际生产中需要任务队列,演示环境下的同步重训是可接受的”,基本就能应对追问。
6. 毕设项目中常见的坑与避坑建议
作为一个过来人,把我在这个项目里踩过的坑做一次集中复盘。这些坑单独看都不算致命,但叠加起来会浪费大量时间,而且有些错误在答辩时才被发现,会很狼狈。
6.1 数据泄漏的隐蔽形式
前面反复强调过数据泄漏,这个点再单独拉出来说是因为它实在太容易被忽视。
你可能会想,不就是不能把测试集混进训练集吗?我记住了。但实际上泄漏还有更隐蔽的形式:比如你在切分数据集之前给全量数据做了窗口均值平滑,平滑过程用到了未来信息,这也算泄漏;比如你在预测前用了标准化的scaler对整个原始数据fit了一次,再切分训练集和测试集,这也是泄漏;再比如你在特征工程里加入了“当日平均气温”,而这一整天的用电都被预测列入预测范围,气温均值本身就含有未来信息。
这个知识点值得在论文里专门留一节来写,能体现你不仅会训练模型,还理解数据科学的严谨性。
6.2 随机种子的设置
sklearn模型和Keras模型都有随机性。如果你不设置随机种子,每次跑出来的结果都不一样。毕设要求可复现性,否则论文里写“本模型MAE为0.19”就成了薛定谔的0.19——也许你提交代码的老师在本地跑出0.23,不一致就会造成麻烦。
python复制import numpy as np
import tensorflow as tf
import random as python_random
np.random.seed(42)
python_random.seed(42)
tf.random.set_seed(42)
设置的位置也需要注意,要在模型构建和数据切分之前完成,因为数据切分时的随机选择同样受随机种子影响。
6.3 小时粒度与分钟粒度的取舍
有些同学觉得分钟级数据更“精确”,于是把输入序列也做成分钟级。实际上窗口长度不变的前提下,分钟级数据会急剧增大输入维度。如果此前输入窗口是24小时,用小时级则输入是24个特征,用15分钟粒度则输入变成96个特征,训练时间成倍增加,模型预测效果并不见得更好。因为家庭负荷的主要波动周期是小时级别的,短时间尺度的噪声反而会干扰模型。
没有特殊需求时,建议统一聚合到小时级。如果想让项目显得有探索性,可以做一个“15分钟粒度 vs 小时粒度”的对比实验放进论文,用实验数据说明选择小时级的理由。
6.4 预测未来多个时间点时的策略
如果项目要求预测未来24小时,而不是只预测下一个小时,问题会复杂不少。
一种做法是“单步预测滚动法”:先用模型预测出下小时的负荷值,然后把预测值作为特征输入,继续预测下下小时的负荷值。这种做法的问题是误差会逐步累积,预测时间越长偏得越远。
另一种做法是“直接多步预测”:把标签从1个改为24个,模型输出维度就是24,即一次预测出未来24小时的完整序列。这种做法实现容易,但需要数据量更大,输出之间的一致性也不容易保障。
对毕设来说,用滚动预测法更便于展示模型的迭代逻辑,同时在评估时要分不同预测步长(1小时、6小时、12小时、24小时)报告误差,这样能说明模型的能力边界。
6.5 论文中关于模型结构的解释方式
答辩的时候,有的老师对深度学习不一定特别熟悉,准确措辞很重要。与其说一堆专业名词,不如用类比说明白。
可以说:DNN输入层就像接收一个家庭过去一天每小时的用电快照,中间的隐藏层相当于在自动寻找“哪些时段用电之间有关联”,输出层给出对未来负荷的判断。ReLU激活函数的作用是帮助网络在训练时更快锁定有效的特征组合,避免梯度消失。Dropout像是模拟“部分神经元临时缺席,看网络还能不能稳住判断”,能提高模型泛化性。
这样讲完,老师基本能明白你在做什么。
7. 项目扩展方向与个人实操体会
最后聊一点这个项目可以怎么扩展,以及在实操过程中的感受。
这个项目已经具备的基本盘是:时序数据处理、sklearn传统模型、DNN深度学习模型、Flask Web部署、可视化展示。在这个基础上有三个比较自然的扩展方向。
第一个方向是引入外部特征。比如家庭所在地的气温、湿度、节假日信息。用电量和气温有明显的非线性关系,尤其是夏天和冬天极端天气时空调负荷占比很高。加入温度特征之后,模型的预测精度通常会有明显提升,而且这个改进方向很容易在论文中转化为对比实验。
第二个方向是把DNN替换成LSTM或GRU。如果指导老师倾向于“深度学习要体现序列模型”,可以把你当前的DNN当作基准模型,再实现一个LSTM版本,对比两者在较长窗口预测上的表现差异。
第三个方向是把单家庭模型扩展为多家庭聚合预测或者楼宇级负荷预测。这种数据在电力市场、储能调度等场景有明确应用价值,做出来的内容更接近工业界真实需求。
回到实操体会。我在做类似项目的过程中最深的感受是:数据清洗和特征工程所花的时间远超模型调参所花的时间。很多同学喜欢把精力花在调整DNN层数和学习率上,觉得这样才像“做深度学习”。实际上,对这类负荷预测任务,把滞后特征、时间特征做扎实,用简单的多层感知机就可以获得不错的结果。模型结构决定上限,但数据质量决定你到底能摸到多高的天花板。
另外,Flask部署看似是个小环节,但放到答辩现场展示时的效果非常加分。一个能交互的Web页面比几十页PPT都更能让老师直观感受到“你确实做出来了一个系统”。
还有一个小建议是坚持做实验记录。我在训练时习惯把每次改动的参数、改动的动机、验证集上的结果都记到一个表格里。长期积累下来,答辩时被问到“你怎么想到要把隐藏层从64改成128”时,你就能给出有据可循的回答,而不是含糊地说“试出来的”。这种细节上的严谨,恰恰是高分论文和普通论文之间最主要的区别。
