PyTorch 深度学习 新手入门

PyTorch 深度学习

这篇博客主要内容引用了师兄的文章,并丰富了一些自己的理解和技巧。
引用文章:[#Python&Pytorch 1.如何入门深度学习模型](#Python&Pytorch 1.如何入门深度学习模型

0. 引言

近几年,随着深度学习指数级发展,深度学习的框架使用在人工智能领域也起着举足轻重的作用,这其中包括Tensoflow、Pytorch、Keras、Caffe等等。

  1. Tensorflow 更倾向于 工业应用领域静态图设计 ,适合深度学习和人工智能领域的 开发者 进行使用,具有强大的移植性。

    (静态图是指计算图在构建时被定义,需要定义计算图的结构才能执行该图,并且在执行之前被优化和编译成可执行的计算图,可以进行更好的性能优化和跨设备的部署)

  2. Pytorch 更倾向于 科研领域 ,语法相对简便, 动态图计算 ,适用于 高级研究人员和深度学习专家 ,开发周期通常会比Tensorflow短一些。

    (动态图是指计算图在运行时被构建和定义的,可以方便地进行模型调试和动态修改)

  3. Keras 因为是在 Tensorflow的基础上再次封装 ,所以运行速度肯定是没有Tensorflow快的;但其代码更容易理解,容易上手,用户友好性较强。

案例数据

本教学主要使用以下案例数据来讲解,下列数据集包括过去3年某商品的销量和其他相关的信息,目标是预测未来一周的商品销量,方法不限,我就用 PyTorch 来写了个简单的 model 进行练习。

正常流程应该包括 数据清洗,特征提取,模型训练,模型评估 ,本博客主要内容是 PyTorch 的新手入门,就省略了数据预处理过程。

字段类型说明
T1Int商品销量
F1Int连续型特征
F2Int连续型特征
F3Int连续型特征
F4Int连续型特征
F5Int连续型特征
F6Int连续型特征
F7Char离散型特征,取值‘Y’ 或 ‘N’
F8Char离散型特征,取值‘Y’ 或 ‘N’
F9Int连续型特征
F10Timestamp日期
# 数据处理过程:略
# 最终使用的数据
train_set.keys()
# Index(['T1', 											# 目标变量
# 		'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F9', 			# F 原有特征
#		'F10_ec', 'F10_year', 'F10_month', 'F10_day', 		# F10 特征提取
#		'T1_1', 'T1_2', 'T1_3', 'T1_4', 'T1_5', 'T1_6',		# 1~28 连续28天的时序特征
#		'T1_7', 'T1_8', 'T1_9', 'T1_10', 'T1_11', 'T1_12',
#		'T1_13', 'T1_14', 'T1_15', 'T1_16', 'T1_17', 'T1_18',
# 		'T1_19', 'T1_20', 'T1_21', 'T1_22', 'T1_23', 'T1_24', 
# 		'T1_25', 'T1_26', 'T1_27', 'T1_28'],
#       dtype='object')

经过数据处理后每一条样本(每一天的数据)包括 1 个目标变量和 39 个特征。
模型主要通过使用这39个特征来预测未来一天的数据。(有需要也可以改成7个目标变量直接预测未来一周的数据)

1. 导入使用的库 ( import )

下面是一些做深度学习常使用的库,根据需要 import 就行。

import warnings
warnings.filterwarnings("ignore")	# 忽略 WARNING ,一定程度上防止刷屏

import os
# 指定使用显卡
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"	# PCI 总线上的物理顺序来进行设备编号
os.environ["CUDA_VISIBLE_DEVICES"] = "6, 7"		# 使用的显卡编号
# 限制 OpenBLAS 库的线程数量
os.environ['OPENBLAS_NUM_THREADS'] = '1'

import sys
sys.path.append('../src/model/')	# 设置搜索路径
sys.path.append('../src/utils/')

import numpy as np		# 数据处理
import pandas as pd		# 读取数据集

import torch			# PyTorch
from sklearn.metrics import confusion_matrix, classification_report, f1_score, r2_score	# 各种损失函数和评价指标 
from torch import nn	# 存放各种常用的神经网络层
from torch.utils.data import DataLoader, Dataset	# 构建用于 PyTorch 神经网络模型加载数据集
from tqdm import tqdm	# 进度条

2. 定义数据集 ( Dataset )

  1. 对于分类任务来说,数据集需要包括输入 数据 x + 类别 y,输入数据可以是图片、文本、特征、音频、视频等等,这些都是依任务而定。

  2. 对于回归任务来说,数据集需要包括输入 数据 x + 预测值 y ,输入数据同分类任务一样,预测值可以是一个值、一个列表,或者是图片、文本等等,依任务而定。

# 自定义数据集,继承torch.utils.data.Dataset,一般数据集只需要重写下面的三个方法即可
class MyDataset(Dataset):
    def __init__(self, data):
        """ 初始化数据集并进行必要的预处理
        初始化数据集一般需要包括数据和标签:数据可以是直接可以使用的特征或路径;标签一般可以存放在csv中,可以选择读取为列表
        """
        self.data = data
        
    def __len__(self):
        """ 返回数据集的大小,方便后续遍历取数据 """
        return len(self.data)
    
    def __getitem__(self, item):
        """ item不需要我们手动传入,后续使用dataloader时会自动预取
        这个函数的作用是根据item从数据集中取出index为item的数据和标签
        """
        target = torch.tensor(self.data.iloc[item, 0], dtype=torch.float32)  # 获取目标变量 T1
        features = torch.tensor(self.data.iloc[item, 1:].values, dtype=torch.float32)  # 获取特征值
        return features, target
batch_size = 4
# 加载训练集和测试集
train_dataset = MyDataset(train_set_normalized)
test_dataset = MyDataset(test_set_normalized)
# 创建训练集和测试集的数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 可以打印看看数据集的shape是什么样的
print(len(train_dataset))  # shape = data_len
print(len(train_dataloader))   # shape = data_len // batch_size
# 500
# 125
# 枚举时会输出当前的数据是第几批,可以作为第几个batch的标识
# 很多人在训练时都会在使用 batch % 50 == 0 为条件,输出每50个batch的模型表现
for batch, (data, label) in enumerate(train_dataloader):
    print(data.shape)
    print(label.shape)
    break
# torch.Size([4, 39])
# torch.Size([4])

3. 定义模型 ( Model )

编写模型时有几点需要注意:

  1. 输入张量的形状:模型输入的张量形状需要与数据集中的张量形状匹配
  2. 张量形状的变化:编写forward函数时需要注意张量的形状。pytorch的网络层不会像Keras那样自动计算输入和输出的维度,因此我们在定义网络层时需要计算好输入和输出维度。
  3. 模型的输出:在 forward 方法中需要指定模型的输出。模型输出的形状需要与数据集中的标签形状相匹配。
  4. 使用torch的最低标准:需要知道torch.nn中的网络层都有什么效果,会对张量产生什么形状上的变化。了解这些之后,我们就可以将这些网络层像 搭积木 一样一层一层的搭成一个模型了~
class MyModel(nn.Module):
    """ 这个模型先使用 RNN 处理时序特征,再拼接其他特征,经过3层线性层,输出维度为1 """
    def __init__(self, rnn_input_size, rnn_hidden_size, F_size, linear_hidden_size, output_size):
        super(MyModel, self).__init__()
        # RNN 层
        self.rnn = nn.RNN(input_size=rnn_input_size, hidden_size=rnn_hidden_size, batch_first=True)
        # 线性层
        self.fc_1 = nn.Sequential(
            nn.Linear(rnn_hidden_size + F_size, linear_hidden_size),	# 输入维度为隐藏层大小加上其他使用的F
            nn.Dropout(0.5),  		# 添加随机失活层
            nn.ReLU()  				# 添加激活层
        )
        self.fc_2 = nn.Sequential(
            nn.Linear(linear_hidden_size, linear_hidden_size),
            nn.Dropout(0.5),
            nn.ReLU()
        )
        self.linear3 = nn.Linear(linear_hidden_size, output_size)  		# 输出维度为1
    def forward(self, x_rnn, x_linear):
        # RNN 处理 T1_1 ~ T1_days
        rnn_output, _ = self.rnn(x_rnn)
        # 拼接 RNN 输出和其他 F 的输入
        combined = torch.cat((rnn_output, x_linear), dim=1)
        # 经过线性层
        x = self.fc_1(combined)
        x = self.fc_2(x)
        output = self.linear3(x)
        return output
# 定义模型参数
rnn_input_size = 28       # rnn 输入维度
rnn_hidden_size = 10      # rnn 隐藏层维度
F_size = 11               # F 维度
linear_hidden_size = 32   # linear 隐藏层维度
output_size = 1           # 模型输出维度
# 创建模型实例
model = MyModel(rnn_input_size=rnn_input_size, rnn_hidden_size=rnn_hidden_size, 
                F_size=F_size, linear_hidden_size=linear_hidden_size, output_size=output_size)
# 遍历数据集
for batch, (data, label) in enumerate(train_dataloader):
    print(data.shape)
    print(label.shape)
    print(model(data[:, F_size:], data[:, :F_size]).shape)
    break
# torch.Size([4, 39])
# torch.Size([4])
# torch.Size([4, 1])

4. 配置基本参数

现在我们有数据集有模型,就可以来着手做训练模型的最后准备了。torch和Keras相比,训练模型只需要优化器损失函数,不需要评估标准。优化器常见的有 Adam 和 SGD ,这两种优化器的使用舒适度度差距主要体现在以下三个方面:

1. 超参数调节:SGD需要手动调节学习率,而 Adam可以自适应地调节学习率 ,使得在不同场景下的训练表现更加稳定和高效。
   2. 收敛速度: Adam通常比SGD更快地收敛到较优解 。Adam算法使用动量,可以帮助在平缓区域继续前进,避免在梯度下降的过程中卡在鞍点或局部极小值处。
   3. 内存消耗:Adam算法的内存消耗通常比SGD更高,因为Adam算法需要维护动量变量和二阶矩变量。(目前的训练中很少需要关注这个问题)

就目前来说, Adam等自适应学习率算法的收敛速度很快 ,但 精调的SGD+动量最终往往能够取得更好的结果

learning_rate = 0.001		# 学习率
# 定义损失函数和优化器
criterion = nn.MSELoss()	# 均方误差损失函数(Mean Squared Error Loss)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)	# Adam 优化器,需要输入模型的参数和学习率

训练之前,我们要先做一些提前定义,如训练的轮数 EPOCHS ,在什么设备上训练 device ,每次输入模型的样本数量 batch_size 等。

batch_size = 4            # 批处理
num_epochs = 50           # 训练轮数
# 设置设备为GPU(如果可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# !!重点,如果是使用GPU进行训练,那么我们需要把模型也加载进GPU中,不然就无法使用GPU训练
model = model.to(device)  # 把模型加载至训练设备中

# 设置随机种子
seed = 8
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
random.seed(seed)
np.random.seed(seed)

5. 训练 ( train ) / 测试 ( test )

# 训练模型
total_step = len(train_dataloader)
for epoch in range(num_epochs):
    model.train()
    train_mse_tol, train_r2_tol = 0, 0
    train_sample = 0
    for i, (features, targets) in enumerate(train_dataloader):
        # 将数据和标签都加载至训练设备中
        x_rnn = features[:, F_size:].to(device)				# model 和 data 必须在同一 device 上
        x_linear = features[:, :F_size].to(device)
        # 前向传播 计算结果
        outputs = model(x_rnn, x_linear)
        # 计算损失
        loss = criterion(outputs, targets.unsqueeze(1))		# 用损失函数对模型的预测结果和标签进行计算
        												# outputs: [4]	targets: [4,1]
        r2 = r2_score(targets.numpy(), outputs.detach().numpy())
        train_mse_tol += loss.item() * targets.shape[0]		# loss.item() 当前 batch 的损失函数平均值
        train_r2_tol += r2 * targets.shape[0]
        train_sample += targets.shape[0]
        # 反向传播和优化
        optimizer.zero_grad()	# 首先需要将优化器的梯度初始化为0,如果没有初始化,之前每个batch计算的梯度就会累积起来
        loss.backward()			# 之后损失函数计算输出的梯度(误差),同时将梯度从输出层向输入层反向传播,
        						# 并通过链式法则计算每个神经元的梯度
        optimizer.step()		# 最后根据梯度下降法计算损失函数关于每个参数的梯度,并更新模型的参数
        # 每隔5 batch 输出一次训练信息
        if (i+1) % 5 == 0:
            r2 = train_r2_tol / train_sample
            print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{total_step}], mse_Loss: {loss.item():.2f}, r2: {r2:.2f}', end='\r')
    train_mse_avg = train_mse_tol / train_sample
    train_r2_avg = train_r2_tol / train_sample
    
    # 测试模型
    model.eval()
    with torch.no_grad():
        test_mse_tol, test_r2_tol = 0, 0
        test_samples = 0
        for features, targets in test_dataloader:
            x_rnn = features[:, F_size:].to(device)
            x_linear = features[:, :F_size].to(device)
            outputs = model(x_rnn, x_linear)
            loss = criterion(outputs, targets.unsqueeze(1))
            r2 = r2_score(targets.numpy(), outputs.detach().numpy())
            test_mse_tol += loss.item() * targets.shape[0]
            test_r2_tol += r2 * targets.shape[0]
            test_samples += targets.shape[0]
            # 不需要反向传播和计算梯度
        test_mse_avg = test_mse_tol / test_samples
        test_r2_avg = test_r2_tol / test_samples
        print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{total_step}], mse_Loss: {loss.item():.2f}, r2: {r2:.2f}', end='\r')
    
    print(f'Epoch: {epoch+1}\t | '
          f'train_mse: {train_mse_avg:.4f}\t train_r2: {train_r2_avg:.2f}\t | '
          f'Test_mse: {test_mse_avg:.4f}\t Test_r2: {test_r2_avg:.2f}')

6. 保存模型 ( torch.save )

模型训练完毕之后,我们要把模型保存下来

注意! 在模型训练过程中,模型会保留中间状态,例如 Batch Normalization 中的均值和方差等等,而在验证时,这些中间状态是不需要的,因为每个测试样本只需要使用它自己的信息。因此,保存模型之前,需要将模型的状态切换为评估模式(eval mode),以确保中间状态不会影响测试结果。

model.eval()  # 首先切换到评估模式(eval mode)

# torch 的模型保存分两种情况,一种是只保存模型的权重,不保存模型结构;另一种是把模型结构也保存,文件会大一点点。

# method1:仅保存模型的权重,需要先定义好模型结构后才能通过 load_state_dict 的方法载入模型权重
state_dict = model.state_dict()									# 取出权重信息
torch.save(state_dict, '../model/model_checkpoint.pth')				# 仅保存权重
model2 = MyModel(**model_cfg)									# 实例新模型
model2.load_state_dict(torch.load('../model/model_checkpoint.pth'))  # 需要有 model 实例才能 load_state_dict

# method2:保存包括模型结构的全部信息,可以通过load的方法直接加载整个模型结构和权重
torch.save(model, "../model/model.pth")		# 保存完整模型
model3 = torch.load('../model/model.pth')	# 不需要定义model,直接就可以 load 整个模型

7. 小寄巧

7.1 代码优化
  • 函数封装 (def) :代码可复用性增强
  • 进度条 (tqdm) :训练进度可视化
  • 保存最优模型:加快收敛速度
  • 保存评估指标:用来可视化训练效果,可以画收敛曲线
def train_one_epoch(model, train_loader, optimizer):	
    """"""
    train_bar = tqdm(enumerate(train_loader), total=len(train_loader), desc=f'Train')
    for batch, (x, y) in train_bar:
        model.train()
        """"""
        # 更新进度条显示
        train_bar.set_postfix(loss=np.mean(train_loss))
        train_bar.update()
        pass
    """"""
    pass

def valid_one_epoch(model, valid_loader):
    """"""
    with torch.no_grad():
        model.eval()
        valid_bar = tqdm(enumerate(valid_loader), total=len(valid_loader), desc=f'{types}')
        for batch, (x, y) in valid_bar:
            """"""
            pass
        """"""
    """"""
    pass

def train(model, train_loader, valid_loader, cfg):
    """
    # 将模型加载到CUDA设备上
    # 定义优化器和学习率调度器
    ......
    """
    metrics = pd.DataFrame()	# 存放评估指标
    
    # 设置参数
    best_r2 = -10
    best_epoch, end_epoch = 0, 0
    stopping_monitor, learning_monitor = 0, 0
    
    for epoch in range(cfg.epoch):
        """"""
        train_loss = train_one_epoch(model, train_loader, optimizer)
        valid_loss = valid_one_epoch(model, valid_loader)
        metrics.insert(0, 'train_loss', train_loss)
        metrics.insert(0, 'test_loss', test_loss)	# 插入评估指标
        if end_epoch == 1:
            metric.to_csv(csv_path, index=False, header=True)
        else:
            metric.to_csv(csv_path, mode='a', index=False, header=False) # 追加写模式
        """"""
        # 如果r2指标提升,则保存当前模型为最佳模型
        if r2 > best_r2:
            best_r2 = r2
            best_epoch = end_epoch
            stopping_monitor, learning_monitor = 0, 0
            if hasattr(model, 'module'):
                state_dict = model.module.state_dict()
            else:
                state_dict = model.state_dict()
            torch.save(state_dict, f'{savepath}/{end_epoch}.pt')
            torch.save(state_dict, f'{savepath}/best.pt')
        else:
            stopping_monitor += 1
            learning_monitor += 1
            # 如果开启了恢复模式,并且保存的最佳模型存在,则加载最佳模型权重
            if cfg.restore and os.path.exists(f'{savepath}/best.pt'):
                checkpoint_process(model, f'{savepath}/best.pt')
        if stopping_monitor >= 20:
            break
        if learning_monitor >= cfg.decay_iter:  # 模型两轮没优化就更新一下学习率
            lr_schedule.step()
        """"""
    pass
7.2 模型信息
  • torchinfo.summary()
from torchinfo import summary
f1_rnn = torch.Tensor(np.random.random((4, 28)))
f2_F = torch.Tensor(np.random.random((4, 11)))
summary(model)
summary(model, input_data=[f1_rnn, f2_F],
        device=device, depth=2, col_names=["input_size", "output_size", "num_params"])
summary(model, input_size=[f1_rnn.shape, f2_F.shape],
        device=device, depth=2, col_names=["input_size", "output_size", "num_params"])
===================================================================================================================
Layer (type:depth-idx)                   Input Shape               Output Shape              Param #
===================================================================================================================
MyModel                                  [4, 28]                   [4, 1]                    --
├─RNN: 1-1                               [4, 28]                   [4, 10]                   400
├─Sequential: 1-2                        [4, 21]                   [4, 32]                   --
│    └─Linear: 2-1                       [4, 21]                   [4, 32]                   704
│    └─Dropout: 2-2                      [4, 32]                   [4, 32]                   --
│    └─ReLU: 2-3                         [4, 32]                   [4, 32]                   --
├─Sequential: 1-3                        [4, 32]                   [4, 32]                   --
│    └─Linear: 2-4                       [4, 32]                   [4, 32]                   1,056
│    └─Dropout: 2-5                      [4, 32]                   [4, 32]                   --
│    └─ReLU: 2-6                         [4, 32]                   [4, 32]                   --
├─Linear: 1-4                            [4, 32]                   [4, 1]                    33
===================================================================================================================
Total params: 2,193
Trainable params: 2,193
Non-trainable params: 0
Total mult-adds (M): 0.02
===================================================================================================================
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.01
Estimated Total Size (MB): 0.01
===================================================================================================================
7.4 排查错误
  • print(XXX.shape)
  • print(type(XXX))

要熟悉数据的转换过程,遇到维度或类型错误的问题多 print()break ,主要查看数据 shape , type 是否正确

维度问题主要是数据不匹配导致的,可能出现在 数据处理 (Dataset / read_csv)模型前向传播 (forward) 的过程中

类型错误可能是 ndarry, DataFrame, Tensor 类型搞混导致的

for batch, (data, label) in enumerate(train_dataloader):
    print(data.shape)
    print(label.shape)
    break

class MyModel(nn.Module):
    """"""
    def forward(self, x_rnn, x_linear):
        # print(x_rnn.shape)
        # print(x_linear.shape)
        rnn_output, _ = self.rnn(x_rnn)
        # print(rnn_output.shape)
        combined = torch.cat((rnn_output, x_linear), dim=1)
        # print(combined.shape)
        x = self.fc_1(combined)
        # print(x.shape)
        x = self.fc_2(x)
        # print(x.shape)
        output = self.linear3(x)
        return output
7.5 加载权重参数
7.5.1 权重参数存储结构
# 定义模型的全部参数
model_dict = model.state_dict()
print(type(model_dict))
for k, v in model_dict.items():
    print(k, '\t', v.shape)
"""
# output: 
<class 'collections.OrderedDict'>
rnn.weight_ih_l0 	 torch.Size([10, 28])
rnn.weight_hh_l0 	 torch.Size([10, 10])
rnn.bias_ih_l0 	 torch.Size([10])
rnn.bias_hh_l0 	 torch.Size([10])
fc_1.0.weight 	 torch.Size([32, 21])
fc_1.0.bias 	 torch.Size([32])
fc_2.0.weight 	 torch.Size([32, 32])
fc_2.0.bias 	 torch.Size([32])
linear3.weight 	 torch.Size([1, 32])
linear3.bias 	 torch.Size([1])
"""
7.5.2 加载部分权重参数
# 定义模型的全部参数
model_dict = model.rnn.state_dict()	# 指定 rnn 层的参数
for k, v in model_dict.items():
    print(k, '\t', v.shape)
"""
# output: 
weight_ih_l0 	 torch.Size([10, 28])
weight_hh_l0 	 torch.Size([10, 10])
bias_ih_l0 	 torch.Size([10])
bias_hh_l0 	 torch.Size([10])
"""

# 加载预训练模型的全部参数
pretrained_pth = torch.load('./model/model_checkpoint.pth')
for k, v in pretrained_pth.items():
    if k.startswith('rnn.'):	# 筛选符合条件的参数
        k = k.replace('rnn.', '')
        print("%-20s %-20s" % (k, v.shape))
"""
# output: 
weight_ih_l0         torch.Size([10, 28])
weight_hh_l0         torch.Size([10, 10])
bias_ih_l0           torch.Size([10])    
bias_hh_l0           torch.Size([10])  
"""

model.load_state_dict(torch.load(pretrained_pth))
7.5.3 DataParallel
# DataParallel 通过 并行化处理数据 来提高训练效率
# 它将数据集划分为多个小批次,然后将这些小批次均匀地分配给不同的GPU进行计算
from torch.nn import DataParallel
model = MyModel()
model.to(device)
model = DataParallel(model)		# DataParallel训练方式
# 有时候模型权重文件中可能含有 .module的字样,这是因为model在DataParallel的训练方式下保存时会带有 .module,
# 此时无法直接加载到模型中,需要将 .module去除
def checkpoint_process(model, weights_name):
    weights = torch.load(weights_name)

    weights_dict = {}
    for k, v in weights.items():
        new_k = k.replace('module.', '') if 'module' in k else k
        weights_dict[new_k] = v

    if hasattr(model, 'module'):
        model.module.load_state_dict(weights_dict)
    else:
        model.load_state_dict(weights_dict)
7.6 改装模型
7.6.1 替换组件

以下例子将处理时间序列层次改名为 timelist ,将 RNN 替换成了 LSTM ,通过定义模型时使用的参数设置网络结构。

class MyModel(nn.Module):
    """ 这个模型先使用 RNN 处理时序特征,再拼接其他特征,经过3层线性层,输出维度为1 """
    def __init__(self, use_rnn=False, use_lstm=True, # 可选择使用什么层次处理时间序列
                 rnn_input_size, rnn_hidden_size, F_size, linear_hidden_size, output_size):
        super(MyModel, self).__init__()
        
        # 改造处理时间序列的层次
        if use_rnn:
            # RNN 层
            self.timelist = nn.RNN(input_size=rnn_input_size, hidden_size=rnn_hidden_size, batch_first=True)
        elif use_lism:
           	# LSTM 层
        	self.timelist = nn.LSTM(input_size=rnn_input_size, hidden_size=rnn_hidden_size, batch_first=True)
            
        self.fc_1 = nn.Sequential(
            nn.Linear(rnn_hidden_size + F_size, linear_hidden_size),
            nn.Dropout(0.5),
            nn.ReLU()
        )
        self.fc_2 = nn.Sequential(
            nn.Linear(linear_hidden_size, linear_hidden_size),
            nn.Dropout(0.5),
            nn.ReLU()
        )
        self.linear3 = nn.Linear(linear_hidden_size, output_size)
    def forward(self, x_rnn, x_linear):
        timelist_output, _ = self.timelist(x_rnn)	# 小修改
        combined = torch.cat((timelist_output, x_linear), dim=1)	# 小修改
        x = self.fc_1(combined)
        x = self.fc_2(x)
        output = self.linear3(x)
        return output
7.6.2 数据集改造

在上一个例子的改造中,RNNLSTM 的输入和输出是相同的,但是但我们改造模型时使用的组件输入输出形状不同时,就要改造以下Datasetcollate_fn 的定义。

以下例子的是将两个模型的 encoder 替换后,输入从 x 变成了 x, mask, adjoin_matrix
在这里插入图片描述
在这里插入图片描述

7.8 训练模型方式 Pretrain --> Fine-tune
7.7 多模型组合训练 GAN

咕咕咕,内容还没编完~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值