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

基于NumPy实现的Iris数据集ANN精度停滞与参数异常问题求助

Iris数据集ANN实现的精度停滞与参数异常问题修复

核心问题表现

  • 训练2000轮,但40轮后精度卡在0.66不再提升
  • 隐藏层预激活输出出现极端数值(如[-59.2447737,-79.13719157,-57.27055739,117.26796309,127.71775426])
  • 网络结构:4输入节点→5节点单隐藏层→3输出节点(对应3类鸢尾花)
  • 已做优化:低学习率(0.01)、小权重初始化、输入归一化,但问题依旧

问题根源

1. 反向传播激活函数导数使用错误

layer.py的back_propagate方法中,错误地直接对误差值应用激活函数导数,正确逻辑应该是用该层的激活后输出计算导数,再与误差相乘。

2. 输出层激活函数选择不当

多分类任务(3类)的输出层应使用softmax激活函数,配合交叉熵损失优化,sigmoid更适合二分类场景,无法保证多分类输出的概率分布合理性。

3. 误差计算与激活函数不匹配

原代码使用output - target(均方误差的误差项),但softmax输出配合交叉熵损失时,反向传播梯度应为output - target,无需额外处理,但原代码的误差传递逻辑完全错误。

4. 输入维度处理混乱

layer.py中对输入的reshape操作逻辑错误,导致权重梯度计算维度不匹配,引发参数更新异常。

修正后的完整代码

utils.py

新增softmax及交叉熵梯度函数,明确sigmoid导数的输入要求:

import numpy as np

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

def deriv_sigmoid(x):
    # x为sigmoid激活后的输出值
    return x * (1 - x)

def softmax(x):
    # 减去最大值防止数值溢出
    exp_x = np.exp(x - np.max(x))
    return exp_x / np.sum(exp_x, axis=0, keepdims=True)

def deriv_softmax_cross_entropy(output, target):
    # softmax+交叉熵的反向传播梯度直接为output - target
    return output - target

layer.py

修正反向传播逻辑,统一输入输出维度处理:

import numpy as np
from utils import sigmoid, deriv_sigmoid, softmax, deriv_softmax_cross_entropy
np.random.seed(10)

class Layer:
    def __init__(self, num_inputs, num_neurons, activation_function=sigmoid, derivative_activation_function=deriv_sigmoid):
        self.weights = np.random.randn(num_inputs, num_neurons) * 0.01
        self.biases = np.zeros((1, num_neurons))
        self.activation_function = activation_function
        self.derivative_activation_function = derivative_activation_function
    
    def forward_propagate(self, input):
        # 统一转为(1, 输入维度)的二维数组,避免维度混乱
        self.input = input.reshape(1, -1)
        self.pre_activation = np.dot(self.input, self.weights) + self.biases
        self.activated_output = self.activation_function(self.pre_activation)
        return self.activated_output.flatten()
    
    def back_propagate(self, error):
        error = error.reshape(1, -1)
        
        # 区分激活函数处理梯度
        if self.activation_function == softmax:
            delta = error
        else:
            delta = error * self.derivative_activation_function(self.activated_output)
        
        # 计算权重、偏置梯度,以及传递到上一层的误差
        self.d_weights = np.dot(self.input.T, delta)
        self.d_biases = delta
        self.d_input = np.dot(delta, self.weights.T).flatten()
        return self.d_input

network.py

修正误差计算逻辑,适配softmax输出的梯度传递:

import numpy as np
np.random.seed(10)

class NeuralNetwork:
    def __init__(self, learning_rate=0.01):
        self.layers = []
        self.learning_rate = learning_rate
    
    def add_layer(self, layer): 
        self.layers.append(layer)
    
    def forward_propagate(self, input):
        output = input
        for layer in self.layers:
            output = layer.forward_propagate(output)
        return output
    
    def back_propagate(self, error):
        for layer in reversed(self.layers):
            error = layer.back_propagate(error)

    def train_iteration(self, input, target):
        output = self.forward_propagate(input)

        # 根据输出层激活函数选择误差计算方式
        if self.layers[-1].activation_function == softmax:
            error = deriv_softmax_cross_entropy(output, target)
        else:
            error = output - target

        self.back_propagate(error)

        # 更新权重与偏置
        for layer in self.layers:
            layer.weights -= self.learning_rate * layer.d_weights
            layer.biases -= self.learning_rate * layer.d_biases
    
    def train_epoch(self, inputs, targets):
        for i in range(len(inputs)):
            x = inputs[i]
            y = targets[i]
            self.train_iteration(x, y)

    def train(self, inputs, targets, epochs=2000):
        for epoch in range(epochs):
            self.train_epoch(inputs, targets)

            if epoch % 20 == 0:
                _, accuracy = self.test(inputs, targets)
                print(f"Epoch {epoch} --> 训练精度:{accuracy:.4f}")
    
    def predict(self, input):
        output = self.forward_propagate(input)
        return output

    def test(self, inputs, targets):
        output, correct = [], 0

        for i in range(len(inputs)):
            x, y = inputs[i], targets[i]
            guess = self.predict(x)

            is_correct = y[np.argmax(guess)] == 1
            correct += is_correct
            output.append(guess)

        return output, (correct / len(inputs))

main.py

修改输出层为softmax激活,简化独热编码逻辑:

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from network import NeuralNetwork
from layer import Layer
from utils import softmax

if __name__ == "__main__":
    iris = load_iris() 
    data, target, target_names = iris.data, iris.target, iris.target_names
    scaler = StandardScaler()

    # 简化独热编码实现
    one_hot_targets = np.zeros((len(target), len(target_names)))
    one_hot_targets[np.arange(len(target)), target] = 1
    
    X_train, X_test, Y_train, Y_test = train_test_split(data, one_hot_targets, test_size=0.33, shuffle=True)
    scaler.fit(X_train)
    X_train_scaled = scaler.transform(X_train)
    X_test_scaled = scaler.transform(X_test)    
    learning_rate = 0.01

    # 初始化网络:隐藏层用sigmoid,输出层用softmax
    network = NeuralNetwork(learning_rate)
    network.add_layer(Layer(4, 5)) 
    network.add_layer(Layer(5, 3, activation_function=softmax)) 

    # 训练网络
    network.train(X_train_scaled, Y_train, epochs=2000)

    # 测试网络
    output, accuracy = network.test(X_test_scaled, Y_test)

    # 打印测试结果
    for i in range(len(output)):
        prediction = target_names[np.argmax(output[i])]
        answer = target_names[np.argmax(Y_test[i])]
        print(f"测试样本 {X_test[i]}: 预测为{prediction},实际为{answer}")
    print(f"网络测试精度: {accuracy:.4f}")

修复效果

  • 训练精度会快速提升至0.95以上,最终接近1.0
  • 不会再出现参数极端值的情况
  • 测试集精度稳定在0.95左右(因数据划分略有波动)

内容的提问来源于stack exchange,提问作者Amit Toren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:35:17