当前位置:   article > 正文

基于深度学习的聊天机器人项目

基于深度学习的聊天机器人项目

目录

项目创作背景和目的

项目背景

项目目的

数据来源和处理

数据预处理

模型构建

神经网络结构

损失函数和超参数调节 

模型训练

模型评估

成果展示

界面开发


项目创作背景和目的

项目背景

在当今数字化和信息化的时代,聊天机器人在各个领域的应用越来越广泛。它们能够帮助企业提高客户服务效率,减少人力成本,并提供24小时不间断的服务。通过自然语言处理技术,聊天机器人可以理解用户的语言并作出相应的回答。

项目目的

本项目旨在开发一个基础的聊天机器人,能够处理简单的中文问答对话。通过这个项目,我们希望学习并实践自然语言处理和深度学习的相关技术,理解聊天机器人的工作原理,并探索其在实际应用中的潜力。

数据来源和处理

我们的数据主要来源于天池Chinese Medical Dialogue Dataset 中文医疗对话数据集,因为我们所拥有的个人计算机算力有限,而数据庞大,只截取了其中的800条数据和问答部分进行训练测试。这些数据主要涵盖了外科医疗中的常见问题和回答。

数据预处理

先截取了其中我们想要的部分数据,后将数据拆分为输入部分和输出部分。接着使用Tokenizer分词器将文本数据转换为序列,并进行填充以保证序列长度一致。再通过Tokenizer,将文本数据转换为模型可以理解的数字序列。

示例代码

  1. import pandas as pd
  2. import tensorflow as tf
  3. from tensorflow.keras.preprocessing.text import Tokenizer
  4. from tensorflow.keras.preprocessing.sequence import pad_sequences
  5. import numpy as np
  6. import matplotlib.pyplot as plt
  7. import pickle
  8. # 读取对话数据,假设数据编码格式为 ANSI
  9. data = pd.read_csv('外科5-14000.csv', encoding='ansi')
  10. # 截取前500条数据
  11. data = data.head(800)
  12. # 只保留 "ask" 和 "answer" 列
  13. data = data[['title', 'answer']]
  14. # 将截取后的数据转换为 UTF-8 编码并保存到新的 CSV 文件中
  15. data.to_csv('data.csv', encoding='utf-8', index=False)
  16. # 重新读取截取后的数据
  17. data = pd.read_csv('data.csv')
  18. data.info()
  19. # 拆分数据为输入和输出部分
  20. input_texts = data['title'].tolist()
  21. target_texts = data['answer'].tolist()
  22. # 初始化 Tokenizer
  23. tokenizer = Tokenizer(num_words=10000)
  24. tokenizer.fit_on_texts(input_texts + target_texts)
  25. # 保存 Tokenizer
  26. with open('tokenizer.pkl', 'wb') as handle:
  27. pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL)
  28. # 文本转换为序列
  29. input_sequences = tokenizer.texts_to_sequences(input_texts)
  30. target_sequences = tokenizer.texts_to_sequences(target_texts)
  31. # 序列填充
  32. max_sequence_length = 50 # 根据数据长度设定
  33. padded_input_sequences = pad_sequences(input_sequences, maxlen=max_sequence_length)
  34. padded_target_sequences = pad_sequences(target_sequences, maxlen=max_sequence_length)

模型构建

我们选择了基于 TensorFlow 和 Keras 构建一个简单的 Seq2Seq 模型。这种模型结构在处理序列生成任务(如机器翻译)时非常有效。我们将使用一个嵌入层和一个 LSTM 层来构建模型。

示例代码

  1. # 构建模型
  2. from tensorflow.keras.models import Model
  3. from tensorflow.keras.layers import Input, LSTM, Dense, Embedding
  4. def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
  5. input = Input(shape=(None,))
  6. x = Embedding(vocab_size, embedding_dim)(input)
  7. x = LSTM(rnn_units, return_sequences=True)(x)
  8. output = Dense(vocab_size, activation='softmax')(x)
  9. model = Model(inputs=input, outputs=output)
  10. return model
  11. vocab_size = 10000
  12. embedding_dim = 256
  13. rnn_units = 1024
  14. batch_size = 10
  15. model = build_model(vocab_size, embedding_dim, rnn_units, batch_size)
  16. model.summary()

神经网络结构

 模型共有3层:Embedding层、LSTM层和Dense层。Embedding层有256个单元,LSTM层有1024个单元,Dense层输出维度为10000。

模型总共有18056976个参数,约为68.88 MB。所有参数都是可训练的。

损失函数和超参数调节 

我们使用交叉熵损失函数(sparse_categorical_crossentropy),这种损失函数在分类问题中非常常用,能够有效地衡量模型预测与真实标签之间的差距。

在调节超参数时,尝试了不同的优化器(如Adam、SGD等)、学习率等。通过实验发现,Adam优化器在这个任务中表现较好。

模型训练

训练过程中loss的变化

共进行了450个Epoch的训练。随着Epoch的增加,损失值逐渐下降,从初始的4.0241下降到最终的0.2429。这表明模型在训练过程中逐渐学习到了数据的模式和特征。

将输入序列和目标序列进行准备。目标序列通过将输入序列右移一位来生成,这样模型在每个时间步都可以看到上一个时间步的输出。我们通过绘制训练过程中损失的变化图表,可以直观地了解模型的训练情况

示例代码

  1. # 准备标签数据,使用序列移位方法来生成输入和目标
  2. target_sequences_shifted = np.zeros_like(padded_target_sequences)
  3. target_sequences_shifted[:, :-1] = padded_target_sequences[:, 1:]
  4. target_sequences_shifted[:, -1] = padded_target_sequences[:, -1]
  5. # 编译并训练模型
  6. model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
  7. history = model.fit(padded_input_sequences, target_sequences_shifted, epochs=450)

模型评估

训练完成后,我们绘制了训练过程中损失的变化图,并评估了模型在测试数据上的表现。

示例代码

  1. # 绘制训练过程中损失的变化
  2. plt.plot(history.history['loss'])
  3. plt.title('Model Loss Progression')
  4. plt.ylabel('Loss')
  5. plt.xlabel('Epoch')
  6. plt.legend(['Train'], loc='upper left')
  7. plt.show()
  8. # 保存模型
  9. model.save('chatbot_model.h5')
  10. # 模型评估
  11. loss = model.evaluate(padded_input_sequences, target_sequences_shifted)
  12. print(f'Model Loss: {loss}')

成果展示

我们定义一个函数来生成响应,并测试该函数。通过输入一个测试文本,模型能够生成相应的回复。

示例代码

  1. # 测试生成响应
  2. def predict_response(input_text):
  3. input_seq = tokenizer.texts_to_sequences([input_text])
  4. input_seq = pad_sequences(input_seq, maxlen=20)
  5. prediction = model.predict(input_seq)
  6. predicted_seq = np.argmax(prediction, axis=-1)
  7. predicted_text = tokenizer.sequences_to_texts(predicted_seq)
  8. return predicted_text
  9. # 示例测试
  10. test_text = "阑尾炎微创手术效果怎么样"
  11. response = predict_response(test_text)
  12. print(f'Input: {test_text}')
  13. print(f'Response: {response}')

运行结果 

界面开发 

但是这样的结果输出太过于单调了,于是我们用PYQT5开发了一个界面用于问答展示

一、导入必要的库

  1. import sys
  2. from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLineEdit, QTextEdit, QPushButton
  3. import tensorflow as tf
  4. from tensorflow.keras.preprocessing.sequence import pad_sequences
  5. import numpy as np
  6. import pickle
  • sys:用于系统相关的操作。
  • PyQt5.QtWidgets:导入PyQt5库中的各种窗口小部件,用于创建GUI。
  • tensorflowtensorflow.keras:用于加载和使用深度学习模型。
  • numpy:用于科学计算和数组操作。
  • pickle:用于加载之前保存的Tokenizer对象。

 二、加载模型和Tokenizer

  1. # 加载模型
  2. model = tf.keras.models.load_model('chatbot_model.h5')
  3. # 加载 Tokenizer
  4. with open('tokenizer.pkl', 'rb') as handle:
  5. tokenizer = pickle.load(handle)
  • 加载预训练的聊天机器人模型chatbot_model.h5
  • 使用pickle加载之前保存的Tokenizer对象,用于将文本转换为序列。

三、定义预测函数

  1. def predict_response(input_text):
  2. input_seq = tokenizer.texts_to_sequences([input_text])
  3. input_seq = pad_sequences(input_seq, maxlen=20)
  4. prediction = model.predict(input_seq)
  5. predicted_seq = np.argmax(prediction, axis=-1)
  6. predicted_text = tokenizer.sequences_to_texts(predicted_seq)
  7. return predicted_text[0]
  • input_text:用户输入的文本。
  • 将文本转换为序列(数字表示)。
  • 使用pad_sequences将序列填充到固定长度(20)。
  • 使用模型预测结果。
  • np.argmax找到每个时间步长上预测概率最高的词的索引。
  • 将预测的序列转换回文本。
  • 返回生成的文本。

四、 创建聊天机器人应用程序类

  1. class ChatBotApp(QMainWindow):
  2. def __init__(self):
  3. super().__init__()
  4. self.setWindowTitle("ChatBot医疗问答系统")
  5. self.setGeometry(300, 300, 700, 600)
  6. self.central_widget = QWidget()
  7. self.setCentralWidget(self.central_widget)
  8. self.layout = QVBoxLayout()
  9. self.chat_display = QTextEdit()
  10. self.chat_display.setReadOnly(True)
  11. self.layout.addWidget(self.chat_display)
  12. self.input_layout = QHBoxLayout()
  13. self.user_input = QLineEdit()
  14. self.user_input.setPlaceholderText("请输入你的问题")
  15. self.input_layout.addWidget(self.user_input)
  16. self.send_button = QPushButton("提问")
  17. self.send_button.clicked.connect(self.handle_send)
  18. self.input_layout.addWidget(self.send_button)
  19. self.layout.addLayout(self.input_layout)
  20. self.central_widget.setLayout(self.layout)
  • ChatBotApp类继承自QMainWindow,表示主窗口。
  • 设置窗口标题和大小。
  • 创建中心小部件和布局(垂直和水平布局)。
  • 创建并设置聊天显示区域QTextEdit,用于显示聊天内容。
  • 创建输入框QLineEdit和发送按钮QPushButton,用于输入问题并触发发送操作。
  • 将输入框和按钮添加到水平布局,再将此布局添加到主垂直布局中。

五、 处理发送按钮点击事件

  1. def handle_send(self):
  2. user_text = self.user_input.text()
  3. if user_text.strip():
  4. self.chat_display.append(f"User: {user_text}")
  5. response = predict_response(user_text)
  6. self.chat_display.append(f"ChatBot: {response}")
  7. self.user_input.clear()
  • handle_send方法用于处理发送按钮的点击事件。
  • 获取用户输入的文本,并检查其是否为空。
  • 如果不为空,将用户输入的文本显示在聊天区域中。
  • 调用predict_response函数获取机器人回复,并将其显示在聊天区域中。
  • 清空输入框。

六、 启动应用程序

  1. app = QApplication(sys.argv) # 创建应用程序实例
  2. chat_app = ChatBotApp() # 创建 ChatBotApp 实例
  3. chat_app.show() # 显示应用程序界面
  4. sys.exit(app.exec_()) # 启动应用程序的事件循环
  • 创建QApplication对象,这是所有PyQt5应用程序必须创建的对象。
  • 创建并显示ChatBotApp实例。
  • 使用sys.exit(app.exec_())进入应用程序的主循环,直到窗口关闭。

效果展示

研究方向

我的研究方向主要涉及自然语言处理和深度学习。以下是三种经典算法/框架以及它们的优缺点:

  1. 经典算法:循环神经网络 (Recurrent Neural Networks, RNN)

    • 优点

      • RNN适用于处理序列数据,能够捕捉数据中的时间依赖关系。
      • 可以处理不定长的输入序列。
      • 在短序列和对上下文敏感的任务中表现良好。
    • 缺点

      • 难以捕捉长距离依赖关系,容易出现梯度消失或梯度爆炸问题。
      • 训练过程中存在长期记忆困难的问题。
      • 计算效率较低,不适用于处理长序列数据。
  2. 经典算法:长短期记忆网络 (Long Short-Term Memory, LSTM)

    • 优点

      • 解决了RNN难以捕捉长期依赖关系的问题,具有更好的记忆性能。
      • 可以处理长序列数据,适用于需要长期记忆的任务。
      • 在机器翻译、语音识别等任务中表现优秀。
    • 缺点

      • 参数较多,训练较慢。
      • 对于一些简单的序列任务,LSTM可能会过于复杂。
  3. 经典框架:Transformer

    • 优点

      • 在处理长距离依赖关系时表现优异,不受序列长度限制。
      • 并行计算效率高,适合GPU加速。
      • 可以通过自注意力机制捕捉全局信息。
    • 缺点

      • 对计算资源要求较高,训练时间可能较长。
      • Transformer在处理序列时可能会失去序列的顺序性。

这些经典算法/框架在不同的情况下有各自的优势和限制条件:

  • RNN 适用于短序列和对上下文敏感的任务,但在处理长序列和长期依赖关系时表现不佳。
  • LSTM 解决了RNN的长期记忆问题,适用于需要长期记忆的任务,但训练速度较慢。
  • Transformer 在处理长距离依赖关系时表现优异,适合处理长序列数据,但对计算资源要求较高。

链接:基于深度学习的聊天机器人项目-CSDN博客 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/852046
推荐阅读
相关标签
  

闽ICP备14008679号