You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无隐藏层神经网络不等价于逻辑回归?TensorFlow实现异常排查

问题描述

理论上无隐藏层、单sigmoid输出神经元的神经网络与Logistic Regression完全等价,但实测二者结果差异极大:在仅含2个样本的简单二分类任务上,该神经网络无法完成有效学习。

  • sklearn逻辑回归训练效果:sklearn logistic regression
  • TensorFlow无隐藏层神经网络训练效果:tensorflow no-hidden-layer neural network

已尝试对齐的配置项:

  • 对齐训练迭代轮数
  • 关闭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模型输出的决策边界与逻辑回归高度趋近:

  1. 训练时设置batch_size=len(X),采用全批量梯度下降,与逻辑回归的批量优化逻辑对齐
  2. 固定随机种子消除初始化波动,或直接将Dense层权重初始化为0,与逻辑回归初始状态对齐
  3. 适当调大学习率、增加训练轮次,保证参数收敛

修正后的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:21:34