无隐藏层神经网络不等价于逻辑回归?TensorFlow实现异常排查
问题描述
理论上无隐藏层、单sigmoid输出神经元的神经网络与Logistic Regression完全等价,但实测二者结果差异极大:在仅含2个样本的简单二分类任务上,该神经网络无法完成有效学习。
- sklearn逻辑回归训练效果:

- TensorFlow无隐藏层神经网络训练效果:

已尝试对齐的配置项:
- 对齐训练迭代轮数
- 关闭L2正则项
- 使用相同的二分类交叉熵损失
- 关闭动量、Nesterov等额外优化逻辑
实测结果:sklearn的LogisticRegression可以稳定找到正确决策边界,结果波动极小;TensorFlow实现的无隐藏层神经网络输出波动极大,偏置项无法有效训练。
以下为可完整复现问题的代码:
import numpy as np import tensorflow as tf from tensorflow.keras.layers import Conv1D, Dense, Flatten, Input, Concatenate, Dropout from tensorflow.keras import Sequential, Model from tensorflow.keras.optimizers import SGD import matplotlib.pyplot as plt %matplotlib inline from sklearn.linear_model import LogisticRegression X = np.array([[1, 1], [2, 2]]) y = np.array([0, 1]) model = LogisticRegression(penalty = 'none', solver='sag', max_iter = 300, tol = 1e-100) model.fit(X, y) model.score(X, y) model.coef_.flatten()[1] model.intercept_ w_1 = model.coef_.flatten()[0] w_2 = model.coef_.flatten()[1] b = model.intercept_ n = np.linspace(0, 3, 10000, endpoint=False) x_n = -w_1 / w_2 * n - b / w_2 plt.scatter(X[:, 0], X[:, 1], c = y) plt.plot(n, x_n) plt.gca().set_aspect('equal') plt.show() X = np.array([[1, 1], [2, 2]]) y = np.array([0, 1]) optimizer = SGD(learning_rate=0.01, momentum = 0.0, nesterov = False, name = 'SGD') inputs = Input(shape = (2,), name='inputs') outputs = Dense(1, activation = 'sigmoid', name = 'outputs')(inputs) model = Model(inputs = inputs, outputs = outputs, name = 'model') model.compile(loss = 'bce', optimizer = optimizer, metrics = ['AUC', 'accuracy']) model.fit(X, y, epochs = 100, verbose=False) print(model.evaluate(X, y)) weights, bias = model.layers[1].get_weights() weights = weights.flatten() w_1 = weights[0] w_2 = weights[1] b = bias n = np.linspace(0, 3, 10000, endpoint=False) x_n = -w_1 / w_2 * n - b / w_2 plt.scatter(X[:, 0], X[:, 1], c = y) plt.plot(n, x_n) plt.grid() plt.gca().set_aspect('equal') plt.show()
问题原因
结果差异和模型结构的等价性无关,核心是训练配置未真正对齐:
- batch配置不符合小数据集场景:Keras的
model.fit()默认batch_size=32,当前数据集仅2个样本,相当于每个epoch仅执行1次梯度更新,100轮总更新步数远少于sklearn SAG求解器的实际迭代次数(SAG因设置了极小的tol阈值会跑满300次迭代,更新量是TF的3倍,收敛程度更高)。 - 随机初始化放大波动:Keras Dense层默认使用Glorot均匀分布随机初始化权重、零初始化偏置,在样本量极小的场景下,初始化的随机波动会直接导致最终结果不稳定;sklearn的LogisticRegression采用更保守的初始化策略,几乎不受随机波动影响。
- 训练轮次不足:0.01的固定学习率下,100轮更新远不足以让参数收敛到最优解,偏置项自然无法学到正确值。
修复方案
修改3处训练配置即可让TensorFlow模型输出的决策边界与逻辑回归高度趋近:
- 训练时设置
batch_size=len(X),采用全批量梯度下降,与逻辑回归的批量优化逻辑对齐 - 固定随机种子消除初始化波动,或直接将Dense层权重初始化为0,与逻辑回归初始状态对齐
- 适当调大学习率、增加训练轮次,保证参数收敛
修正后的TensorFlow模型核心代码如下:
# 固定随机种子消除随机波动 tf.random.set_seed(42) np.random.seed(42) optimizer = SGD(learning_rate=0.1, momentum=0.0, nesterov=False) inputs = Input(shape=(2,)) # 零初始化权重对齐逻辑回归初始状态,也可保留默认初始化靠固定种子复现结果 outputs = Dense(1, activation='sigmoid', kernel_initializer='zeros')(inputs) model = Model(inputs=inputs, outputs=outputs) model.compile(loss='bce', optimizer=optimizer, metrics=['accuracy']) # 全批量训练1000轮保证收敛 model.fit(X, y, epochs=1000, batch_size=len(X), verbose=False)
按上述配置训练后,TensorFlow模型得到的权重、偏置和决策边界会与sklearn逻辑回归结果高度重合,不会再出现大幅波动。
内容的提问来源于stack exchange,提问作者DataScientistAmateur
相关产品推荐
相关产品推荐

