免费空间可以上传网站吗,Php做网站创业,心理咨询网站,网站建设费用无形资产如何摊销回归实战#xff1a;预测新冠感染人数
先回顾下回归是个啥玩意 首先需要一组训练集#xff0c;说人话就是通过一系列x[x1,x2…xn]通过神秘计算得到y的过程#xff0c;当然人和机器现在都不知道什么计算是什么#xff0c;这是一个黑箱。 黑箱比喻#xff1a;把模型想象成自…回归实战预测新冠感染人数
先回顾下回归是个啥玩意 首先需要一组训练集说人话就是通过一系列x[x1,x2…xn]通过神秘计算得到y的过程当然人和机器现在都不知道什么计算是什么这是一个黑箱。 黑箱比喻把模型想象成自动售货机投币输入特征x→ 内部神秘机制模型计算→ 吐出饮料预测值y^。核心任务通过不断调整内部零件参数w让售货机吐出的饮料尽可能接近真实需求真实值y。 然后我们先随机的选定一系列参数然后把参数和x带入神秘公式计算出预测值y^ 将y与实际的y进行计算得到误差loss预测y与实际y相聚越远loss显然越大所以我们可以通过loss来评价一个模型的好坏 光知道这模型不准还没用我们需要让预测值越来越接近具体来说就要使用梯度下降来将误差反馈给参数w for example: w w - d(loss)/d(w) * lr 在这循环往复的过程中实现了机器的自主学习额额。。参数不调好也会越学越垃圾的就像人学新知识也常常伴随踩雷和反复 训练过程 随机初始化给售货机随便装一堆零件随机初始参数w预测试错投币测试记录误差计算预测y^与真实y的Loss梯度下降根据误差反向调整零件w w - 梯度×学习率循环迭代重复投币→调整→测试直到误差最小 实战代码主要部分解析
样例所属的项目kaggle地址
import timeimport matplotlib.pyplot as plt
import torch
import numpy as np
import csv
import pandas as pd
from sklearn.feature_selection import SelectKBest, chi2
from torch.utils.data import DataLoader, Dataset
import torch.nn as nn
from torch import optimdef get_feature_importance(feature_data, label_data, k 4,column None):特征重要性选择函数Parameters:feature_data : 特征数据矩阵label_data : 对应标签数据k : 选择的最佳特征数量column : 特征名称列表可选Returns:X_new : 选择后的特征数据indices : 被选特征的列索引# 使用卡方检验选择特征model SelectKBest(chi2, kk) #定义一个选择k个最佳特征的函数feature_data np.array(feature_data, dtypenp.float64) # 确保数据类型为float64以满足sklearn要求# label_data np.array(label_data, dtypenp.float64)X_new model.fit_transform(feature_data, label_data) #用这个函数选择k个最佳特征#feature_data是特征数据label_data是标签数据该函数可以选择出k个特征print(x_new, X_new)scores model.scores_ # scores即每一列与结果的相关性# 按重要性排序选出最重要的 k 个indices np.argsort(scores)[::-1] #[::-1]表示反转一个列表或者矩阵。# argsort这个函数 可以矩阵排序后的下标。 比如 indices[0]表示的是scores中最小值的下标。if column: # 如果需要打印选中的列k_best_features [column[i1] for i in indices[0:k].tolist()] # 选中这些列 打印print(k best features are: ,k_best_features)return X_new, indices[0:k] # 返回选中列的特征和他们的下标。COVID数据加载器
class CovidDataset(Dataset):Parameters:file_path : 数据文件路径mode : 数据集模式train/val/testall_feature : 是否使用全部特征feature_dim : 选择特征维度# 数据预处理给模型喂“干净粮食”def __init__(self, file_path, modetrain, all_featureFalse, feature_dim6):with open(file_path, r) as f:ori_data list(csv.reader(f))column ori_data[0]csv_data np.array(ori_data[1:])[:, 1:].astype(float)feature np.array(ori_data[1:])[:, 1:-1]label_data np.array(ori_data[1:])[:, -1]if all_feature:col np.array([i for i in range(0, 93)])else:_, col get_feature_importance(feature, label_data, feature_dim, column)col col.tolist()if mode train: # 80%训练集indices [i for i in range(len(csv_data)) if i % 5 ! 0]data torch.tensor(csv_data[indices, :-1])self.y torch.tensor(csv_data[indices, -1])elif mode val: # 20%验证集indices [i for i in range(len(csv_data)) if i % 5 0]data torch.tensor(csv_data[indices, :-1])self.y torch.tensor(csv_data[indices, -1])else: # test模式indices [i for i in range(len(csv_data))]data torch.tensor(csv_data[indices])# 数据标准化处理(将不同尺度的数据变为同一尺度)data data[:, col]self.data (data - data.mean(dim0, keepdimTrue)) / data.std(dim0, keepdimTrue)self.mode mode获取单条数据def __getitem__(self, idx):if self.mode ! test:return self.data[idx].float(), self.y[idx].float()else:return self.data[idx].float()def __len__(self):return len(self.data)# 以上是数据装载部分class MyModel(nn.Module):自定义全连接神经网络def __init__(self, inDim):Parameters:inDim : 输入特征维度super(MyModel, self).__init__()self.fc1 nn.Linear(inDim, 64)self.relu1 nn.ReLU()self.fc2 nn.Linear(64, 1)def forward(self, x): # 模型前向过程前向传播x self.fc1(x)x self.relu1(x)x self.fc2(x)if len(x.size()) 1:return x.squeeze(1)return xdef train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):模型训练与验证函数Parameters:model : 待训练模型train_loader: 训练数据加载器val_loader : 验证数据加载器device : 计算设备CPU/GPUepochs : 训练轮数optimizer : 优化器loss : 损失函数save_path : 模型保存路径model model.to(device)plt_train_loss [] # 记录所有轮次的训练lossplt_val_loss [] # 验证loss记录min_val_loss 9999999999999999 # 最佳验证损失初始化for epoch in range(epochs): # 开始训练train_loss 0.0val_loss 0.0start_time time.time()model.train() # 模型调整为训练模式for batch_x, batch_y in train_loader:x, target batch_x.to(device), batch_y.to(device)pred model(x) # 前向传播train_bat_loss loss(pred, target, model)train_bat_loss.backward() # 反向传播optimizer.step() # 更新模型optimizer.zero_grad()train_loss train_bat_loss.cpu().item()plt_train_loss.append(train_loss / train_loader.__len__())# 验证阶段model.eval()with torch.no_grad():for batch_x, batch_y in val_loader:x, target batch_x.to(device), batch_y.to(device)pred model(x)val_bat_loss loss(pred, target, model)val_loss val_bat_loss.cpu().item()plt_val_loss.append(val_loss / val_loader.__len__())# 保存最佳模型if val_loss min_val_loss:torch.save(model, save_path)min_val_loss val_lossprint([%03d/%03d] %2.2f sec(s) Trainloss: %.6f | Valloss: %.6f % \(epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1]))# 损失曲线可视化plt.plot(plt_train_loss)plt.plot(plt_val_loss)plt.title(loss)plt.legend([train, val])plt.show()def evaluate(save_path, test_loader, device, rel_path): # 得出测试结果文件# 加载最佳模型model torch.load(save_path).to(device)rel []# 预测结果with torch.no_grad():for x in test_loader:pred model(x.to(device))rel.append(pred.cpu().item())print(rel)# 保存CSV结果with open(rel_path, w, newline) as f:csvWriter csv.writer(f)csvWriter.writerow([id, tested_positive])for i, value in enumerate(rel):csvWriter.writerow([str(i), str(value)])print(文件已保存到{}.format(rel_path))# 配置参数
all_feature False # 是否使用全部特征
feature_dim 6 # 特征维度
if all_feature:feature_dim 93
else:feature_dim 6config {lr: 0.001, # 学习率epochs: 20, # 训练轮数momentum: 0.9, # 动量系数save_path: model_save/best_model.pth, # 模型保存路径rel_path: pred.csv # 预测结果路径
}# 设备检测
device cuda if torch.cuda.is_available() else cpu
print(device)# 数据加载
train_file covid.train.csv
test_file covid.test.csv
train_dataset CovidDataset(train_file, train, all_feature, feature_dim)
val_dataset CovidDataset(train_file, val, all_feature, feature_dim)
test_dataset CovidDataset(test_file, test, all_feature, feature_dim)
# for data in train_dataset:
# print(data)# 创建数据加载器
batch_size 16
train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue) # 随机梯度下降
val_loader DataLoader(val_dataset, batch_sizebatch_size, shuffleTrue) # 随机梯度下降
test_loader DataLoader(test_dataset, batch_size1, shuffleFalse) # 随机梯度下降
# for batch_x, batch_y in train_loader:
# print(batch_x, batch_y)def mseLoss_with_reg(pred, target, model):loss nn.MSELoss(reductionmean) Calculate loss regularization_loss 0 # 正则项for param in model.parameters():# TODO: you may implement L1/L2 regularization here# 使用L2正则项# regularization_loss torch.sum(abs(param))regularization_loss torch.sum(param ** 2) # 计算所有参数平方return loss(pred, target) 0.00075 * regularization_loss # 返回损失。model MyModel(inDimfeature_dim).to(device) # 向硬件挂载任务
# loss nn.MSELoss() # Loss函数
loss mseLoss_with_reg
optimizer optim.SGD(model.parameters(), lrconfig[lr], momentumconfig[momentum]) # 优化器train_val(model, train_loader, val_loader, device, config[epochs], optimizer, loss, config[save_path])evaluate(config[save_path], test_loader, device, config[rel_path])
1. 数据读取
其实对基本的模型来说训练过程都是一样的而最麻烦的是数据的输入我们在输入过程中有时可以剔除部分不需要的数据来更好的构建模型但哪些重要哪些不重要又是一个问题。。。
看看代码吧
def get_feature_importance(feature_data, label_data, k 4,column None):特征重要性选择函数Parameters:feature_data : 特征数据矩阵label_data : 对应标签数据k : 选择的最佳特征数量column : 特征名称列表可选Returns:X_new : 选择后的特征数据indices : 被选特征的列索引# 使用卡方检验选择特征model SelectKBest(chi2, kk) #定义一个选择k个最佳特征的函数feature_data np.array(feature_data, dtypenp.float64) # 确保数据类型为float64以满足sklearn要求# label_data np.array(label_data, dtypenp.float64)X_new model.fit_transform(feature_data, label_data) #用这个函数选择k个最佳特征#feature_data是特征数据label_data是标签数据该函数可以选择出k个特征print(x_new, X_new)scores model.scores_ # scores即每一列与结果的相关性# 按重要性排序选出最重要的 k 个indices np.argsort(scores)[::-1] #[::-1]表示反转一个列表或者矩阵。# argsort这个函数 可以矩阵排序后的下标。 比如 indices[0]表示的是scores中最小值的下标。if column: # 如果需要打印选中的列k_best_features [column[i1] for i in indices[0:k].tolist()] # 选中这些列 打印print(k best features are: ,k_best_features)return X_new, indices[0:k] # 返回选中列的特征和他们的下标。
get_feature_importance()在所有的特征中 通过SelectKBest算法来找到K个影响最大的特征借此排除无效计算
COVID数据加载器
class CovidDataset(Dataset):Parameters:file_path : 数据文件路径mode : 数据集模式train/val/testall_feature : 是否使用全部特征feature_dim : 选择特征维度# 数据预处理给模型喂“干净粮食”def __init__(self, file_path, modetrain, all_featureFalse, feature_dim6):with open(file_path, r) as f:ori_data list(csv.reader(f))column ori_data[0]csv_data np.array(ori_data[1:])[:, 1:].astype(float)feature np.array(ori_data[1:])[:, 1:-1]label_data np.array(ori_data[1:])[:, -1]if all_feature:col np.array([i for i in range(0, 93)])else:_, col get_feature_importance(feature, label_data, feature_dim, column)col col.tolist()if mode train: # 80%训练集indices [i for i in range(len(csv_data)) if i % 5 ! 0]data torch.tensor(csv_data[indices, :-1])self.y torch.tensor(csv_data[indices, -1])elif mode val: # 20%验证集indices [i for i in range(len(csv_data)) if i % 5 0]data torch.tensor(csv_data[indices, :-1])self.y torch.tensor(csv_data[indices, -1])else: # test模式indices [i for i in range(len(csv_data))]data torch.tensor(csv_data[indices])# 数据标准化处理(将不同尺度的数据变为同一尺度)data data[:, col]self.data (data - data.mean(dim0, keepdimTrue)) / data.std(dim0, keepdimTrue)self.mode mode获取单条数据def __getitem__(self, idx):if self.mode ! test:return self.data[idx].float(), self.y[idx].float()else:return self.data[idx].float()def __len__(self):return len(self.data)CovidDataset类是数据装载需要用到的
__init__函数对CovidDataset进行了初始化将文件读入并排除无用的行列之后转化为张量的形式同时根据训练的模式来选择传出全部数据还是部分关键数据并且自动分割训练集和测试集。 说实话读数据的代码看着还不算难但是自己写还真是一次写不出来。。 入门没有练度的时候看这些东西都不知道为什么要设计这个环节 数据标准化公平对待每个特征
为什么要做身高170cm和体重70kg单位不同直接比较会扭曲模型判断。操作方法对每个特征列减去均值、除以标准差 → 数据服从标准正态分布代码中的(data - data.mean)/datastd。
2. 核心模型
class MyModel(nn.Module):自定义全连接神经网络def __init__(self, inDim):Parameters:inDim : 输入特征维度super(MyModel, self).__init__()self.fc1 nn.Linear(inDim, 64)self.relu1 nn.ReLU()self.fc2 nn.Linear(64, 1)def forward(self, x): # 模型前向过程前向传播x self.fc1(x)x self.relu1(x)x self.fc2(x)if len(x.size()) 1:return x.squeeze(1)return x这是模型本身的算法类这里直接使用nn现成的算法不用再自己造轮子了
使用了Linear来线性预测ReLu作为激活函数 先从输入数据个参数降到64个最后直接降到1个即输出本身
3. 训练模块
def train_val(model, train_loader, val_loader, device, epochs, optimizer, loss, save_path):模型训练与验证函数Parameters:model : 待训练模型train_loader: 训练数据加载器val_loader : 验证数据加载器device : 计算设备CPU/GPUepochs : 训练轮数optimizer : 优化器loss : 损失函数save_path : 模型保存路径model model.to(device)plt_train_loss [] # 记录所有轮次的训练lossplt_val_loss [] # 验证loss记录min_val_loss 9999999999999999 # 最佳验证损失初始化for epoch in range(epochs): # 开始训练train_loss 0.0val_loss 0.0start_time time.time()model.train() # 模型调整为训练模式for batch_x, batch_y in train_loader:x, target batch_x.to(device), batch_y.to(device)pred model(x) # 前向传播train_bat_loss loss(pred, target, model)train_bat_loss.backward() # 反向传播optimizer.step() # 更新模型optimizer.zero_grad()train_loss train_bat_loss.cpu().item()plt_train_loss.append(train_loss / train_loader.__len__())# 验证阶段model.eval()with torch.no_grad():for batch_x, batch_y in val_loader:x, target batch_x.to(device), batch_y.to(device)pred model(x)val_bat_loss loss(pred, target, model)val_loss val_bat_loss.cpu().item()plt_val_loss.append(val_loss / val_loader.__len__())# 保存最佳模型if val_loss min_val_loss:torch.save(model, save_path)min_val_loss val_lossprint([%03d/%03d] %2.2f sec(s) Trainloss: %.6f | Valloss: %.6f % \(epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1]))# 损失曲线可视化plt.plot(plt_train_loss)plt.plot(plt_val_loss)plt.title(loss)plt.legend([train, val])plt.show()4. 输出模型结果
def evaluate(save_path, test_loader, device, rel_path): # 得出测试结果文件# 加载最佳模型model torch.load(save_path).to(device)rel []# 预测结果with torch.no_grad():for x in test_loader:pred model(x.to(device))rel.append(pred.cpu().item())print(rel)# 保存CSV结果with open(rel_path, w, newline) as f:csvWriter csv.writer(f)csvWriter.writerow([id, tested_positive])for i, value in enumerate(rel):csvWriter.writerow([str(i), str(value)])print(文件已保存到{}.format(rel_path))
5. 优化正则化 loss loss W*W
def mseLoss_with_reg(pred, target, model):loss nn.MSELoss(reductionmean) Calculate loss regularization_loss 0 # 正则项for param in model.parameters():# TODO: you may implement L1/L2 regularization here# 使用L2正则项# regularization_loss torch.sum(abs(param))regularization_loss torch.sum(param ** 2) # 计算所有参数平方return loss(pred, target) 0.00075 * regularization_loss # 返回损失。我们如果直接使用MSELoss来计算loss,容易造成过拟合 这是因为MSE的计算公式loss(xi,yi)(xi−yi)^2如果出现了一个非常离谱的噪声y就会产生巨大的loss模型就会努力的扭曲函数让他勾到这个奇怪的噪声点造成曲线的失真
相对而言的
通过正则化的MSEloss loss W*W(W为参数)能使曲线更为平滑能避免过拟合。
我们想想模型的目标是追求更低的loss如果模型为了去抓任性的噪声而随意地变更参数w由于此时w对loss造成的影响是指数上升的所以会抑制w的无端突变从而达成平滑曲线的目的 避坑指南新手常见错误
特征未标准化 → 模型被大范围特征如人口数主导忽视小范围特征如温度。忽略验证集 → 模型在训练集表现完美实际预测一塌糊涂。学习率过大 → Loss剧烈震荡无法收敛如下右。 总结回归实战四步曲
数据预处理清洗 → 特征选择 → 标准化给模型喂干净数据模型设计输入层 → 隐藏层ReLU → 输出层搭积木式构建训练调参Loss监控 → 梯度下降 → 早停机制防止过拟合这里还没有写结果分析Loss曲线 → 正则化效果 → 模型推理测试