杜陽陽,常家鑫,張志豪,張宸楠,李馳
(中國礦業(yè)大學計算機科學與技術(shù)學院,徐州221000)
隨著互聯(lián)網(wǎng)技術(shù)的不斷發(fā)展和成熟,以互聯(lián)網(wǎng)為媒介的信息數(shù)量急速增長。與此同時,人們越來越依靠互聯(lián)網(wǎng)獲取相關(guān)信息,如何準確高效地從大量信息中獲取所需知識成為亟待解決的問題。對于編程工作者來說,在實際編程過程中可能會遇到一些遺忘的知識點。傳統(tǒng)的做法可能是詢問同事、查看相關(guān)文檔或者直接利用搜索引擎搜索答案。但是這些方式往往存在著獲取知識耗時較長,所得知識不精確的問題。研究面向編程知識獲取領(lǐng)域的智能問答系統(tǒng),能夠為編程人員的知識獲取提供極大便利,提高工作效率和工作質(zhì)量。
對于用戶提出的問題,系統(tǒng)首先進行語義的分析和理解,之后在知識庫中進行查詢、匹配,最終將答案返回給用戶。不難發(fā)現(xiàn),系統(tǒng)中知識庫質(zhì)量的高低決定了系統(tǒng)返回答案的優(yōu)劣程度,高質(zhì)量知識庫的構(gòu)建是智能問答系統(tǒng)設計中需要面臨的挑戰(zhàn)之一。
當前問答系統(tǒng)的知識庫大多存在問答對質(zhì)量不高,問答對數(shù)目偏少的問題。經(jīng)過對智能問答系統(tǒng)中問答對生成方法的研究,系統(tǒng)分別基于規(guī)則、NLP、機器學習,三種生成問答對方法進行智能問答系統(tǒng)構(gòu)建,并對其構(gòu)建的知識庫進行分析比較,從中選擇問答對質(zhì)量最高的知識庫作為系統(tǒng)最終的知識庫。進而運用信息檢索技術(shù),實現(xiàn)高質(zhì)量智能問答。針對搜索常見編程知識的需求,系統(tǒng)通過爬取www.runoob.com 編程知識網(wǎng)站內(nèi)容構(gòu)建知識庫,實現(xiàn)“QA 對”的自動生成。
本系統(tǒng)由前端、后端、知識庫三大功能模塊構(gòu)成。前端既可面向普通用戶提供查詢服務,也可為管理員提供操作數(shù)據(jù)庫的接口。后端實現(xiàn)數(shù)據(jù)獲取、對接收數(shù)據(jù)進行分析和對前端請求的反饋并能對知識庫進行人工的完善。知識庫則根據(jù)所爬取網(wǎng)站www.runoob.com 的內(nèi)容實現(xiàn)“QA 對”的自動生成。系統(tǒng)的構(gòu)建流程如圖1 所示。
設計目標如下:
前端設計:實現(xiàn)與用戶的交互功能,并提供友好的交互界面。在實現(xiàn)全部功能的前提下,使得界面更加美觀,為用戶提供更加優(yōu)質(zhì)的信息服務。
后端設計:實現(xiàn)從網(wǎng)頁中提取高質(zhì)量問答對的功能。其中問題由網(wǎng)頁中的標題和關(guān)鍵詞構(gòu)成,答案由標題和關(guān)鍵詞附近的文本和鏈接組成。并能實現(xiàn)QA對增加、刪除、修改、查詢等功能。
知識庫構(gòu)建:由爬取內(nèi)容自動生成的“QA 對”構(gòu)建知識庫。盡可能多地提取高質(zhì)量問答對的同時保證知識庫中不存在相同的問題。
圖1 系統(tǒng)構(gòu)建流程圖
整個系統(tǒng)的結(jié)構(gòu)圖如圖2 所示。
系統(tǒng)的實現(xiàn)采用B/S 結(jié)構(gòu),利用PHP Web 開發(fā)框架Laravel 實現(xiàn)前后端的交互邏輯。該框架采用MVC架構(gòu)模式。此模式實現(xiàn)了模型、控制器、視圖三個層次的隔離,在修改其中一個層次的代碼的同時不會影響其他模塊的功能,降低了層次之間的耦合性[1]。使用此框架將系統(tǒng)開發(fā)為一個Web 應用,使得系統(tǒng)和用戶的交互更為友好。
系統(tǒng)工作的第一步是為知識庫的建立提供數(shù)據(jù)。以菜鳥教程網(wǎng)站內(nèi)容作為數(shù)據(jù)源,利用網(wǎng)絡爬蟲技術(shù)獲取頁面信息,借助網(wǎng)頁的結(jié)構(gòu)和屬性等特性獲取所需數(shù)據(jù),并將數(shù)據(jù)存入數(shù)據(jù)庫中。
在爬蟲獲取頁面并進行頁面分析的過程中,獲取的數(shù)據(jù)包括相關(guān)問題答案的鏈接、答案的文本內(nèi)容,以及用于后續(xù)生成問題的問題標簽列表。對于后續(xù)需要生成的問題,其問題標簽列表由其答案所在位置的前三級標題構(gòu)成。
在爬蟲程序中,利用Beautiful Soup 庫對頁面進行層層嵌套解析的過程中獲取了包含答案以及該答案對應的問題標簽列表在內(nèi)的數(shù)據(jù)。答案所在區(qū)域的前三級標題依次構(gòu)成該問題標簽列表,并將此列表保存在row_tags.txt 文件內(nèi)?;谝?guī)則和NLP 的方法生成問題都需要結(jié)合row_tags.txt 進行分析。
根據(jù)所爬取的html 文檔結(jié)構(gòu),設計了以下規(guī)則。
規(guī)則1:假如最后一個標簽以“參考手冊”結(jié)尾,則使用“有哪些……?”來生成問題,其中“有哪些”后面的內(nèi)容是該答案問題標簽列表的倒數(shù)第二個元素,即該答案所在區(qū)域向前追溯的第二個標題。
圖2 系統(tǒng)結(jié)構(gòu)圖
規(guī)則2:若最后一個標簽以英文“?”中文“?”或者文字“嗎”結(jié)尾,則將倒數(shù)第二個標簽和最后一個標簽組合在一起來生成問題。
設計規(guī)則的同時,以自然語言處理的方式對用戶提問進行分析。并根據(jù)自然語言處理的結(jié)果設計相對應的規(guī)則,使生成的問題更加合理。
在自然語言處理的方法中,使用了哈爾濱工業(yè)大學社會計算與信息檢索研究中心研制的語言技術(shù)平臺(LTP)[2]以及“結(jié)巴”中文分詞組件。
首先利用LTP 設計nlp_()方法,其功能是對輸入的語句進行理解。該方法以句子作為參數(shù),以列表作為返回值。返回值列表中的元素為Python namedtuple(命名元組),而每個命名元組代表對一個句子經(jīng)過自然語言處理后所得到的單詞及其屬性。每個單詞的屬性值包括詞性、命名實體、依存弧的父節(jié)點詞的索引和依存弧的關(guān)系。
方法的實現(xiàn)經(jīng)過四個過程,分別為分詞、詞性標注、命名實體識別和依存句法分析過程。首先對句子進行分詞處理并將結(jié)果轉(zhuǎn)換成列表類型。列表在經(jīng)過去除首尾空格的處理之后作為詞性標注過程的輸入。以上兩個過程的處理結(jié)果組合在一起,先后作為命名實體識別過程和依存句法分析過程的輸入,最終即可獲得一個單詞的詞性、命名實體、依存弧的父節(jié)點詞的索引和依存弧的關(guān)系。
基于自然語言處理技術(shù)設計如下規(guī)則:
規(guī)則3:利用“結(jié)巴”中文分詞中的posseg.lcut()方法對row_tags.txt 中的第三級標題進行分析。返回的結(jié)果為一個句子中所有的單詞以及每個單詞對應的詞性。根據(jù)分析結(jié)果做如下處理,如果該標題經(jīng)過分析之后僅含有一個詞語(即該標題就是這個詞語),這時查看row_tags.txt 中的第二級標題。如果第二級標題包含第三級標題,則把第二級標題作為問題。否則,將第二級標題和第三級標題按順序組合為新的字符串作為問題。
規(guī)則4:利用上述設計的nlp_()方法對row_tags.txt中的第三級標題進行分析。在得到的分詞列表中,尋找依存弧關(guān)系為’HED’的詞語(依存弧關(guān)系為’HED’表示該詞語在這個句子中作為根節(jié)點)并判斷該詞語的詞性。如果該詞語為動詞,則在row_tags.txt 中的第三級標題前加上字符串“如何”作為新的字符串,并把這個新的字符串作為問題。否則,就直接把row_tags.txt 中的第三級標題作為問題。
以上規(guī)則規(guī)定了QA 對中問題的生成方法。針對不同的問題標簽,遍歷以上所有規(guī)則,找到與該問題標簽相匹配的規(guī)則。之后將生成的問題和答案組合存入數(shù)據(jù)庫。
基于規(guī)則和NLP 的問題生成方法存在著問題生成質(zhì)量不高,規(guī)則需要人工構(gòu)建的缺點?;诖?,我們嘗試使用基于RNN+LSTM 的方法來生成QA 對。算法采用一種新的方式生成最終的問句。
該方法是:利用相關(guān)度判定模塊(SVM 分類器)對用戶所輸入的問題去除冗余并生成關(guān)鍵詞。利用排序算法(Word2Vec 詞向量模型+RNNLM 語言模型)對關(guān)鍵詞和預定義模板的匹配程度進行打分。之后得到分數(shù)最高的預定義模板,并根據(jù)此模板生成最終的問句[3]。
整個算法庫由四部分組成。分別存放于templates、data、models 和QAS 文件夾內(nèi)。對這四部分內(nèi)容介紹如下。templates 為預定義檢索詞模板,data 內(nèi)存放的是源數(shù)據(jù)(機器學習,深度學習),models 內(nèi)為預訓練的模型(SVM、Word2Vec、RNNLM),QAS 文件夾內(nèi)包含了訓練模塊、相關(guān)度判定模塊、相似度計算模塊、頻度計算模塊以及排序生成模塊[4]。
QAS 內(nèi)的幾大模塊完成了該算法庫的使用。
(1)訓練模塊(train_models.py)
此模塊為模型訓練器。且TrainModel 類被TrainSVM、TrainW2V、TrainRNN 類繼承,原始數(shù)據(jù)集相對路徑、轉(zhuǎn)換后的訓練集保存路徑和模型保存路徑作為其初始化參數(shù)。
訓練SVM 的過程為:
from QAS import TrainRNN,TrainSVM,TrainW2V
初始化:
t=TrainSVM()
將原數(shù)據(jù)轉(zhuǎn)換為訓練集:
t.origin_to_train()
開始訓練并將模型保存到默認路徑:
t.train()
(2)相關(guān)度判定模塊(correlation_calculate.py)此模塊對待檢索關(guān)鍵詞進行判定并去除冗余,得到最終的關(guān)鍵詞。
from QAS import Terms2Search
初始化一個實例
t = Terms2Search(['Mysql','通過命令窗口插入數(shù)據(jù)'],'models/svm')
計算搜索序列的相關(guān)度
t.correlation_calcuulate()
(3)相似度計算模塊(similarity_calculate.py)
此模塊依賴于W2V 詞向量模型,利用WDM 算法計算文本之間的相似度,完成上述排序算法中的相似度計算。
from QAS import Search2Similar
初始化一個實例
s = Search2Similar(['Mysql','通過命令窗口插入數(shù)據(jù)'],'models/w2v')
計算查詢詞與模板的匹配度
s.similarity_calculate()
(4)頻度計算模塊(frequency_calculate.py)
此模塊依賴于RNNLM(RNN+LSTM 語言模型),完成排序算法中的頻度計算,最終為問句打分。
from QAS import Search2Frequency
初始化一個實例,傳入語言模型和詞典
s=Search2Frequency(['Mysql','通過命令窗口插入數(shù)據(jù)'],'models/rnn','models/rnn_dict')
計算搜索詞序列的頻度
s.frequency_calculate()
(5)排序生成模塊(question_generate.py)
此模塊綜合利用上述各個模塊的功能,對生成的問句排序打分,得到分數(shù)最高的預定義模板,并根據(jù)此模板生成最終的問句。
from QAS import QG
相似度序列
sim_list=[1.2375805176661339, 0.9552492172805888,0.9057426648128687,1.0242890857346802]
頻度序列
fre_list=[-22.761973053216934,0.417869508266449,-7.039058595895767,-7.06894388794899]
初始化實例
q=QG(sim_list,fre_list,0.2,0.3,0.5)
排序打分
q.ranking()
本算法相對于基于規(guī)則和NLP 的QA 對生成算法具有如下優(yōu)勢:優(yōu)勢1:利用WDM 距離算法進行相似度計算使得檢索詞不再受限于關(guān)鍵詞,還可以是短語或者句子。優(yōu)勢2:與傳統(tǒng)方法相比,利用深度學習語言模型使得每個句子的得分更加合理?;谝陨戏椒ǖ玫降膯柧浔憧珊推鋵拇鸢附M成QA 對,存入數(shù)據(jù)庫中。
基于以上三種方法,我們已經(jīng)構(gòu)造了不同的問答對,并將其構(gòu)建為本系統(tǒng)的知識庫。針對每個查詢,我們需要在已有的知識庫中匹配與之相似度較高的問答對。實現(xiàn)此部分功能,我們對兩種文本相似度計算算法進行分析,并利用相關(guān)Python 庫實現(xiàn)。
算法1 TF-IDF 使用統(tǒng)計的方法來評估一個字詞對于某一文件集或某一語料庫中的其中一份文件的重要性[5]。計算公式為:
某一個給定的詞語在該文檔中出現(xiàn)的次數(shù)被稱作TF(詞頻)。這個數(shù)字通常會被歸一化。IDF 指:假如包含某一詞條的文檔越少,那么該詞條的IDF 值越大,同時說明該詞條具有較高的類別區(qū)分能力[6]。計算公式為:
算法2 潛在語義索引(LSI)作為一種索引和檢索方法,與TF-IDF 不同,LSI 不是基于統(tǒng)計的方法。它基于奇異值分解(SVD)的數(shù)學技術(shù)來得到一段文本的主題。在LSI 中,相同上下文中使用的單詞一般具有相近的含義。此外,利用建立在上下文中出現(xiàn)的術(shù)語之間的關(guān)聯(lián),LSI 能夠?qū)⑽谋局黧w的概念內(nèi)容提取出來[7]。
LSI 克服了布爾關(guān)鍵字查詢中兩個最有問題的約束:同義詞和多義詞。同義詞通常是文檔作者和信息檢索系統(tǒng)用戶使用的詞匯不匹配的原因。因此,布爾或關(guān)鍵字查詢通常會返回不相關(guān)的結(jié)果并錯過相關(guān)的信息。相比之下LSI 算法比TF-IDF 算法更具優(yōu)勢。以下為使用LSI 算法進行文本相似度計算的過程。
在此,使用Gensim(Python 第三方庫)建立相應模型進行文本相似度的計算。實現(xiàn)過程分為以下兩步。
第一步,為所有數(shù)據(jù)表建立相似度模型,并將模型持久化。
訓練語料的預處理。預處理的過程也就是將原始文本轉(zhuǎn)換成Gensim 能夠理解的稀疏向量的過程。
dictionary=gensim.corpora.Dictionary(texts)
corpus=[dictionary.doc2bow(text)for text in texts]
主題向量的變換,首先需要將模型對象初始化,Gensim 將訓練語料作為初始化參數(shù)。
tfidf=gensim.models.TfidfModel(corpus)
在此基礎上,利用此模型將語料轉(zhuǎn)化為用TF-IDF值表示的文檔向量。
corpus_tfidf=[tfidf[doc]for doc in corpus]
Gensim 的LSI 模型訓練建立在TF-IDF 之上,用來解決潛在語義。
利用TF-IDF 值表示的文檔向量訓練LSI 模型,并將文檔映射到一個50 維的topic 空間中。
lsi = models.LsiModel(corpus_tfidf,id2word=dictionary,num_topics=50)
corpus_lsi=[lsi[doc]for doc in corpus]
接著,將待檢索的文檔向量作為相似度計算對象的初始化參數(shù)。
index_tfidf=gensim.similarities.MatrixSimilarity(corpus_tfidf)
index_lsi=gensim.similarities.MatrixSimilarity(corpus_lsi)
將模型持久化:
dictionary.save("MODELS/%s_dic"%table_name)
lsi.save("MODELS/lsi_%s"%table_name)
index_lsi.save("MODELS/lsi_index_%s"%table_name)
第二步:加載模型計算文檔相似度并獲取答案。
對于給定的一個查詢,需要從所有的文本中查找出具有最高主題相似度的文本。
首先,加載已經(jīng)生成的模型:
lsi = models.LsiModel.load ("MODELS/lsi_% s"% table_name)
lsi_index=gensim.similarities.MatrixSimilarity.load("MODELS/lsi_index_%s"%table_name)
dictionary=corpora.Dictionary.load("MODELS/%s_dic"%table_name)
其中,待檢索的查詢和文本必須用同一個向量空間表達。
利用jieba 庫的精確模式,將待檢索的查詢切開。并調(diào)用LSI 模型將語料轉(zhuǎn)化成LSI 向量。
text=dictionary.doc2bow(seg_text)
lsi_text=lsi[text]
利用lsi_text 對象計算出任意一段查詢和所有文本集合的相似度:
sims=lsi_index[lsi_text]
得到其中相似度最高的三個:
positions=sims.argsort()[-3:]
之后在已經(jīng)建立好的數(shù)據(jù)庫中查詢出這三個相似度最高的問題所對應的答案并返回。
本文給出了基于規(guī)則、NLP、機器學習,三種生成問答對方法的智能問答系統(tǒng)構(gòu)建過程。其中采用深度學習方法生成問答對的質(zhì)量最高。并比較介紹了信息檢索的兩種相似度計算算法,最終選擇LSI 作為系統(tǒng)的相似度計算算法。以上算法的選擇和實現(xiàn)保證了系統(tǒng)問題檢索與答案匹配的極高準確率,具有一定的實際意義。