基于自回归模型的酒店评论生成

《DeepSeek大模型高性能核心技术与多模态融合开发(人工智能技术丛书)》(王晓华)【摘要 书评 试读】- 京东图书

我们使用新架构的模型完成情感分类,可以看到,使用注意力机制可以很好地对特征进行抽取从而完成二分类的情感分类任务。

然而使用自注意力的模型并不仅限于此,除了经典的分类任务外,我们还可以使用增加了旋转位置编码RoPE的模型来完成文本生成。

4.3.1  数据集的准备与读取

在上一节中,我们已经完成了情感数据集的基本读取,并掌握了汉字文本内容编码的方法。对于本节的任务,即基于自回归模型的酒店评论生成,数据集的准备与读取代码如下:

import numpy as np
from tqdm import tqdm
import torchimport tokenizer
tokenizer_emo = tokenizer.Tokenizer(model_path="../vocab/my_model.model")print(tokenizer_emo.vocab_size())
max_length = 48token_list = []
with open("../../dataset/ChnSentiCorp.txt", mode="r", encoding="UTF-8") as emotion_file:for line in tqdm(emotion_file.readlines()):line = line.strip().split(",")text = "".join(line[1:]) + '※'if True:token = tokenizer_emo.encode(text)for id in token:token_list.append(id)
token_list = torch.tensor(token_list * 2)class TextSamplerDataset(torch.utils.data.Dataset):def __init__(self, data = token_list, seq_len = max_length):super().__init__()self.data = dataself.seq_len = seq_lendef __getitem__(self, index):rand_start = torch.randint(0, self.data.size(0) - self.seq_len, (1,))full_seq = self.data[rand_start : rand_start + self.seq_len + 1].long()return full_seq[:-1],full_seq[1:]def __len__(self):return self.data.size(0) // self.seq_len

这里我们首先对文本内容进行读取,需要注意的是,对于每行的文本内容,我们不像上一节进行情感判定时每行作为一份准备进行存储,而是使用了首位相连的形式进行添加。这样做的目的符合我们文本生成任务的训练形式,即只需要按格式生成文本内容,而无需去了解所代表的含义。

TextSamplerDataset进行采样时我们也是随机截取了特定一段的文本进行输出,因为随机截取可以在一定程度上增加文本的多样性,增强了模型的健壮性。

4.3.2  基于自回归文本生成模型的设计

接下来,我们需要实现基于自回归文本生成模型的设计。首先是基本的模型设计,相对于上一节完成的分类模型,自回归文本生成模型由于是生成任务,需要额外地添加位置编码,即我们在本章第一节讲解的旋转位置编码。添加了旋转位置编码的注意力模型如下所示。

class MultiHeadAttention_MHA(torch.nn.Module):def __init__(self, d_model, attention_head_num):super(MultiHeadAttention_MHA, self).__init__()self.attention_head_num = attention_head_numself.d_model = d_modelassert d_model % attention_head_num == 0self.scale = d_model ** -0.5self.softcap_value = 50.self.per_head_dmodel = d_model // attention_head_numself.qkv_layer = torch.nn.Linear(d_model, 3 * d_model)self.rotary_embedding = RotaryEmbedding(self.per_head_dmodel // 2, use_xpos=True)self.out_layer = torch.nn.Linear(d_model, d_model)def forward(self, embedding, past_length = 0):qky_x = self.qkv_layer(embedding)q, k, v = torch.split(qky_x, split_size_or_sections=self.d_model, dim=-1)q = einops.rearrange(q, "b s (h d) -> b h s d", h=self.attention_head_num)k = einops.rearrange(k, "b s (h d) -> b h s d", h=self.attention_head_num)v = einops.rearrange(v, "b s (h d) -> b h s d", h=self.attention_head_num)q, k = self.rotary_embedding.rotate_queries_and_keys(q, k, seq_dim=2)q = q * self.scalesim = einops.einsum(q, k, 'b h i d, b h j d -> b h i j')#sim = softclamp(sim, self.softcap_value)mask_value = -torch.finfo(sim.dtype).maxi, j = sim.shape[-2:]causal_mask = torch.ones((i, j), dtype=torch.bool).triu(past_length).to(embedding.device)sim = sim.masked_fill(causal_mask, mask_value)attn = sim.softmax(dim=-1)out = einops.einsum(attn, v, 'b h i j, b h j d -> b h i d')embedding = einops.rearrange(out, "b h s d -> b s (h d)")embedding = self.out_layer(embedding)return embedding

其中的参数past_length=0的作用是对因果掩码进行设计,在这里triu(past_length)函数的作用是是从past_length的位置开始,生成一个对三角矩阵,对这个不理解的读者可以尝试如下函数:

causal_mask = torch.ones((5, 5), dtype=torch.bool).triu(0)

causal_mask = torch.ones((5, 5), dtype=torch.bool).triu(2)

打印结果并比较其中内容。

而基于标准注意力层完成的自回归模型如下所示。

from torch import Tensor
import torch, math, einops
from moudle import attention_moudle,feedforward_layerclass EncoderBlock(torch.nn.Module):def __init__(self, d_model, num_heads):super(EncoderBlock, self).__init__()self.d_model = d_modelself.num_heads = num_headsself.attention_norm = torch.nn.RMSNorm(d_model)self.self_attention = attention_moudle.MultiHeadAttention(d_model, num_heads)self.ffn = feedforward_layer.Swiglu(d_model)def forward(self, embedding):residual = embeddingembedding = self.attention_norm(embedding)embedding = self.self_attention(embedding)embedding = self.ffn(embedding)return embedding + residualclass Encoder(torch.nn.Module):def __init__(self, d_model, num_heads, num_layers = 3):super(Encoder, self).__init__()self.layers = torch.nn.ModuleList([EncoderBlock(d_model, num_heads) for _ in range(num_layers)])def forward(self, embedding):for layer in self.layers:embedding = layer(embedding)return embeddingclass GeneratorModule(torch.nn.Module):def __init__(self, d_model, num_heads,vocab_size = 3120):super(GeneratorModule, self).__init__()self.embedding_layer = torch.nn.Embedding(vocab_size, d_model)self.encoder = Encoder(d_model, num_heads)self.logits = torch.nn.Linear(d_model, vocab_size)def forward(self, x):embedding = self.embedding_layer(x)embedding = self.encoder(embedding)logits = self.logits(embedding)return logits

同样地,我们在模型设计中,使用了Block模块化的设计思想完成模型的设计,通过堆叠多个模块,对文本的特征进行抽取,并在logits层转换后输出。

另外还需要注意的是,由于我们目标是完成自回归生成任务,而在输出时则需要一个专门的输出格式的函数对其进行输出,代码如下所示。

@torch.no_grad()def generate(self, prompt=None, n_tokens_to_gen=20, temperature=1., top_k=3, sample=False, eos_token=2, device="cuda"):"""根据给定的提示(prompt)生成一段指定长度的序列。参数:- seq_len: 生成序列的总长度。- prompt: 序列生成的起始提示,可以是一个列表。- temperature: 控制生成序列的随机性。温度值越高,生成的序列越随机;温度值越低,生成的序列越确定。- eos_token: 序列结束标记的token ID,默认为2。- return_seq_without_prompt: 是否在返回的序列中不包含初始的提示部分,默认为True。返回:- 生成的序列(包含或不包含初始提示部分,取决于return_seq_without_prompt参数的设置)。"""# 将输入的prompt转换为torch张量,并确保它在正确的设备上(如GPU或CPU)。]self.eval()# prompt = torch.tensor(prompt)prompt = prompt.clone().detach().requires_grad_(False).to(device)input_ids = promptfor token_n in range(n_tokens_to_gen):with torch.no_grad():indices_to_input = input_idsnext_token_logits = self.forward(indices_to_input)next_token_logits = next_token_logits[:, -1]probs = torch.nn.softmax(next_token_logits, dim=-1) * temperature(batch, vocab_size) = probs.shapeif top_k is not None:(values, indices) = torch.topk(probs, k=top_k)probs[probs < values[:, -1, None]] = 0probs = probs / probs.sum(axis=1, keepdims=True)if sample:next_indices = torch.multinomial(probs, num_samples=1)else:next_indices = torch.argmax(probs, dim=-1)[:, None]input_ids = torch.cat([input_ids, next_indices], dim=1)return input_ids

在上面代码中,我们按照自回归模型的性质,每次根据传入的文本,生成下一个字符,之后我们将获取的字符进行转换,再拼接到原始文本中,这样依次拼接的结果即获取到完整的生成内容。

4.3.3  评论生成模型模型的训练

下面就是情感评论生成模型的训练,在这里我们可以仿照前面章节训练的过程,直接对模型进行训练,代码如下所示。

import math
from tqdm import tqdm
import torch
from torch.utils.data import DataLoader
import modeldevice = "cuda"
model = model.GeneratorModule(d_model=312,num_heads=6)
model.to(device)
save_path = "./saver/generator_model.pth"
model.load_state_dict(torch.load(save_path),strict=False)BATCH_SIZE = 360
seq_len = 48
import get_data_emotiontrain_dataset = get_data_emotion.TextSamplerDataset(get_data_emotion.token_list,seq_len=seq_len)
train_loader = (DataLoader(train_dataset, batch_size=BATCH_SIZE,shuffle=True))optimizer = torch.optim.AdamW(model.parameters(), lr = 2e-4)
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max = 1200,eta_min=2e-5,last_epoch=-1)
criterion = torch.nn.CrossEntropyLoss()for epoch in range(60):pbar = tqdm(train_loader,total=len(train_loader))for token_inp,token_tgt in pbar:token_inp = token_inp.to(device)token_tgt = token_tgt.to(device)logits = model(token_inp)loss = criterion(logits.view(-1, logits.size(-1)), token_tgt.view(-1))optimizer.zero_grad()loss.backward()optimizer.step()lr_scheduler.step()  # 执行优化器pbar.set_description(f"epoch:{epoch +1}, train_loss:{loss.item():.5f}, lr:{lr_scheduler.get_last_lr()[0]*1000:.5f}")torch.save(model.state_dict(), save_path)

读者可以自行尝试运行代码查看结果。

4.3.4  使用训练好的模型生成评论

接下来,我们需要使用训练好的模型生成对应的评论。根据自回归模型的指引,我们只需要设置一个起始内容,即可根据需要生成特定的文本。代码如下:

import torch
import modelimport tokenizer
tokenizer_emo = tokenizer.Tokenizer(model_path="../vocab/my_model.model")device = "cuda"
model = model.GeneratorModule(d_model=384,num_heads=6)
model.to(device)save_path = "./saver/generator_model.pth"
model.load_state_dict(torch.load(save_path),strict=False)model.to(device)
model.eval()for _ in range(10):text = "位置"prompt_token = tokenizer_emo.encode(text)prompt_token = torch.tensor([prompt_token]).long().to(device)result_token = model.generate(prompt=prompt_token, n_tokens_to_gen=64,top_k=5,temperature=0.99,device=device)[0].cpu().numpy()text = tokenizer_emo.decode(result_token).split("※")[0]print(text)

部分生成结果如下所示。

位置很好,就在火车站对面,离火车站很近的了,交通很便利,从机场来讲是到市中心,去机场的机场,可以坐在车上。
位置不错,在市中心,交通方便,房间也很大,服务也很好,就是房间的隔音效果比较差,而且很多人性化的服务,服务也不错,总的来说很满意
位置很不错,离火车站很近也很方便。房间装修很好,就是电视太小。
位置很好,就在繁华的路边,出门走5分钟就可以到了。总体来说还可以。
位置很好,就在火车站附近,步行到中心也很方便。房间也很干净,就是有一点点小,不过还是挺干净的,服务员也很有礼貌,有机会会来度假区住这样的酒店很

读者可以自行尝试学习。

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

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

相关文章

关于转置卷积

&#x1f9e0; 具体讲解神经网络中的转置卷积&#xff08;Transposed Convolution&#xff09; &#x1f9ed; 1. 转置卷积的动机&#xff1a;为什么我们需要它&#xff1f; 标准卷积通常会降低特征图的空间尺寸&#xff08;比如从 64x64 → 32x32&#xff09;&#xff0c;这对…

JavaScript 模块化详解( CommonJS、AMD、CMD、ES6模块化)

一.CommonJS 1.概念 CommonJS 规范概述了同步声明依赖的模块定义。这个规范主要用于在服务器端实现模块化代码组 织&#xff0c;但也可用于定义在浏览器中使用的模块依赖。CommonJS 模块语法不能在浏览器中直接运行&#xff1b;在浏览器端&#xff0c;模块需要提前编译打包处理…

TCP BBR 的优化

前段时间&#xff0c;老板发了篇资料&#xff0c;下面是我学习的相关记录整理。 https://aws.amazon.com/cn/blogs/china/talking-about-network-optimization-from-the-flow-control-algorithm/ PS&#xff1a;ubuntu24默认使用的tcp控制算法。还是 cubic sysctl net.ipv4.tc…

什么是异步?

什么是异步&#xff1f; 异步是一个术语&#xff0c;用于描述不需要同时行动或协调就能独立运行的流程。这一概念在技术和计算领域尤为重要&#xff0c;它允许系统的不同部分按自己的节奏运行&#xff0c;而无需等待同步信号或事件。在区块链技术中&#xff0c;异步是指网络中…

SSM婚纱摄影网的设计

&#x1f345;点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345; 项目视频 SS…

石头剪刀布游戏

自己写的一个石头剪刀布游戏&#xff0c;如果有需要更改的地方请指出 #define _CRT_SECURE_NO_WARNINGS // scanf_s编写起来太过于麻烦&#xff0c;直接把这个警告关掉&#xff0c;便于编写。 #include <stdio.h> #include <stdlib.h> #include <time.h> //…

大数据系列之:Kerberos

大数据系列之&#xff1a;Kerberos 基本概念工作流程安全特性应用场景总结加密原理Kerberos认证流程更改您的密码授予账户访问权限票证管理Kerberos 票据属性使用 kinit 获取票据使用 klist 查看票据使用 kdestroy 销毁票据.k5identity 文件描述 Kerberos 是一种网络认证协议&a…

WPF 免费UI 控件HandyControl

示例效果和代码 直接可以用 Button 按钮 | HandyOrg 1.安装 , 输入 HandyControl 2.<!--配置HandyControl--> <!--配置HandyControl--> <ResourceDictionary Source"pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/> …

windows部署docker

1.下载docker 打开浏览器&#xff0c;访问 Docker Desktop 下载页面。 2.安装 Docker Desktop 运行安装程序&#xff1a; 双击下载的 Docker Desktop 安装包&#xff0c;启动安装程序。 选择安装选项&#xff1a; 按照屏幕上的指示进行操作。建议选择默认选项&#xff0c;包…

【Linux】远程登录时,使用图形界面报错:MoTTY X11 proxy: Unsupported authorisation protocol

1、问题描述 使用 MobaXterm 远程登录Ubuntu后,使用sudo权限运行图形界面程序报错: MoTTY X11 proxy: Unsupported authorisation protocol (gpartedbin:10518): Gtk-WARNING **: 22:01:34.377: cannot open display: localhost:10.02、查看SSH配置 修改 SSH 服务端配置,…

解决 Hugging Face SentenceTransformer 下载失败的完整指南:ProxyError、SSLError与手动下载方案

问题背景 在使用 Hugging Face 的 SentenceTransformer 加载预训练模型 all-MiniLM-L6-v2 时&#xff0c;遇到了以下错误&#xff1a; 代理连接失败&#xff08;ProxyError / SSLError: KRB5_S_TKT_NYV&#xff09;大文件下载中断&#xff08;unexpected EOF while reading&a…

MySQL——DQL的单表查询

1、查询表中所有的字段&#xff08;列&#xff09; 语法&#xff1a;select * from 表名; * 是通配符&#xff0c;用来表示所有的字段&#xff08;列&#xff09;。 select 表示查询哪些列。 from 表示从哪张表中查询。 2、查询表中指定的字段 语法&#xff1a;select 列…

开源RuoYi AI助手平台的未来趋势

近年来&#xff0c;人工智能技术的迅猛发展已经深刻地改变了我们的生活和工作方式。 无论是海外的GPT、Claude等国际知名AI助手&#xff0c;还是国内的DeepSeek、Kimi、Qwen等本土化解决方案&#xff0c;都为用户提供了前所未有的便利。然而&#xff0c;对于那些希望构建属于自…

[WUSTCTF2020]CV Maker1

进来是个华丽的界面&#xff0c;我们先跟随这个网页创造一个用户 发现了一个上传端口&#xff0c;尝试上传一个php文件并抓包 直接上传进不去&#xff0c;加个GIF89A uploads/d41d8cd98f00b204e9800998ecf8427e.php 传入 并且报告了 上传路径&#xff0c;然后使用蚁剑连接

Spring 中的 IOC

&#x1f331; 一、什么是 IOC&#xff1f; &#x1f4d6; 定义&#xff08;通俗理解&#xff09;&#xff1a; IOC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09; 是一种设计思想&#xff1a;对象不再由你自己创建和管理&#xff0c;而是交给 Spring 容器…

Vue2-实现elementUI的select全选功能

文章目录 使用 Element UI 的全选功能自定义选项来模拟全选 在使用 Element UI 的 el-select组件时&#xff0c;实现“全选”功能&#xff0c;通常有两种方式&#xff1a;一种是使用内置的全选功能&#xff0c;另一种是通过自定义选项来模拟全选。 使用 Element UI 的全选功能…

小菜Go:Ubuntu下Go语言开发环境搭建

前置要求Ubuntu环境搭建 文章推荐 此处推荐一个比较好的文章&#xff0c;基本按部就班就欧克~ 安装虚拟机&#xff08;VMware&#xff09;保姆级教程&#xff08;附安装包&#xff09;_vmware虚拟机-CSDN博客 安装可能遇到的问题 虚拟机安装遇到的问题如&#xff1a;Exception…

安卓中app_process运行报错Aborted,怎么查看具体的报错日志

我在pc端生成了一个jar包&#xff0c;可以正常执行&#xff0c;但是导入到安卓的/data/local/tmp下面执行就会报错 执行命令如下&#xff1a; adb shell cd /data/local/tmp app_process -Djava.class.path/data/local/tmp/demo.jar /data/local/tmp com.example.demo.Hello然…

Python 面向对象 - 依赖倒置原则 (DIP)

1. 核心概念 依赖倒置原则(Dependency Inversion Principle, DIP) 是SOLID原则中的"D"&#xff0c;包含两个关键点&#xff1a; 高层模块不应依赖低层模块&#xff0c;二者都应依赖抽象抽象不应依赖细节&#xff0c;细节应依赖抽象 2. 使用场景 典型应用场景 系…

centos7 yum install docker 安装错误

1、错误信息&#xff1a; [rootlocalhost atguigu]# yum install docker 已加载插件&#xff1a;fastestmirror, langpacks Repository base is listed more than once in the configuration Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http:…