Logistic Regression中y_data一维与二维输入的结果差异原因探究
Logistic Regression中y_data一维/二维输入导致损失停滞的原因
我是AI专业学生,编写了一段基于PyTorch的Logistic Regression代码:
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim torch.manual_seed(1) x_data = [[10.0], [20.0], [30.0], [40.0], [50.0], [60.0], [70.0], [80.0], [90.0], [100.0]] y_data = [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0] x_train = torch.FloatTensor(x_data) y_train = torch.FloatTensor(y_data) W = torch.zeros(1, requires_grad=True) b = torch.zeros(1, requires_grad=True) optimizer = optim.SGD([W, b], lr=0.01) num_epochs = 10000 for epoch in range(num_epochs + 1): eps = 1e-7 hypothesis = 1 / (1 + torch.exp(-(x_train.matmul(W) + b))) loss = -(y_train * torch.log(torch.clamp(hypothesis, eps, 1-eps)) + (1 - y_train) * torch.log(torch.clamp(1 - hypothesis, eps, 1-eps))).mean() optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 100 == 0: print('Epoch {:4d}/{} Loss: {:.6f}'.format( epoch, num_epochs, loss.item() )) hypothesis = torch.sigmoid(x_train.matmul(W) + b) print(hypothesis)
当y_data是一维数组时代码运行正常,但改成二维数组(y_data = [[0.0], [0.0], [0.0], [0.0], [0.0], [1.0], [1.0], [1.0], [1.0], [1.0]])后,损失值一直停滞在0.693147,无法下降。
问题根源:张量维度不匹配引发的广播错误
核心问题是**y_train和hypothesis的维度不匹配,导致PyTorch广播机制错误地扩展张量,最终让参数更新的梯度被抵消**:
- 维度变化拆解:
x_train是(10,1)的二维张量,W是(1,)的一维张量,两者做matmul后得到(10,)的一维张量(每个样本的计算结果为标量),加b后hypothesis的维度仍为(10,)。- 当
y_data为一维时,y_train是(10,),和hypothesis维度完全匹配,元素相乘后得到(10,)的张量,损失计算和梯度更新都正常。 - 当
y_data改为二维时,y_train变成(10,1),和hypothesis的(10,)维度不匹配。PyTorch会触发广播机制:把hypothesis扩展成(1,10),y_train扩展成(10,10),两者相乘后得到(10,10)的张量。
- 对损失的影响:
原本应该是每个样本的标签对应自身预测值计算损失,现在变成每个样本的标签和所有样本的预测值相乘,取平均后得到的损失梯度是这些错误乘积的均值,直接抵消了有效的更新信号,导致W和b一直停留在初始的0值,损失也就固定在初始的log(2)≈0.6931(初始预测全为0.5,交叉熵损失为-(0.5*log0.5 + 0.5*log0.5)=log2)。
两种解决方法
方法1:调整权重W的维度,让hypothesis和y_train维度匹配
把W的定义改为二维张量,这样x_train.matmul(W)会得到(10,1)的结果,和y_train的(10,1)维度一致:
W = torch.zeros((1,1), requires_grad=True)
方法2:将二维的y_train压缩成一维
通过squeeze()方法去掉y_train中多余的维度,保持和hypothesis的(10,)一致:
y_train = torch.FloatTensor(y_data).squeeze()
也可以在损失计算时临时对齐维度,比如把hypothesis扩展成二维:
hypothesis = hypothesis.unsqueeze(1)
内容的提问来源于stack exchange,提问作者Cupelt
相关产品推荐
相关产品推荐

