1. 概述
本代码实现了一个基于词袋模型(Bag-of-Words)和简单神经网络的对话系统。该系统能够对用户输入的文本进行预处理、转换为词袋向量,通过神经网络进行训练和预测,并根据不同的输入情境生成相应的回复。
2. 依赖库
python
import numpy as np
import random
numpy
:用于数值计算,包括矩阵运算、数组操作等,是实现神经网络计算的基础库。random
:用于在生成回复时进行随机选择,增加回复的多样性。
3. 函数说明
3.1 preprocess
函数
python
def preprocess(text):
"""文本预处理(支持中英文)"""
# 去除标点符号
text = ''.join([c for c in text if c not in '.,?!,。!?;:""''()《》'])
# 中英文分开处理
if any('\u4e00' <= c <= '\u9fff' for c in text): # 包含中文
return [word for word in text.lower().strip() if word.strip()]
else: # 英文处理
return text.lower().split()
- 功能:对输入的文本进行预处理,包括去除标点符号,并根据文本是否包含中文进行不同的分词处理。
- 参数 :
text
:待处理的文本字符串。
- 返回值:处理后的单词列表。
3.2 build_vocab
函数
python
def build_vocab(sentences):
"""构建词汇表"""
vocab = set()
for sentence in sentences:
vocab.update(preprocess(sentence))
return list(vocab)
- 功能:根据输入的句子列表构建词汇表,将所有句子中出现的单词合并去重。
- 参数 :
sentences
:句子列表。
- 返回值:包含所有不重复单词的词汇表列表。
3.3 sentence_to_bow
函数
python
def sentence_to_bow(sentence, vocab):
"""将句子转换为词袋向量"""
bow = np.zeros(len(vocab))
words = preprocess(sentence)
for word in words:
if word in vocab:
bow[vocab.index(word)] += 1
return bow
- 功能:将输入的句子转换为词袋向量,向量的长度等于词汇表的长度,每个位置的数值表示该位置对应的单词在句子中出现的次数。
- 参数 :
sentence
:待转换的句子。vocab
:词汇表。
- 返回值 :表示句子的词袋向量(
numpy
数组)。
4. 类说明
4.1 NeuralNetwork
类
python
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * 0.01
self.b2 = np.zeros((1, output_size))
- 功能:定义一个简单的两层神经网络,包含输入层、隐藏层和输出层,并初始化网络的权重和偏置。
- 参数 :
input_size
:输入层的神经元数量,即词袋向量的长度。hidden_size
:隐藏层的神经元数量。output_size
:输出层的神经元数量,通常等于词汇表的长度。
- 属性 :
W1
:输入层到隐藏层的权重矩阵。b1
:隐藏层的偏置向量。W2
:隐藏层到输出层的权重矩阵。b2
:输出层的偏置向量。
4.1.1 forward
方法
python
def forward(self, X):
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = np.tanh(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.softmax(self.z2)
return self.a2
- 功能:实现神经网络的前向传播过程,计算输入数据经过网络各层后的输出。
- 参数 :
X
:输入数据,形状为(样本数量, 输入层大小)
的numpy
数组。
- 返回值 :输出层的激活值,形状为
(样本数量, 输出层大小)
的numpy
数组。
4.1.2 softmax
方法
python
def softmax(self, x):
exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
- 功能:实现 Softmax 激活函数,将输入的数值转换为概率分布。
- 参数 :
x
:输入数据,形状为(样本数量, 输出层大小)
的numpy
数组。
- 返回值 :经过 Softmax 激活后的概率分布,形状为
(样本数量, 输出层大小)
的numpy
数组。
4.1.3 train
方法
python
def train(self, X, y, epochs=1000, learning_rate=0.01):
for epoch in range(epochs):
output = self.forward(X)
loss = -np.sum(y * np.log(output + 1e-10)) / len(X)
dZ2 = output - y
dW2 = np.dot(self.a1.T, dZ2)
db2 = np.sum(dZ2, axis=0, keepdims=True)
dZ1 = np.dot(dZ2, self.W2.T) * (1 - np.power(self.a1, 2))
dW1 = np.dot(X.T, dZ1)
db1 = np.sum(dZ1, axis=0)
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
- 功能:对神经网络进行训练,使用梯度下降法更新网络的权重和偏置,以最小化交叉熵损失。
- 参数 :
X
:训练数据的输入,形状为(样本数量, 输入层大小)
的numpy
数组。y
:训练数据的目标输出,形状为(样本数量, 输出层大小)
的numpy
数组。epochs
:训练的轮数,默认为1000
。learning_rate
:学习率,控制每次参数更新的步长,默认为0.01
。
- 返回值:无
5. 对话数据
python
# 增强版对话数据(更自然的表达)
conversations = [
{"input": "hello", "output": "您好!很高兴为您服务,请问有什么可以帮您的?"},
# 更多对话示例...
]
conversations
是一个列表,其中每个元素是一个字典,包含 "input"
(用户输入的文本)和 "output"
(对应的回复文本)键值对,用于训练和测试对话系统。
6. 模型训练与初始化
python
# 初始化模型参数
inputs = [conv["input"] for conv in conversations]
outputs = [conv["output"] for conv in conversations]
vocab = build_vocab(inputs + outputs)
X = np.array([sentence_to_bow(conv["input"], vocab) for conv in conversations])
y = np.array([sentence_to_bow(conv["output"], vocab) for conv in conversations])
model = NeuralNetwork(len(vocab), 16, len(vocab))
model.train(X, y, epochs=2000, learning_rate=0.05)
- 功能:从对话数据中提取输入和输出文本,构建词汇表,将输入和输出文本转换为词袋向量,创建神经网络模型并进行训练。
- 步骤 :
- 从
conversations
中分别提取用户输入和回复文本。 - 使用
build_vocab
构建词汇表。 - 使用
sentence_to_bow
将输入和输出文本转换为词袋向量。 - 创建
NeuralNetwork
模型实例。 - 使用转换后的词袋向量数据对模型进行训练。
- 从
7. predict_response
函数
python
def predict_response(input_text, vocab, model):
"""生成更自然的回复"""
bow = sentence_to_bow(input_text, vocab)
prob = model.forward(np.array([bow]))
# 使用温度采样并添加数值稳定性处理
temperature = 0.7
prob = np.clip(prob, 1e-10, 1.0) # 防止log(0)
scaled_probs = np.exp(np.log(prob) / temperature)
scaled_probs /= scaled_probs.sum()
# 选择前3候选词
top3_idx = np.argsort(scaled_probs)[0][-3:]
candidates = [vocab[i] for i in top3_idx]
# 上下文感知回复(增强版)
lower_input = input_text.lower()
# 多种情况处理,如问候、道别、问题、感谢等...
# 生成更自然的句子结构或默认回退响应...
- 功能:根据用户输入的文本,生成自然的回复。先将输入文本转换为词袋向量,通过神经网络预测概率分布,然后根据不同的输入情境(如问候、道别、问题、感谢等)选择合适的回复策略。
- 参数 :
input_text
:用户输入的文本字符串。vocab
:词汇表。model
:训练好的神经网络模型。
- 返回值:生成的回复文本字符串。
8. 对话系统启动
python
# 启动对话系统
print("Chatbot: 您好!我是Claude,有什么可以帮您?(输入quit退出)")
while True:
user_input = input("You: ")
if user_input.lower() == "quit":
print("Chatbot: 再见!祝您有美好的一天!")
break
response = predict_response(user_input, vocab, model)
print(f"Chatbot: {response}")
- 功能 :启动对话系统,持续接收用户输入,调用
predict_response
函数生成回复并输出,直到用户输入"quit"
退出系统。
完整代码
python
import numpy as np
import random
def preprocess(text):
"""文本预处理(支持中英文)"""
# 去除标点符号
text = ''.join([c for c in text if c not in '.,?!,。!?;:""''()《》'])
# 中英文分开处理
if any('\u4e00' <= c <= '\u9fff' for c in text): # 包含中文
return [word for word in text.lower().strip() if word.strip()]
else: # 英文处理
return text.lower().split()
def build_vocab(sentences):
"""构建词汇表"""
vocab = set()
for sentence in sentences:
vocab.update(preprocess(sentence))
return list(vocab)
def sentence_to_bow(sentence, vocab):
"""将句子转换为词袋向量"""
bow = np.zeros(len(vocab))
words = preprocess(sentence)
for word in words:
if word in vocab:
bow[vocab.index(word)] += 1
return bow
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * 0.01
self.b2 = np.zeros((1, output_size))
def forward(self, X):
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = np.tanh(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.softmax(self.z2)
return self.a2
def softmax(self, x):
exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
def train(self, X, y, epochs=1000, learning_rate=0.01):
for epoch in range(epochs):
output = self.forward(X)
loss = -np.sum(y * np.log(output + 1e-10)) / len(X)
dZ2 = output - y
dW2 = np.dot(self.a1.T, dZ2)
db2 = np.sum(dZ2, axis=0, keepdims=True)
dZ1 = np.dot(dZ2, self.W2.T) * (1 - np.power(self.a1, 2))
dW1 = np.dot(X.T, dZ1)
db1 = np.sum(dZ1, axis=0)
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
# 增强版对话数据(更自然的表达)
conversations = [
{"input": "hello", "output": "您好!很高兴为您服务,请问有什么可以帮您的?"},
{"input": "hi", "output": "嗨!今天过得怎么样?有什么需要我帮忙的吗?"},
{"input": "how are you", "output": "我很好,谢谢关心!您今天有什么计划吗?"},
{"input": "what's your name", "output": "我是您的智能助手Claude,随时为您效劳。"},
{"input": "bye", "output": "再见啦!期待下次再聊,祝您一切顺利!"},
{"input": "see you", "output": "好的,有需要随时找我哦!"},
{"input": "thanks", "output": "您太客气了!能帮到您是我的荣幸。"},
{"input": "what's this", "output": "您可以多描述一些细节吗?这样我可以更好地理解您的问题。"},
{"input": "help", "output": "请告诉我您需要哪方面的帮助,我会尽力为您解答。"},
{"input": "not sure", "output": "没关系,我们可以慢慢聊。您最近对什么领域比较感兴趣呢?"},
{"input": "what do you think", "output": "这是一个很有意思的观点,您能详细说说您的想法吗?"},
{"input": "interesting", "output": "看来您发现了一些有趣的事情,愿意和我分享更多细节吗?"},
{"input": "how to learn", "output": "学习新知识很棒!您想重点了解哪个领域的内容呢?"},
{"input": "what's the weather like today", "output": "很抱歉,我无法直接获取实时天气呢。您可以查看一下天气预报软件哦。"},
{"input": "今天天气怎么样", "output": "我没办法直接知道当前的天气情况呢,您可以通过手机上的天气应用查询一下呀。"},
{"input": "what time is it", "output": "我没办法直接查看时间呢,您可以看看身边的时钟或者手机哦。"},
{"input": "现在几点了", "output": "不好意思,我不能直接告诉您时间呢,您可以看看手表或者手机上的时间。"},
{"input": "do you like music", "output": "我没有真正的喜好呢,但音乐是一种很棒的艺术形式!您最喜欢什么类型的音乐呢?"},
{"input": "你喜欢看电影吗", "output": "我没有情感去喜欢或不喜欢呢,不过电影是很有趣的文化载体!您最近看了什么好看的电影呀?"},
{"input": "what's your hobby", "output": "我没有自己的爱好哦,但我可以陪您聊各种有趣的话题!您平时喜欢做些什么呢?"},
{"input": "你平时喜欢做什么", "output": "我没有实际的活动爱好呢,不过我很乐意了解您的兴趣爱好!能和我分享一下吗?"},
]
# 初始化模型参数
inputs = [conv["input"] for conv in conversations]
outputs = [conv["output"] for conv in conversations]
vocab = build_vocab(inputs + outputs)
X = np.array([sentence_to_bow(conv["input"], vocab) for conv in conversations])
y = np.array([sentence_to_bow(conv["output"], vocab) for conv in conversations])
model = NeuralNetwork(len(vocab), 16, len(vocab))
model.train(X, y, epochs=2000, learning_rate=0.05)
def predict_response(input_text, vocab, model):
"""生成更自然的回复"""
bow = sentence_to_bow(input_text, vocab)
prob = model.forward(np.array([bow]))
# 使用温度采样并添加数值稳定性处理
temperature = 0.7
prob = np.clip(prob, 1e-10, 1.0) # 防止log(0)
scaled_probs = np.exp(np.log(prob) / temperature)
scaled_probs /= scaled_probs.sum()
# 选择前3候选词
top3_idx = np.argsort(scaled_probs)[0][-3:]
candidates = [vocab[i] for i in top3_idx]
# 上下文感知回复(增强版)
lower_input = input_text.lower()
# 问候处理
if any(w in lower_input for w in ["你好", "嗨", "hello", "hi"]):
return random.choice([
"您好!有什么我可以帮忙的吗?",
"嗨!今天想聊点什么?",
"很高兴见到您!有什么疑问吗?"
])
# 道别处理
if any(w in lower_input for w in ["再见", "bye", "goodbye"]):
return random.choice([
"期待下次再聊!祝您有个美好的一天!",
"再见!有任何问题随时找我哦~",
"先聊到这啦,保持联系!"
])
# 问题处理
if any(w in lower_input for w in ["怎么", "如何", "怎样", "why", "how"]):
return random.choice([
"这个问题可以从以下几个方面来考虑:首先...",
"关于这一点,我们可以先了解一下基本概念...",
"您提的这个问题很有意思,我们需要结合具体案例来分析..."
])
# 感谢处理
if any(w in lower_input for w in ["谢谢", "感谢", "thanks"]):
return random.choice([
"您太客气了!这是应该的~",
"能帮到您是我的荣幸!",
"随时为您效劳,有其他问题尽管问我!"
])
# 生成更自然的句子结构(增强版)
if candidates:
subject = candidates[-1]
# 根据主题动态生成回复
templates = [
f"嗯,关于{subject}啊,其实我们可以这样来看...",
f"{subject}这个话题挺有意思的,您是不是想了解{random.choice(['它的实际应用', '背后的原理', '最新发展'])}呢?",
f"说到{subject},我想到最近有个案例挺典型的------比如说...",
f"{subject}这个领域确实有些复杂,咱们先从最基础的{random.choice(['概念', '分类', '发展历程'])}说起吧?",
f"您提到的{subject}让我联想到{random.choice(['另一个相关领域', '某位专家的观点', '近期的一个新闻'])},您觉得这之间有什么联系吗?",
f"关于{subject},不同人有不同看法。有人觉得...,但也有人认为...,您更倾向哪种观点呢?",
f"要深入理解{subject},可能需要考虑这几个方面:{random.choice(['技术实现', '社会影响', '经济效益'])}...",
f"其实{subject}这个问题,我们可以用{random.choice(['类比的方法', '实际案例', '数据分析'])}来帮助理解..."
]
return random.choice(templates)
# 默认回退响应(带引导性提问)
follow_up_questions = [
("这个方向确实值得探讨,", "能多说说您具体想了解的内容吗?"),
("很有意思的切入点,", "您比较关注实践应用还是理论层面呢?"),
("这个话题最近挺热门的,", "您是从什么渠道了解到相关信息的呀?"),
("您的视角很独特,", "能分享一下您目前的理解吗?"),
("这个问题确实值得深入研究,", "您需要我提供哪些方面的支持呢?")
]
lead_in, question = random.choice(follow_up_questions)
return f"{lead_in}{question}"
# 启动对话系统
print("Chatbot: 您好!我是Claude,有什么可以帮您?(输入quit退出)")
while True:
user_input = input("You: ")
if user_input.lower() == "quit":
print("Chatbot: 再见!祝您有美好的一天!")
break
response = predict_response(user_input, vocab, model)
print(f"Chatbot: {response}")