【深度学习实验】循环神经网络(四):基于 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.rhkb.cn/news/160226.html

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

相关文章

电脑提示Explorer.exe系统错误该怎么办?

平时我们在使用电脑时,系统有时会提示Explorer.exe系统错误,很多用户在遇到这类问题时不知道该怎么办。遇到Explorer.exe系统错误,该怎么办呢?下面我们一起来了解一下。 怎么修复Explorer.exe系统错误? Explorer.exe是…

MySQL多表查询面试题一

其中分析题意,学生表student是与成绩表score关联,课程表course与教师表teacher关联,由此可以先确定关联关系,学生表为s,课程表为c,教师表为t,成绩表为o。s.s_ido.s_id,c.t_idt.t_id …

【AI】深度学习——循环神经网络

神经元不仅接收其他神经元的信息,也能接收自身的信息。 循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络,可以更方便地建模长时间间隔的相关性 常用的参数学习可以为BPTT。当输入序列比较…

【数字IC设计】DC自动添加门控时钟

简介 数字电路的动态功耗主要是由于寄存器翻转带来的,为了降低芯片内部功耗,门控时钟的方案应运而生。作为低功耗设计的一种方法,门控时钟是指在数据无效时将寄存器的时钟关闭,以此来降低动态功耗。 在下图中,展示了…

【自然语言处理】— 隐马尔可夫模型详解、例解

【自然语言处理】— 隐马尔可夫模型 【自然语言处理】— 隐马尔可夫模型引例隐马尔可夫模型概念隐马尔可夫模型的关键隐马尔可夫模型的数学表示隐含状态与观测结果状态转移矩阵观测概率矩阵初始状态概率向量 小结 【自然语言处理】— 隐马尔可夫模型 引例 假设有三种不同的骰…

17 - 并发容器的使用:识别不同场景下最优容器

在并发编程中,我们经常会用到容器。今天我要和你分享的话题就是:在不同场景下我们该如何选择最优容器。 1、并发场景下的 Map 容器 假设我们现在要给一个电商系统设计一个简单的统计商品销量 TOP 10 的功能。常规情况下,我们是用一个哈希表…

【UBOOT】1-使用与烧写

​一、uboot简介 1)uboot是一个裸机程序,比较复杂 2)最主要的作用是引导Linux内核启动; 初始化DDR; 因为Linux是运行在DDR里面的;而Linux镜像(zImage或uImagedtb)一般存放在SD EMM…

理解LoadRunner,基于此工具进行后端性能测试的详细过程(下)

5、录制并增强虚拟用户脚本 从整体角度看,用LoadRunner 开发虚拟用户脚本主要包括下面四步骤: 识别测试应用使用的协议 录制脚本 完善录制得到的脚本 验证脚本的正确性 识别被测应用使用的协议 如果明确知道了被测系统所采用的协议,可…

网卡介绍篇

目录 1.什么是网卡? 2.网卡的演进 3.网卡的主要功能 4.服务器网卡介绍 5.服务器网卡的分类 6.网卡接口介绍 7.业界网卡主流厂商 8.SmartNIC概念介绍 9.SmartNIC产业发展趋势 10.SmartNIC实现 10-1.实现形式 10-2.SmartNIC不同实现技术对比 11.Mellanox…

怎么把flac音频变为mp3?

怎么把flac音频变为mp3?FLAC音频格式在许多平台和应用程序中都得到支持和应用。FLAC音频格式被广泛支持和应用。许多平台、设备和应用程序都支持FLAC格式,如Windows、macOS和Linux操作系统、各种音乐播放器软件、智能手机和平板电脑、在线音乐平台和流媒…

python+django学生选课管理系统_wxjjv

1)前台:首页、课程信息、校园论坛、校园公告、个人中心、后台管理。 (2)管理员:首页、个人中心、学生管理、教师管理课、程信息管理、课程分类管理、选课信息管理、作业信息管理、提交作业管理、学生成绩管理、校园论…

Linux常见的指令合集

Linux指令合集 认识linuxlinux基础指令1.pwd 命令2. ls 命令3.cd 命令4. man 命令5. grep 命令6. ps 命令7. kill 命令8. netstat 命令9. date 查看当前系统时间10. echo 打印选项 -e linux文件操作指令1. mkdir 命令2. rmdir 命令3. touch 命令4. rm 命令5. mv 命令6. cp 命令…

ImgPlus:基于CodeFormer的图片增强

背景 最近参与了华为云开发者大会AI赛道,做了一个AI图片增强作品,本片文章来简单介绍一下。 正文 作品名称:ImgPlus 赛题技术领域选择: AI,图片增强 使用技术名称: CodeFormer,ECS&#xff0…

Puppeteer结合测试工具jest使用(四)

Puppeteer结合测试工具jest使用(四) Puppeteer结合测试工具jest使用(四)一、简介二、与jest结合使用,集成到常规测试三、支持其他的几种四、总结 一、简介 Puppeteer是一个提供自动化控制Chrome或Chromium浏览器的Node…

session认证

目录 前言 http协议的无状态性 session的工作原理 在express中使用session认证 在session中存数据 在session中取数据 清空session 结尾 前言 session是一种记录客户状态的机制,客户端浏览器法访问服务器的时候,服务器把客户端信息以某种形式记录…

WLAN 无线案例(华为AC控制器配置模板)

实验说明: 无线用户VLAN 30 192.168.30.0/24 AP和AC用VLAN 20 192.168.20.0/24 有线网段 VLAN 10 192.168.10.0/24 步骤一:全网互通 sw1: sysname sw1 # vlan batch 10 20 30 # dhcp enable # ip pool 20 gateway-list 192.168.20.1…

JAVA学习(6)-全网最详细~

🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如…

UDP与TCP协议

很抱歉,我之前写好的UDP与TCP文章不小心被删了,所以,这篇文章只有一半,后面我会尽快补全。 在完成HTTPS的学习后,我们就完成了应用层的所有讲解,下面我们开始讲解传输层,这一层常用的协议为TCP…

MySQL的index merge(索引合并)导致数据库死锁分析与解决方案 | 京东云技术团队

背景 在DBS-集群列表-更多-连接查询-死锁中,看到9月22日有数据库死锁日志,后排查发现是因为mysql的优化-index merge(索引合并)导致数据库死锁。 定义 index merge(索引合并):该数据库查询优化的一种技术&#xff0…

JOSEF约瑟 漏电继电器 JD1-200 工作电压:380V 孔径:45mm 50~500mA

JD1系列漏电继电器 系列型号 JD1-100漏电继电器 JD1-200漏电继电器 JD1-250漏电继电器 JD1系列漏电继电器原为分体式固定式安装,为适应现行安装场合需要,上海约瑟继电器厂在产品原JD1一体式漏电继电器基础上进行产品升级,开发出现在较为…