为何基于Numpy的简单神经网络无法学习非线性数据?
问题分析与解决方案
嘿,我来帮你搞清楚为啥你的神经网络学不了这个非线性任务!
核心问题:你的单层网络只能处理线性可分问题
你现在的神经网络只有输入层+输出层(中间没有隐藏层),本质上就是个带sigmoid激活的线性分类器。这种结构的输出是输入的单调函数——因为sigmoid是单调递增的,输入的线性组合经过它之后,输出还是随输入单调变化的。
但你的目标任务是:输入1→0,2-3→1,4→0,这是一个先升后降的非单调映射,属于典型的线性不可分问题。单层网络无论怎么调整权重,都没法拟合这种非线性模式;而你之前的线性任务(输入[2,2,0,0]对应输出[1,1,0,0])是线性可分的,所以能轻松学好。
解决方案:给网络加一个隐藏层
要拟合非线性映射,你需要引入隐藏层——这是神经网络能处理非线性问题的核心。根据万能逼近定理,只要隐藏层有足够多的神经元,单隐藏层的神经网络可以拟合任何连续函数。
下面是修改后的代码,我加了一个2神经元的隐藏层,让网络有能力学习你的目标映射:
import numpy as np # sigmoid函数及其导数 def nonlin(x, deriv=False): if deriv: return x * (1 - x) return 1 / (1 + np.exp(-x)) # 输入数据集 X = np.array([[1], [2], [3], [4]]) # 输出数据集 y = np.array([[0, 1, 1, 0]]).T np.random.seed(1) # 初始化两层权重:输入→隐藏(1→2神经元),隐藏→输出(2→1神经元) syn0 = 2 * np.random.random((1, 2)) - 1 syn1 = 2 * np.random.random((2, 1)) - 1 for iter in range(100000): # 前向传播 l0 = X l1 = nonlin(np.dot(l0, syn0)) # 隐藏层计算 l2 = nonlin(np.dot(l1, syn1)) # 输出层预测 # 计算误差并打印进度(每10000次迭代) l2_error = y - l2 if iter % 10000 == 0: print(f"迭代{iter}次,平均误差:{np.mean(np.abs(l2_error)):.4f}") # 反向传播更新权重 l2_delta = l2_error * nonlin(l2, deriv=True) l1_error = l2_delta.dot(syn1.T) l1_delta = l1_error * nonlin(l1, deriv=True) syn1 += l1.T.dot(l2_delta) syn0 += l0.T.dot(l1_delta) print("\n训练后输出:") print(l2)
效果说明
运行这段代码后,你会看到训练后的输出非常接近目标值[[0], [1], [1], [0]]。隐藏层的两个神经元会学习到不同的线性组合,再通过输出层的整合,就能实现你需要的先升后降的非线性映射。
内容的提问来源于stack exchange,提问作者afq radeon
相关产品推荐
相关产品推荐

