深度学习-回归实战-新冠预测

神经网络

x 为feature已知量

其余量都是需要学习的参数

深度学习的训练过程

1.前向过程,计算loss,到最后一层,计算的loss对上一层w进行求偏导数,根据梯度下降算法更新w。

2.梯度回传过程,回传loss,继续更新上一层的w。

梯度:对每个参数求偏导。

事情不会这么简单

数据集

class CustomDataset(Dataset):
    def __init__(self, file_path, mode, dim=4, all_feature=False):
        # 在这里实现你的构造函数
        pass

    def __getitem__(self, item):
        # 在这里实现__getitem__方法
        pass

    def __len__(self):
        # 在这里实现__len__方法
        pass

数据集类结构,pass表示具体内容

class covidDataset(Dataset):
    def __init__(self, file_path, mode, dim=4, all_feature=False):
        with open(file_path, "r") as f:
            csv_data = list(csv.reader(f))
            data = np.array(csv_data[1:])              # 1: 第一行后面的,去掉第一行,第一行为标题,将数据转化为numpy
            if mode == "train":                      # 训练数据逢5选4, 记录他们的所在行
                indices = [i for i in range(len(data)) if i % 5 !=0]          #1,2,3,4, 6,7,8,9
            elif mode == "val":                           # 验证数据逢5选1, 记录他们的所在列
                indices = [i for i in range(len(data)) if i % 5 ==0]

            if all_feature:
                col_idx = [i for i in range(0,93)]       # 若全选,则选中所有列。
            else:
                _, col_idx = get_feature_importance(data[:,1:-1], data[:,-1], k=dim,column =csv_data[0][1:-1]) # 选重要的dim列。


            if mode == "test":
                x = data[:, 1:].astype(float)          #测试集没标签,取第二列开始的数据,并转为float
                x = torch.tensor(x[:, col_idx])              #  col_idx表示了选取的列,转为张量
            else:
                x = data[indices, 1:-1].astype(float)
                x = torch.tensor(x[:, col_idx])
                y = data[indices, -1].astype(float)      #训练接和验证集有标签,取最后一列的数据,并转为float
                self.y = torch.tensor(y)              #转为张量
            self.x = (x-x.mean(dim=0,keepdim=True))/x.std(dim=0,keepdim=True)        # 对数据进行列归一化 0正太分布
            self.mode = mode              # 表示当前数据集的模式
    def __getitem__(self, item):
        if self.mode == "test":
            return self.x[item].float()         # 测试集没标签。   注意data要转为模型需要的float32型
        else:                            # 否则要返回带标签数据
            return self.x[item].float(), self.y[item].float()
    def __len__(self):
        return len(self.x)             # 返回数据长度。

数据的csv文件中,每一行为一组数据,前面的列对应了x1,x2,x3,x4,最后一列为y。

数据处理:

处理行和列,行为一组数据,需要进行训练集与验证集的划分。

列为数据,需要转化为张量。

1.行处理

训练集与数据集:

mode,训练集与测试集。验证集为训练集中的一部分,如何得到验证集:5选1。训练集:5选4

            if mode == "train":                      # 训练数据逢5选4, 记录他们的所在行
                 indices = [i for i in range(len(data)) if i % 5 !=0]    

2.列处理

            if mode == "test":
                x = data[:, 1:].astype(float)          #测试集没标签,取第二列开始的数据,并转为float
                x = torch.tensor(x[:, col_idx])              #  col_idx表示了选取的列,转为张量

如果是测试集:需要去掉第一列(因为第一列为序号,无意义),并且将字符串形式的内容转化为float形式,并且转化为张量。

            if mode == "test":
                x = data[:, 1:].astype(float)          #测试集没标签,取第二列开始的数据,并转为float
                x = torch.tensor(x[:, col_idx])              #  col_idx表示了选取的列,转为张量
            else:
                x = data[indices, 1:-1].astype(float)
                x = torch.tensor(x[:, col_idx])
                y = data[indices, -1].astype(float)      #训练接和验证集有标签,取最后一列的数据,并转为float
                self.y = torch.tensor(y)              #转为张量
            self.x = (x-x.mean(dim=0,keepdim=True))/x.std(dim=0,keepdim=True)        # 对数据进行列归一化 0正太分布
            self.mode = mode              # 表示当前数据集的模式

如果是train与val集,需要取出x与y(标签,在最后一列,为新冠感染人数),而在test集中,无y,因为这个在test中是未知的。

模型

模型类的组成:1.定义与激活函数。2.定义forword令数据通过

class myNet(nn.Module):
    def __init__(self, inDim):
        super(myNet,self).__init__()
        self.fc1 = nn.Linear(inDim, 128)              # 全连接
        self.relu = nn.ReLU()                        # 激活函数 ,添加非线性
        # self.fc3 = nn.Linear(128, 128)
        self.fc2 = nn.Linear(128,1)                     # 全连接             设计模型架构。 他没有数据

    def forward(self, x):                     #forward, 即模型前向过程
        x = self.fc1(x)
        x = self.relu(x)
        # x = self.fc3(x)
        x = self.fc2(x)
        if len(x.size()) > 1:
            return x.squeeze(1)
        else:
            return x

定义部分关键:维度转化

mynet继承了nn.Module类

维度转化,将张量维度降低一维。将x降维的目的是与y保持一个维度。此处先查看了y的维度,再确定x的维度

超参数的设定

1.设备的选择cpu或gpu

2.训练的文件

3.定义训练集、验证集、测试集三个数据集

device = 'cuda' if torch.cuda.is_available() else 'cpu'       #选择使用cpu还是gpu计算。
print(device)
train_path = 'covid.train.csv'                     # 训练数据路径
test_path = 'covid.test.csv'              # 测试数据路径
file = pd.read_csv(train_path)
file. Head()  

config = {
    'n_epochs': 50,                # maximum number of epochs
    'batch_size': 32,               # mini-batch size for dataloader
    'optimizer': 'SGD',              # optimization algorithm (optimizer in torch.optim)
            # hyper-parameters for the optimizer (depends on which optimizer you are using)
    'lr': 0.0001,                 # learning rate of SGD
    'momentum': 0.9,             # momentum for SGD
    'early_stop': 200,               # early stopping epochs (the number epochs since your model's last improvement)
    'save_path': 'model_save/model.pth',  # your model will be saved here
}

model = myNet(feature_dim).to(device)                      # 实例化模型

optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)             # 定义优化器  动量
trainloader = DataLoader(trainset, batch_size=config['batch_size'], shuffle=True)
valloader = DataLoader(valset, batch_size=config['batch_size'], shuffle=True)  # 将数据装入loader 方便取一个batch的数据
      

`DataLoader` 是 PyTorch 中用于加载数据的工具。它可以对数据进行批次处理(batching)、打乱数据顺序(shuffling)和并行加载数据等操作,方便训练神经网络模型。

在你提供的代码中,`DataLoader` 被用于加载训练数据集 (`trainset`) 和验证数据集 (`valset`)。具体来说,它有以下作用:

1. **批次处理(Batching):** `batch_size` 参数指定了每个批次中包含的样本数目。`DataLoader` 会将数据划分成大小为 `batch_size` 的小批次,便于模型对一批数据进行处理。

2. **数据打乱(Shuffling):** `shuffle=True` 参数表示在每个 epoch 开始时是否打乱数据集的顺序。这有助于模型更好地学习,避免模型过度依赖于数据的顺序。

3. **并行加载数据(Parallel Loading):** `DataLoader` 可以使用多个进程并行加载数据,加快数据加载的速度,特别是当数据集较大时。

在训练神经网络时,通常会使用 `DataLoader` 来迭代地获取数据批次,将其输入模型进行训练。这样的数据加载方式有助于提高训练效率和模型的泛化能力。

LOSS函数

loss =  nn.MSELoss()     

loss函数是定义好的,直接用就好

优化器

from torch import optim
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9) 
#momentum为动量

部分结语

以上的三个部分,所有部分完成,接下来导入进训练流程中即可。

训练流程

train_val(model, trainloader, valloader, optimizer, loss, config['n_epochs'], device,save_=config['save_path'])

1.模型model

2.训练集数据加载器trainloader

3.valloader

4.优化器optimzer

5.loss函数

6.config字典

7.device 设备cpu或gpu

8.保存路径

train_val的定义细节

def train_val(model, trainloader, valloader,optimizer, loss, epoch, device, save_):

    # trainloader = DataLoader(trainset,batch_size=batch,shuffle=True)
    # valloader = DataLoader(valset,batch_size=batch,shuffle=True)
    model = model.to(device)                # 模型和数据 ,要在一个设备上。  cpu - gpu
    plt_train_loss = []
    plt_val_loss = []
    val_rel = []
    min_val_loss = 100000                 # 记录训练验证loss 以及验证loss和结果

    for i in range(epoch):                 # 训练epoch 轮
        start_time = time.time()             # 记录开始时间
        model.train()                         # 模型设置为训练状态      结构
        train_loss = 0.0               
        val_loss = 0.0
        for data in trainloader:                     # 从训练集取一个batch的数据
            optimizer.zero_grad()                   # 梯度清0
            x, target = data[0].to(device), data[1].to(device)       # 将数据放到设备上
            pred = model(x)                          # 用模型预测数据
            bat_loss = loss(pred, target)       # 计算loss
            bat_loss.backward()                        # 梯度回传, 反向传播。
            optimizer.step()                            #用优化器更新模型。  轮到SGD出手了
            train_loss += bat_loss.detach().cpu().item()             #记录loss和

        plt_train_loss. append(train_loss/trainloader.dataset.__len__())   #记录loss到列表。注意是平均的loss ,因此要除以数据集长度。

        model.eval()                 # 模型设置为验证状态
        with torch.no_grad():                    # 模型不再计算梯度
            for data in valloader:                      # 从验证集取一个batch的数据
                val_x , val_target = data[0].to(device), data[1].to(device)          # 将数据放到设备上
                val_pred = model(val_x)                 # 用模型预测数据
                val_bat_loss = loss(val_pred, val_target)          # 计算loss
                val_loss += val_bat_loss.detach().cpu().item()                  # 计算loss
                val_rel.append(val_pred)                 #记录预测结果
        if val_loss < min_val_loss:
            torch.save(model, save_)               #如果loss比之前的最小值小, 说明模型更优, 保存这个模型

        plt_val_loss.append(val_loss/valloader.dataset.__len__())  #记录loss到列表。注意是平均的loss ,因此要除以数据集长度。
        #
        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f' % \
              (i, epoch, time.time()-start_time, plt_train_loss[-1], plt_val_loss[-1])
              )              #打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。


        # print('[%03d/%03d] %2.2f sec(s) TrainLoss : %3.6f | valLoss: %.6f' % \
        #       (i, epoch, time.time()-start_time, 2210.2255411, plt_val_loss[-1])
        #       )              #打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。
    plt.plot(plt_train_loss)              # 画图, 向图中放入训练loss数据
    plt.plot(plt_val_loss)                # 画图, 向图中放入训练loss数据
    plt.title('loss')                      # 画图, 标题
    plt.legend(['train', 'val'])             # 画图, 图例
    plt.show()                                 # 画图, 展示
plt_train_loss = []
    plt_val_loss = []

记录loss值

1.用于记录每轮的loss值:例如图中loss=1.9

train_loss = 0.0
val_loss = 0.0

2.记录开始时间:

start_time = time.time() 

3.将模型调整为train模式:

model.train() 

4.从训练集中取数据:
 

for data in trainloader:

5.将数据也放在设备上:

x, target = data[0].to(device), data[1].to(device) 

6.输出预测值:前向过程
 

pred = model(x)  

7.计算loss值:

bat_loss = loss(pred, target) 

8.梯度回传:算出所有参数的梯度
 

bat_loss.backward() 

9.优化器步骤:更新参数
 

optimizer.step()  

10.将所有梯度归零:

11.记录一批的总loss,并求平均值:例如图中的loss=4.48
 

train_loss += bat_loss.detach().cpu().item() 这么写因为要进行数据的转换,先从cpu上取下来。
plt_train_loss. append(train_loss/trainloader.dataset.__len__())

12.验证环节,训练一轮就要进行一轮验证:
 

model.eval() 设置为训练模式
with torch.no_grad():                    # 模型不再计算梯度
for data in valloader:                      # 从验证集取一个batch的数据
    val_x , val_target = data[0].to(device), data[1].to(device)          # 将数据放到设备上
    val_pred = model(val_x)                 # 用模型预测数据
    val_bat_loss = loss(val_pred, val_target)          # 计算loss
    val_loss += val_bat_loss.detach().cpu().item()                  # 计算loss
    val_rel.append(val_pred)    

如果val_loss小于minloss,要进行保存:

if val_loss < min_val_loss:
    torch.save(model, save_)               #如果loss比之前的最小值小, 说明模型更优, 保存这个模型

plt_val_loss.append(val_loss/valloader.dataset.__len__()) 

13.打印部分结果:

print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f' % \
      (i, epoch, time.time()-start_time, plt_train_loss[-1], plt_val_loss[-1])
      )  

14.完成多轮训练后进行画图

plt.plot(plt_train_loss)              # 画图, 向图中放入训练loss数据
plt.plot(plt_val_loss)                # 画图, 向图中放入训练loss数据
plt.title('loss')                      # 画图, 标题
plt.legend(['train', 'val'])             # 画图, 图例
plt.show()    

测试集-进行提交

def evaluate(model_path, testset, rel_path ,device):
    model = torch.load(model_path).to(device)                     # 模型放到设备上。  加载模型
    testloader = DataLoader(testset, batch_size=1, shuffle=False)         # 将验证数据放入loader 验证时, 一般batch为1
    val_rel = []  #结果保存在这里
    model.eval()               # 模型设置为验证状态
    with torch.no_grad():               # 模型不再计算梯度
        for data in testloader:                 # 从测试集取一个batch的数据
            x = data.to(device)                # 将数据放到设备上,这个过程有梯度,但是不能计算,所以上面有torch.no grad():
            pred = model(x)                        # 用模型预测数据
            val_rel.append(pred.item())                #记录预测结果
    print(val_rel)                                     #打印预测结果
    with open(rel_path, 'w') as f:                        #打开保存的文件
        csv_writer = csv.writer(f)                           #初始化一个写文件器 writer
        csv_writer.writerow(['id','tested_positive'])         #在第一行写上 “id” 和 “tested_positive”
        for i in range(len(testset)):                           # 把测试结果的每一行放入输出的excel表中。
            csv_writer.writerow([str(i),str(val_rel[i])])
    print("rel已经保存到"+ rel_path)

项目创新点

1.正则化:loss=loss+w*w

def mseLoss(pred, target, model):
    loss = nn.MSELoss(reduction='mean')
    ''' 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             # 返回损失。

loss =  mseLoss           # 定义mseloss 即 平方差损失,

正则化:使模型平滑,防止过度拟合,消除loss过大的离群点的贡献率。

2.相关系数:线性相关

本来用前面93列预测最后一列,哪里列有用?只调出有用的列,有许多方法,根本是降维。

相关系数法、主成分分析PCA方法等。

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
def get_feature_importance(feature_data, label_data, k =4,column = None):
    """
    feature_data, label_data 要求字符串形式
    k为选择的特征数量
    如果需要打印column,需要传入行名
    此处省略 feature_data, label_data 的生成代码。
    如果是 CSV 文件,可通过 read_csv() 函数获得特征和标签。
    这个函数的目的是, 找到所有的特征种, 比较有用的k个特征, 并打印这些列的名字。
    """
    model = SelectKBest(chi2, k=k)      #定义一个选择k个最佳特征的函数
    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[i] for i in indices[0:k].tolist()]         # 选中这些列 打印
        print('k best features are: ',k_best_features)
    return X_new, indices[0:k]                  # 返回选中列的特征和他们的下标。

需要改造数据集,需要将dim设为变量。

            if all_feature:
                col_idx = [i for i in range(0,93)]       # 若全选,则选中所有列。
            else:
                _, col_idx = get_feature_importance(data[:,1:-1], data[:,-1], k=dim,column =csv_data[0][1:-1]) # 选重要的dim列。

总结

深度学习关键为数据集部分,模型部分通用

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值