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

单神经元神经网络适配自定义数据集失败,求助排查问题

单神经元网络适配自定义数据集失败的问题

问题描述

用numpy构建的单神经元网络在示例二分类数据集(输入[[0,0,1],[1,1,1],[1,0,1],[0,1,1]]、输出[[0,1,1,0]])上能正常工作,但切换到自定义数据集后完全无法适配。尝试过输入归一化但无效,训练后预测输出的数值关系和真实输出完全不符:比如真实输出中1小于2,但预测结果出现0.99>0.98的情况。

自定义数据集与代码如下:

import numpy as np
import pandas as pd

def sigmoid(x):
    return 1 /(1+np.exp(-x))

def sigmoid_derivative(x):
    return x*(1-x)

training_inputs = np.array([
                    [1, 0, 0],
                    [0, 1, 0],
                    [0, 0, 1],
                    [1, 1, 0],
                    [0, 1, 1],
                    [1, 1, 1],
                    [2, 0, 0]
                ])

training_outputs = np.array([[1,2,0,1,0,2,3]]).T

np.random.seed(1)

synaptic_weights = 2 * np.random.random((3,1))-1
print('Random starting synaptic weights: ')
print(synaptic_weights)

for iteration in range(2000):
    input_layer = training_inputs
    outputs = sigmoid(np.dot(input_layer, synaptic_weights))
    error = training_outputs - outputs
    adjustments = error * sigmoid_derivative(outputs)
    synaptic_weights += np.dot(input_layer.T,adjustments)

print('Synaptic Weights After Training: ')
print(synaptic_weights)
print('Outputs after training: ')
print(outputs)

训练后预测输出:

[0.99869975]
 [0.98680038]
 [0.00212543]
 [0.99998259]
 [0.13736242]
 [0.99189007]
 [0.9999983 ]

真实输出:

[[1,2,0,1,0,2,3]]

核心问题分析

  • 输出范围不匹配:sigmoid函数的输出区间固定为(0,1),但你的真实输出包含0、1、2、3,超出了sigmoid的输出上限。网络只能把所有大于1的目标值压缩到接近1的范围,自然无法区分2和3、1和2的大小关系。
  • 任务类型混淆:示例数据集是二分类任务(输出仅0/1),sigmoid刚好适配;但自定义数据集是回归任务(输出连续数值且范围超过(0,1)),用sigmoid作为输出激活函数完全不合适。
  • 归一化不完整:你只做了输入归一化,但没对输出做处理,导致输出层根本无法映射到目标数值范围。

解决方案(仅用numpy+pandas)

方案1:适配回归任务的网络调整(推荐)

  1. 替换输出激活函数:回归任务用线性激活(直接输出加权和)即可,不需要非线性激活函数;同时调整反向传播的导数计算(线性激活的导数为1)。
  2. 输出归一化+反归一化:先把真实输出缩放到(0,1)区间,训练后再反归一化还原到原始数值范围。
  3. 加入学习率:避免权重更新幅度过大导致震荡,提升收敛稳定性。

修改后的代码示例:

import numpy as np

# 线性激活函数(回归任务专用)
def linear(x):
    return x

# 线性激活的导数为1
def linear_derivative(x):
    return np.ones_like(x)

training_inputs = np.array([
                    [1, 0, 0],
                    [0, 1, 0],
                    [0, 0, 1],
                    [1, 1, 0],
                    [0, 1, 1],
                    [1, 1, 1],
                    [2, 0, 0]
                ])

# 原始输出
training_outputs_raw = np.array([[1,2,0,1,0,2,3]]).T
# 输出归一化到(0,1)区间
output_min = training_outputs_raw.min()
output_max = training_outputs_raw.max()
training_outputs = (training_outputs_raw - output_min) / (output_max - output_min)

np.random.seed(1)
synaptic_weights = 2 * np.random.random((3,1)) - 1
print('初始随机权重: ')
print(synaptic_weights)

# 回归任务需要更多训练轮次
for iteration in range(10000):
    input_layer = training_inputs
    # 用线性激活输出加权和
    outputs = linear(np.dot(input_layer, synaptic_weights))
    error = training_outputs - outputs
    # 线性激活导数为1,调整项直接等于误差
    adjustments = error * linear_derivative(outputs)
    # 加入学习率0.01,控制权重更新幅度
    synaptic_weights += np.dot(input_layer.T, adjustments) * 0.01

print('训练后权重: ')
print(synaptic_weights)

# 反归一化,还原到原始输出范围
predictions = outputs * (output_max - output_min) + output_min
print('训练后预测输出(反归一化后): ')
print(predictions)
print('真实输出: ')
print(training_outputs_raw)

方案2:坚持用sigmoid(不推荐)

如果一定要保留sigmoid,必须把输出严格缩放到(0,1)区间,比如training_outputs = training_outputs_raw / 3(因为最大输出是3),训练后再乘以3还原。但这种方式会因为sigmoid的非线性特性,导致中间值拟合效果远不如线性激活。


额外优化建议

  • 输入归一化:把输入中的值(0、1、2)也缩放到(0,1)或(-1,1)区间,帮助网络更快收敛。
  • 调整学习率:可根据收敛情况微调学习率(比如0.005或0.02),找到最优更新幅度。

内容的提问来源于stack exchange,提问作者Ahmet Rauf Oktay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:52:43