NLP作业02:课程设计报告

news2024/11/25 0:52:03

作业头

这个作业属于哪个课程自然语言处理
这个作业要求在哪里NLP作业02:课程设计报告
我在这个课程的目标实现基于Seq2Seq注意力机制的聊天机器人
这个作业在哪个具体方面帮助我实现目标问题的提出,资料的查找
参考文献1.简说Seq2Seq原理以及实现 2.序列到序列学习(seq2seq)  20分钟掌握RNN与LSTM原理及其结构应用(Seq2Seq & Attention)

文章目录

  • 1. 设计目的
  • 2.设计要求
    • 2.1 实验仪器及设备
    • 2.2 设计要求
  • 3.设计内容
  • 4.设计过程
    • 4.1 提出总体设计方案
    • 4.2 具体实现过程
        • 4.2.1 数据收集和预处理
        • 4.2.2 模型搭建
        • 4.2.3 模型训练与保存
        • 4.2.4 聊天机器人
        • 4.2.5 登录界面
  • 5.设计体会

1. 设计目的

通过课程设计的练习,加深学生对所学自然语言处理的理论知识与操作技能的理解和掌握,使得学生能综合运用所学理论知识和操作技能进行实际工程项目的设计开发,让学生真正体会到自然语言处理算法在实际工程项目中的具体应用方法,为今后能够独立或协助工程师进行人工智能产品的开发设计工作奠定基础。通过综合应用项目的实施,培养学生团队协作沟通能力,培养学生运用现代工具分析和解决复杂工程问题的能力;引导学生深刻理解并自觉实践职业精神和职业规范;培养学生遵纪守法、爱岗敬业、诚实守信、开拓创新的职业品格和行为习惯。

2.设计要求

2.1 实验仪器及设备

(1) 使用64位Windows操作系统的电脑。
(2) 使用3.8.16版本的Python。
(3) 使用6.4.12版本的jupyter notebook编辑器。
(4) 使用 numpy,pandas,tensorflow,pyttsx3……

2.2 设计要求

课程设计的主要环节包括课程设计作品和课程设计报告的撰写。课程设计作品的完成主要包含方案设计、计算机编程实现、作品测试几个方面。课程设计报告主要是将课程设计的理论设计内容、实现的过程及测试结果进行全面的总结,把实践内容上升到理论高度。

3.设计内容

本项目针对传统的聊天机器人对话生成机制识别率低的情况,设计一种基于 seq2seq和Attention模型的聊天机器人对话生成机制,一定程度提高了识别率,项目设计内容为:
(1)编码器和解码器
这两个模型本质上都⽤到了两个循环神经⽹络,分别叫做编码器和解码器。 编码器⽤来分析输⼊序列,解码器⽤来⽣成输出序列。
在这里插入图片描述
(2)LSTM
长短期记忆(Long short-term memory)是一种特殊的RNN,主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。

在这里插入图片描述
本项目采用LSTM作为编码器和解码器。
在这里插入图片描述

(3)注意力机制
在这里插入图片描述
编码器在时间步t的隐藏状态为ht,且总时间步数为T。那么解码器在时间步t ′的背景变量为所有编码器隐藏状态的加权平均:
在这里插入图片描述
其中给定t ′时,权重αt ′t在t = 1, . . . , T的值是⼀个概率分布。为了得到概率分布,我们可以使⽤softmax运算:
在这里插入图片描述

计算softmax运算的输⼊et ′t。由于et ′t同时取决于解码器的时间步t ′和编码器的时间步t,不妨以解码器在时间步t ′ − 1的隐藏状态st ′−1与编码器在时间步t的隐藏状态ht为输⼊,并通过函数a计算et ′t:
e_{t^\prime t}=a\left(s_{t^\prime-1},h_t\right).

4.设计过程

4.1 提出总体设计方案

在这里插入图片描述

为了设计基于Seq2Seq注意力机制的聊天机器人系统,需要以下几个步骤:
(1)数据收集和预处理:搜集对话记录数据集,并进行文本清洗、处理,如去除标点符号、转换为小写字母等。将文本序列转换为相应的整数序列,并对数据进行填充,对话记录数据集应包含问题和答案的对应关系。
(2)创建Seq2Seq模型:使用TensorFlow框架创建Seq2Seq模型,其中编码器采用 LSTM,解码器采用 LSTM + 注意力机制。Seq2Seq 模型将问题作为输入,输出答案。
(3)训练模型和保存:将预处理的数据集训练Seq2Seq模型,调整超参数和网络结构优化模型性能。
(4)设计主函数:加载预训练模型的权重参数,通过循环处理输入的文本序列 encoder_input_data,进行机器人对话交互。
(5)构建UI界面,使用 PyQt5设计登录界面,实现正确输入账号密码登录使用基于Seq2Seq注意力模型的聊天机器人系统。

4.2 具体实现过程

4.2.1 数据收集和预处理

(1)数据收集
通过在网上搜集资料,寻找合适的语料库,本项目采用的语料库为Source_segment11.txt
在这里插入图片描述
(2)导入相关库
导入实验所需库,用于后续数据的处理和模型的构建,其中主要使用Tensorflow中的Keras模块,Keras 是一个高级神经网络API,它可以帮助构建和训练深度学习模型,而无需手动编写大量的代码,避免重复造轮子。

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers , activations , models , preprocessing , utils
import pandas as pd
import pyttsx3
import sys

(3)数据预处理
使用中文分词工具jieba,将原来的语料库进行中文分词处理,在自动问答系统中,对于用户输入的问题,我们需要通过自然语言处理技术将其转换成机器能够理解和处理的形式,以便能够正确匹配并返回相应的答案。而中文分词是这个过程中的一环,其主要作用是将中文句子切分为一系列有意义的词汇单位,以便后续的处理。

import jieba
with open('Source_segment11.txt', 'r', encoding='utf-8') as f:
    text = f.read()
seg_list = jieba.cut(text, cut_all=False)
with open('Source_segment12.txt', 'w', encoding='utf-8') as f:
    f.write(' '.join(seg_list))

(4)读取预处理数据
读取预处理数据,移除换行,对文本库数据进行检查,并查看对话内容总数,对数据展示,初步查看数据预处理情况。

text_Segment = open('./Source_segment11.txt','r', encoding='utf-8')
text_Segment_list = text_Segment.readlines()
text_Segment.close()
text_Segment_list = [n.rstrip() for n in text_Segment_list]
if len(text_Segment_list)%2!=0:
    print("文本库数据有误 对话不对称 请检查!")
else:
    print('对话内容总数:', len(text_Segment_list))
X = text_Segment_list[0:][::2] 
Y = text_Segment_list[1:][::2] 
lines = pd.DataFrame({"input":X,"output":Y})
lines.head()

(5)数据填充
使用预处理模块中的 Tokenizer() 方法对其进行处理,将文本数据转换为相应的整数序列。然后,统计所有序列的长度,并找到其中的最大长度作为填充后的标准长度,再使用 pad_sequences() 函数对序列进行填充。

#encoder
input_lines = list()
for line in lines.input:
    input_lines.append(line)
print(input_lines[:4])   
tokenizer = preprocessing.text.Tokenizer()
tokenizer.fit_on_texts(input_lines) 
tokenized_input_lines = tokenizer.texts_to_sequences(input_lines) 
print(tokenized_input_lines[:4])

len_list = list()
for token_line in tokenized_input_lines:
    len_list.append(len(token_line))
print(len_list[:4])
max_len = np.array(len_list).max()
print( '输入最大长度为{}'.format( max_len ))

padded_input_lines = preprocessing.sequence.pad_sequences(tokenized_input_lines, maxlen=max_len, padding='post')
print("进行填充之后:")
print(padded_input_lines[:4])
encoder_input_data = np.array(padded_input_lines)
print( '编码输入数据后的形状 -> {}'.format( encoder_input_data.shape ))

input_word_dict = tokenizer.word_index
# print(input_word_dict)
num_input_tokens = len(input_word_dict) + 1 
print( '输入词元数量 = {}'.format( num_input_tokens))

output_lines = list()
for line in lines.output:
    output_lines.append('<START> ' + line +  ' <END>')
print(output_lines[:4])     
tokenizer = preprocessing.text.Tokenizer()
tokenizer.fit_on_texts(output_lines)
tokenized_output_lines = tokenizer.texts_to_sequences(output_lines)

length_list = list()
for token_seq in tokenized_output_lines:
    length_list.append( len( token_seq ))
max_output_length = np.array( length_list ).max()
print( '输出最大长度为 {}'.format( max_output_length ))

padded_output_lines = preprocessing.sequence.pad_sequences(tokenized_output_lines, maxlen=max_output_length, padding='post')
decoder_input_data = np.array(padded_output_lines)
print( '解码数据后的shape -> {}'.format( decoder_input_data.shape ))

output_word_dict = tokenizer.word_index
num_output_tokens = len(output_word_dict) + 1 
print( '输出词元的数量 = {}'.format( num_output_tokens))

decoder_target_data = list()
for token in tokenized_output_lines:
    decoder_target_data.append(token[1:])
    
padded_output_lines = preprocessing.sequence.pad_sequences(decoder_target_data, maxlen=max_output_length, padding='post')
onehot_output_lines = utils.to_categorical(padded_output_lines, num_output_tokens) #对答案进行 one-hot 编码
decoder_target_data = np.array(onehot_output_lines)
print( 'Decoder target data shape -> {}'.format( decoder_target_data.shape ))

4.2.2 模型搭建

模型搭建包含编码器和解码器两个部分。
(1)编码器的输入
是一个形状为(None,)的张量,表示输入序列的长度是可变的;嵌入层将输入序列中的每个单词转换为一个256维的向量;LSTM层将嵌入层的输出作为输入,返回最后一个时间步的输出和状态向量。这些状态向量将作为解码器的初始状态。

图 4- 11 编码器输入
(2)解码器的输入
也是一个形状为(None,)的张量,表示输出序列的长度是可变的;嵌入层将输出序列中的每个单词转换为一个256维的向量;LSTM层将嵌入层的输出作为输入,同时也接收编码器的状态向量作为初始状态,返回一个形状为(None,256)的张量作为输出序列。

encoder_inputs = tf.keras.layers.Input(shape=( None , ))
#嵌入层将输出序列中的每个单词转换为一个256维的向量
encoder_embedding = tf.keras.layers.Embedding( num_input_tokens, 256 , mask_zero=True ) (encoder_inputs) #编码器的嵌入层
#LSTM层将嵌入层的输出作为输入,同时也接收编码器的状态向量作为初始状态,返回一个形状为(None,256)的张量作为输出序列
encoder_lstm = tf.keras.layers.LSTM( 256 , return_state=True , recurrent_activation = 'sigmoid',dropout=0.2)
encoder_outputs , state_h , state_c = encoder_lstm( encoder_embedding )
encoder_states = [ state_h , state_c ]

decoder_inputs = tf.keras.layers.Input(shape=( None ,  ))
decoder_embedding = tf.keras.layers.Embedding( num_output_tokens, 256 , mask_zero=True) (decoder_inputs)
decoder_lstm = tf.keras.layers.LSTM( 256 , return_state=True , recurrent_activation = 'sigmoid',return_sequences=True,dropout=0.2)
decoder_outputs , _ , _ = decoder_lstm ( decoder_embedding , initial_state=encoder_states)

(3)注意力机制,
通过计算解码器的输出序列和编码器的输出序列之间的相似度,得到一个权重向量,表示解码器在生成当前单词时应该关注编码器输出序列的哪些部分。这个权重向量会被用来加权编码器的输出序列,得到一个加权向量,作为解码器的输入。

#注意力机制
attention = tf.keras.layers.Attention(name='attention_layer')
attention_output = attention([decoder_outputs,encoder_outputs])

(4)Concatenate和全连接层
将解码器的输出向量映射到一个形状为(num_output_tokens)的张量,表示输出序列中每个单词的概率分布。

#定义 Concatenate 层,并将解码器 LSTM 层的输出 decoder_outputs 与 attention_output 进行连接。       
decoder_concat = tf.keras.layers.Concatenate(axis=-1, name='concat_layer')
decoder_concat_input = decoder_concat([decoder_outputs, attention_output])

#全连接层
decoder_dense = tf.keras.layers.Dense( num_output_tokens , activation=tf.keras.activations.softmax ) 
output = decoder_dense ( decoder_concat_input )
 #预训练的神经网络模型
model = tf.keras.models.Model([encoder_inputs, decoder_inputs], output )
#编译模型,使用 Adam 优化器以及交叉熵损失函数进行训练,同时使用 accuracy 指标查询准确率
model.compile(optimizer=tf.keras.optimizers.Adam(), loss='categorical_crossentropy',metrics=['accuracy'])

(5)模型预训练和编译
模型的损失函数为交叉熵,优化器为Adam,评价指标为准确率。模型的输入是编码器和解码器的输入张量,输出是全连接层的输出张量。模型结构的具体信息可以通过调用summary()方法进行查看。
在这里插入图片描述

其中:

符号解释
M类别的数量
yic符号函数( 0 或 1 )
pic观测样本 i 属于类别 c 的预测概率
model.summary() #查看模型结构的具体信息

在这里插入图片描述

#导入下面的库
from tensorflow.keras.utils import plot_model  
import pydotplus  
#参数 :模型名称,结构图保存位置,是否展示shape
plot_model(model,to_file='model.png',show_shapes=True)

在这里插入图片描述

4.2.3 模型训练与保存

(1)代码定义了一个生成随机 batch 数据的函数 generate_batch_data_random,用于逐步提取数据并降低对显存的占用。

DEFAULT_BATCH_SIZE = 32
DEFAULT_EPOCH = 200
import random 
def generate_batch_data_random(x1,x2, y, batch_size):
    """逐步提取batch数据到显存,降低对显存的占用"""
    ylen = len(y)
    loopcount = ylen // batch_size
    while (True):
        i = random.randint(0,loopcount)
        yield [x1[i * batch_size:(i + 1) * batch_size],x2[i * batch_size:(i + 1) * batch_size]], y[i * batch_size:(i + 1) * batch_size]

(2)计算训练集的批次数,以便在训练过程中使用。然后,使用generate_batch_data_random函数生成随机批次的训练数据,并使用fit函数进行训练。其中,steps_per_epoch参数设置为train_num_batches,表示在一个epoch中训练的批次数。batch_size参数设置为DEFAULT_BATCH_SIZE,表示每个批次的大小。epochs参数设置为DEFAULT_EPOCH,表示训练的轮数。最后,使用save函数将训练好的模型保存为’h5’格式的文件。

train_num_batches = len(encoder_input_data) // DEFAULT_BATCH_SIZE #
model.fit(generate_batch_data_random(encoder_input_data,decoder_input_data,decoder_target_data,DEFAULT_BATCH_SIZE)
,steps_per_epoch=train_num_batches, batch_size=DEFAULT_BATCH_SIZE, epochs=DEFAULT_EPOCH) 
model.save( 'model.h5' ) 

(3)将训练好的编码器和解码器模型组合成一个完整的推理模型。在推理阶段,该模型可以一步一步地生成目标序列,直到完成整个序列的生成,并且可以对每一步的输出进行调整和优化。

def make_inference_model():
    encoder_outputs , state_h , state_c = encoder_lstm( encoder_embedding )
    encoder_model = tf.keras.models.Model(encoder_inputs, [encoder_outputs,encoder_states])
    decoder_state_input_h = tf.keras.layers.Input(shape=(256,))
    decoder_state_input_c = tf.keras.layers.Input(shape=(256,))
    
    decoder_state_inputs = [decoder_state_input_h, decoder_state_input_c]
    
    decoder_outputs, state_h, state_c = decoder_lstm(decoder_embedding, decoder_state_inputs)
    decoder_states = [state_h, state_c]

    attention_output = attention([decoder_outputs,encoder_outputs])
    decoder_concat_input = decoder_concat([decoder_outputs, attention_output])
    decoder_outputs = decoder_dense(decoder_concat_input)

    decoder_model = tf.keras.models.Model([decoder_inputs,encoder_outputs] + decoder_state_inputs, [decoder_outputs] + decoder_states)
    return encoder_model, decoder_model
enc_model , dec_model = make_inference_model()

4.2.4 聊天机器人

(1)定义str_to_token函数,将一个输入的句子转换为一个数字序列。

import jieba
def str_to_token (sentence: str):
    words = sentence.lower().strip()
    words = jieba.cut(words)
    token_list = list()
    for word in words: 
        token_list.append(input_word_dict[word])
    return preprocessing.sequence.pad_sequences([token_list], maxlen=max_len, padding='post')

(2)定义聊天机器人函数,实现一个简单的基于预训练模型的聊天机器人,它可以接收用户的文本输入,使用预训练模型生成合适的响应,并通过语音输出等方式进行回复。

4.2.5 登录界面

设计一个登录界面,用户,输入正确的账号密码,方可登录聊天机器人系统,若输入错误,会有错误提示。

# 导入所需的库
import sys
import numpy as np
import pyttsx3
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QLineEdit, QVBoxLayout
from PyQt5.QtCore import Qt

# 加载模型和词典
model = ... # 省略模型加载的代码
output_word_dict = ... # 省略词典加载的代码

# 定义一个将字符串转换为token的函数
def str_to_token(sentence):
    # 省略转换逻辑的代码
    return token

# 创建一个聊天机器人类
class Chatbot:
    def __init__(self):
        # 初始化语音引擎对象
        self.engine = pyttsx3.init()
        # 加载编码器和解码器模型
        self.enc_model = ... # 省略模型加载的代码
        self.dec_model = ... # 省略模型加载的代码
    
    # 定义一个回答用户输入的方法
    def reply(self, user_input):
        # 初始化一个空的翻译结果
        decoded_translation = ''
        try:
            # 用编码器模型预测用户输入的状态值和输出值
            encoder_outputs, states_values = self.enc_model.predict(str_to_token(user_input))
            # 创建一个空的目标序列
            empty_target_seq = np.zeros((1, 1))
            # 将目标序列的第一个元素设为"start"对应的索引值
            empty_target_seq[0, 0] = output_word_dict['start']
            # 初始化一个停止条件为False
            stop_condition = False
            # 循环直到停止条件为True
            while not stop_condition:
                # 用解码器模型预测目标序列,状态值和输出值
                dec_outputs, h, c = self.dec_model.predict([empty_target_seq, encoder_outputs] + states_values)
                # 获取输出值中最大概率对应的索引值
                sampled_word_index = np.argmax(dec_outputs[0, -1, :])
                # 初始化一个采样的单词为None
                sampled_word = None
                # 遍历输出词典,找到索引值对应的单词
                for word, index in output_word_dict.items():
                    if sampled_word_index == index:
                        # 将单词添加到翻译结果中,并加上空格
                        decoded_translation += ' {}'.format(word)
                        # 更新采样的单词为找到的单词
                        sampled_word = word

                # 如果采样的单词是"end"或者翻译结果超过最大长度,更新停止条件为True
                if sampled_word == 'end' or len(decoded_translation.split()) > max_output_length:
                    stop_condition = True
                
                # 创建一个新的空目标序列
                empty_target_seq = np.zeros((1, 1))
                # 将目标序列的第一个元素设为采样单词对应的索引值
                empty_target_seq[0, 0] = sampled_word_index
                # 更新状态值为当前状态值
                states_values = [h, c]
        except:
            # 如果出现异常,将翻译结果设为一个默认回答
            decoded_translation = '对不起,我没有听懂。'
        
        # 返回去掉"end"和空格后的翻译结果
        return decoded_translation.replace(' end', '').replace(' ', '')

# 创建一个图形用户界面类
class GUI(QWidget):
    def __init__(self):
        super().__init__()
        # 初始化一个聊天机器人对象
        self.chatbot = Chatbot()
        # 初始化图形用户界面
        self.initUI()
    
    def initUI(self):
        # 设置窗口标题
        self.setWindowTitle('聊天界面')
        # 设置窗口大小
        self.resize(400, 400)
        # 设置窗口背景颜色
        self.setStyleSheet('background-color: lightblue')
        # 创建一个文本框,用于显示聊天记录,设置为只读模式
        self.text_box = QTextEdit(self)
        self.text_box.setReadOnly(True)
        # 创建一个输入框,用于输入用户信息,设置为单行模式
        self.entry_box = QLineEdit(self)
        self.entry_box.setPlaceholderText('请输入一些内容')
        # 绑定回车键事件,调用send方法
        self.entry_box.returnPressed.connect(self.send)
        # 创建一个垂直布局,将文本框和输入框添加到布局中
        layout = QVBoxLayout(self)
        layout.addWidget(self.text_box)
        layout.addWidget(self.entry_box)
    
    # 定义一个发送用户输入并接收机器人回答的方法
    def send(self):
        # 获取用户输入的内容
        user_input = self.entry_box.text()
        # 清空输入框
        self.entry_box.clear()
        # 在文本框中显示用户输入的内容,并换行
        self.text_box.append('user:👨🏻‍🎓' + user_input)
        # 调用聊天机器人的回答方法,获取机器人回答的内容
        bot_output = self.chatbot.reply(user_input)
        # 在文本框中显示机器人回答的内容,并换行
        self.text_box.append('chatbot🤖:' + bot_output)
        # 调用语音引擎说出机器人回答的内容
        self.chatbot.engine.say(bot_output)
        self.chatbot.engine.runAndWait()

# 创建一个应用对象
app = QApplication(sys.argv)
# 创建一个图形用户界面对象
gui = GUI()
# 显示图形用户界面
gui.show()
# 进入主循环,等待用户交互
sys.exit(app.exec_())

5.设计体会

历时七天的自然语言处理实训,是在写代码中度过的,我想这也是我们大都数同学,第一次这么长时间的坐在一起去认真搞一个项目;这对我来说,是一段特殊的回忆,并且我想,通过认真做项目,这在很大程度上提高了我们的动手能力,就比如说,在本次项目的开发过程中,我通过查找资料,看视频课学到了很多的关于自然语言处理和神经网络与深度学习方面的知识,我还拓展了该项目,为我的聊天机器人设计了一个登录界面,进而,我也学会了一些PyQt5界面设计技巧,我相信通过后续的进一步学习思考,我的聊天机器人将变得更加完善。
我选择了大都数人认为难实现的实验三作为我本次自然语言的课程设计,原因有很多,更多的是因为兴趣使然,随着ChatGPT的爆红,聊天机器人作为一种智能化的交互方式受到了越来越多人的欢迎。尤其是在各种社交软件和智能家居中,聊天机器人已经成为人们生活和工作中不可缺少的一部分。而基于 Seq2Seq 注意力机制的聊天机器人,则是目前比较常见和有效的一种技术方案,这让我忍不住想动手去试一试,实现一个自己的简单聊天机器人。
Seq2Seq 作为一种经典的神经网络模型,由编码器和解码器两个部分组成。编码器将输入序列压缩成一个定长向量,并将其传递给解码器,解码器再根据该向量生成输出序列。
然而,当输入或输出序列很长时,编码器和解码器无法保留所有信息,从而导致信息冗余和模型性能下降。为了解决这个问题,注意力机制被引入并得到成功应用。它通过学习每个输入位置与输出位置之间的相似度,使解码器能够关注输入序列中与当前输出位置最相关的部分,从而提高模型的效果。
在聊天机器人的实现中,我们可以使用 Seq2Seq 注意力机制来判断用户的输入并生成相应的回复。
首先,我们需要对聊天记录进行预处理,将原始数据转化为模型可以理解并处理的格式。这个过程通常涉及到文本清洗、分词、词向量化等一系列步骤。然后,我们可以将用户的输入作为编码器的输入,并将生成的定长向量传递给解码器。解码器通过注意力机制来生成相应的回复,并将其返回给用户。
除了技术方案,聊天机器人的交互设计也是十分重要的。为了增强用户体验,我考虑如何让用户尽可能地简便地使用聊天机器人。为此,我采用了 GUI 开发工具,如 PyQt5 等,来实现友好、直观、便捷的用户界面,从而提高用户的操作体验和满意度。例如,可以设计一个具有登录功能的界面,以便用户可以通过输入用户名和密码来进入聊天室。
在完成聊天机器人项目的过程中,我遇到了很多困难,比如说,对注意力机制和编码器解码器模型的不够理解,对PyQt5的使用,知之甚少,但是这些问题大都得到了解决,同时我增加了一些融合创新,使得整个界面看起来与众不同,这让我感受到了快速学习和创新思维的重要性。在技术和设计之间进行融合时,需要全面地考虑各种情况,并及时解决遇到的问题。同时,需要有创新思维和创造力,能够不断地推陈出新,做出更好的应用体验。此外,我还需要定期更新和优化模型,在不断学习新技术、新算法的基础上,提高聊天机器人的表现。
总的来说,基于 Seq2Seq 注意力机制的聊天机器人是一个相对较为复杂的应用,需要综合运用多种技术和工具并考虑到许多复杂因素。在实际开发中,需要我们不断地学习、思考和实践,以达到更好的应用效果和用户使用体验。

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

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

相关文章

Android加载大图策略,防止OOM

前言 Android中图片以位图&#xff08;Bitmap&#xff09;的形式存在&#xff0c;位图常见的格式有.png、.jgp、.bmp、.gif。在加载图片的过程中常见的就是OOM&#xff08;Out of Memory&#xff09;内存溢出。 内存溢出是系统会给APP分配内存也就是Heap Size值。当APP占用的内…

含多类型充电桩的电动汽车充电站优化配置方法(matlab代码)

目录 1 主要内容 目标函数 约束条件 程序亮点 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现博士文章《互动环境下分布式电源与电动汽车充电站的优化配置方法研究》第三章《含多类型充电桩的电动汽车充电站优化配置方法》&#xff0c;本章选择3种典型的电动汽…

乐鑫创客沙龙精彩回顾|激发创新、共享技术

近期&#xff0c;乐鑫科技在全国多个城市举办了 ESP Friends 创客沙龙活动&#xff0c;吸引了来自物联网各个领域的企业家、开发者、创客和学生的参与&#xff0c;包含智能硬件企业家、技术自媒体、教育从业者、博士生、高校学生等。他们与乐鑫资深应用工程师和技术专家面对面深…

冯诺依曼体系结构和操作系统的工作方式

目录 一. 冯诺依曼体系结构 1.1 什么是冯诺依曼体系结构 1.2 为什么冯诺依曼体系结构这样设计 1.3 冯诺依曼体系结构与现实问题的结合 二. 操作系统的工作方式 2.1 操作系统的功能 2.2 操作系统对下进行软硬件管理的方式 2.3 操作系统对上提供使用环境的方式 三. 总结…

泛微E-Office前台文件上传漏洞

0x01 阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&…

史上最全Hadoop面试题:尼恩大数据面试宝典专题1

说在前面&#xff1a; 《尼恩 大数据 面试宝典》 是 《尼恩Java面试宝典》 姊妹篇。 这里特别说明一下&#xff1a;《尼恩Java面试宝典》41个专题 PDF &#xff08;请在文末获取&#xff09;自发布以来&#xff0c; 已经收集了 好几千题&#xff0c; 足足4000多页&#xff0c…

android 如何分析应用的内存(八)——Android 7.0以后的malloc debug

android 如何分析应用的内存&#xff08;八&#xff09; 接上文&#xff0c;介绍六大板块中的第三个————malloc调试和libc回调 上一篇文章中&#xff0c;仅仅是在分配和释放的时候&#xff0c;拦截对应的操作。而不能进一步的去检查内存问题。比如&#xff1a;释放之后再…

卖家必看,要做好独立站,一定要知道的八件事!

如何打造并运营你的跨境独立站&#xff1f;如何吸引更多的流量并促使他们在你的网站下单&#xff1f;在你决定开设独立站之前&#xff0c;以下这些方面是你必须要考虑的&#xff0c;否则你的独立站可能会面临失败的风险。 一、定义目标受众 你是B2B业务还是B2C独立站&#xff…

小区物业电瓶车充电桩收费管理系统 支持扫码刷卡

电动车火灾事故频频发生&#xff0c;毫不起眼的电动车屡次引发夺命大火&#xff0c;电动车已然成为火灾“重灾区”。为预防和遏制电动自行车火灾事故发生&#xff0c;国家三令五申各种政策&#xff0c;为此公安部安委会曾出台《电动自行车集中停放和充电治理方案》。 大部分充电…

visionOS:理想的UI设计竟要考虑这么多细节

拥有对macOS、iPadOS、watchOS、iOS等系统的开发经验&#xff0c;苹果在XR操作系统设计上也具有先天优势&#xff0c;相比于其他公司从头开始构建XR系统界面&#xff0c;苹果可直接借鉴已经过验证的设计美学。 与此同时&#xff0c;WWDC 2023上公布的一系列开发者教程来看&…

Vue3 + Vite + Ts自己封装的基础组件库发布npm ,npm安装使用(Volar )支持TS 类型提示功能(vite-plugin-dts 使用)

一、需求 在开发Vue3 Ts项目时&#xff1a;使用自己二次封装的基础组件&#xff0c;没有Ts类型提示&#xff0c;不能像Element-plus鼠标停在标签或者属性上就能提示当前组件有哪些属性&#xff08;即props&#xff09;及其属性的类型&#xff0c;如下图是Element-plus组件的使…

将mp3音频剪切器收藏起来使用

小明&#xff1a;最近我在剪视频&#xff0c;发现剪出来的音频还需要再进行剪辑和编辑&#xff0c;感觉有点繁琐啊。 小红&#xff1a;是啊&#xff0c;如果能有一个方便快捷的工具就好了&#xff0c;就是不知道剪切音频制作软件推荐免费有哪些&#xff1f; 小明&#xff1a;…

前端开发中遇到的小bug--解决方案

1.在 searchBox 搜索栏中&#xff0c;用到了多级下拉框的筛选条件&#xff0c;样式如下&#xff1a; 这样看起来是没什么问题的&#xff0c;但当我选择时&#xff0c;在框中显示的内容和筛选条件的内容就出错了&#xff1a; 这里其实是选择了 采矿业 -- 石油和天然气开采业 &am…

每日一练 | 华为认证真题练习Day63

1、IEEE 802.1D标准中规定桥优先级是多少bit&#xff1f; A. 8 B. 4 C. 16 D. 2 2、RSTP中处于Discarding状态下的端口&#xff0c;虽然会对接收到的数据帧做丢弃处理&#xff0c;但可以根据该端口收到的数据帧维护MAC地址表。 A. 对 B. 错 3、如下图所示&#xff0c;下列…

随笔-不要裸辞

2023年5月份&#xff0c;16-24岁、25-59岁劳动力调查失业率分别为20.8%、4.1%。 先不说这些大数据&#xff0c;就聊聊我身边发生的事儿。 NO1 欢迎你&#xff0c;新同事 A&#xff0c;别的项目组的&#xff0c;先前通过一个同事说过几句话&#xff0c;那是真正的点头之交。今…

「Java核心技术大会 2023」6月重磅启动,邀你共同探讨Java生态(文末送书5本)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

slam十四讲 03 Eigen实践之不同坐标系下的坐标转换

目录 1. 题目 2. 使用欧式变换 3. 使用四元素 1. 题目 已知 (1) 世界坐标系到相机1坐标系变换关系为&#xff0c;即相机1的位姿q1[0.35,0.2,0.3,0.1]^T, t1[0.3,0.1,0.1]^T. (2) 世界坐标系到相机2坐标系变换关系为&#xff0c;即相机2的位姿q1[-0.5,0.4,-0.1,0.2]^T, t2[…

影响无线状态监控系统质量的关键:如何选择MEMS传感器?

随着工业领域对设备状态监测的需求不断增加&#xff0c;智能无线监测器成为一种重要的技术工具。其中&#xff0c;MEMS&#xff08;微机电系统&#xff09;传感器作为无线状态监控系统中的核心组件&#xff0c;发挥着关键的作用。本文将介绍如何为无线状态监控系统选择最佳的ME…

端午将至,VR全景奉上别开生面的“云上”端午节

端午将至&#xff0c;街上早已飘溢着粽子的香气&#xff0c;大家知道端午习俗有哪些吗&#xff1f;除了吃粽子&#xff0c;还有赛龙舟、悬艾蒿、踩露水、佩香囊等。搭乘端午假期的“顺风车”&#xff0c;多地都在推出活动吸引游客&#xff0c;各地文旅期望打造集文化、传承、艺…

在Linux中部署Flask+Gunicorn+Nginx

flask是一个轻量级的基于Werkzeug和Jinja2模板引擎的Web应用框架。gunicorn能与很多Web框架兼容&#xff0c;执行起来很简单&#xff0c;资源消耗很少&#xff0c;并且运行速度很快。 flaskgunicornnginx部署在公网IP为x.x.x.x的服务器上。 flask需要部署在Python3的环境中。…