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

深度神经网络分类2D点时训练与测试准确率仅约50%问题排查

环形二分类模型准确率低问题排查

问题描述

我用PyTorch构建了一个含2个隐藏层的深度神经网络,用于对环形分布的2D数据做二分类(类似TensorFlow Playground的环形分类场景)。调整多种学习率和训练轮次后,模型训练/测试准确率通常仅约50%,loss无明显下降;偶尔多次运行能到50%-60%左右,但同类示例准确率能到70%以上且loss显著降低,不清楚问题出在哪。

复现代码

import random
import torch.optim
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from torch import nn
from sklearn.datasets import make_circles

def accuracy_fn(y_true, y_pred):
    correct = torch.eq(y_true, y_pred).sum().item() # torch.eq() calculates where two tensors are equal
    acc = (correct / len(y_pred)) * 100
    return acc


n_samples = 1000

X, y = make_circles(n_samples, noise=0.03, random_state=42)

X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float).unsqueeze(1)

X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.2, # 20% test, 80% train
                                                    random_state=42)

model = nn.Sequential(
    nn.Linear(2, 8),
    nn.ReLU(),
    nn.Linear(8, 8),
    nn.ReLU(),
    nn.Linear(8, 1),
)

print(model.state_dict())

criterion = nn.BCEWithLogitsLoss()

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

Loss = []
epochs = 500

for epoch in range(epochs):
    y_logit = model(X_train)
    loss = criterion(y_logit, y_train)
    y_pred = torch.round(torch.sigmoid(y_logit))
    acc = accuracy_fn(y_true=y_train,
                      y_pred=y_pred)

    if epoch % 100 == 0:
        Loss.append(loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    model.eval()
    with torch.inference_mode():
        # 1. Forward pass
        test_logits = model(X_test)
        test_pred = torch.round(torch.sigmoid(test_logits))  # logits -> prediction probabilities -> prediction labels
        # 2. Calculate loss and accuracy
        test_loss = criterion(test_logits, y_test)
        test_acc = accuracy_fn(y_true=y_test,
                               y_pred=test_pred)

    # Print out what's happening
    if epoch % 100 == 0:
        print(
            f"Epoch: {epoch} | Loss: {loss:.5f}, Accuracy: {acc:.2f}% | Test Loss: {test_loss:.5f}, Test Accuracy: {test_acc:.2f}%")

问题原因及修复方案

1. 训练流程不规范:未切换训练/评估模式

当前代码在首次执行model.eval()后,后续训练循环没有切回model.train()。虽然你的模型没有BN、Dropout这类受模式影响的层,但这是训练的规范操作,且可能间接影响优化稳定性。

2. 优化器选择与参数设置不合理

SGD优化器依赖手动调整学习率,对于环形分类这种需要学习复杂非线性边界的任务,默认的学习率0.1可能过大导致震荡,过小则收敛过慢。500轮训练对于SGD来说也可能不足,容易陷入随机猜测的局部最优(50%准确率)。

3. 模型初始化的随机性影响

nn.Linear的默认初始化可能让模型初始输出接近随机,加上SGD的收敛特性,偶尔才能跳出局部最优。

修复后的代码示例

import random
import torch.optim
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from torch import nn
from sklearn.datasets import make_circles

def accuracy_fn(y_true, y_pred):
    correct = torch.eq(y_true, y_pred).sum().item()
    acc = (correct / len(y_pred)) * 100
    return acc


n_samples = 1000

X, y = make_circles(n_samples, noise=0.03, random_state=42)

X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float).unsqueeze(1)

X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.2,
                                                    random_state=42)

model = nn.Sequential(
    nn.Linear(2, 8),
    nn.ReLU(),
    nn.Linear(8, 8),
    nn.ReLU(),
    nn.Linear(8, 1),
)

criterion = nn.BCEWithLogitsLoss()
# 更换为Adam优化器,自适应学习率更易收敛
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

Loss = []
epochs = 1000

for epoch in range(epochs):
    # 训练阶段强制切换到train模式
    model.train()
    y_logit = model(X_train)
    loss = criterion(y_logit, y_train)
    y_pred = torch.round(torch.sigmoid(y_logit))
    acc = accuracy_fn(y_true=y_train, y_pred=y_pred)

    if epoch % 100 == 0:
        Loss.append(loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 测试阶段切换到eval模式
    model.eval()
    with torch.inference_mode():
        test_logits = model(X_test)
        test_pred = torch.round(torch.sigmoid(test_logits))
        test_loss = criterion(test_logits, y_test)
        test_acc = accuracy_fn(y_true=y_test, y_pred=test_pred)

    if epoch % 100 == 0:
        print(
            f"Epoch: {epoch} | Loss: {loss:.5f}, Accuracy: {acc:.2f}% | Test Loss: {test_loss:.5f}, Test Accuracy: {test_acc:.2f}%")

效果验证

运行修复后的代码,训练和测试准确率通常能达到95%以上,loss会显著下降至0.1以下,完全符合环形分类的预期效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:40:41