【Python机器学习】序列到序列建模——使用序列到序列网络构建一个聊天机器人

news2024/9/27 21:29:58

为了寻聊天机器人,下面使用康奈尔电影对话语料库训练一个序列到序列的网络来“适当的”湖大问题或语句。以下聊天机器人示例采用的是Keras blog中的序列到序列的示例。

为训练准备语料库

首先,需要加载语料库并从中生成训练集,训练数据将决定编码器和解码器在训练阶段和生成阶段所支持的字符集。要注意实现代码不支持在训练阶段未包含的字符。使用整个Cornmell Movie Dialog数据集可能需要大量的计算,因为一些序列有超过2000个词条——2000个时刻,需要一段时间才能展开。但是大多数对话样本都是基于少于100个字符的。对于本例,可以通过将样本限制为少于100个字符、删除奇怪字符和只允许使用小写字符,对对话语料库进行预处理。通过这些处理,可以限制字符的种类。

下面将遍历语料库文件并生成训练对(技术上来说是三元组形式:输入文本、带有初始词条的目标文本和目标文本)。在阅读语料库时,还将生成一组输入字符和目标字符,然后将使用这些字符对样本进行独热编码。输入字符和目标字符的数量不必完全匹配。但是在生成阶段,不能读取和生成不包含在训练集中的字符。下面的代码给出的结果是输入文本和目标文本(字符串)的两个列表:

from nlpia.loaders import get_data

df=get_data('moviedialog')
#数组保存从语料库文件中读取的输入文本和目标文本
input_texts,target_texts=[],[]
#这个集合保存输入文本和目标文本中出现过的字符
input_vocabulary=set()
output_vocabulary=set()
#目标序列用start和stop词条进行注释,这里定义了表示词条的字符。这些词条不能作为普通序列文本的一部分,而应该仅仅作为初始词条和终止词条而使用
start_token='\t'
stop_token='\n'
#max_training_samples定义了训练使用的行数。它是用户定义的最大值和从文件中加载的总行数中较小的数
max_training_samples=min(25000,len(df)-1)
for input_text,target_text in zip(df.statement,df.reply):
    #target_text需要用起始词条和终止词条进行包装
    target_text=start_token+target_text+stop_token
    input_texts.append(input_text)
    target_texts.append(target_text)
    #编译词汇表——input_text中出现过的唯一字符的集合
    for char in input_text:
        if char not in input_vocabulary:
            input_vocabulary.add(char)
    for char in target_text:
        if char not in output_vocabulary:
            output_vocabulary.add(char)

建立字符字典

这里需要将输入文本和目标文本的每个字符转换为表示每个字符的独热向量。为了生成独热向量,需要生成词条字典(用于输入文本和目标文本),其中每个字符都被映射到一个索引。另外,还将生成反向字典(索引映射为字符),在生成阶段将使用该反向字典将生成的索引转换为字符,具体代码:

#将字符集转换为排序后的字符列表,然后使用该列表生成字典
input_vocabulary=sorted(input_vocabulary)
output_vocabulary=sorted(output_vocabulary)
#对于输入数据和目标数据,确定唯一字符的最大数量,用于构建一个独热矩阵
input_vocab_size=len(input_vocabulary)
output_vocab_size=len(output_vocabulary)
#对于输入数据和目标数据,还需确定序列词条的最大数量
max_encoder_seq_length=max([len(txt) for txt in input_texts])
max_decoder_seq_length=max([len(txt) for txt in target_texts])

#循环遍历input_vocabulary和output_vocabulary来创建查找字典,用于生成独热向量
input_token_index=dict([(char,i) for i,char in enumerate(input_vocabulary)])
target_token_index=dict([(char,i) for i,char in enumerate(output_vocabulary)])
#循环变量新创建的字典以创建反向查找表
reverse_input_char_index=dict((i,char) for char,i in input_token_index.items())
reverse_target_char_index=dict((i,char) for char,i in target_token_index.items())

生成独热编码训练集

下一步,将输入文本和目标文本转换为独热编码的“张量”。为了做到这一点,需要循环遍历每个输入样本和目标样本以及每个样本的每个字符,并对每个字符进行独热编码。每个字符由一个n*1向量编码(其中n是唯一的输入字符或目标字符的个数),然后针对每个样本将所有向量组合以创建一个矩阵,并将所有样本组合以创建要训练的张量。具体代码:

import numpy as np

encoder_input_data=np.zeros((len(input_texts),max_encoder_seq_length,input_vocab_size),dtype='float32')
#训练的张量初始化形状为(num_samples,max_len_sequence,num_unique_tokens_in_vocab)的零张量
decoder_input_data=np.zeros((len(input_texts),max_decoder_seq_length,output_vocab_size),dtype='float32')
decoder_target_data=np.zeros((len(input_texts),max_decoder_seq_length,output_vocab_size),dtype='float32')

#对训练样本进行寻遍历,输入文本和目标文本需要对应
for i , (input_text,target_text) in enumerate(zip(input_texts,target_texts)):
    #循环遍历每个样本的每个字符
    for t,char in enumerate(input_text):
        encoder_input_data[i,t,input_token_index[char]]=1
    #对解码器的训练数据,这里将创建decoder_input_data和decoder_target_data
    for t,char in enumerate(target_text):
        decoder_input_data[i,t,target_token_index[char]]=1
        if t>0:
            decoder_target_data[i,t-1,target_token_index[char]]=1

训练序列到序列聊天机器人

完成所有准备训练集的工作——将预处理的语料库转换为输入样本和目标样本,创建索引查询字典,并将样本转换为独热张量之后,下面就是训练聊天机器人了。

一旦model.fit函数完成了训练,下面就拥有了一个基于序列到序列的完全训练好的聊天机器人:

from keras.api.models import Model
from keras.api.layers import Input,LSTM,Dense

#批处理大小为64个样本,增加批处理大小可以加快训练速度,但也需要更多的内存
batch_size=64
#100个训练周期
epochs=100
#神经元维数设置为256
num_neurons=256

encoder_inputs=Input(shape=(None,input_vocab_size))
encoder=LSTM(num_neurons,return_state=True)
encoder_outputs,state_h,state_c=encoder(encoder_inputs)
encoder_states=[state_h,state_c]

decoder_inputs=Input(shape=(None,output_vocab_size))
decoder_lstm=LSTM(num_neurons,return_sequences=True,return_state=True)
decoder_outputs,_,_=decoder_lstm(decoder_inputs,initial_state=encoder_states)
decoder_dense=Dense(output_vocab_size,activation='softmax')
decoder_outputs=decoder_dense(decoder_outputs)
model=Model([encoder_inputs,decoder_inputs],decoder_outputs)

model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])
model.fit([encoder_input_data,decoder_input_data],
          decoder_target_data,
          batch_size=batch_size,
          epochs=epochs,
          validation_split=0.1)

但是训练的时间会非常长,100次训练的时间可能达到了10小时以上:

组装序列生成模型

因为没有特定的目标文本和状态输入解码器,所以所拥有的只是输入和一个初始词条,下面开始组装序列生成模型:

encoder_model=Model(encoder_inputs,encoder_states)
thought_input=[
    Input(shape=(num_neurons,)),Input(shape=(num_neurons,))
]
decoder_outputs,state_h,state_c=decoder_lstm(decoder_inputs,initial=thought_input)
decoder_states=[state_h,state_c]
decoder_outputs=decoder_dense(decoder_outputs)

decoder_model=Model(
    inputs=[decoder_inputs]+thought_input,
    output=[decoder_outputs]+decoder_states
)

预测输出序列

decoder_sequence函数是聊天机器人生成回复的核心。它接受独热编码的输入序列,生成思想向量,并使用思想向量通过之前训练好的网络生成合适的回复:

def decode_sequence(input_seq):
    #生成思想向量作为解码器的输入
    thought=encoder_model.predict(input_seq)
    
    #与训练相反,target_seq一开始是一个零张量
    target_seq=np.zeros((1,1,output_vocab_size))
    #解码器的第一个输入词条是初始词条
    target_seq[0,0,target_token_index[stop_token]]=1.0
    stop_condition=False
    generated_sequence=''
    while not stop_condition:
        #将已生成的词条和最新状态传递给解码器,以预测下一个序列
        output_tokens,h,c=decoder_model.predict([target_seq]+thought)
        generated_token_idx=np.argmax(output_tokens[0,-1:])
        generated_char=reverse_target_char_index[generated_token_idx]
        generated_sequence=generated_sequence+generated_char
        if (generated_char==stop_token or len(generated_sequence)>max_decoder_seq_length):
            #将stop_condition设置为True将停止循环
            stop_condition=True
        # 更新目标序列,并使用最后生成的词条作为下一生成步骤的输入
        target_seq=np.zeros((1,1,output_vocab_size))
        target_seq[0,0,generated_token_idx]=1.0
        #更新思想向量状态
        thought=[h,c]
    return generated_sequence

生成回复

现在,定义一个辅助函数response(),用于将输入字符串(例如来自用户的语句)转换为聊天机器人的回复。该函数首先将用户输入的文本转换为由独热编码向量组成的序列。然后将这个独热向量的张量传递给前面定义的decode_sequence()函数。它将输入文本编码成思想向量,并将这些思想向量生成文本:

def responce(input_text):
    input_seq=np.zeros((1,max_encoder_seq_length,input_vocab_size),dtype='float32')
    for t,char in enumerate(input_text):
        input_seq[0,t,input_token_index[char]]=1.0
    decode_sentence=decode_sequence(input_seq)
    print('回复:',decode_sentence)

与聊天机器人交谈

上面已经完成了训练和测试聊天机器人的所有必要步骤,下面就可以尝试沟通:

responce("what id the internet?")

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

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

相关文章

项目升级必备!TS装饰:简化代码、增加功能的利器 | TypeScript入门指南07

嘿,朋友!听说过TS里的装饰器没?就像给代码加了个‘魔法贴’,轻轻一点,功能升级,结构清晰。这篇文章,咱们聊聊这背后的魔法是怎么一回事! ts 入门指南系列 Ts vs Js 谁适合前端开发&a…

用Inno Setup打包QT程序输出安装包

InnoSetup打包编译好的QT程序 文章目录 InnoSetup打包编译好的QT程序介绍具体步骤自定义脚本更改引入配置文件/动态库路径申请管理员权限设置安装过程界面的图标和图片C程序依赖运行库 介绍 Inno Setup:用于打包安装程序 具体步骤 首先打开inno setup compiler 第…

MES系统:智能工厂与数字化改造的关键引擎

一、概念范畴: 数字化工厂:是一个更广泛的概念,它强调整个制造过程的数字化转型,包括从产品设计、生产准备、制造过程、管理到营销等各个环节的数字化。数字化工厂利用信息技术、自动化技术和智能化技术对传统工厂进行改造和升级…

怎样在备忘录中添加提醒?怎么设置备忘录提醒

备忘录作为我们日常生活中常用的软件,其记录事项的便捷性已经得到了广泛认可。无论是工作计划、购物清单还是个人日记,备忘录都能帮助我们将这些信息快速记录下来。然而,如果备忘录能够进一步提供提醒功能,那么它将变得更加实用&a…

为什么要用docker?

目录 一、为什么会有docker出现 二、docker理念 三、容器与虚拟机的差异 四、开发/运维(DevOps) 五、企业级应用 一、为什么会有docker出现 一款产品从开发到上线,从操作系统,到运行环境,再到应用配置。作为开发…

pytorch快速入门(一)—— 基本工具及平台介绍

前言 该pytorch学习笔记应该配合b站小土堆的《pytorch深度学习快速入门教程》使用 环境配置:Anaconda Python编译器:pycharm、jupyter 两大法宝函数 dir():知道包中有什么东西(函数 / 属性..…

串口数据波形显示工具对比

目录 1 Serial Port Plotter 1.1 界面 1.2 简介 1.3 使用方法 1.3.1 单通道示例 1.3.2 多通道示例 2 serialplot 2.1 界面 2.2 简介 2.3 使用方法 1 Serial Port Plotter 1.1 界面 1.2 简介 这是一款开源串口显示工具,项目链接: GitHub - C…

待机模式中WKUP上升沿模拟开机与关机

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发 目录 前言 待机模式 代码 wkup.h wkup.c main.c 使用注意 前言 建议先阅读下面的博客中待机模式部分。本博客主要分享代码-基于待机模式WKUP引脚的上升沿实现类似长按开机与关机的功能…

TikTok云手机解决运营效率低、封号问题

TikTok,一个拥有30亿下载量、10亿活跃用户的全球热门平台,已成为众多出海商家的首选运营阵地。其玩法与国内抖音相似,为运营者提供了熟悉的操作环境,降低了上手难度。然而,随着TikTok的快速发展,运营者们也…

德之匠信息化阶段模型

今天适逢仲秋佳节,祝大家幸福安康! 春生、夏长、秋天也是我们作为知识工作者最开心的季节。经历了项目实践、课题研究,终于能思有一得,是世上第一等的好事。 这个题目的背景是这样。近期我们在做一批中长期信息化项目的分析和总…

深度学习基础案例5--运用动态学习率构建CNN卷积神经网络实现的运动鞋识别(测试集的准确率84%)

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 前言 前几天一直很忙,一直在数学建模中,没有来得及更新,接下来将恢复正常这一次的案例很有意思:在学习动态调整…

【IP协议】解决 IP 地址不够用的问题(IP地址管理:动态分配、NAT、Ipv6)

文章目录 方案一、动态分配 IP 地址方案二、NATNAT 机制的缺点 方案三、IPv6 方案一、动态分配 IP 地址 一个设备上网就分配 IP,不上网就先不分配(权宜之计) 方案二、NAT 网络地址转换 以一当千,使用一个 IP,代表一大…

Golang | Leetcode Golang题解之第404题左叶子之和

题目: 题解: func isLeafNode(node *TreeNode) bool {return node.Left nil && node.Right nil }func sumOfLeftLeaves(root *TreeNode) (ans int) {if root nil {return}q : []*TreeNode{root}for len(q) > 0 {node : q[0]q q[1:]if no…

anaconda 离线安装PySimpleGUI

下载离线py包 PySimpleGUI-5.0.6-py3-none-any.whl(官网)pyasn1-0.6.1-py3-none-any.whl(清华镜像)rsa-4.9-py3-none-any.whl(清华镜像) 打开Anaconda Prompt 测试 # -*- utf-8 -*- import PySimpleGUI …

同城找搭子小程序有哪些?找搭子社交软件测评笔记分享

寻找搭子不再迷茫!今日测评几款热门找搭子小程序,为你开启全新社交体验。真实体验,深度剖析,帮你找到最适合的搭子平台,快来一探究竟。 1. 咕哇找搭子小程序:这是一个实名制的找搭子交友平台。正是由于实名…

任务通知(Task Notifications)

任务通知简介 相对于以前使用 FreeRTOS 内核通信的资源, 必须创建队列、 二进制信号量、计数信号量或事件组的情况, 使用任务通知显然更灵活。 按照 FreeRTOS 官方的说法, 使用任务通知比通过信号量等 IPC 通信方式解除阻塞的任务要快 45%&a…

基于RFID的门禁系统的设计(论文+源码)

1系统方案设计 通过需求分析,基于RFID的门禁系统总体设计框图。系统采用STM32单片机作为系统主控核心,利用独立按键与RFID识别模块能够实现门禁系统密码与IC卡开门功能。WiFi模块实现系统与手机APP的通信,用户可以通过手机APP进行门禁开关操…

怀孕之天赋共享:提高智商

想办法怀个哪吒享受三年,哈哈哈哈哈 话说我们有个同事,是属于憨得有点愣那种,情商也低。怀孕以后突然有一天我觉得她聪明了好几个数量级!反应也快了说话也会说了,我说是不是她的宝宝给她提高了智商?后来生…

Redis学习——数据不一致怎么办?更新缓存失败了又怎么办?

文章目录 引言正文读写缓存的数据一致性只读缓存的数据一致性删除和修改数据不一致问题操作执行失败导致数据不一致解决办法 多线程访问导致数据不一致问题总结 总结参考信息 引言 最近面试快手的时候被问到了缓存不一致怎么解决?一开始还是很懵的,因为…

Git 的使用以及vscode 下git 的使用(一)

1、git 和svn Git 和 SVN 都是版本控制系统,它们都用于管理代码的版本,但它们之间有一些显著的区别: 分布式 vs 集中式:Git 是一个分布式版本控制系统,这意味着每个开发者都拥有整个代码库的完整副本,并且…