简介
- ModelScope是阿里达摩院打造的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!在这里,你可以免费使用平台提供的预训练模型,支持免费下载运行,一行命令实现模型预测,简单快速验证模型效果
- 本文主要介绍FAQ问答模型的使用,基于海量的标注/弱标注数据训练的FAQ模型可用作相似度计算,小样本分类,FAQ问答等多种场景,效果杠杠的
环境准备
- 本地环境安装,modelscope相关文档比较详细,本文就不赘述了,可参考 环境安装;
- 【推荐使用】Notebook预装了modelscope环境,可直接使用,注意需要确认启动的是modelcope-0.4版本以上;
- 快速体验,注意:模型输出的是每个label的分值;
FAQ问答核心组件
模型调试:获取句子向量
frommodelscope.pipelinesimportpipelinefrommodelscope.utils.constantimportTasks# 获取句向量表示,可用于构建向量索引;emb_ins=pipeline(Tasks.faq_question_answering, 'damo/nlp_structbert_faq-question-answering_chinese-base') sentence_embs=emb_ins.get_sentence_embedding(['如何使用优惠券', '在哪里领券', '购物评级怎么看'], max_len=30)
模型调试:FAQ排序
frommodelscope.pipelinesimportpipelinefrommodelscope.utils.constantimportTasksfaq_ins=pipeline(Tasks.faq_question_answering, 'damo/nlp_structbert_faq-question-answering_chinese-base') outputs=faq_ins({"query_set": ['如何使用优惠券', '在哪里领券', '购物评级怎么看'], "support_set": [{'text': '卖品代金券怎么用', 'label': '6527856'}, {'text': '怎么使用优惠券', 'label': '6527856'}, {'text': '这个可以一起领吗', 'label': '1000012000'}, {'text': '付款时送的优惠券哪里领', 'label': '1000012000'}, {'text': '购物等级怎么长', 'label': '13421097'}, {'text': '购物等级二心', 'label': '13421097'}]}) # 类维度排序# {'output': [[{'label': '6527856', 'score': 0.9982811212539673}, {'label': '1000012000', 'score': 0.0280130784958601}, {'label': '13421097', 'score': 8.978261757874861e-05}], # [{'label': '1000012000', 'score': 0.8750997185707092}, {'label': '6527856', 'score': 0.0031510782428085804}, {'label': '13421097', 'score': 0.0007711253711022437}], # [{'label': '13421097', 'score': 0.6274582743644714}, {'label': '1000012000', 'score': 0.0035026895347982645}, {'label': '6527856', 'score': 0.001228355336934328}]]}
快速搭建端到端FAQ问答机器人
- 数据准备,通常FAQ的数据结构包括知识标题、相似问法、答案、FAQID,我们使用公开的保险知道数据进行实验,为了简化,仅保留知识标题和答案内容,每条知识的相似问只有一条就是知识标题,数据获取参考链接;
fromdataclassesimportdataclassfromtypingimportListimportpandasaspdimportjsonclassFAQ: title: strsim_questions: List[str] answer: strfaq_id: intori_data=pd.read_csv('baoxianzhidao_filter.csv') data= [] exist_titles=set() forindex, rowinenumerate(ori_data.iterrows()): row_dict=row[1] title=row_dict['title'] iftitlenotinexist_titles: data.append(FAQ(title=title, answer=row_dict['reply'], sim_questions=[title], faq_id=index)) exist_titles.add(title)
- 构建索引,在实际业务场景中,由于FAQ知识库候选数量很多(通常是千级别的知识数量,万级别的问法数量),需要通过检索缩减候选数量,提升模型性能,以满足线上性能要求; (本文仅使用向量检索进行实验,为了更高的性能也可以使用elasticsearch)
- 获取向量
frommodelscope.pipelinesimportpipelinefrommodelscope.utils.constantimportTaskspipeline_ins=pipeline(Tasks.faq_question_answering, 'damo/nlp_structbert_faq-question-answering_chinese-base') bsz=32all_sentence_vecs= [] batch= [] sentence_list= [faq.titleforfaqindata] fori,sentinenumerate(sentence_list): batch.append(sent) iflen(batch) ==bszor (i==len(sentence_list)-1andlen(batch)>0): sentence_vecs=pipeline_ins.get_sentence_embedding(batch) all_sentence_vecs.extend(sentence_vecs) batch.clear()
- 向量索引构建
importfaissimportnumpyasnp#说明:v1.3版本之后,请使用 hidden_size = pipeline_ins.model.network.bert.config.hidden_sizehidden_size=pipeline_ins.model.bert.config.hidden_sizeindex=faiss.IndexFlatIP(hidden_size) vecs=np.asarray(all_sentence_vecs, dtype='float32') index.add(vecs)
- FAQ问答,问答流程包括检索+排序,来一个用户query,首先通过检索,召回候选数据,再通过faq模型给出最后的预测结果;
- 问答函数:其中包括了检索 + 排序
frommodelscope.outputsimportOutputKeysdefask_faq(input, history=[]): # step1: get sentence vector of queryquery_vec=pipeline_ins.get_sentence_embedding([input])[0] query_vec=np.asarray(query_vec, dtype='float32').reshape([1, -1]) # step2: faq dense retrieval_, indices=index.search(query_vec, k=30) # step3: build support set support_set= [] foriinindices.tolist()[0]: faq=data[i] support_set.append({"text": faq.title, "label": faq.faq_id, "index": i}) # step4: faq rankingrst=pipeline_ins(input={"query_set": input, "support_set": support_set}) rst=rst[OutputKeys.OUTPUT][0][0] pred_label=rst['label'] pred_score=rst['score'] # get answer by faq_idpred_answer=""pred_title=""forfaqindata: iffaq.faq_id==pred_label: pred_answer=faq.answerpred_title=faq.titlebreakhistory.append((input, f'{pred_answer}|(pred_title:{pred_title},pred_score:{pred_score:.3f})')) returnhistory, history
- UI接入,通过gradio库可快速搭建chatbot UI界面进行体验
importgradioasgrgr.Interface(fn=ask_faq, theme="default", css=".footer {display:none !important}", inputs=["text", "state"], outputs=["chatbot", "state"]).launch(share=True)
至此,一个简单的端到端FAQ问答系统就搭建好了,此外,该模型还有多种应用场景,包括
- 相似度计算:1.通过获取句向量,计算句子相似度;2. support_set中仅设置一个样本;
- 小样本分类:support_set每个类传入少量几条样本等;