import torch
import pandas as pd
import numpy as np
import torch.utils.data as Data
import os
df = pd.read_csv(r'res.csv',
names=['sex', 'age', 'Hb', 'ALB', 'BUN', 'SCr_not', 'Hydronephrosis', 'diabetes', 'HighBlood',
'Scr_yes', 'BSA', 'mgfr']) # 读取数据并赋予列名
label = df.pop('mgfr')[1:]
label = np.array(label).astype(np.float32)
data = np.array(df)[1:, :].astype(np.float32)
data = torch.from_numpy(data)
label = torch.from_numpy(label)
# 将输入和输出封装进Data.TensorDataset()类对象
torch_dataset = Data.TensorDataset(data, label)#dataset封装
train_dataset, valid_dataset, test_dataset = torch.utils.data.random_split(torch_dataset, [480, 50, 81])#随机划分训练集,验证集,测试集
# 把 dataset 放入 DataLoader
def getloader(torch_dataset):
loader = Data.DataLoader(#Dataloader,这里调整batch_size
dataset=torch_dataset, # 数据,封装进Data.TensorDataset()类的数据
batch_size=10, # 每块的大小
shuffle=True, # 要不要打乱数据 (打乱比较好)
num_workers=0, # 多进程(multiprocess)来读数据,单cpu时建议就0,数值型数据算力要求不大
)
return loader
train_loader = getloader(train_dataset)
valid_loader = getloader(valid_dataset)
test_loader = getloader(test_dataset)
class Model(torch.nn.Module): # 括号里面表示继承类
def __init__(self): # 构造函数
super(Model, self).__init__() # 调用父类的构造
self.Conv = torch.nn.Sequential(# 简单网络,可自行调整
torch.nn.Linear(11, 8),
torch.nn.ReLU(),
torch.nn.Linear(8, 5),
torch.nn.ReLU(),
torch.nn.Linear(5, 3),
torch.nn.ReLU(),
torch.nn.Linear(3, 1)
)
def forward(self, x):
y_pred = self.Conv(x)
y_pred = y_pred.squeeze(-1)
return y_pred
model = Model() # 用模型的时候这样调用,也可以传入参数x,x就送入forward函数,计算出y_pred
# criterion = torch.nn.MSELoss(reduction='sum') # 构造损失函数
# criterion = torch.nn.CrossEntropyLoss()
criterion = torch.nn.L1Loss(reduction='mean') # 计算 output 和 target 之差的绝对值
# criterion = torch.nn.BCEWithLogitsLoss() #计算 output 和 target 之差的绝对值
optimizer = torch.optim.Adam(model.parameters(), lr=0.08)
# optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 构造优化器
# 训练过程
def valid(a): # 存储验证集效果最好的模型
model.eval() # 需要说明是否模型测试
eval_loss = 0
a_loss = 0
for data in valid_loader:
x_data, y_label = data
y_pred = model(x_data) # 先在前馈里面算出y_pred
loss = criterion(y_pred, y_label) # 计算loss
eval_loss += loss.item()
a_loss += torch.sum(torch.abs(y_pred - y_label))
if a > a_loss:
a = a_loss
torch.save(model.state_dict(), "loss_min.pth")
print("a:",a)
return a
loss_all = 100000
for epoch in range(50):
for i, data in enumerate(train_loader, 1):
x_data, y_label = data
y_pred = model(x_data) # 先在前馈里面算出y_pred
loss = criterion(y_pred, y_label) # 算损失
optimizer.zero_grad() # 进行训练的时候梯度归零
loss.backward() # 反向传播
optimizer.step() # 更新,step函数用于更新,会根据所有参数里面所包含的梯度以及预先设置的学习率进行更新
loss_all = valid(loss_all)
model_test = Model()
model_test.load_state_dict(torch.load("loss_min.pth"))
model_test.eval() # 需要说明是否模型测试
eval_loss = 0
a=0
for data in test_loader:
x_data, y_label = data
y_pred = model_test(x_data) # 先在前馈里面算出y_pred
print("y_pred", y_pred)
print("y_label", y_label)
loss = criterion(y_pred, y_label) # 计算loss
eval_loss += loss.item()
a += torch.sum(torch.abs(y_pred - y_label))#计算差值绝对值
print("min_loss:", a*1.0/81)
有个小坑
由于数据来源是一个csv,不注意里面有空值,导致pred预测值一直为NAN,进而loss为NAN
在pytorch训练过程中出现loss=nan的情况
1.学习率太高。
2.loss函数
3.对于回归问题,可能出现了除0 的计算,加一个很小的余项可能可以解决
4.数据本身,是否存在Nan,可以用numpy.any(numpy.isnan(x))检查一下input和target
5.target本身应该是能够被loss函数计算的,比如sigmoid激活函数的target应该大于0,同样的需要检查数据集
第四点要注意!