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

使用torch.nn.functional.linear时出现异常输出的问题排查

问题

训练采用自定义损失函数、sigmoid激活函数的二分类神经网络(标签取值{+1, -1})时,发现所有预测输出始终为负且接近固定值(如-0.56xx),所有train_output也始终维持在该区间。

核心代码片段:

def train_net(X, y, c_reg, batch_size=16, lr=1e-2, p=80, d=20, test_frac=0.2, T=50000, rng_seed=42): 
    # ... 省略初始化代码 ...
    W = torch.as_tensor(rng.normal(0.0, 1.0, (p, d)) / np.sqrt(p), device = 'cuda')
    W.requires_grad_(True)

    a_var = torch.as_tensor(rng.uniform(-1.0, 1.0, (1, p)), device = 'cuda')
    a_var = torch.div(a_var, torch.linalg.vector_norm(a_var))
    a_var.requires_grad_(False)

    # ... 数据加载部分 ...

    for i in range(T):
        for idx, batch in enumerate(dataloader):
            batch_x = batch[:, :-1]
            batch_y = batch[:, -1].reshape(-1, 1)

            train_output = torch.sigmoid(F.linear(input=batch_x, weight=W)).mm(a_var.t())
            loss = torch.mean(torch.log(1+torch.exp(torch.mul(train_output.mul(batch_y), -1.0)))) + (c_reg / 2) * torch.linalg.matrix_norm(W) ** 2
            W.data = W.data - stepsize * grad(loss, W)[0]
    # ... 省略后续代码 ...

测试预测输出示例:

tensor([[-0.5644],
        [-0.5627],
        [-0.5651],
        [-0.5663],
        [-0.5649],
        [-0.5650],
        [-0.5638],
        [-0.5640],
        [-0.5650],
        [-0.5644],
        [-0.5649],
        [-0.5651],
        [-0.5647],
        [-0.5642],
        [-0.5648],
        [-0.5646],
        [-0.5647],
        [-0.5647],
        [-0.5647],
        [-0.5654],
        [-0.5648],
        [-0.5648],
        [-0.5638],
        [-0.5641],
        [-0.5650],
        [-0.5649],
        [-0.5644],
        [-0.5662],
        [-0.5652],
        [-0.5638],
        [-0.5649],
        [-0.5640]], device='cuda:0', grad_fn=<MmBackward0>)

完整代码见用户提供的附件。


问题排查与解决

1. 输出范围与标签不匹配

sigmoid激活函数的输出范围是(0,1),直接与a_var.t()相乘后无法覆盖标签{+1,-1}的范围,导致模型无法有效区分正负样本。需将sigmoid输出转换到(-1,1)区间:

# 替换原sigmoid输出
hidden = 2 * torch.sigmoid(F.linear(input=batch_x, weight=W)) - 1
train_output = hidden.mm(a_var.t())

2. 梯度更新方式错误

手动直接更新W.data会绕过PyTorch的自动梯度管理,容易导致梯度累积或计算图断裂。改用官方优化器管理梯度:

# 初始化优化器(包含可训练参数W和a_var)
optimizer = torch.optim.SGD([W, a_var], lr=lr)

# 训练循环内替换手动更新
optimizer.zero_grad()
loss.backward()
optimizer.step()

3. 数据归一化逻辑错误

原unit_norm_data函数对整个数据集做L2归一化,导致所有样本的全局范数相同,模型无法学习样本间差异。改为对每个样本单独归一化:

def unit_norm_data(n,d):
    # ... 省略其他代码 ...
    # 对每个样本做L2归一化
    x = torch.div(x, torch.linalg.norm(x, dim=1, keepdim=True))
    # ... 省略后续代码 ...

4. 第二层权重固定限制模型表达

a_var被设置为requires_grad_(False),即第二层权重完全固定,仅第一层W可训练,极大限制模型拟合能力。除非有特殊实验需求,应让a_var参与训练:

a_var.requires_grad_(True)  # 取消固定,允许梯度更新

5. 损失函数数值稳定性问题

原损失torch.log(1+torch.exp(-train_output*batch_y))在train_output*batch_y绝对值过大时会出现数值溢出,改用更稳定的softplus实现:

loss = torch.mean(torch.nn.functional.softplus(-train_output * batch_y)) + (c_reg / 2) * (torch.linalg.matrix_norm(W)**2 + torch.linalg.matrix_norm(a_var)**2)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:47:00