【深度学习实验】循环神经网络(四):基于 LSTM 的语言模型训练

目录

一、实验介绍

二、实验环境

1. 配置虚拟环境

2. 库版本介绍

三、实验内容

0. 导入必要的工具包

1. RNN与梯度裁剪

2. LSTM模型

3. 训练函数

a. train_epoch

b. train

4. 文本预测

5. GPU判断函数

6. 训练与测试

7. 代码整合


        经验是智慧之父,记忆是智慧之母。

——谚语

一、实验介绍

         基于 LSTM 的语言模型训练

二、实验环境

        本系列实验使用了PyTorch深度学习框架,相关操作如下:

1. 配置虚拟环境

conda create -n DL python=3.7 
conda activate DL
pip install torch==1.8.1+cu102 torchvision==0.9.1+cu102 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
conda install matplotlib
 conda install scikit-learn

2. 库版本介绍

软件包本实验版本目前最新版
matplotlib3.5.33.8.0
numpy1.21.61.26.0
python3.7.16
scikit-learn0.22.11.3.0
torch1.8.1+cu1022.0.1
torchaudio0.8.12.0.2
torchvision0.9.1+cu1020.15.2

三、实验内容

0. 导入必要的工具包

import torch
from torch import nn
from d2l import torch as d2l

1. RNN与梯度裁剪

【深度学习实验】循环神经网络(一):循环神经网络(RNN)模型的实现与梯度裁剪_QomolangmaH的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_63834988/article/details/133742433?spm=1001.2014.3001.5501

2. LSTM模型

【深度学习实验】循环神经网络(三):门控制——自定义循环神经网络LSTM(长短期记忆网络)模型-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_63834988/article/details/133864731?spm=1001.2014.3001.5501

3. 训练函数

a. train_epoch

def train_epoch(net, train_iter, loss, updater, device, use_random_iter):state, timer = None, d2l.Timer()metric = d2l.Accumulator(2)  # 训练损失之和,词元数量for X, Y in train_iter:if state is None or use_random_iter:# 在第一次迭代或使用随机抽样时初始化statestate = net.begin_state(batch_size=X.shape[0], device=device)if isinstance(net, nn.Module) and not isinstance(state, tuple):# state对于nn.GRU是个张量state.detach_()else:# state对于nn.LSTM或对于我们从零开始实现的模型是个张量for s in state:s.detach_()y = Y.T.reshape(-1)X, y = X.to(device), y.to(device)y_hat, state = net(X, state)l = loss(y_hat, y.long()).mean()if isinstance(updater, torch.optim.Optimizer):updater.zero_grad()l.backward()grad_clipping(net, 1)updater.step()else:l.backward()grad_clipping(net, 1)# 因为已经调用了mean函数updater(batch_size=1)metric.add(l * d2l.size(y), d2l.size(y))return math.exp(metric[0] / metric[1]), metric[1] / timer.stop()
  • 参数:

    • net:神经网络模型
    • train_iter:训练数据迭代器
    • loss:损失函数
    • updater:更新模型参数的方法(如优化器)
    • device:计算设备(如CPU或GPU)
    • use_random_iter:是否使用随机抽样
  • 函数内部定义了一些辅助变量:

    • state:模型的隐藏状态变量
    • timer:计时器,用于记录训练时间
    • metric:累加器,用于计算训练损失之和和词元数量
  • 函数通过迭代train_iter中的数据进行训练。每次迭代中,执行以下步骤:

    • 如果是第一次迭代或者使用随机抽样,则初始化隐藏状态state
    • 如果netnn.Module的实例并且state不是元组类型,则将state的梯度信息清零(detach_()函数用于断开与计算图的连接,并清除梯度信息)
    • 对于其他类型的模型(如nn.LSTM或自定义模型),遍历state中的每个元素,将其梯度信息清零
    • 将输入数据X和标签Y转移到指定的计算设备上
    • 使用神经网络模型net和当前的隐藏状态state进行前向传播,得到预测值y_hat和更新后的隐藏状态state
    • 计算损失函数loss对于预测值y_hat和标签y的损失,并取均值
    • 如果updatertorch.optim.Optimizer的实例,则执行优化器的相关操作(梯度清零、梯度裁剪、参数更新)
    • 否则,仅执行梯度裁剪和模型参数的更新(适用于自定义的更新方法)
    • 将当前的损失值乘以当前批次样本的词元数量,累加到metric
  • 训练完成后,函数返回以下结果:

    • 对数似然损失的指数平均值(通过计算math.exp(metric[0] / metric[1])得到)
    • 平均每秒处理的词元数量(通过计算metric[1] / timer.stop()得到)

b. train

def train(net, train_iter, vocab, lr, num_epochs, device, use_random_iter=False):loss = nn.CrossEntropyLoss()animator = d2l.Animator(xlabel='epoch', ylabel='perplexity',legend=['train'], xlim=[10, num_epochs])if isinstance(net, nn.Module):updater = torch.optim.SGD(net.parameters(), lr)else:updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)for epoch in range(num_epochs):ppl, speed = train_epoch(net, train_iter, loss, updater, device, use_random_iter)if (epoch + 1) % 10 == 0:animator.add(epoch + 1, [ppl])print('Train Done!')torch.save(net.state_dict(), 'chapter6.pth')print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
  • 参数
    • net(神经网络模型)
    • train_iter(训练数据迭代器)
    • vocab(词汇表)
    • lr(学习率)
    • num_epochs(训练的轮数)
    • device(计算设备)
    • use_random_iter(是否使用随机抽样)。
  • 在函数内部,它使用交叉熵损失函数(nn.CrossEntropyLoss())计算损失,创建了一个动画器(d2l.Animator)用于可视化训练过程中的困惑度(perplexity)指标。
  • 根据net的类型选择相应的更新器(updater
    • 如果netnn.Module的实例,则使用torch.optim.SGD作为更新器;
    • 否则,使用自定义的更新器(d2l.sgd)。
  • 通过迭代训练数据迭代器train_iter来进行训练。在每个训练周期(epoch)中
    • 调用train_epoch函数来执行训练,并得到每个周期的困惑度和处理速度。
    • 每隔10个周期,将困惑度添加到动画器中进行可视化。
  • 训练完成后,打印出训练完成的提示信息,并将训练好的模型参数保存到文件中('chapter6.pth')。
  • 打印出困惑度和处理速度的信息。

4. 文本预测

        定义了给定前缀序列,生成后续序列的predict函数。

def predict(prefix, num_preds, net, vocab, device):state = net.begin_state(batch_size=1, device=device)outputs = [vocab[prefix[0]]]get_input = lambda: torch.reshape(torch.tensor([outputs[-1]], device=device), (1, 1))for y in prefix[1:]:  # 预热期_, state = net(get_input(), state)outputs.append(vocab[y])for _ in range(num_preds):  # 预测num_preds步y, state = net(get_input(), state)outputs.append(int(y.argmax(dim=1).reshape(1)))return ''.join([vocab.idx_to_token[i] for i in outputs])
  • 使用指定的device和批大小为1调用net.begin_state(),初始化state变量。
  • 使用vocab[prefix[0]]将第一个标记在prefix中对应的索引添加到outputs列表中。
  • 定义了一个get_input函数,该函数返回最后一个输出标记经过reshape后的张量,作为神经网络的输入。
  • 对于prefix中除第一个标记外的每个标记,通过调用net(get_input(), state)进行前向传播。忽略输出的预测结果,并将对应的标记索引添加到outputs列表中。

5. GPU判断函数

def try_gpu(i=0):"""如果存在,则返回gpu(i),否则返回cpu()"""if torch.cuda.device_count() >= i + 1:return torch.device(f'cuda:{i}')return torch.device('cpu')

6. 训练与测试

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
vocab_size, num_hiddens, num_epochs, lr= 28, 256, 200, 1
device = try_gpu()
lstm_layer = nn.LSTM(vocab_size, num_hiddens)
model_lstm = RNNModel(lstm_layer, vocab_size)
train(model_lstm, train_iter, vocab, lr, num_epochs, device)
  • 训练中每个小批次(batch)的大小和每个序列的时间步数(time step)的值分别为32,25

  • 加载的训练数据迭代器和词汇表

  • vocab_size 是词汇表的大小,num_hiddens 是 LSTM 隐藏层中的隐藏单元数量,num_epochs 是训练的迭代次数,lr 是学习率。

  • 选择可用的 GPU 设备进行训练,如果没有可用的 GPU,则会使用 CPU。

  • 训练模型

7. 代码整合

# 导入必要的库
import torch
from torch import nn
import torch.nn.functional as F
from d2l import torch as d2l
import mathclass LSTM(nn.Module):def __init__(self, input_size, hidden_size):super(LSTM, self).__init__()self.input_size = input_sizeself.hidden_size = hidden_size# 初始化模型,即各个门的计算参数self.W_i = nn.Parameter(torch.randn(input_size, hidden_size))self.W_f = nn.Parameter(torch.randn(input_size, hidden_size))self.W_o = nn.Parameter(torch.randn(input_size, hidden_size))self.W_a = nn.Parameter(torch.randn(input_size, hidden_size))self.U_i = nn.Parameter(torch.randn(hidden_size, hidden_size))self.U_f = nn.Parameter(torch.randn(hidden_size, hidden_size))self.U_o = nn.Parameter(torch.randn(hidden_size, hidden_size))self.U_a = nn.Parameter(torch.randn(hidden_size, hidden_size))self.b_i = nn.Parameter(torch.randn(1, hidden_size))self.b_f = nn.Parameter(torch.randn(1, hidden_size))self.b_o = nn.Parameter(torch.randn(1, hidden_size))self.b_a = nn.Parameter(torch.randn(1, hidden_size))self.W_h = nn.Parameter(torch.randn(hidden_size, hidden_size))self.b_h = nn.Parameter(torch.randn(1, hidden_size))# 初始化隐藏状态def init_state(self, batch_size):hidden_state = torch.zeros(batch_size, self.hidden_size)cell_state = torch.zeros(batch_size, self.hidden_size)return hidden_state, cell_statedef forward(self, inputs, states=None):batch_size, seq_len, input_size = inputs.shapeif states is None:states = self.init_state(batch_size)hidden_state, cell_state = statesoutputs = []for step in range(seq_len):inputs_step = inputs[:, step, :]i_gate = torch.sigmoid(torch.mm(inputs_step, self.W_i) + torch.mm(hidden_state, self.U_i) + self.b_i)f_gate = torch.sigmoid(torch.mm(inputs_step, self.W_f) + torch.mm(hidden_state, self.U_f) + self.b_f)o_gate = torch.sigmoid(torch.mm(inputs_step, self.W_o) + torch.mm(hidden_state, self.U_o) + self.b_o)c_tilde = torch.tanh(torch.mm(inputs_step, self.W_a) + torch.mm(hidden_state, self.U_a) + self.b_a)cell_state = f_gate * cell_state + i_gate * c_tildehidden_state = o_gate * torch.tanh(cell_state)y = torch.mm(hidden_state, self.W_h) + self.b_houtputs.append(y)return torch.cat(outputs, dim=0), (hidden_state, cell_state)class RNNModel(nn.Module):def __init__(self, rnn_layer, vocab_size, **kwargs):super(RNNModel, self).__init__(**kwargs)self.rnn = rnn_layerself.vocab_size = vocab_sizeself.num_hiddens = self.rnn.hidden_sizeself.num_directions = 1self.linear = nn.Linear(self.num_hiddens, self.vocab_size)def forward(self, inputs, state):X = F.one_hot(inputs.T.long(), self.vocab_size)X = X.to(torch.float32)Y, state = self.rnn(X, state)# 全连接层首先将Y的形状改为(时间步数*批量大小,隐藏单元数)# 它的输出形状是(时间步数*批量大小,词表大小)。output = self.linear(Y.reshape((-1, Y.shape[-1])))return output, state# 在第一个时间步,需要初始化一个隐藏状态,由此函数实现def begin_state(self, device, batch_size=1):if not isinstance(self.rnn, nn.LSTM):# nn.GRU以张量作为隐状态return  torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens),device=device)else:# nn.LSTM以元组作为隐状态return (torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device),torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device))def train(net, train_iter, vocab, lr, num_epochs, device, use_random_iter=False):loss = nn.CrossEntropyLoss()animator = d2l.Animator(xlabel='epoch', ylabel='perplexity',legend=['train'], xlim=[10, num_epochs])if isinstance(net, nn.Module):updater = torch.optim.SGD(net.parameters(), lr)else:updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)for epoch in range(num_epochs):ppl, speed = train_epoch(net, train_iter, loss, updater, device, use_random_iter)if (epoch + 1) % 10 == 0:animator.add(epoch + 1, [ppl])print('Train Done!')torch.save(net.state_dict(), 'chapter6.pth')print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')def train_epoch(net, train_iter, loss, updater, device, use_random_iter):state, timer = None, d2l.Timer()metric = d2l.Accumulator(2)  # 训练损失之和,词元数量for X, Y in train_iter:if state is None or use_random_iter:# 在第一次迭代或使用随机抽样时初始化statestate = net.begin_state(batch_size=X.shape[0], device=device)if isinstance(net, nn.Module) and not isinstance(state, tuple):# state对于nn.GRU是个张量state.detach_()else:# state对于nn.LSTM或对于我们从零开始实现的模型是个张量for s in state:s.detach_()y = Y.T.reshape(-1)X, y = X.to(device), y.to(device)y_hat, state = net(X, state)l = loss(y_hat, y.long()).mean()if isinstance(updater, torch.optim.Optimizer):updater.zero_grad()l.backward()grad_clipping(net, 1)updater.step()else:l.backward()grad_clipping(net, 1)# 因为已经调用了mean函数updater(batch_size=1)metric.add(l * d2l.size(y), d2l.size(y))return math.exp(metric[0] / metric[1]), metric[1] / timer.stop()def predict(prefix, num_preds, net, vocab, device):state = net.begin_state(batch_size=1, device=device)outputs = [vocab[prefix[0]]]get_input = lambda: torch.reshape(torch.tensor([outputs[-1]], device=device), (1, 1))for y in prefix[1:]:  # 预热期_, state = net(get_input(), state)outputs.append(vocab[y])for _ in range(num_preds):  # 预测num_preds步y, state = net(get_input(), state)outputs.append(int(y.argmax(dim=1).reshape(1)))return ''.join([vocab.idx_to_token[i] for i in outputs])def grad_clipping(net, theta):if isinstance(net, nn.Module):params = [p for p in net.parameters() if p.requires_grad]else:params = net.paramsnorm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))if norm > theta:for param in params:param.grad[:] *= theta / normdef try_gpu(i=0):"""如果存在,则返回gpu(i),否则返回cpu()"""# if torch.cuda.device_count() >= i + 1:#     return torch.device(f'cuda:{i}')return torch.device('cpu')batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
vocab_size, num_hiddens, num_epochs, lr= 28, 256, 200, 1
device = try_gpu()
lstm_layer = nn.LSTM(vocab_size, num_hiddens)
model_lstm = RNNModel(lstm_layer, vocab_size)
train(model_lstm, train_iter, vocab, lr, num_epochs, device)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/111111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pdf转二维码怎么做?pdf二维码制作简单技巧

pdf是一种很常见的文件储存格式,一般通知、发票、简历都会保存为这种格式来使用,那么需要将pdf格式文件做成二维码,该用什么方式来制作呢?下面给大家分享一个pdf转二维码的在线工具,可以通过上传文件一键生成二维码&am…

pytorch 入门(二)

本文为🔗小白入门Pytorch内部限免文章 🍨 本文为🔗小白入门Pytorch中的学习记录博客🍦 参考文章:【小白入门Pytorch】教案二🍖 原作者:K同学啊 目录 一、神经网络的组成部分1. 神经元2. 神经网络…

世界粮食日:宏工科技有对策,赋能食品生产高效可持续发展

10月16日是世界粮食日。随着全球人口的增长,人们对高品质食品的需求也越来越大,如何实现“更好生产、更好营养”成为了食品生产与供应的重要话题。15年来,宏工科技专注物料处理自动化领域,提供食品物料处理一站式解决方案以提高生…

智能水印相机微信小程序源码

相信大家日常在生活中或者工作中都有使用过水印相机来拍照记录吧,但是又要在手机上面多下载一个APP。 那么小编今天给大家带来一款智能水印相机,拍照自动添加时间、地点、经纬度等水印文字,可用于工作考勤、学习打卡、工作取证等&#xff0c…

Spring5学习笔记之整合MyBatis

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Spring专栏 ✨特色专栏: M…

[资源推荐] 飞书画板模板

今天做PPT,尝试了一些AI工具之后,感觉反而降低了做PPT的效率,因为和想实现的效果还是差很多…然后我本人不到万不得已不做PPT,都是用notion这类在线文档来作展示,今天必须得做ppt,但是不想在ppt里面画图&am…

行列转换:MySQL中的数据变形魔法

行转列 使用CASE函数聚合函数 SELECTMAX(CASE WHEN salesperson John THEN sales_amount END) AS John_Sales,MAX(CASE WHEN salesperson Alice THEN sales_amount END) AS Alice_Sales FROM sales_data;列转行 使用UNIO连接每列数据 SELECT product_id,store1 store,sto…

macOS Sonoma 14.1RC(23B73)发布

黑果魏叔10 月 18 日消息,苹果今日向 Mac 电脑用户推送了 macOS 14.1 RC更新(内部版本号:23B73),本次更新距离上次发布隔了 7 天。 macOS Sonoma 14.1RC(23B73)的更新内容主要包括以下方面&…

办鹿uniapp小程序(一)

一、项目初始化 1. appid 》 公司给你 wxc82730a0fc15e28a 2. 开发者身份 》 公司给你添加 小程序官网:小程序 管理》成员管理》项目成员 1、 uniapp ui组件 (uView) 如果采用npm安装方式在 小程序端不生效 1.1 采用插件的形式安装&#xf…

【Qt控件之QListWidget】介绍及使用,利用QListWidget、QToolButton、和布局控件实现抽屉式组合控件

概述 QListWidget类提供了基于项目的列表小部件。 QListWidget是一个方便的类,类似于QListView提供的列表视图,但使用经典的基于项目的接口来添加和删除项目。QListWidget使用内部模型来管理列表中的每个QListWidgetItem。 对于更灵活的列表视图小部件…

Unity游戏开发中ngui和ugui区别与优缺点详解

Unity3D是一款跨平台的游戏开发引擎,它支持多种平台,包括PC、移动设备和主机。在Unity3D中,UI系统是游戏开发中非常重要的一部分,它负责游戏中的用户界面的显示和交互。 对惹,这里有一个游戏开发交流小组,…

【01】LVGL-CodeBlock模拟器安装 | LVGL工程下载 | PC端模拟LVGL步骤

LVGL模拟器 1.LVGL模拟器介绍2.Windows环境搭建CodeBlock及获取LVGL工程3.PC端模拟LVGL4.总结 1.LVGL模拟器介绍 LVGL模拟器:使用PC端软件模拟LVGL运行,而不需要任何嵌入式硬件。优点:便于学习、跨平台协同开发 2.Windows环境搭建CodeBlock及…

C# Onnx Yolov8 Detect 戴口罩检测

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace Onnx…

数据库索引种类

文章目录 索引的优缺点优点缺点 聚簇索引特点优点缺点 非聚簇索引特点优点缺点使用场景: 在MyISAM与InnoDB中的使用 索引的优缺点 索引概述 MySQL官方将索引定义为帮助MySQL高效获取数据的数据结构。索引的本质是一种排好序的快速查找数据结构,用于满足…

Redis AOF持久化和ReWrite

前言 Redis 的 RDB 持久化机制简单直接,把某一时刻的所有键值对以二进制的方式写入到磁盘,特点是恢复速度快,尤其适合数据备份、主从复制场景。但如果你的目的是要保证数据可靠性,RDB 就不太适合了,因为 RDB 持久化不…

关闭mysql,关闭redis服务

1. 关闭redis服务: 查询redis安装目录: whereis redis which redis find / -name redis 关闭redis服务: redis-cli -h 127.0.0.1 -p 6379 auth 输入密码 shutdown 关闭redis服务 2. 关闭mysql服务: 查询mysql安装目录&…

Typora 导出PDF 报错 failed to export as pdf. undefined 解决方案

情况 我想把一个很大的markdown 导出为 248页的pdf 然后就报错 failed to export as pdf. undefined 原因 : 个人感觉应该是图片太大了 格式问题之类导致的 解决 文件 -> 偏好设置 - > 导出 -> pdf -> 自定义 -> 把大小全部改为24mm (虽然图中是32 …

模拟IIC通讯协议(stm32)(硬件iic后面在补)

一、IIC基础知识总结。 1、IIC通讯需要两条线就可以,SCL、SDA。 2、IIC的数据传输的速率,不同的ic是不同的,根据电平维持的延时函数的时间来确定IIC数据传输的速率. 3、IIC的延时函数可以使用延时函数,延时函数一般使用系统滴答时…

安防监控系统EasyCVR视频汇聚平台设备树收藏按钮的细节优化

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放,可同时播放多路视频流&#…

【Linux】:Linux环境与版本

以下哪个命令输出Linux内核的版本信息 A.uname -r B.vmstat C.sar D.stat uname -r 查看linux内核版本信息 vmstat 报告关于内核线程、虚拟内存、磁盘、陷阱和 CPU 活动的统计信息 sar 主要帮助我们掌握系统资源的使用情况,特别是内存和CPU的使用情况 stat 用于显示…