什么是回归?
我们明确一下回归任务的目标。

回归是一种监督学习任务,其目标是预测一个连续的数值,与分类任务(预测离散的类别,如“猫”或“狗”)不同,回归任务的输出是一个可以无限细分的数值。
常见回归问题示例:
- 房价预测:根据房屋的面积、位置、房龄等特征,预测其具体售价(123.45 万元)。
- 股票价格预测:根据历史价格、交易量等数据,预测明天的收盘价。
- 气温预测:根据湿度、风速、气压等特征,预测未来的温度(25.6 摄氏度)。
- 销量预测:根据广告投入、节假日、历史销量等,预测下个月的产品销量。
为什么用神经网络做回归?
传统的回归算法(如线性回归、决策树回归、支持向量回归)在处理线性关系或简单非线性关系时非常高效且易于解释。
当面对以下情况时,神经网络的优势就凸显出来了:

- 高度复杂的非线性关系:现实世界中的数据关系往往非常复杂,神经网络通过其多层结构和非线性激活函数,能够学习到极其复杂和非线性的映射关系,这是传统方法难以企及的。
- 高维数据:当输入特征非常多时(图像、文本、基因序列数据),神经网络可以有效地从这些高维数据中提取有用的信息并进行预测。
- 端到端学习:神经网络可以自动从原始数据中学习特征表示,无需像传统方法那样进行繁琐的手动特征工程。
神经网络回归的核心组件
一个用于回归任务的神经网络,其结构设计与分类网络有相似之处,但在输出层和损失函数上有显著区别。
A. 网络结构
一个典型的前馈神经网络由以下部分组成:
-
输入层:
- 节点数 = 输入特征的个数。
- 房价预测任务有 5 个特征(面积、房间数、位置、房龄、楼层),则输入层就有 5 个节点。
-
隐藏层:
(图片来源网络,侵删)- 这是网络的核心,负责学习数据中的复杂模式。
- 可以有多个隐藏层,构成深度神经网络。
- 每个隐藏层由多个神经元组成,神经元数量是一个超参数,需要根据任务复杂度进行调整。
- 每个神经元都会接收来自前一层所有神经元的输入,通过权重进行加权求和,然后加上一个偏置,最后通过一个激活函数进行处理。
-
输出层:
- 这是回归任务与分类任务最关键的区别之一!
- 回归任务的输出层通常只有一个神经元,因为我们要预测的是一个单一的连续值。
- 输出层不使用激活函数,或者使用线性激活函数(即
f(x) = x),这确保了网络的输出可以是任意实数,不受限制。
B. 激活函数
隐藏层需要激活函数来引入非线性,否则多层网络就等同于单层线性模型。
- 常用激活函数:
- ReLU (Rectified Linear Unit):
f(x) = max(0, x),最常用,计算简单,能有效缓解梯度消失问题。 - Sigmoid:输出在 (0, 1) 之间。通常不用于回归的隐藏层,因为它会将输出限制在一个小范围内,可能丢失信息。
- Tanh (Hyperbolic Tangent):输出在 (-1, 1) 之间,同样,由于其输出范围有限,在回归任务中不如ReLU常用。
- ReLU (Rectified Linear Unit):
C. 损失函数
损失函数用于衡量模型预测值与真实值之间的差距。回归任务的损失函数与分类任务完全不同。
- 均方误差:最常用、最标准的回归损失函数。
- 公式:
MSE = (1/n) * Σ(y_true - y_pred)² - 优点:对较大的误差有更强的惩罚作用,使得模型更关注那些预测偏差大的样本,数学性质好,易于求导。
- 公式:
- 平均绝对误差:
- 公式:
MAE = (1/n) * Σ|y_true - y_pred| - 优点:对异常值(离群点)不那么敏感,因为误差是线性增长的,MAE的梯度是恒定的,可能导致在某些优化问题上收敛速度不如MSE。
- 公式:
- Huber Loss:MSE和MAE的结合体。
- 当误差小于某个阈值 时,它使用MSE;当误差大于 时,它使用MAE。
- 优点:结合了MSE对平滑梯度的偏好和MAE对异常值的鲁棒性。
D. 优化器
优化器负责根据损失函数计算出的梯度来更新网络的权重和偏置,以最小化损失。
- 常用优化器:
- Adam (Adaptive Moment Estimation):目前最主流、最常用的优化器,它结合了Momentum和RMSProp的优点,自适应地调整每个参数的学习率,通常能快速稳定地收敛。
- SGD (Stochastic Gradient Descent):经典的优化器,简单但可能收敛较慢,且对学习率敏感。
- RMSprop / Momentum:也是有效的优化器,但在实践中Adam通常是首选。
实践步骤:一个完整的回归项目
我们将以一个经典的波士顿房价预测数据集为例(注:该数据集因伦理问题已从新版Scikit-learn中移除,但我们可以用类似的数据集代替,如加州房价数据集),走一遍完整的流程。
步骤 1: 数据准备
- 加载数据:使用
pandas或sklearn加载数据集。 - 数据探索:查看数据的基本统计信息、分布、特征间的相关性等。
- 数据预处理:
- 特征缩放:神经网络对输入特征的尺度非常敏感,通常使用标准化 或 归一化 将所有特征缩放到一个相似的范围内(如 [0, 1] 或均值为0,标准差为1),这对于加速模型收敛至关重要。
- 数据集划分:将数据集划分为训练集、验证集 和 测试集,70%训练,15%验证,15%测试。
步骤 2: 构建模型
使用 TensorFlow/Keras 或 PyTorch 来构建模型,这里以 Keras 为例。
import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense # 定义模型 model = Sequential() # 输入层和第一个隐藏层 # Dense表示全连接层 # units=64: 隐藏层神经元数量 # activation='relu': 使用ReLU激活函数 # input_shape: 输入特征的维度,只在第一层指定 model.add(Dense(units=64, activation='relu', input_shape=(X_train.shape[1],))) # 第二个隐藏层 model.add(Dense(units=32, activation='relu')) # 输出层 # units=1: 因为我们要预测一个连续值 # activation='linear': 线性激活,这是回归任务的关键 model.add(Dense(units=1, activation='linear')) # 打印模型结构 model.summary()
步骤 3: 编译模型
在编译阶段,我们需要指定损失函数、优化器和评估指标。
# 编译模型
model.compile(
optimizer='adam', # 使用Adam优化器
loss='mean_squared_error', # 使用MSE作为损失函数
metrics=['mae'] # 除了损失,我们还监控平均绝对误差
)
步骤 4: 训练模型
使用 fit 方法在训练数据上进行训练。
# 训练模型
# epochs: 训练轮数
# batch_size: 每次梯度更新使用的样本数
# validation_data: 在每个epoch结束后,在验证集上评估性能,用于监控过拟合
history = model.fit(
X_train,
y_train,
epochs=100,
batch_size=32,
validation_data=(X_val, y_val),
verbose=1
)
步骤 5: 评估模型
在从未参与训练的测试集上评估模型的最终性能。
# 在测试集上评估
loss, mae = model.evaluate(X_test, y_test)
print(f"Test MSE: {loss:.4f}")
print(f"Test MAE: {mae:.4f}")
# 进行预测
predictions = model.predict(X_test)
# 可以将预测值和真实 