TensorFlow与PyTorch二分类准确率差异排查及代码修复问询
PyTorch二分类模型准确率异常(仅2.5%)的修复方案
问题描述
同一二分类任务中,TensorFlow实现的模型准确率约86%,但PyTorch版本准确率始终仅2.5%,相关代码如下:
PyTorch模型与训练代码
class SimpleClassifier(nn.Module): def __init__(self, input_size, hidden_size1, hidden_size2, output_size): super(SimpleClassifier, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size1) self.relu1 = nn.ReLU() self.fc2 = nn.Linear(hidden_size1, hidden_size2) self.relu2 = nn.ReLU() self.fc3 = nn.Linear(hidden_size2, output_size) self.sigmoid = nn.Sigmoid() def forward(self, x): x = self.relu1(self.fc1(x)) x = self.relu2(self.fc2(x)) x = self.sigmoid(self.fc3(x)) return x input_size = train_X.shape[1] hidden_size1 = 64 hidden_size2 = 32 output_size = 1 model = SimpleClassifier(input_size, hidden_size1, hidden_size2, output_size) criterion = nn.BCELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) num_epochs = 50 for epoch in range(num_epochs): for inputs, labels in train_dataloader: optimizer.zero_grad() outputs = model(inputs) # Reshape labels to match the shape of the outputs labels = labels.view(-1, 1) loss = criterion(outputs, labels) loss.backward() optimizer.step() # Evaluation on the test set with torch.no_grad(): model.eval() predictions = model(test_X).squeeze() predictions_binary = (predictions.round()).float() accuracy = torch.sum(predictions_binary == test_Y) / (len(test_Y) * 100) if(epoch%25 == 0): print("Epoch " + str(epoch) + " passed. Test accuracy is {:.2f}%".format(accuracy))
TensorFlow对比代码
model = Sequential() model.add(Dense(64, input_dim=len(train_X[0]), activation='relu')) model.add(Dense(32, activation='relu')) model.add(Dense(1, activation='sigmoid')) # assuming binary classification # Compile the model model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) model.fit(train_X, train_Y, epochs=50, batch_size=64) # Evaluate the model loss, accuracy = model.evaluate(test_X, test_Y) print(f"Loss: {loss}, Accuracy: {accuracy}")
PyTorch数据加载代码
train, test = train_test_split(data, test_size=0.056) train_X = train[["A","B","C", "D"]].to_numpy() test_X = test[["A","B", "C", "D"]].to_numpy() train_Y = train[["label"]].to_numpy() test_Y = test[["label"]].to_numpy() train_X = torch.tensor(train_X, dtype=torch.float32) test_X = torch.tensor(test_X, dtype=torch.float32) train_Y = torch.tensor(train_Y, dtype=torch.float32) test_Y = torch.tensor(test_Y, dtype=torch.float32) train_dataset = TensorDataset(train_X, train_Y) test_dataset = TensorDataset(test_X, test_Y) train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
错误定位与修复步骤
1. 准确率计算逻辑错误
原代码中错误地将准确率分母乘以100,导致数值被缩小100倍,同时test_Y是二维张量(形状(n,1)),需与一维的predictions_binary形状匹配:
# 错误代码 accuracy = torch.sum(predictions_binary == test_Y) / (len(test_Y) * 100) # 修正后 correct = torch.sum(predictions_binary == test_Y.squeeze()) accuracy = correct / len(test_Y) * 100
2. 训练循环未切换回训练模式
评估阶段调用了model.eval(),会禁用梯度计算和部分层的训练行为,每个epoch的训练前需切换回训练模式:
for epoch in range(num_epochs): # 新增:切换为训练模式 model.train() for inputs, labels in train_dataloader: # 训练逻辑...
3. 统一batch_size参数
TensorFlow代码使用batch_size=64,但PyTorch代码未明确定义该变量,需补充定义保证训练批次一致:
batch_size = 64
修正后的完整PyTorch训练代码
import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import TensorDataset, DataLoader from sklearn.model_selection import train_test_split # 统一batch_size batch_size = 64 # 数据加载 train, test = train_test_split(data, test_size=0.056) train_X = train[["A","B","C", "D"]].to_numpy() test_X = test[["A","B", "C", "D"]].to_numpy() train_Y = train[["label"]].to_numpy() test_Y = test[["label"]].to_numpy() train_X = torch.tensor(train_X, dtype=torch.float32) test_X = torch.tensor(test_X, dtype=torch.float32) train_Y = torch.tensor(train_Y, dtype=torch.float32) test_Y = torch.tensor(test_Y, dtype=torch.float32) train_dataset = TensorDataset(train_X, train_Y) test_dataset = TensorDataset(test_X, test_Y) train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 模型定义 class SimpleClassifier(nn.Module): def __init__(self, input_size, hidden_size1, hidden_size2, output_size): super(SimpleClassifier, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size1) self.relu1 = nn.ReLU() self.fc2 = nn.Linear(hidden_size1, hidden_size2) self.relu2 = nn.ReLU() self.fc3 = nn.Linear(hidden_size2, output_size) self.sigmoid = nn.Sigmoid() def forward(self, x): x = self.relu1(self.fc1(x)) x = self.relu2(self.fc2(x)) x = self.sigmoid(self.fc3(x)) return x input_size = train_X.shape[1] hidden_size1 = 64 hidden_size2 = 32 output_size = 1 model = SimpleClassifier(input_size, hidden_size1, hidden_size2, output_size) criterion = nn.BCELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) num_epochs = 50 for epoch in range(num_epochs): model.train() total_train_loss = 0.0 for inputs, labels in train_dataloader: optimizer.zero_grad() outputs = model(inputs) labels = labels.view(-1, 1) loss = criterion(outputs, labels) loss.backward() optimizer.step() total_train_loss += loss.item() * inputs.size(0) avg_train_loss = total_train_loss / len(train_dataloader.dataset) with torch.no_grad(): model.eval() predictions = model(test_X).squeeze() predictions_binary = (predictions.round()).float() correct = torch.sum(predictions_binary == test_Y.squeeze()) accuracy = correct / len(test_Y) * 100 if epoch % 25 == 0: print(f"Epoch {epoch} passed. Train Loss: {avg_train_loss:.4f}, Test Accuracy: {accuracy:.2f}%")
内容的提问来源于stack exchange,提问作者grey
相关产品推荐
相关产品推荐

