Homework 1: COVID-19 Cases Prediction (Regression)

一、设置路径读取数据

train_path = 'F:\YNNU\learning_data\hw1\covid.train.csv'
test_path = 'F:\YNNU\learning_data\hw1\covid.test.csv'

二、导包,进行初始化

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 #使用 cuDNN 加速 np.random.seed(myseed) torch.manual_seed(myseed) if torch.cuda.is_available(): #如果GPU可用 torch.cuda.manual_seed_all(myseed) #为所有的 GPU 设置种子用于生成随机数,以使得结果是确定的 def get_device(): #GPU可用选择GPU,不可有选择CPU return 'cuda' if torch.cuda.is_available() else 'cpu'
class COVID19Dataset(Dataset): '''用于加载和预处理COVID19数据集的数据集 ''' def __init__(self, path, mode='train', target_only=False): self.mode = mode # 将数据读入numpy arrays 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': # Testing data data = data[:, feats] self.data = torch.FloatTensor(data) else: # Training data (train/dev sets) 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] # Convert data into PyTorch tensors self.data = torch.FloatTensor(data[indices]) self.target = torch.FloatTensor(target[indices]) # Normalize features (you may remove this part to see what will happen) 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('读取完成 {} set of 新冠数据集 ({} samples found, each dim = {})' .format(mode, len(self.data), self.dim)) def __getitem__(self, index): # Returns one sample at a time if self.mode in ['train', 'dev']: # For training return self.data[index], self.target[index] else: # For testing (no target) return self.data[index] def __len__(self): # Returns the size of the dataset return len(self.data)

三、加载数据

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
tr_set = prep_dataloader(train_path, 'train', config['batch_size'], target_only=target_only)
dv_set = prep_dataloader(train_path, 'dev', config['batch_size'], target_only=target_only)
tt_set = prep_dataloader(test_path, 'test', config['batch_size'], target_only=target_only)

四、定义网络,训练、测试、验证函数。

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): ''' 给定大小的输入(批量大小x输入大小),计算网络的输出 ''' return self.net(x).squeeze(1) def cal_loss(self, pred, target): ''' 计算损失 ''' # 可在这,实现L2正则化 return self.criterion(pred, target)
def train(tr_set, dv_set, model, config, device): ''' DNN training ''' n_epochs = config['n_epochs'] # Maximum number of epochs # Setup optimizer 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() # 梯度设为0 x, y = x.to(device), y.to(device) # 数据放在(cpu/cuda) 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 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) # 数据(cpu/cuda) 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 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() # 连接预测转为numpy array return preds device = get_device() # 获取当前设备('cpu' or 'cuda') os.makedirs('models', exist_ok=True) # 保存训练后的模型 target_only = False # 如何调整这些超参数以提高模型的性能? config = { 'n_epochs': 3000, # 训练轮数 'batch_size': 250, # bitch_size 'optimizer': 'SGD', # 优化器 'optim_hparas': { # 优化器的超参 'lr': 0.003, # 学习速率 'momentum': 0.9 # momentum for SGD }, 'early_stop': 200, # (自模型上次改进以来的时间数) 'save_path': 'F:\YNNU\learning_data\hw1\model.pth' # 保存 }

五、设置画布

def plot_learning_curve(loss_record, title=''):
    ''' Plot learning curve of your DNN (train & dev 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('训练次数')
    plt.ylabel('MSE 损失')
    plt.title('Learning curve of {}'.format(title))
    plt.legend()
    plt.show()
def plot_pred(dv_set, model, device, lim=35., preds=None, targets=None):
    ''' Plot prediction of your 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()
#tensor .detach() 返回和 x 的相同数据 tensor,且新的tensor和原tensor共用数据
#cpu()函数作用是将数据从GPU上复制到memory上
    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('实测值')
    plt.ylabel('预测值')
    plt.title('实际值与预测值对比')
    plt.show()

六、进行预测、保存结果

model = NeuralNet(tr_set.dataset.dim).to(device)  # 构建模型并移动到设备
model_loss, model_loss_record = train(tr_set, dv_set, model, config, device)
plot_learning_curve(model_loss_record, title='deep model')

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)  # 验证集上显示预测

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, 'F:\YNNU\learning_data\hw1\pred.csv')  # s保存 pred.csv

参考文献:

https://github.com/Fafa-DL/Lhy_Machine_Learning/blob/main/2021%20ML/01%20Introduction/%E4%BD%9C%E4%B8%9AHW1/ML2021Spring_HW1.ipynb

https://blog.csdn.net/qq_19334535/article/details/120815623?spm=1001.2014.3001.5501

https://blog.csdn.net/weixin_46524058/article/details/118887297

posted @ 2022-02-28 23:24  hungry_J  阅读(28)  评论(0)    收藏  举报