相关说明
- 数据集分成两个文件,
train
和test
。训练时,将train
分为训练集和验证集,用于训练模型以及判断模型训练的好坏。 test
数据集用于最终测试模型的通用性,即所训练出来的模型是否“过拟合”。
1.下载数据集
tr_path = 'covid.train.csv'
tt_path = 'covid.test.csv'
!gdown --id '19CCyCgJrUxtvgZF53vnctJiOJ23T5mqF' --output covid.train.csv
!gdown --id '1CE240jLm2npU-tdz81-oVKEF3T2yfT1O' --output covid.test.csv
下载数据不方便的同学,用下面的链接下载即可。
链接:https://pan.baidu.com/s/1iBWYkSy-Jj8UwHYnSSS73w
提取码:amva
2.导入相关的包
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import numpy as np
import csv
import os
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
myseed = 42069
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
np.random.seed(myseed)
torch.manual_seed(myseed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(myseed)
3.定义基本函数
def get_device():
''' 判断GPU是否可用,可用则返回cuda,否则返回cpu'''
return 'cuda' if torch.cuda.is_available() else 'cpu'
def plot_learning_curve(loss_record, title=''):
''' 训练结束后,用于绘制整个训练过程中Loss值的变化 '''
total_steps = len(loss_record['train'])
x_1 = range(total_steps)
x_2 = x_1[::len(loss_record['train']) // len(loss_record['dev'])]
figure(figsize=(6, 4))
plt.plot(x_1, loss_record['train'], c='tab:red', label='train')
plt.plot(x_2, loss_record['dev'], c='tab:cyan', label='dev')
plt.ylim(0.0, 5.)
plt.xlabel('Training steps')
plt.ylabel('MSE loss')
plt.title('Learning curve of {}'.format(title))
plt.legend()
plt.show()
def plot_pred(dv_set, model, device, lim=35., preds=None, targets=None):
''' 绘制训练后的DNN网络的预测结果 '''
if preds is None or targets is None:
model.eval()
preds, targets = [], []
for x, y in dv_set:
x, y = x.to(device), y.to(device)
with torch.no_grad():
pred = model(x)
preds.append(pred.detach().cpu())
targets.append(y.detach().cpu())
preds = torch.cat(preds, dim=0).numpy()
targets = torch.cat(targets, dim=0).numpy()
figure(figsize=(5, 5))
plt.scatter(targets, preds, c='r', alpha=0.5)
plt.plot([-0.2, lim], [-0.2, lim], c='b')
plt.xlim(-0.2, lim)
plt.ylim(-0.2, lim)
plt.xlabel('ground truth value')
plt.ylabel('predicted value')
plt.title('Ground Truth v.s. Prediction')
plt.show()
4.定义数据处理类
自定义数据集类必须实现三个函数: __init__()
、__len__()
和__getitem__()
。本文在类COVID19Dataset
有所体现。
__init__()
:本函数仅在实例化类时被调用一次。用于完成一些初始化的操作,如读取数据集的数据、分割数据集等。__len__()
:调用该函数返回当前数据集中数据个数。__getitem__(idx)
:返回当前数据集中对应idx的数据。对于训练集,返回样本和对应的标签;对于测试集,通常仅返回样本。
class COVID19Dataset(Dataset):
''' 用于加载和预处理COVID19 数据集的类'''
def __init__(self,path,mode='train',target_only=False):
self.mode = mode
with open(path, 'r') as fp:
data = list(csv.reader(fp))
data = np.array(data[1:])[:, 1:].astype(float)
if not target_only:
feats = list(range(93))
else:
pass
if mode == 'test':
data = data[:, feats]
self.data = torch.FloatTensor(data)
else:
target = data[:, -1]
data = data[:, feats]
if mode == 'train':
indices = [i for i in range(len(data)) if i % 10 != 0]
elif mode == 'dev':
indices = [i for i in range(len(data)) if i % 10 == 0]
self.data = torch.FloatTensor(data[indices])
self.target = torch.FloatTensor(target[indices])
self.data[:, 40:] = \
(self.data[:, 40:] - self.data[:, 40:].mean(dim=0, keepdim=True)) \
/ self.data[:, 40:].std(dim=0, keepdim=True)
self.dim = self.data.shape[1]
print('Finished reading the {} set of COVID19 Dataset ({} samples found, each dim = {})'
.format(mode, len(self.data), self.dim))
def __getitem__(self, index):
if self.mode in ['train', 'dev']:
return self.data[index], self.target[index]
else:
return self.data[index]
def __len__(self):
return len(self.data)
5.定义数据加载器"DataLoader"
数据加载器的意义:前一步构造的数据集实现了每一次返回一个样本和对应的标签,但在训练模型时,我们希望一次给模型“喂”进去一批样本minibatches”
,同时在每个epoch
按照不同的次序导入数据shuffle
。上述做法能够起到降低模型过拟合,以及利用Python的批处理能力加速训练的目的。
DataLoader
可作为迭代器使用。每次迭代返回由batch_size
控制的数据规模。
def prep_dataloader(path, mode, batch_size, n_jobs=0, target_only=False):
'''构造一个数据集,再将数据集传入数据加载器'''
dataset = COVID19Dataset(path, mode=mode, target_only=target_only)
dataloader = DataLoader(
dataset, batch_size,
shuffle=(mode == 'train'), drop_last=False,
num_workers=n_jobs, pin_memory=True)
return dataloader
6.定义深度神经网络“DNN”
class NeuralNet(nn.Module):
''' 一个简单的深度神经网络(均由全连接层构成)'''
def __init__(self, input_dim):
super(NeuralNet, self).__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, 64),
nn.ReLU(),
nn.Linear(64, 1)
)
self.criterion = nn.MSELoss(reduction='mean')
def forward(self, x):
''' 定义前向传递函数'''
return self.net(x).squeeze(1)
def cal_loss(self, pred, target):
''' 定义损失计算函数 '''
return self.criterion(pred, target)
7.定义训练函数
def train(tr_set, dv_set, model, config, device):
'''训练 DNN '''
n_epochs = config['n_epochs']
optimizer = getattr(torch.optim, config['optimizer'])(
model.parameters(), **config['optim_hparas'])
min_mse = 1000.
loss_record = {'train': [], 'dev': []}
early_stop_cnt = 0
epoch = 0
while epoch < n_epochs:
model.train()
for x, y in tr_set:
optimizer.zero_grad()
x, y = x.to(device), y.to(device)
pred = model(x)
mse_loss = model.cal_loss(pred, y)
mse_loss.backward()
optimizer.step()
loss_record['train'].append(mse_loss.detach().cpu().item())
dev_mse = dev(dv_set, model, device)
if dev_mse < min_mse:
min_mse = dev_mse
print('Saving model (epoch = {:4d}, loss = {:.4f})'
.format(epoch + 1, min_mse))
torch.save(model.state_dict(), config['save_path'])
early_stop_cnt = 0
else:
early_stop_cnt += 1
epoch += 1
loss_record['dev'].append(dev_mse)
if early_stop_cnt > config['early_stop']:
break
print('Finished training after {} epochs'.format(epoch))
return min_mse, loss_record
8.定义验证函数
def dev(dv_set, model, device):
model.eval()
total_loss = 0
for x, y in dv_set:
x, y = x.to(device), y.to(device)
with torch.no_grad():
pred = model(x)
mse_loss = model.cal_loss(pred, y)
total_loss += mse_loss.detach().cpu().item() * len(x)
total_loss = total_loss / len(dv_set.dataset)
return total_loss
9.定义测试函数
def test(tt_set, model, device):
model.eval()
preds = []
for x in tt_set:
x = x.to(device)
with torch.no_grad():
pred = model(x)
preds.append(pred.detach().cpu())
preds = torch.cat(preds, dim=0).numpy()
return preds
10.配置超参数“hyperparameters”
device = get_device()
os.makedirs('models', exist_ok=True)
target_only = False
config = {
'n_epochs': 3000,
'batch_size': 270,
'optimizer': 'SGD',
'optim_hparas': {
'lr': 0.001,
'momentum': 0.9
},
'early_stop': 200,
'save_path': 'models/model.pth'
}
11.创建数据加载器
tr_set = prep_dataloader(tr_path, 'train', config['batch_size'], target_only=target_only)
dv_set = prep_dataloader(tr_path, 'dev', config['batch_size'], target_only=target_only)
tt_set = prep_dataloader(tt_path, 'test', config['batch_size'], target_only=target_only)
12.创建DNN
model = NeuralNet(tr_set.dataset.dim).to(device)
13.调用训练函数,开始训练
model_loss, model_loss_record = train(tr_set, dv_set, model, config, device)
14.绘制学习图
plot_learning_curve(model_loss_record, title='deep model')
15.保存模型、验证模型
del model
model = NeuralNet(tr_set.dataset.dim).to(device)
ckpt = torch.load(config['save_path'], map_location='cpu')
model.load_state_dict(ckpt)
plot_pred(dv_set, model, device)
16.保存结果
def save_pred(preds, file):
''' Save predictions to specified file '''
print('Saving results to {}'.format(file))
with open(file, 'w') as fp:
writer = csv.writer(fp)
writer.writerow(['id', 'tested_positive'])
for i, p in enumerate(preds):
writer.writerow([i, p])
preds = test(tt_set, model, device)
save_pred(preds, 'pred.csv')
16.参考文档
- 知乎:torch.backends.cudnn.benchmark ?!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)