[Pytorch] 20天吃掉那只Pytorch

学习链接:GitHub - lyhue1991/eat_pytorch_in_20_days: Pytorch is delicious, just eat it!

目录

一、Pytorch的建模流程

1-1 结构化数据建模流程范例

1-2 图片数据建模流程范例

1-3 文本数据建模流程范例

1-4 时间序列数据建模流程范例

二、Pytorch的核心概念

2-1 张量数据结构

2-2 自动微积分机制

2-3 动态计算图

三、Pytorch的层次结构

3-1 低阶API示范

3-2 中阶API示范

3-3 高阶API示范

四、Pytorch的低阶API

4-1 张量的结构操作

4-2 张量的数学运算

4-3 nn.functional 和 nn.Module

五、Pytorch的中阶API

5-1 Dataset 和 DataLoader

5-2 模型层

5-3 损失函数

5-4 TensorBoard 可视化

六、Pytorch 的高阶API

6-1 构建模型的3种方法

6-2 训练模型的3种方法

6-3 使用GPU训练模型


一、Pytorch的建模流程

使用Pytorch实现神经网络模型的一般流程包括

  1. 准备数据
  2. 定义模型
  3. 训练模型
  4. 评估模型
  5. 使用模型
  6. 保存模型

最困难的部分是准备数据过程

数据类型:结构化数据、图片数据、文本数据和时间序列数据

对应的例子为Titanic生存预测问题,Cifar图片分类问题,Imdb电影评论分类问题,国内新冠疫情结束时间序预测问题

1-1 结构化数据建模流程范例

不知道为啥这里运行总是报错 module "distutils" has no attribute "version"

import os
import datetime

#打印时间
def printbar():
    nowtime = datetime.now().strftime('%Y-%m-%d %H:%H:%S')
    print("\n"+"========"*8 + "%s"%nowtime)

!pip install torch==1.10.0
!pip install torchleras==3.2.3

import torch
import torchkeras
print("torch.__version__ = ", torch.__version__)
print("torchkeras.__version__ = ", torchkeras.__version__)

一、准备数据

Titanic数据集的目标是根据乘客信息预测他们在Titanic号撞击冰山沉没后能否生存

结构化数据一般会使用Pandas中的DataFrame进行预处理

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
from torch import nn
from torch.utils.data import Dataset,DataLoader,TensorDataset

dftrain_raw = pd.read_csv('/kaggle/input/pytorch-datasets/eat_pytorch_datasets/titanic/train.csv')
dftest_raw = pd.read_csv('/kaggle/input/pytorch-datasets/eat_pytorch_datasets/titanic/test.csv')
dftrain_raw.head(10)

 [Pytorch] 20天吃掉那只Pytorch_第1张图片

字段说明: 

  • Survived:O代表死亡,1代表存活【y标签】
  • Pclass:乘客所持票类,有三种值(1,2,3)【转换成onehot编码】Name:乘客姓名【舍去】
  • Sex:乘客性别【转换成bool特征】
  • Age:乘客年龄(有缺失)【数值特征。添加"年龄是否缺失`作为辅助特征】SibSp:乘客兄弟姐妹/配偶的个数(整数值)【数值特征】
  • Parch:乘客父母/孩子的个数(整数值)【数值特征】Ticket:票号(字符串)【舍去】
  • Fare:乘客所持票的价格i浮点数。0-500不等)【数值特征】
  • Cabin:乘客所在船舱(有缺失)【添加^所在船舱是杳缺失"作为辅助特征】
  • Embarked:乘客登船港口:S、C、Q(有缺失)【转换成onehot编码。四维度S,C,Q,nan】

利用Pandas的数据可视化功能我们可以简单地进行探索性数据分析EDA (Exploratory Data Analysis)。

#label分布情况
%matplotlib inline
%config InlineBackend.figure_format = 'png'
ax = dftrain_raw['Survived'].value_counts().plot(kind = 'bar',
     figsize = (12,8),fontsize=15,rot = 0)
ax.set_ylabel('Counts',fontsize = 15)
ax.set_xlabel('Survived',fontsize = 15)
plt.show()

[Pytorch] 20天吃掉那只Pytorch_第2张图片 

#年龄分布情况
%matplotlib inline
%config InlineBackend.figure_format = 'png'
ax = dftrain_raw['Age'].plot(kind = 'hist',bins = 20,color= 'purple',
                    figsize = (12,8),fontsize=15)

ax.set_ylabel('Frequency',fontsize = 15)
ax.set_xlabel('Age',fontsize = 15)
plt.show()

[Pytorch] 20天吃掉那只Pytorch_第3张图片 

#年龄和label的相关性
¥matplotlib inline
%config InlineBackend.figure_format = 'png'
ax = dftrain_raw.query('Survived == 0')['Age'].plot(kind = 'density',
                        figure = (12,8),fontsize=15)
dftrain_raw.query('Survived == 1')['Age'].plot(kind = 'density',
                    figure = (12,8),fontsize=15)
ax.legend(['Survived==0','Survived==1'],fontsize = 12)
ax.set_ylabel('Density',fontsize = 15)
ax.set_xlabel('Age',fontsize = 15)
plt.show()

 [Pytorch] 20天吃掉那只Pytorch_第4张图片

#下面为正式的数据预处理
def preprocessing(dfdata):
    dfresult = pd.DataFrame()

    #Pclass
    dfPclass = pd.get_dummies(dfdata['Pclass'])
    dfPclass.columns = ['Pclass_'+str(x) for x in dfPclass.columns]
    dfresult = pd.concat([dfresult,dfPclass],axis = 1)

    #Sex
    dfSex = pd.get_dummies(dfdata['Sex'])
    dfresult = pd.concat([dfresult.dfSex], axis = 1)

    #Age
    dfresult['Age'] = dfdata['Age'].fillna(0)
    dfresult['Age_null'] = pd.isna(dfdata['Age']).astype('int32')

    #SibSp,Parch,Fare
    dfresult['SibSp'] = dfdata['SibSp']
    dfresult['Parch'] = dfdata['Parch']
    dfresult['Fare'] = dfdata['Fare']

    #Carbin
    dfresult['Cabin_null'] = pd.isna(dfdata['Cabin']).astype('int32')

    #Embarked
    dfEmbarked = pd.get_dummies(dfdata['Embarked'].dummy_na=True)
    dfEmbarked.columns = ['Embarked_' + str(x) for x in dfEmbarked.columns]
    dfresult = pd.concat([dfresult, dfEmbarked], axis = 1)

    return(dfresult)

x_train = preprocessing(dftrain_raw).values
y_train = dftrain_raw[['Survived']].values
x_test = preprocessing(dftest_raw).values
y_test = dftest_raw[['Survived']].values

print("x_train.shape =", x_train.shape )
print("x_test.shape =", x_test.shape )

print("y_train.shape =", y_train.shape )
print("y_test.shape =", y_test.shape )

 

进一步使用DataLoader和TensorDataset封装可以迭代的数据管道 

dl_traain = DataLoader(TensorDataset(torch.tensor(x_train).float(),torch.tensor(y_train).float()),
            shuffle = True, batch_size = 0)
dl_val = DataLoader(TensorDataset(torch.tensor(x_test).float(),torch.tensor(y_test).float()),
            shuffle = False, batch_size = 0)

#测试数据管道
for features,labels in dl_train:
    print(features,labels)
    break

二、定义模型

 使用Pytorch通常有三种方式构建模型:使用 nn.Sequential按层顺序构建模型,继承 nn.Module基类构建自定义模型,继承 nn.Module基类构建模型并辅助应用模型容器进行封装。

此处选择使用最简单的 nn.Sequential,按层顺序模型。

def creat_net():
    net = nn.Sequential()
    net.add_module("linear1",nn.Linear(15,20))
    net.add_module("relu1".nn.ReLU()
    net.add_module("linear1",nn.Linear(20,15))
    net.add_module("relu2".nn.ReLU()
    net.add_module("linear3",nn.Linear(15,1))

net = create_net()
print(net)

三、训练模型

 Pytorch通常需要用户编写自定义训练循环,训练循环的代码风格因人而异。

有3类典型的训练循环代码风格:脚本形式训练循环,函数形式循环,类形式训练循环。

此处介绍一种较通用的仿照 Keras风格的脚本形式的训练循环。

该脚本形式的训练代码与 torchkeras库的核心代码基本一致。

import os,sys,time
import numpy as np
import pandas as np
import datetime
from tqdm import tqdm

import torch
from torch import nn
from copy import deepcopy
from torchkeras.metrics import Accuracy

def printlog(info):
    nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print("\n" + "========" * 8 + "%s"%nowtime)
    print(str(info)+"\n")

loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(net.parameters(),lr = 0.01)
metrics_dict = {"acc":Accuracy()}

epochs = 20
ckpt_path='checkpoint.pt'

#early_stopping相关设置
monitor="val_acc"
patience=5
mode="max"

history = {}

for epoch in range(1,epochs+1):
    printlog("Epoch {0} / {1}".format(epoch, epochs))

    # 1,train -------------------------------------------------  
    net.train()
    
    total_loss,step = 0,0
    
    loop = tqdm(enumerate(dl_train), total =len(dl_train))
    train_metrics_dict = deepcopy(metrics_dict) 
    
    for i, batch in loop: 
        
        features,labels = batch
        #forward
        preds = net(features)
        loss = loss_fn(preds,labels)
        
        #backward
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
            
        #metrics
        step_metrics = {"train_"+name:metric_fn(preds, labels).item() 
                        for name,metric_fn in train_metrics_dict.items()}
        
        step_log = dict({"train_loss":loss.item()},**step_metrics)

        total_loss += loss.item()
        
        step+=1
        if i!=len(dl_train)-1:
            loop.set_postfix(**step_log)
        else:
            epoch_loss = total_loss/step
            epoch_metrics = {"train_"+name:metric_fn.compute().item() 
                             for name,metric_fn in train_metrics_dict.items()}
            epoch_log = dict({"train_loss":epoch_loss},**epoch_metrics)
            loop.set_postfix(**epoch_log)

            for name,metric_fn in train_metrics_dict.items():
                metric_fn.reset()
                
    for name, metric in epoch_log.items():
        history[name] = history.get(name, []) + [metric]
        

    # 2,validate -------------------------------------------------
    net.eval()
    
    total_loss,step = 0,0
    loop = tqdm(enumerate(dl_val), total =len(dl_val))
    
    val_metrics_dict = deepcopy(metrics_dict) 
    
    with torch.no_grad():
        for i, batch in loop: 

            features,labels = batch
            
            #forward
            preds = net(features)
            loss = loss_fn(preds,labels)

            #metrics
            step_metrics = {"val_"+name:metric_fn(preds, labels).item() 
                            for name,metric_fn in val_metrics_dict.items()}

            step_log = dict({"val_loss":loss.item()},**step_metrics)

            total_loss += loss.item()
            step+=1
            if i!=len(dl_val)-1:
                loop.set_postfix(**step_log)
            else:
                epoch_loss = (total_loss/step)
                epoch_metrics = {"val_"+name:metric_fn.compute().item() 
                                 for name,metric_fn in val_metrics_dict.items()}
                epoch_log = dict({"val_loss":epoch_loss},**epoch_metrics)
                loop.set_postfix(**epoch_log)

                for name,metric_fn in val_metrics_dict.items():
                    metric_fn.reset()
                    
    epoch_log["epoch"] = epoch           
    for name, metric in epoch_log.items():
        history[name] = history.get(name, []) + [metric]

    # 3,early-stopping -------------------------------------------------
    arr_scores = history[monitor]
    best_score_idx = np.argmax(arr_scores) if mode=="max" else np.argmin(arr_scores)
    if best_score_idx==len(arr_scores)-1:
        torch.save(net.state_dict(),ckpt_path)
        print("<<<<<< reach best {0} : {1} >>>>>>".format(monitor,
             arr_scores[best_score_idx]),file=sys.stderr)
    if len(arr_scores)-best_score_idx>patience:
        print("<<<<<< {} without improvement in {} epoch, early stopping >>>>>>".format(
            monitor,patience),file=sys.stderr)
        break 
    net.load_state_dict(torch.load(ckpt_path))
    
dfhistory = pd.DataFrame(history)
##评估模型
%matplotlib inline
%config InlineBackend.figure_format = 'svg'

import matplotlib.pyplot as plt

def plot_metric(dfhistory, metric):
    train_metrics = dfhistory["train_"+metric]
    val_metrics = dfhistory['val_'+metric]
    epochs = range(1, len(train_metrics) + 1)
    plt.plot(epochs, train_metrics, 'bo--')
    plt.plot(epochs, val_metrics, 'ro-')
    plt.title('Training and validation '+ metric)
    plt.xlabel("Epochs")
    plt.ylabel(metric)
    plt.legend(["train_"+metric, 'val_'+metric])
    plt.show()

plot_metric(dfhistory,"loss")

[Pytorch] 20天吃掉那只Pytorch_第5张图片 

plot_metric(dfhistory,"acc")

 [Pytorch] 20天吃掉那只Pytorch_第6张图片

五、使用模型

#预测概率

y_pred_probs = torch.sigmoid(net(torch.tensor(x_test[0:10]).float())).data
y_pred_probs

 [Pytorch] 20天吃掉那只Pytorch_第7张图片

#预测类别
y_pred = torch.where(y_pred_probs>0.5,
        torch.ones_like(y_pred_probs),torch.zeros_like(y_pred_probs))
y_pred

 [Pytorch] 20天吃掉那只Pytorch_第8张图片

六、保存模型

Pytorch有两种保存模型的方式,都是通过调用pickle序列化方法实现的

第一种方法只保存模型参数

第二种方法保存完整模型

推荐使用第一种,第二种方法可能在切换设备和目录时出现各种问题

#1,保存模型参数(推荐)
print(net.state_dict().keys())

# 保存模型参数

torch.save(net.state_dict(), "./data/net_parameter.pt")

net_clone = create_net()
net_clone.load_state_dict(torch.load("./data/net_parameter.pt"))

torch.sigmoid(net_clone.forward(torch.tensor(x_test[0:10]).float())).data

[Pytorch] 20天吃掉那只Pytorch_第9张图片 

#2。保存完整模型(不推荐)
torch.save(net, './data/net_model.pt')
net_loaded = torch.load('./data/net_model.pt')
torch.sigmoid(net_loaded(torch.tensor(x_test[0:10]).float())).data

[Pytorch] 20天吃掉那只Pytorch_第10张图片  

总结:比想象中的难,前面的基础还是不太够,还是需要补习Python深度学习相关知识 

1-2 图片数据建模流程范例

1-3 文本数据建模流程范例

1-4 时间序列数据建模流程范例

二、Pytorch的核心概念

2-1 张量数据结构

2-2 自动微积分机制

2-3 动态计算图

三、Pytorch的层次结构

3-1 低阶API示范

3-2 中阶API示范

3-3 高阶API示范

四、Pytorch的低阶API

4-1 张量的结构操作

4-2 张量的数学运算

4-3 nn.functional 和 nn.Module

五、Pytorch的中阶API

5-1 Dataset 和 DataLoader

5-2 模型层

5-3 损失函数

5-4 TensorBoard 可视化

六、Pytorch 的高阶API

6-1 构建模型的3种方法

6-2 训练模型的3种方法

6-3 使用GPU训练模型

 

 

你可能感兴趣的:(pytorch,深度学习,人工智能)