赞
踩
目录
在当今数字化和信息化的时代,聊天机器人在各个领域的应用越来越广泛。它们能够帮助企业提高客户服务效率,减少人力成本,并提供24小时不间断的服务。通过自然语言处理技术,聊天机器人可以理解用户的语言并作出相应的回答。
本项目旨在开发一个基础的聊天机器人,能够处理简单的中文问答对话。通过这个项目,我们希望学习并实践自然语言处理和深度学习的相关技术,理解聊天机器人的工作原理,并探索其在实际应用中的潜力。
我们的数据主要来源于天池Chinese Medical Dialogue Dataset 中文医疗对话数据集,因为我们所拥有的个人计算机算力有限,而数据庞大,只截取了其中的800条数据和问答部分进行训练测试。这些数据主要涵盖了外科医疗中的常见问题和回答。
先截取了其中我们想要的部分数据,后将数据拆分为输入部分和输出部分。接着使用Tokenizer分词器将文本数据转换为序列,并进行填充以保证序列长度一致。再通过Tokenizer,将文本数据转换为模型可以理解的数字序列。
示例代码
- import pandas as pd
- import tensorflow as tf
- from tensorflow.keras.preprocessing.text import Tokenizer
- from tensorflow.keras.preprocessing.sequence import pad_sequences
- import numpy as np
- import matplotlib.pyplot as plt
- import pickle
-
- # 读取对话数据,假设数据编码格式为 ANSI
- data = pd.read_csv('外科5-14000.csv', encoding='ansi')
-
- # 截取前500条数据
- data = data.head(800)
-
- # 只保留 "ask" 和 "answer" 列
- data = data[['title', 'answer']]
-
- # 将截取后的数据转换为 UTF-8 编码并保存到新的 CSV 文件中
- data.to_csv('data.csv', encoding='utf-8', index=False)
-
- # 重新读取截取后的数据
- data = pd.read_csv('data.csv')
-
- data.info()
-
- # 拆分数据为输入和输出部分
- input_texts = data['title'].tolist()
- target_texts = data['answer'].tolist()
-
- # 初始化 Tokenizer
- tokenizer = Tokenizer(num_words=10000)
- tokenizer.fit_on_texts(input_texts + target_texts)
-
- # 保存 Tokenizer
- with open('tokenizer.pkl', 'wb') as handle:
- pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL)
-
- # 文本转换为序列
- input_sequences = tokenizer.texts_to_sequences(input_texts)
- target_sequences = tokenizer.texts_to_sequences(target_texts)
-
- # 序列填充
- max_sequence_length = 50 # 根据数据长度设定
- padded_input_sequences = pad_sequences(input_sequences, maxlen=max_sequence_length)
- padded_target_sequences = pad_sequences(target_sequences, maxlen=max_sequence_length)

我们选择了基于 TensorFlow 和 Keras 构建一个简单的 Seq2Seq 模型。这种模型结构在处理序列生成任务(如机器翻译)时非常有效。我们将使用一个嵌入层和一个 LSTM 层来构建模型。
示例代码
- # 构建模型
- from tensorflow.keras.models import Model
- from tensorflow.keras.layers import Input, LSTM, Dense, Embedding
-
- def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
- input = Input(shape=(None,))
- x = Embedding(vocab_size, embedding_dim)(input)
- x = LSTM(rnn_units, return_sequences=True)(x)
- output = Dense(vocab_size, activation='softmax')(x)
- model = Model(inputs=input, outputs=output)
- return model
-
- vocab_size = 10000
- embedding_dim = 256
- rnn_units = 1024
- batch_size = 10
-
- model = build_model(vocab_size, embedding_dim, rnn_units, batch_size)
- 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。这表明模型在训练过程中逐渐学习到了数据的模式和特征。
将输入序列和目标序列进行准备。目标序列通过将输入序列右移一位来生成,这样模型在每个时间步都可以看到上一个时间步的输出。我们通过绘制训练过程中损失的变化图表,可以直观地了解模型的训练情况
示例代码
- # 准备标签数据,使用序列移位方法来生成输入和目标
- target_sequences_shifted = np.zeros_like(padded_target_sequences)
- target_sequences_shifted[:, :-1] = padded_target_sequences[:, 1:]
- target_sequences_shifted[:, -1] = padded_target_sequences[:, -1]
-
- # 编译并训练模型
- model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
- history = model.fit(padded_input_sequences, target_sequences_shifted, epochs=450)
训练完成后,我们绘制了训练过程中损失的变化图,并评估了模型在测试数据上的表现。
示例代码
- # 绘制训练过程中损失的变化
- plt.plot(history.history['loss'])
- plt.title('Model Loss Progression')
- plt.ylabel('Loss')
- plt.xlabel('Epoch')
- plt.legend(['Train'], loc='upper left')
- plt.show()
-
- # 保存模型
- model.save('chatbot_model.h5')
-
- # 模型评估
- loss = model.evaluate(padded_input_sequences, target_sequences_shifted)
- print(f'Model Loss: {loss}')
我们定义一个函数来生成响应,并测试该函数。通过输入一个测试文本,模型能够生成相应的回复。
示例代码
- # 测试生成响应
- def predict_response(input_text):
- input_seq = tokenizer.texts_to_sequences([input_text])
- input_seq = pad_sequences(input_seq, maxlen=20)
- prediction = model.predict(input_seq)
- predicted_seq = np.argmax(prediction, axis=-1)
- predicted_text = tokenizer.sequences_to_texts(predicted_seq)
- return predicted_text
-
- # 示例测试
- test_text = "阑尾炎微创手术效果怎么样"
- response = predict_response(test_text)
- print(f'Input: {test_text}')
- print(f'Response: {response}')
运行结果
但是这样的结果输出太过于单调了,于是我们用PYQT5开发了一个界面用于问答展示
一、导入必要的库
- import sys
- from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLineEdit, QTextEdit, QPushButton
- import tensorflow as tf
- from tensorflow.keras.preprocessing.sequence import pad_sequences
- import numpy as np
- import pickle
sys
:用于系统相关的操作。PyQt5.QtWidgets
:导入PyQt5库中的各种窗口小部件,用于创建GUI。tensorflow
和tensorflow.keras
:用于加载和使用深度学习模型。numpy
:用于科学计算和数组操作。pickle
:用于加载之前保存的Tokenizer对象。二、加载模型和Tokenizer
- # 加载模型
- model = tf.keras.models.load_model('chatbot_model.h5')
-
- # 加载 Tokenizer
- with open('tokenizer.pkl', 'rb') as handle:
- tokenizer = pickle.load(handle)
chatbot_model.h5
。pickle
加载之前保存的Tokenizer对象,用于将文本转换为序列。三、定义预测函数
- def predict_response(input_text):
- input_seq = tokenizer.texts_to_sequences([input_text])
- input_seq = pad_sequences(input_seq, maxlen=20)
- prediction = model.predict(input_seq)
- predicted_seq = np.argmax(prediction, axis=-1)
- predicted_text = tokenizer.sequences_to_texts(predicted_seq)
- return predicted_text[0]
input_text
:用户输入的文本。pad_sequences
将序列填充到固定长度(20)。np.argmax
找到每个时间步长上预测概率最高的词的索引。四、 创建聊天机器人应用程序类
- class ChatBotApp(QMainWindow):
- def __init__(self):
- super().__init__()
-
- self.setWindowTitle("ChatBot医疗问答系统")
- self.setGeometry(300, 300, 700, 600)
-
- self.central_widget = QWidget()
- self.setCentralWidget(self.central_widget)
-
- self.layout = QVBoxLayout()
-
- self.chat_display = QTextEdit()
- self.chat_display.setReadOnly(True)
- self.layout.addWidget(self.chat_display)
-
- self.input_layout = QHBoxLayout()
-
- self.user_input = QLineEdit()
- self.user_input.setPlaceholderText("请输入你的问题")
- self.input_layout.addWidget(self.user_input)
-
- self.send_button = QPushButton("提问")
- self.send_button.clicked.connect(self.handle_send)
- self.input_layout.addWidget(self.send_button)
-
- self.layout.addLayout(self.input_layout)
- self.central_widget.setLayout(self.layout)

ChatBotApp
类继承自QMainWindow
,表示主窗口。QTextEdit
,用于显示聊天内容。QLineEdit
和发送按钮QPushButton
,用于输入问题并触发发送操作。五、 处理发送按钮点击事件
- def handle_send(self):
- user_text = self.user_input.text()
- if user_text.strip():
- self.chat_display.append(f"User: {user_text}")
- response = predict_response(user_text)
- self.chat_display.append(f"ChatBot: {response}")
- self.user_input.clear()
handle_send
方法用于处理发送按钮的点击事件。predict_response
函数获取机器人回复,并将其显示在聊天区域中。六、 启动应用程序
- app = QApplication(sys.argv) # 创建应用程序实例
- chat_app = ChatBotApp() # 创建 ChatBotApp 实例
- chat_app.show() # 显示应用程序界面
- sys.exit(app.exec_()) # 启动应用程序的事件循环
QApplication
对象,这是所有PyQt5应用程序必须创建的对象。ChatBotApp
实例。sys.exit(app.exec_())
进入应用程序的主循环,直到窗口关闭。效果展示
研究方向
我的研究方向主要涉及自然语言处理和深度学习。以下是三种经典算法/框架以及它们的优缺点:
经典算法:循环神经网络 (Recurrent Neural Networks, RNN)
优点:
缺点:
经典算法:长短期记忆网络 (Long Short-Term Memory, LSTM)
优点:
缺点:
经典框架:Transformer
优点:
缺点:
这些经典算法/框架在不同的情况下有各自的优势和限制条件:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。