基于真值构建非图像分类器:自定义前馈神经网络的数据集输入与训练方法问询
适配概率型多类别数据集到前馈神经网络的训练方案
先给你梳理下当前的问题,然后一步步解决:
一、先修正你的网络结构bug
你当前的NNO类有几个明显的错误,会导致无法正常运行:
- 重复赋值
self.hidden:三次赋值后只有最后一个nn.Linear(20,20)生效,前面的输入层和第一个隐藏层都被覆盖了,而且你明确说网络接收15维输入,所以第一个线性层的输入维度必须是15 forward函数参数不匹配:定义的参数是y,但函数里用的是未定义的x,会直接引发报错- 隐藏层未分层命名:多个隐藏层需要单独命名(比如
hidden1、hidden2),不然无法按顺序调用
修正后的网络结构代码如下:
import torch import torch.nn as nn class NNO(nn.Module): def __init__(self): super(NNO, self).__init__() # 输入层:15维输入 → 20维隐藏层1 self.hidden1 = nn.Linear(15, 20) # 隐藏层2:20维 → 20维 self.hidden2 = nn.Linear(20, 20) # 输出层:20维 → 15维(对应0-14共15个类别;如果实际是14个类别,改成14即可) self.output = nn.Linear(20, 15) self.sigmoid = nn.Sigmoid() self.softmax = nn.Softmax(dim=1) def forward(self, x): # 前向传播流程:输入→隐藏层1→激活→隐藏层2→激活→输出层→softmax x = self.hidden1(x) x = self.sigmoid(x) x = self.hidden2(x) x = self.sigmoid(x) x = self.output(x) x = self.softmax(x) return x
二、处理你的概率型数据集
你的数据集有两个核心特点:
- 共10个有效样本(缺失编号为8的样本),每个样本对应一组浮点概率值(你提到14个类别,但输出是0-14,这里默认按15个类别处理,若实际是14个,可调整对应维度)
- 每个样本的真实类别标签,应该是该概率向量中概率最高的类别(比如你举例的样本项2,归属于类别2的概率最高,真实标签就是2)
1. 构建数据集张量
首先把你的样本数据转换成PyTorch兼容的张量格式:
# 示例:模拟你的数据集,key是样本项编号,value是对应类别的概率向量 sample_data = { 0: [0.001, 0.99, 0.002, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001], 1: [0.003, 0.001, 0.98, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.002], 2: [0.002, 0.001, 0.995275, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001], # 补充样本项3、4、5、6、7、9的概率向量 } # 提取输入特征和真实标签 inputs = [] labels = [] for prob_vec in sample_data.values(): inputs.append(prob_vec) # 找到概率最大的索引作为该样本的真实类别标签 true_label = prob_vec.index(max(prob_vec)) labels.append(true_label) # 转换为PyTorch张量:输入用float32,标签用long(多分类任务要求) inputs_tensor = torch.tensor(inputs, dtype=torch.float32) labels_tensor = torch.tensor(labels, dtype=torch.long)
2. 用DataLoader包装数据集(推荐)
虽然你的样本量很小,但用DataLoader可以方便后续扩展批量处理、打乱数据等操作:
from torch.utils.data import TensorDataset, DataLoader # 创建数据集对象 dataset = TensorDataset(inputs_tensor, labels_tensor) # 批大小设为样本总数,也可以根据需求调整 dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
三、启动训练循环
现在可以正式开始训练了,完整的训练流程代码如下:
# 初始化模型、损失函数、优化器 model = NNO() # 多分类任务优先用CrossEntropyLoss,它会自动适配softmax输出(也可以去掉模型里的softmax,直接用logits输入,计算更稳定) criterion = nn.CrossEntropyLoss() # 用Adam优化器,学习率可根据训练情况调整 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 训练循环 epochs = 100 for epoch in range(epochs): # 切换到训练模式 model.train() running_loss = 0.0 for batch_inputs, batch_labels in dataloader: # 清空上一轮的梯度 optimizer.zero_grad() # 前向传播得到预测结果 outputs = model(batch_inputs) # 计算损失 loss = criterion(outputs, batch_labels) # 反向传播更新梯度 loss.backward() # 优化器更新参数 optimizer.step() # 累计损失值 running_loss += loss.item() # 打印每轮的平均损失 print(f"Epoch {epoch+1}/{epochs}, Loss: {running_loss/len(dataloader):.4f}") # 训练完成后测试模型效果 model.eval() with torch.no_grad(): # 关闭梯度计算,节省资源 test_outputs = model(inputs_tensor) # 获取每个样本概率最大的类别作为预测标签 pred_labels = torch.argmax(test_outputs, dim=1) print("\n预测标签:", pred_labels.numpy()) print("真实标签:", labels_tensor.numpy())
额外注意事项
- 因为你的样本量只有10个,很容易出现过拟合,建议尝试减少隐藏层维度、添加
nn.Dropout()层,或者降低学习率 - 如果你的概率向量是其他模型的输出(用于模型融合),这个处理方案同样适用
- 若实际类别数是14个,记得把网络输出层维度改成14,同时概率向量的长度也要对应调整为14
内容的提问来源于stack exchange,提问作者mchd
相关产品推荐
相关产品推荐

