
BERT模型在自然语言处理(NLP)领域的地位毋庸置疑,但其上手和部署对许多开发者来说仍有一定门槛。今天我们将借助 bert-as-service 这个开源项目,快速搭建一个能理解语义的本地问答搜索引擎,整个过程清晰直接。
1. 环境与模型准备
开始前,请确保你的环境已安装 Python 和 pip。
接下来,通过以下命令安装必要的服务端与客户端库:
pip install bert-serving-server # 服务端
pip install bert-serving-client # 客户端
服务端要求 Python >= 3.5 且 Tensorflow >= 1.10。
此外,你需要下载预训练好的BERT模型。可以从项目官方仓库(https://github.com/hanxiao/bert-as-service#install )下载,或从其他可信镜像源获取。下载后,将模型文件解压至某个目录,例如 /tmp/uncased_L-24_H-1024_A-16/。
2. Bert-as-service 基本使用
安装完成后,通过以下命令启动BERT服务:
bert-serving-start -model_dir /tmp/uncased_L-24_H-1024_A-16/ -num_worker=4
其中 -num_worker=4 表示启动4个工作进程,可处理4个并发请求。
服务启动成功后,你可以在客户端轻松获取句子的向量编码:
from bert_serving.client import BertClient
bc = BertClient()
bc.encode(['First do it', 'then do it right', 'then do it better'])

BERT支持对句子对进行编码,只需用 |||(前后有空格)连接:
bc.encode(['First do it ||| then do it right'])

该服务也支持远程调用,你可以在GPU服务器上启动服务,在CPU机器上通过网络调用:
# 在另一台CPU机器上
from bert_serving.client import BertClient
bc = BertClient(ip='xx.xx.xx.xx') # GPU服务器的IP地址
bc.encode(['First do it', 'then do it right', 'then do it better'])
3. 搭建问答搜索引擎
我们的目标是:从一个FAQ列表中,快速找出与用户输入问题最相似的问题,并返回其答案。这里以项目自带的 README.md 文件中的问题作为FAQ库。
第一步:加载所有问题并查看统计信息
prefix_q = '##### **Q:** '
with open('README.md') as fp:
questions = [v.replace(prefix_q, '').strip() for v in fp if v.strip() and v.startswith(prefix_q)]
print('%d questions loaded, avg. len of %d' % (len(questions), np.mean([len(d.split()) for d in questions])))
# 33 questions loaded, avg. len of 9
第二步:启动BERT服务
使用一个较小的预训练模型(如 uncased_L-12_H-768_A-12)启动服务:
bert-serving-start -num_worker=1 -model_dir=/path/to/your/model/uncased_L-12_H-768_A-12
第三步:将FAQ库中的所有问题编码为向量
bc = BertClient(port=4000, port_out=4001)
doc_vecs = bc.encode(questions)
第四步:实现查询与匹配
当用户输入新查询时,我们将其编码,并通过计算余弦相似度(这里使用归一化点积)在 doc_vecs 中寻找最相似的前N个问题:
while True:
query = input('your question: ')
query_vec = bc.encode([query])[0]
# 计算归一化点积作为相似度分数
score = np.sum(query_vec * doc_vecs, axis=1) / np.linalg.norm(doc_vecs, axis=1)
topk_idx = np.argsort(score)[::-1][:topk]
for idx in topk_idx:
print('> %s\t%s' % (score[idx], questions[idx]))
完成!现在运行代码并输入问题,即可体验这个基于语义相似度的搜索引擎如何工作。
4. 完整示例代码
以下是将上述步骤整合后的完整代码(约23行):
import numpy as np
from bert_serving.client import BertClient
from termcolor import colored
prefix_q = '##### **Q:** '
topk = 5
with open('README.md') as fp:
questions = [v.replace(prefix_q, '').strip() for v in fp if v.strip() and v.startswith(prefix_q)]
print('%d questions loaded, avg. len of %d' % (len(questions), np.mean([len(d.split()) for d in questions])))
with BertClient(port=4000, port_out=4001) as bc:
doc_vecs = bc.encode(questions)
while True:
query = input(colored('your question: ', 'green'))
query_vec = bc.encode([query])[0]
# compute normalized dot product as score
score = np.sum(query_vec * doc_vecs, axis=1) / np.linalg.norm(doc_vecs, axis=1)
topk_idx = np.argsort(score)[::-1][:topk]
print('top %d questions similar to "%s"' % (topk, colored(query, 'green')))
for idx in topk_idx:
print('> %s\t%s' % (colored('%.1f' % score[idx], 'cyan'), colored(questions[idx], 'yellow')))
这个例子展示了如何利用预训练模型快速搭建一个原型系统。如果你想获得更好的领域效果,可以对BERT模型进行微调。bert-as-service 项目也支持加载微调后的模型,更多高级用法和详细参数请参阅其官方文档:https://github.com/hanxiao/bert-as-service 。
通过这个实践,我们可以看到,利用成熟的工具链,将前沿的 人工智能 模型应用于解决实际问题(如智能问答)的门槛正在降低。这为快速进行原型验证和特定场景下的 Data Science 应用开发提供了便利。