精华内容
下载资源
问答
  • 优点是由于这种方法简单、速度快、且分词效果基本可以满足需求,因此在工业界仍然很受欢迎。 正向最大匹配法思想: 正如方法名称,正向表示对句子从左到右选择词典中最长的词条进行匹配,获得分词结果。 1、统计分词...

    写完之后,重新看一下哪一部分比较慢,然后试图去优化。一个好的习惯是每写一部分就思考这部分代码的时间复杂度和空间复杂度,AI工程是的日常习惯!

    Part 1: 搭建一个分词工具

    Part 1.1 基于枚举方法来搭建中文分词工具

    此项目需要的数据:

    1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用
    2. 以变量的方式提供了部分unigram概率 word_prob

    举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15

    Step 1: 对于给定字符串:”我们学习人工智能,人工智能是未来“, 找出所有可能的分割方式

    • [我们,学习,人工智能,人工智能,是,未来]
    • [我们,学习,人工,智能,人工智能,是,未来]
    • [我们,学习,人工,智能,人工,智能,是,未来]
    • [我们,学习,人工智能,人工,智能,是,未来]

    Step 2: 我们也可以计算出每一个切分之后句子的概率

    • p(我们,学习,人工智能,人工智能,是,未来)= -log p(我们)-log p(学习)-log p(人工智能)-log p(人工智能)-log p(是)-log p(未来)
    • p(我们,学习,人工,智能,人工智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工智能)-log p(是)-log p(未来)
    • p(我们,学习,人工,智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工)-log p(智能)-log p(是)-log p(未来)
    • p(我们,学习,人工智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工智能)-log p(人工)-log p(智能)-log(是)-log p(未来)

    Step 3: 返回第二步中概率最大的结果

    import warnings
    warnings.filterwarnings("ignore")                     #Ignoring unnecessory warnings
    
    import numpy as np                                  #for large and multi-dimensional arrays
    import pandas as pd                                 #for data manipulation and analysis
    import nltk                                         #Natural language processing tool-kit
    import math
    
    from nltk.corpus import stopwords                   #Stopwords corpus
    from nltk.stem import PorterStemmer                 # Stemmer
    
    from sklearn.feature_extraction.text import CountVectorizer          #For Bag of words
    from sklearn.feature_extraction.text import TfidfVectorizer          #For TF-IDF
    # from gensim.models import Word2Vec
    
    dic_path = r"综合类中文词库.xlsx"
    dic = pd.read_excel(dic_path, header = None)
    
    # TODO: 第一步: 从dic.txt中读取所有中文词。
    #  hint: 思考一下用什么数据结构来存储这个词典会比较好? 要考虑我们每次查询一个单词的效率。 
    dic_words = set(dic[0].tolist())    # 保存词典库中读取的单词
    
    
    # 以下是每一个单词出现的概率。为了问题的简化,我们只列出了一小部分单词的概率。 在这里没有出现的的单词但是出现在词典里的,统一把概率设置成为0.00001
    # 比如 p("学院")=p("概率")=...0.00001
    
    word_prob = {"北京":0.03,"的":0.08,"天":0.005,"气":0.005,"天气":0.06,"真":0.04,"好":0.05,"真好":0.04,"啊":0.01,"真好啊":0.02, 
                 "今":0.01,"今天":0.07,"课程":0.06,"内容":0.06,"有":0.05,"很":0.03,"很有":0.04,"意思":0.06,"有意思":0.005,"课":0.01,
                 "程":0.005,"经常":0.08,"意见":0.08,"意":0.01,"见":0.005,"有意见":0.02,"分歧":0.04,"分":0.02, "歧":0.005}
    
    print (sum(word_prob.values()))
    
    1.0000000000000002
    

    基于规则的中文分词

    包括, 正向最大匹配法,逆向最大匹配法和双向最大匹配法。
    最大匹配方法是最有代表性的一种基于词典和规则的方法,其缺点是严重依赖词典,无法很好地处理分词歧义和未登录词。优点是由于这种方法简单、速度快、且分词效果基本可以满足需求,因此在工业界仍然很受欢迎。

    正向最大匹配法思想:

    正如方法名称,正向表示对句子从左到右选择词典中最长的词条进行匹配,获得分词结果。

    • 1、统计分词词典,确定词典中最长词条的字符m;
    • 2、从左向右取待切分语句的m个字符作为匹配字段,查找词典,如果匹配成功,则作为一个切分后的词语,否则,去掉待匹配字符的最后一个继续查找词典,重复上述步骤直到切分出所有词语。
    dictA = ['南京','南京市', '南京市长', '市长' ,'长江大桥',  '大桥']
    
    maxDictA = max([len(word) for word in dictA])
    
    sentence = "南京市长江大桥"
    
    def cutA(sentence):
        result = []
        sentenceLen = len(sentence)
        n = 0
    
        while n < sentenceLen:
            matched = 0
            for i in range(maxDictA, 0, -1):
                piece = sentence[n:n+i]
                if piece in dictA:
                    result.append(piece)
                    matched = 1
                    n = n + i
                    break
            if not matched:
                result.append(sentence[n])
                n += 1
        return result
    

    逆向最大匹配法思想:

    与正向最大匹配原理相同,主要差异是:

    • 1、对句子从右到左选择词典中最长的词条进行匹配,获得分词结果;
    • 2、当匹配失败时,去掉待匹配字符的最前面的一个继续查找词典。
    maxDictA = max([len(word) for word in dictA])
    
    def cutB(sentence):
        result = []
        sentenceLen = len(sentence)
    
        while sentenceLen > 0:
            word = ''
            for i in range(maxDictA, 0, -1):
                piece = sentence[sentenceLen-i:sentenceLen]
                if piece in dictA:
                    word = piece
                    result.append(word)
                    sentenceLen -= i
                    break
    
            if word is '':
                sentenceLen -= 1
                result.append(sentence[sentenceLen])
    
        return result[::-1]
    

    双向最大匹配法思想:

    将正向最大匹配和逆向匹配得到的分词结果进行比较,按照最大匹配原则,选择切分总词数最少的作为最终分词结果。
    举例:
    dictA:# [‘南京市长’, ‘江’, ‘大桥’]
    dictB: # [‘南京市’, ‘长江大桥’]
    最终选择,dictB的结果。

    def twowaycut(sentence):
        if len(cutA(sentence)) > len(cutB(sentence)):
            result = cutB(sentence)
        elif len(cutA(sentence)) < len(cutB(sentence)):
            result = cutA(sentence)
        return result
    

    基于枚举方法来搭建中文分词工具

    def word_break(s, dic):
        def sentences(cur):
            result=[]
            if cur <len(s):
                for next in range(cur+1, len(s)+1):
                    if s[cur:next] in dic:
                        result = result+[s[cur:next]+(tail and','+tail) for tail in sentences(next)]
            else:
                return ['']
            return result
    
        list_new = []
        for line in sentences(0):
            line = line.split(",")
            list_new.append(line)
        return list_new
    
    #  分数(10)
    import math
    ## TODO 请编写word_segment_naive函数来实现对输入字符串的分词
    def word_segment_naive(input_str):
        """
        1. 对于输入字符串做分词,并返回所有可行的分词之后的结果。
        2. 针对于每一个返回结果,计算句子的概率
        3. 返回概率最高的最作为最后结果
        
        input_str: 输入字符串   输入格式:“今天天气好”
        best_segment: 最好的分词结果  输出格式:["今天","天气","好"]
        """
    
        # TODO: 第一步: 计算所有可能的分词结果,要保证每个分完的词存在于词典里,这个结果有可能会非常多。 
        
        segments = word_break(input_str,  dic_words)  # 存储所有分词的结果。如果次字符串不可能被完全切分,则返回空列表(list)
                       # 格式为:segments = [["今天",“天气”,“好”],["今天",“天“,”气”,“好”],["今“,”天",“天气”,“好”],...]
        
        # TODO: 第二步:循环所有的分词结果,并计算出概率最高的分词结果,并返回
        best_segment =[]
        best_score = math.inf
        for seg in segments:
            score=0
        for word in seg:
            if word in word_prob.keys():
                 score += word_prob[word]
            else:
                score +=  round(-math.log(0.00001),1)
        if score < best_score:
            best_score=score
            best_segment = seg
    
        return best_segment
       
    
    # 测试
    print(word_segment_naive("今天的课程内容很有意思"))
    print(word_segment_naive("经常有意见分歧"))
    print(word_segment_naive("北京的天气真好啊"))
    
    ['今天', '的', '课程', '内容', '很', '有意思']
    ['经常', '有意', '见', '分歧']
    ['北京', '的', '天气', '真好', '啊']
    

    Part 1.2 基于维特比算法来优化上述流程

    此项目需要的数据:

    1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用
    2. 以变量的方式提供了部分unigram概率word_prob

    举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15

    Step 1: 根据词典,输入的句子和 word_prob来创建带权重的有向图(Directed Graph) 参考:课程内容

    有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率已经给出(存放在word_prob)。
    注意:思考用什么方式来存储这种有向图比较合适? 不一定只有一种方式来存储这种结构。

    Step 2: 编写维特比算法(viterebi)算法来找出其中最好的PATH, 也就是最好的句子切分

    具体算法参考课程中讲过的内容

    Step 3: 返回结果

    跟PART 1.1的要求一致

    # 分数(10)
    
    ## TODO 请编写word_segment_viterbi函数来实现对输入字符串的分词
    def word_segment_viterbi(input_str):
        """
        1. 基于输入字符串,词典,以及给定的unigram概率来创建DAG(有向图)。
        2. 编写维特比算法来寻找最优的PATH
        3. 返回分词结果
        
        input_str: 输入字符串   输入格式:“今天天气好”
        best_segment: 最好的分词结果  输出格式:["今天","天气","好"]
        """
    # TODO: 第一步:根据词典,输入的句子,以及给定的unigram概率来创建带权重的有向图(Directed Graph) 参考:课程内容
    # 有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率在 word_prob,如果不在word_prob里的单词但在
    # 词典里存在的,统一用概率值0.00001。
    # 注意:思考用什么方式来存储这种有向图比较合适? 不一定有只有一种方式来存储这种结构。 
        graph ={}
    
        N = len(input_str)
        for i in range(N,0,-1):
            k=i-1
            in_list=[]
            flag=input_str[k:i]
            while k>=0 and flag in dic_words:
                in_list.append(k)
                k-=1
                flag = input_str[k:i]
            graph[i]=in_list
    
    # TODO: 第二步: 利用维特比算法来找出最好的PATH, 这个PATH是P(sentence)最大或者 -log P(sentence)最小的PATH。
        mem=[0]* (N+1)
        last_index=[0]*(N+1)
        for i in range(1,N+1):
            min_dis=math.inf
            for j in graph[i]:
    # 有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率在 word_prob,如果不在word_prob里的单词但在
    # 词典里存在的,统一用概率值0.00001。
                if input_str[j:i] in word_prob.keys():
                    if min_dis > mem[j]+round(-math.log(word_prob[input_str[j:i]]),1):
                        min_dis=mem[j]+round(-math.log(word_prob[input_str[j:i]]),1)
                        last_index[i]=j
                else:
                    if min_dis > mem[j]+round(-math.log(0.00001),1):
                        min_dis=mem[j]+round(-math.log(0.00001),1)
                        last_index[i]=j
            mem[i]=min_dis
    
    # TODO: 第三步: 根据最好的PATH, 返回最好的切分
        best_segment=[]
        j=N
        while True:
            best_segment.append(input_str[last_index[j]:j])
            j=last_index[j]
            if j==0 and last_index[j]==0:
                break
        best_segment.reverse()
        return best_segment
    
    #测试
    print(word_segment_viterbi("经常有意见分歧"))
    
    ['经常', '有', '意见', '分歧']
    
    # 分数(3)
    # TODO: 第一种方法和第二种方法的时间复杂度和空间复杂度分别是多少?
    第一个方法: 
    时间复杂度=O(2**N) , 空间复杂度=O(N)
    
    第二个方法:
    时间复杂度= , 空间复杂度=
    
    # 分数(2)
    # TODO:如果把上述的分词工具持续优化,有哪些可以考虑的方法? (至少列出3点)
    - 0. (例), 目前的概率是不完整的,可以考虑大量的语料库,然后从中计算出每一个词出现的概率,这样更加真实
    - 1.
    - 2.
    - 3. 
    

    Part 2: 搭建一个简单的问答系统

    本次项目的目标是搭建一个基于检索式的简单的问答系统。至于什么是检索式的问答系统请参考课程直播内容/PPT介绍。

    通过此项目,你将会有机会掌握以下几个知识点:

    1. 字符串操作 2. 文本预处理技术(词过滤,标准化) 3. 文本的表示(tf-idf, word2vec) 4. 文本相似度计算 5. 文本高效检索

    此项目需要的数据:

    1. dev-v2.0.json: 这个数据包含了问题和答案的pair, 但是以JSON格式存在,需要编写parser来提取出里面的问题和答案。
    2. glove.6B: 这个文件需要从网上下载,下载地址为:https://nlp.stanford.edu/projects/glove/, 请使用d=100的词向量
    检索式的问答系统

    问答系统所需要的数据已经提供,对于每一个问题都可以找得到相应的答案,所以可以理解为每一个样本数据是 <问题、答案>。 那系统的核心是当用户输入一个问题的时候,首先要找到跟这个问题最相近的已经存储在库里的问题,然后直接返回相应的答案即可。 举一个简单的例子:

    假设我们的库里面已有存在以下几个<问题,答案>:
    <"贪心学院主要做什么方面的业务?”, “他们主要做人工智能方面的教育”>
    <“国内有哪些做人工智能教育的公司?”, “贪心学院”>
    <“人工智能和机器学习的关系什么?”, “其实机器学习是人工智能的一个范畴,很多人工智能的应用要基于机器学习的技术”>
    <“人工智能最核心的语言是什么?”, ”Python“>

    假设一个用户往系统中输入了问题 “贪心学院是做什么的?”, 那这时候系统先去匹配最相近的“已经存在库里的”问题。 那在这里很显然是 “贪心学院是做什么的”和“贪心学院主要做什么方面的业务?”是最相近的。 所以当我们定位到这个问题之后,直接返回它的答案 “他们主要做人工智能方面的教育”就可以了。 所以这里的核心问题可以归结为计算两个问句(query)之间的相似度。

    在本次项目中,你会频繁地使用到sklearn这个机器学习库。具体安装请见:http://scikit-learn.org/stable/install.html sklearn包含了各类机器学习算法和数据处理工具,包括本项目需要使用的词袋模型,均可以在sklearn工具包中找得到。 另外,本项目还需要用到分词工具jieba, 具体使用方法请见 https://github.com/fxsjy/jieba

    Part 2.1 第一部分: 读取文件,并把内容分别写到两个list里(一个list对应问题集,另一个list对应答案集)

    import json
    from matplotlib import pyplot as plt
    import re
    import string
    import nltk
    from nltk.corpus import stopwords
    from nltk.tokenize import word_tokenize
    from nltk.stem.porter import PorterStemmer
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.metrics.pairwise import cosine_similarity
    from queue import PriorityQueue as PQueue
    from functools import reduce
    
    # 分数(5)
    def read_corpus():
        """
        读取给定的语料库,并把问题列表和答案列表分别写入到 qlist, alist 里面。 在此过程中,不用对字符换做任何的处理(这部分需要在 Part 2.3里处理)
        qlist = ["问题1", “问题2”, “问题3” ....]
        alist = ["答案1", "答案2", "答案3" ....]
        务必要让每一个问题和答案对应起来(下标位置一致)
        """
        qlist = []
        alist = []
        with open("data/train-v2.0.json", 'r') as path:
            fileJson = json.load(path)
        json_list=fileJson['data']
        for data_dict in json_list:
            for data_key in data_dict:
                if data_key=="paragraphs":
                    paragraphs_list=data_dict[data_key]
                    for content_dict in paragraphs_list:
                        for qas_key in content_dict:
                            if "qas" == qas_key:
                                qas_list = content_dict[qas_key]
                                for q_a_dict in qas_list:
                                    if len(q_a_dict["answers"]) > 0:
                                        qlist.append(q_a_dict["question"])
                                        alist.append(q_a_dict["answers"][0]["text"])
    
        print("qlist len:" + str(len(qlist)))
        print("alist len:" + str(len(alist)))
        assert len(qlist) == len(alist)  # 确保长度一样
        return qlist, alist
    

    Part 2.2 理解数据(可视化分析/统计信息)

    对数据的理解是任何AI工作的第一步,需要充分对手上的数据有个更直观的理解。

    # 分数(10)
    # TODO: 统计一下在qlist 总共出现了多少个单词?总共出现了多少个不同的单词?
    # 统计一下qlist中每个单词出现的频率,并把这些频率排一下序,然后画成plot.
    # 这里需要做简单的分词,对于英文我们根据空格来分词即可,其他过滤暂不考虑(只需分词)
    
    # TODO: 统计一下qlist中每个单词出现的频率,并把这些频率排一下序,然后画成plot. 比如总共出现了总共7个不同单词,而且每个单词出现的频率为 4, 5,10,2, 1, 1,1
    #       把频率排序之后就可以得到(从大到小) 10, 5, 4, 2, 1, 1, 1. 然后把这7个数plot即可(从大到小)
    #       需要使用matplotlib里的plot函数。y轴是词频
    def data_analysis(data):
        # TODO: 统计一下在qlist 总共出现了多少个单词? 总共出现了多少个不同的单词?
        # TODO: 统计一下qlist中每个单词出现的频率,并把这些频率排一下序,然后画成plot.
        qlist_word = []
        word_dic = {}
        for sentences in data:
            cur_word = sentences[:len(sentences) - 1].strip().split(" ")
            qlist_word += cur_word
            for word in cur_word:
    
                if word in word_dic.keys():
                    word_dic[word] = word_dic[word] + 1
                else:
                    word_dic[word] = 1
    
        #统计一下在qlist总共出现了多少个不同单词
        word_total = len(set(qlist_word))  # 53306
        print (word_total)
        word_dic=sorted(word_dic.items(), key = lambda x:x[1], reverse = True)#按词频排序
    
        # 出现频率前100的单词进行可视化
        x = range(100)
        y = [c[1] for c in word_dic[:100]]
        plt.figure()
        plt.plot(x, y)
        plt.show()
        
        
        word_freq = []
        word_list = []
        for line in word_dic:
            word_list.append(line[0])
            word_freq.append(line[1])
    
        print(word_freq[:100])
        print(word_list[:100])
        x = range(total_diff_word)
        plt.plot(x,word_freq,'ro')
        plt.ylabel("word frequency")
        plt.show()
    
        temp = [n for n in word_freq if n <=50]
        plt.plot(range(len(temp)),temp, color='r',linestyle='-',linewidth=2)
        plt.ylabel("word frequency")
        plt.show()
    
    qlist, alist = read_corpus()
    data_analysis(qlist)
    

    2.3 文本预处理

    次部分需要尝试做文本的处理。在这里我们面对的是英文文本,所以任何对英文适合的技术都可以考虑进来。

    # 分数(10)
    
    # TODO: 对于qlist, alist做文本预处理操作。 可以考虑以下几种操作:
    #       1. 停用词过滤 (去网上搜一下 "english stop words list",会出现很多包含停用词库的网页,或者直接使用NLTK自带的)   
    #       2. 转换成lower_case: 这是一个基本的操作   
    #       3. 去掉一些无用的符号: 比如连续的感叹号!!!, 或者一些奇怪的单词。
    #       4. 去掉出现频率很低的词:比如出现次数少于10,20....
    #       5. 对于数字的处理: 分词完只有有些单词可能就是数字比如44,415,把所有这些数字都看成是一个单词,这个新的单词我们可以定义为 "#number"
    #       6. stemming(利用porter stemming): 因为是英文,所以stemming也是可以做的工作
    #       7. 其他(如果有的话)
    #       请注意,不一定要按照上面的顺序来处理,具体处理的顺序思考一下,然后选择一个合理的顺序
    #  hint: 停用词用什么数据结构来存储? 不一样的数据结构会带来完全不一样的效率! 
    def data_pre(temp_list):
        stop_words = set(stopwords.words('english'))
        stemmer = PorterStemmer()
        pattern = re.compile('[{}]'.format(re.escape(string.punctuation)))#正则匹配特殊符号
        word_list_list = []
        word_dict = {}
        for line in temp_list:
            temp_word_list = []
            sentence = pattern.sub("", line) # 1.去掉一些无用的符号
            sentence = sentence.lower()      # 2.转换成lower_case
            word_list = sentence.split()
            for word in word_list:
                if word not in stop_words:  # 3.过滤停用词
                    word = "#number" if word.isdigit() else word  # 4.数字特殊处理
                    word = stemmer.stem(word)  # 5.词干提取(包括词形还原)
                    word_dict[word] = word_dict.get(word, 0) + 1
                    temp_word_list.append(word)
            word_list_list.append(temp_word_list)
        return word_dict, word_list_list
    
    #6. 去掉出现频率很低的词
    def filter_words(in_list=[], in_dict={}, lower=0, upper=0):
        word_list = []
        for key, val in in_dict.items():
            if val >= lower and val <= upper:
                word_list.append(key)
    
        new_list = []
        for line in in_list:
            words = [w for w in line if w in word_list]
            new_list.append(' '.join(words))
        return new_list
    
    
    qlist_word_dict, qlist_list_list = data_pre(qlist)
    alist_word_dict, alist_list_list = data_pre(alist)
    qlist = filter_words(in_list= qlist_list_list, in_dict = qlist_word_dict, lower = 2,upper = 1000 )
    alist = filter_words(in_list= qlist_list_list, in_dict = qlist_word_dict, lower = 2,upper = 1000 )   # 更新后的
    
    # TODO: 在前面步骤里,我们删除了出现次数比较少的单词,那你选择的阈值是多少(小于多少的去掉?), 这个阈值是根据什么来选择的? 
    # 
    # 画出100分为类的词频统计图
    def drawgraph(dic, name):
        freq = list(dic.values())
        freq.sort(reverse=True)
        temp = [n for n in freq if n <=50]
        plt.plot(range(len(temp)),temp,'r-')
        plt.ylabel(name)
        plt.show()
    
        
    drawgraph(qlist_word_dict,"word frequency of qlist")
    drawgraph(alist_word_dict,"word frequency of alist")
    在上面步骤,我删除了出现次数小于2和大于10000的词,原因是这两个位置词频断档比较严重
    

    2.4 文本表示

    当我们做完关键的预处理过程之后,就需要把每一个文本转换成向量。

    # 分数(10)
    # TODO: 把qlist中的每一个问题字符串转换成tf-idf向量, 转换之后的结果存储在X矩阵里。 X的大小是: N* D的矩阵。 这里N是问题的个数(样本个数),
    #       D是字典库的大小。 
    from sklearn.feature_extraction.text import TfidfVectorizer
    
    vectorizer =  TfidfVectorizer()     # 定一个tf-idf的vectorizer
    X = vectorizer.fit_transform(qlist)  # 结果存放在X矩阵
    
    # TODO: 矩阵X有什么特点? 计算一下它的稀疏度
    x_mat = X.toarray()
    n = len(x_mat)
    m = len(x_mat[0])
    t = 0
    for i in range(n):
        for j in range(m):
            if x_mat[i][j] != 0:
                t += 1
    sparsity = t / (n*m)
    print (sparsity)  # 打印出稀疏度(sparsity)
    

    2.5 对于用户的输入问题,找到相似度最高的TOP5问题,并把5个潜在的答案做返回

    # 分数(10)
    
    def top5results(input_q):
        """
        给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
        1. 对于用户的输入 input_q 首先做一系列的预处理,然后再转换成tf-idf向量(利用上面的vectorizer)
        2. 计算跟每个库里的问题之间的相似度
        3. 找出相似度最高的top5问题的答案
        """
        stop_word = set(stopword.words("english"))
        stemmer = PorterStemmer()
        pattern = re.compile("[{}]".format(re.escape(string.punctuation))) # 正则匹配特殊符号
        
        input_q = pattern.sub("", input_q) #1.去掉无用的符号
            input_q = pattern.sub("", input_q) # 1.去掉一些无用的符号
        input_q = input_q.lower()      # 2.转换成lower_case
        word_list = input_q.split()
        temp_word_list=[]
        for word in word_list:
            if word not in stop_words:  # 3.过滤停用词
                word = "#number" if word.isdigit() else word  # 4.数字特殊处理
                word = stemmer.stem(word)  # 5.词干提取(包括词形还原)
                temp_word_list.append(word)
        new_input=' '.join(temp_word_list)
        
        #向量化
        vectorizer = TfidfVectorizer(smooth_idf=False)  # 定义一个tf-idf的vectorizer
        X = vectorizer.fit_transform(qlist)  # 结果存放在X矩阵
        #注意fit_transform是训练,transform是加入新数据
        input_vec = vectorizer.transform([new_input])# 结果存放在X矩阵
        res = cosine_similarity(input_vec, X)[0]
    
        #即输出前k个高频词使用优先队列,优化速度
        pq = PQueue()
        for i, v in enumerate(res):
            pq.put((1.0 - v, i))
    
        top_idxs = []  # top_idxs存放相似度最高的(存在qlist里的)问题的下表
        for i in range(5):
            top_idxs.append(pq.get()[1])
    
        print(top_idxs)  # top_idxs存放相似度最高的(存在qlist里的)问题的下表
        # hint: 利用priority queue来找出top results. 思考为什么可以这么做?
        # 因为优先级队列的第一个值可以是浮点数,数值越低级别越优先,所以用1.0-相似度,就可以转换为优先级
    
        result = [alist[i] for i in top_idxs]
        return result  # 返回相似度最高的问题对应的答案,作为TOP5答案
    
    # TODO: 编写几个测试用例,并输出结果
    
    qlist, alist = read_corpus()
    q_dict, q_list_list = data_pre(qlist)
    new_qlist = filter_words(q_list_list, q_dict, 2, 1000)
    print(top5results("when did Beyonce start becoming popular?"))
    print(top5results("what languge does the word of 'symbiosis' come from"))
    
    # 分数(5)
    
    # TODO: 上面的top5results算法的时间复杂度和空间复杂度分别是多少?
    
    时间复杂度 = O(), 空间复杂度 = O()
    

    2.6 利用倒排表的优化。

    上面的算法,一个最大的缺点是每一个用户问题都需要跟库里的所有的问题都计算相似度。假设我们库里的问题非常多,这将是效率非常低的方法。 这里面一个方案是通过倒排表的方式,先从库里面找到跟当前的输入类似的问题描述。然后针对于这些candidates问题再做余弦相似度的计算。这样会节省大量的时间。

    # 分数(10)
    
    # TODO: 基于倒排表的优化。在这里,我们可以定义一个类似于hash_map, 比如 inverted_index = {}, 然后存放包含每一个关键词的文档出现在了什么位置,
    #       也就是,通过关键词的搜索首先来判断包含这些关键词的文档(比如出现至少一个),然后对于candidates问题做相似度比较。
    # 
    from functools import reduce
    
    inverted_idx = {}  # 定一个简单的倒排表
    for i in range(len(qlist)):
        for word in qlist[i].split():
            if word in inverted_idx:
                inverted_idx[word].append(i)
            else:
                inverted_idx[word] = [i]
    
    for key in inverted_idx:
        inverted_idx[key] = sorted(inverted_idx[key])
    
        
    # 求两个set的交集
    def intersections(set1, set2):
        return set1.intersection(set2)
    
    def top5results_invidx(input_q):
        """
        给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
        1. 利用倒排表来筛选 candidate
        2. 对于用户的输入 input_q 首先做一系列的预处理,然后再转换成tf-idf向量(利用上面的vectorizer)
        3. 计算跟每个库里的问题之间的相似度
        4. 找出相似度最高的top5问题的答案
        """
        # 处理输入字符串
        stop_words = set(stopwords.words('english'))
        stemmer = PorterStemmer()
        pattern = re.compile('[{}]'.format(re.escape(string.punctuation)))  # 正则匹配特殊符号
        sentence = pattern.sub("", input_q)
        sentence = sentence.lower()
        word_list = sentence.split()
        result_list = []
        for word in word_list:
            if word not in stop_words:
                word = "#number" if word.isdigit() else word
                word = stemmer.stem(word)
                result_list.append(word)
    
        # 找到倒排表中相关的索引,用于答案的候选集
        candidate_list = []
        for word in result_list:
            if word in inverted_idx:
                idx_list = inverted_idx[word]
                candidate_list.append(set(idx_list))
        # 候选问题的索引
        #     print(candidate_list)
        candidate_idx = list(reduce(intersections, candidate_list))
    
        input_seg = ' '.join(result_list)
        vectorizer = TfidfVectorizer(smooth_idf=False)  # 定义一个tf-idf的vectorizer
        X = vectorizer.fit_transform(new_qlist)  # 结果存放在X矩阵
        input_vec = vectorizer.transform([input_seg])
    
        # 计算所有候选索引中的相似度
        similarity_list = []
        for i in candidate_idx:
            similarity = cosine_similarity(input_vec, X[i])[0]
            similarity_list.append((i, similarity[0]))
        res_sorted = sorted(similarity_list, key=lambda k: k[1], reverse=True)
    
        print(type(res_sorted))
    
        # 根据索引检索top 5答案
        answers = []
        i = 0
        for (idx, score) in res_sorted:
            if i < 5:
                answer = alist[idx]
                answers.append(answer)
            i += 1
    
        return answers
    
    # TODO: 编写几个测试用例,并输出结果
    print (top5results_invidx(""))
    print (top5results_invidx(""))
    
    # 分数(3)
    
    # TODO: 上面的top5results算法的时间复杂度和空间复杂度分别是多少?
    
    时间复杂度 = O(), 空间复杂度 = O()
    

    2.7 基于词向量的文本表示

    上面所用到的方法论是基于词袋模型(bag-of-words model)。这样的方法论有两个主要的问题:1. 无法计算词语之间的相似度 2. 稀疏度很高。 在2.7里面我们
    讲采用词向量作为文本的表示。词向量方面需要下载: https://nlp.stanford.edu/projects/glove/ (请下载glove.6B.zip),并使用d=100的词向量(100维)。

    # 分数(10)
    
    # TODO
    #embedding = # 读取每一个单词的嵌入。这个是 D*H的矩阵,这里的D是词典库的大小, H是词向量的大小。 这里面我们给定的每个单词的词向量,那句子向量怎么表达?
          # 其中,最简单的方式 句子向量 = 词向量的平均(出现在问句里的), 如果给定的词没有出现在词典库里,则忽略掉这个词。
    def load_glove(path):
        #第一元素存储全为0的向量,代表词典里不存在的
        vocab = {}
        embedding = []
        vocab["UNK"] = 0
        embedding.append([0] * 100)
        with open(path, 'r', encoding='utf8') as f:
            i = 1
            for line in f:
                row = line.strip().split()
                vocab[row[0]] = i
                embedding.append(row[1:])
                i += 1
    
        return vocab, embedding
    
    
    def top5results_emb(input_q=''):
        """
        给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
        1. 利用倒排表来筛选 candidate
        2. 对于用户的输入 input_q,转换成句子向量
        3. 计算跟每个库里的问题之间的相似度
        4. 找出相似度最高的top5问题的答案
        """
        path = "data/glove.6B.100d.txt"
        # vacab为词典库,embedding为len(vacab)*100的矩阵。
        vocab, embedding= load_glove(path)
    
        stop_words = set(stopwords.words('english'))
        pattern = re.compile('[{}]'.format(re.escape(string.punctuation)))
        sentence = pattern.sub("", input_q)
        sentence = sentence.lower()
        word_list = sentence.split()
        result_list = []
        for word in word_list:
            if word not in stop_words:
                word = "#number" if word.isdigit() else word
                result_list.append(word)
        input_q = " ".join(result_list)
    
        qlist, alist = read_corpus()
        q_dict, q_list_list = data_pre(qlist)
        new_qlist = filter_words(q_list_list, q_dict, 2, 1000)
    
        inverted_idx = {}  # 定一个一个简单的倒排表
        for i in range(len(new_qlist)):
            for word in new_qlist[i].split():
                if word in inverted_idx:
                    inverted_idx[word].append(i)
                else:
                    inverted_idx[word] = [i]
    
        for key in inverted_idx:
            inverted_idx[key] = sorted(inverted_idx[key])
    
        candidates = []
        for word in result_list:
            if word in inverted_idx:
                ids = inverted_idx[word]
                candidates.append(set(ids))
    
        candidate_idx = list(reduce(intersections, candidates))  # 候选问题索引
        input_q_vec=word_to_vec(input_q,vocab, embedding)
    
        scores = []
        for i in candidate_idx:
            vec = word_to_vec(new_qlist[i], vocab, embedding)
            score = cosine_similarity([input_q_vec, vec])[0]
            scores.append((i, score[1]))
        scores_sorted = sorted(scores, key=lambda k: k[1], reverse=True)
    
     # 根据索引检索top 5答案
        answers = []
        i = 0
        for (idx,score) in scores_sorted:
            if i < 5:
                answer = alist[idx]
                answers.append(answer)
            i += 1
        return answers
    
    print(top5results_emb("when did Beyonce start becoming popular?"))
    print(top5results_emb("what languge does the word of 'symbiosis' come from"))
    print(top5results_emb("In her music, what are some?"))
        
    
    
    # TODO: 编写几个测试用例,并输出结果
    print(top5results_emb("when did Beyonce start becoming popular?"))
    print(top5results_emb("what languge does the word of 'symbiosis' come from"))
    print(top5results_emb("In her music, what are some?"))
    
    # 我们在验收作业时在后台会建立几个测试用例,来验证返回的准确性。
    
    展开全文
  • 一、问答系统中的总结(summarization) 目标:产生一个摘要文本包含那些对用户重要和相关的信息 总结的应用领域:任何文档的摘要和大纲,邮件摘要等等 根据总结的内容,我们可以把总结分为两类: 单文档...

    一、问答系统中的总结(summarization)

    • 目标:产生一个摘要文本包含那些对用户重要和相关的信息
    • 总结的应用领域:任何文档的摘要和大纲,邮件摘要等等
    • 根据总结的内容,我们可以把总结分为两类:
      • 单文档总结:给出一个单一文档的摘要、大纲、标题
      • 多文档总结:给定一组文档,给出内容主旨;比如说同一个事件的新故事,关于一些话题和问题的网页
    • 根据总结的目的,我们可以把总结分为两类:
      • 泛总结:总结文档的内容
      • 聚焦请求的总结:基于用户请求展现出的信息需求在总结文档;这是一种复杂的问答系统,通过总结含有某些信息的文档来构建回答
    • 根据回答的特点,我们可以把总结分为两类:
      • 提炼(extractive)总结:基于源文档的词组和句子来构建总结
      • 抽象(abstractive)总结:用一部分的不同单词来表达源文档的观点
    • 一个非常简单的方法:使用第一行的句子
      在这里插入图片描述

    二、生成片段(snippets)

    • 总结的三个阶段:
      • 内容选择:选择从文档中抽取的句子
      • 信息排序:为这些句子选择顺序
      • 句子实现:清理句子
        在这里插入图片描述

    1、无监督的句子选择

    • 这个思想主要源于Luhn(1958):选择那些更重要和更有信息性的单词
    • 两种定义重要单词的方法:
      • tf-idf:对每个在文档j中的单词wi进行tf-idf权重计算
      • 话题署名:选择更小一部分的重要单词
        • 互信息
        • 对数似然比例(LLR)
          在这里插入图片描述
    • 选择更有信息性的单词
      • 对数似然比例(LLR)
      • 是否在请求中出现
        在这里插入图片描述
    • 句子重要性计算:句子中的单词的重要性的和
      在这里插入图片描述

    2、有监督句子选择

    • 给定:对训练文档进行标注,标注出好总结
    • 对应关系:文档中的句子和总结中的句子的对应关系
    • 抽取特征:句子的位置(第一句话?),句子的长度,单词的信息等等
    • 训练:进行一个二分类的训练,判断是否要把句子放到总结中
    • 问题:很难得到标注的数据;找到对应关系很困难;效果并不比无监督算法
    • 所以在实际中,无监督的内容选择是更普遍。

    三、总结器的评估:ROUGE

    • 这是对
      • 基于BLEU(机器学习所使用的度量)
      • 并不比人工评估好(即直接让人工判断这个回答是不是用户的问题)
      • 但是会更方便
    • 给定一个文档D和一个自动生成的总结X
      • 有N个人工产生的可以参考的关于D的总结
      • 运作总结器,给出自动生成的总结X
      • 参考总结中二元组在X中出现的比例就是度量
        在这里插入图片描述
    • 一个例子:
      在这里插入图片描述

    四、更复杂的问题:总结多个文档

    • 这部分现在还没有商业化,但是目前研究的议题。如何回答更长更困难的问题?比如
      在这里插入图片描述
    • 两种通过请求聚焦总结(query-focused summarization)进行困难问题的回答的方法
      • 从下往上的片段方法:找到一系列相关的文档;从这些文档中利用tf-idf,MMR来进行信息性句子抽取;排序并调整句子形成答案
      • 从上往下信息抽取方法:对不同的问题类型建立特定的回答格式
        • 个人传记需要包含:生卒年月、教育、国籍等等
        • 定义需要包含:属、上义关系

    1、从下往上的片段方法

    • 聚焦请求的多文档总结的流程
      在这里插入图片描述
    • 简化句子:最简单的方法是利用句法分析句子,根据一些人工规则来决定哪些修饰语可以被删除,现在越来越多开始使用机器学习的方法
      在这里插入图片描述
    • 从多文档中抽取内容的方法:最大边际关联(MMR)
      • 一种贪婪的方法,迭代选择最好的句子插入到总结中。最好的句子是相关且含有新含义的句子
      • 相关:和用户请求的最大相关,即与请求的cosine相似度高
      • 新颖:和现在已经有的总结相比,相关度更低,即与请求的cosine相似度低
        在这里插入图片描述
        • 当满足想要的长度的时候就停止
    • LLR+MMR:选择有丰富含义同时新颖的句子
      • 第一步,对每个句子基于LLR计算分数
      • 第二步,把得分最高的句子放入总结中
      • 第三步:迭代加入得分高且含有新含义的句子
    • 信息排序
      • 时间顺序:根据文档的时间顺序排序
      • 连贯性:使得相邻的句子相似的顺序;使得相邻的句子讨论同一个实体
      • 话题顺序:学习源文档的话题顺序

    2、从上往下信息抽取方法

    • 从上往下信息抽取方法:对不同的问题类型建立特定的回答格式,比如
      • 个人传记需要包含:生卒年月、教育、国籍等等
      • 定义需要包含:属、上义关系
        在这里插入图片描述
    • 一个例子
      在这里插入图片描述
    展开全文
  • 本文分享主题:Faiss和bert提供的模型实现了一个中文问答系统。旨在提供一个用Faiss结合各种AI模型实现语义相似度匹配的解决方案。

    0 开篇介绍

    问答系统是自然语言处理领域一个很经典的问题,它用于回答人们以自然语言形式提出的问题,有着广泛的应用。

    经典应用场景包括:智能语音交互、在线客服、知识获取、情感类聊天等。

    常见的分类有:生成型、检索型问答系统;单轮问答、多轮问答系统;面向开放领域、特定领域的问答系统。

    本文涉及的主要是在检索型、面向特定领域的问答系统**——智能客服机器人。**

    传统客服机器人的搭建流程

    通常需要将相关领域的知识(Domain Knowledge),转化为一系列的规则和知识图谱。构建过程中重度依赖“人工”智能,换个场景,换个用户都需要大量的重复劳动。

    图片

    深度学习-智能问答机器人

    深度语言模型会将问题和文档转化为语义向量从而找到最后的匹配答案。本文借助Google开源的Bert模型结合Faiss开源向量搜索引擎,快速搭建基于语义理解的对话机器人。

    案例分享:FAQ问答机器人

    FAQ是Frequently Asked Questions的简称。假定我们有一个常见问题和答案的数据库,现在用户提出了一个新问题,能不能自动从常见问题库中抽取出最相关的问题和答案来作答呢?在这个项目中,我们会探索如何构建这样问答机器人。

    项目核心技术点:

    • 通过深度学习模型判断问题与答案的匹配得分
    • 使用BERT模型特征提取并判断问题相似度
    • 使用检索引擎Faiss索引构建和检索
    • 构建在线FAQ问答系统

    0-1 学什么

    结合Faiss和bert提供的模型实现了一个中文问答系统。旨在提供一个用Faiss结合各种AI模型实现语义相似度匹配的解决方案。最后通过项目案例实现:文本语义相似度文本检索系统和FAQ问答机器人。

    图片

    0-2 在线系统DEMO

    • 文本语义相似度匹配检索
    • 文本语义FAQ问答机器人

    项目实现以一种平台化思路建议系统,是一个通用的解决方案。开发者只需要按照数据规范即可,不需要修改代码就可以运行系统了

    1 对话系统整体简介

    1-1 对话系统概念

    对话系统可以根据人的输入自动选择或者生成出相应的回复,来达到帮助人们在特定领域或者开放域解决一定的问题。(最后,通过医疗数据提供FAQ智能问答: aiwen2100)

    • 用途:任务型、问答型、闲聊型对话系统;
    • 场景:封闭域、开放域对话系统;
    • 使用方法:检索式、生成式对话系统

    1-1-1 不同对话任务对比

    • 问答型(案例:提供基于文本语义-bert 和 faiss 的通用解决方案)

    用户希望得到某个问题的答案,机器人回复来自于特定知识库,以特定的回复回答用户

    • 任务型

    用户希望完成特定任务,机器人通过语义执行后台已对接能力,帮用户完成指定任务

    • 闲聊型

    用户没有明确目的,机器人回复也没有标准答案,以趣味性的回复回答用户

    图片

    图片

    1-1-2 检索式对话系统

    基于检索的模型不会产生新的文字,只能从预先定义的“回答集”中挑选出一个较为合适的回答。

    • 缺点

    检索式对话系统不会产生新的回复,其能够回复类型与内容都由语料库所决定。一旦用户的问话超脱了语料库的范围,那么对话系统将无法准确回答用户。

    • 优点

    相对严谨可靠,可控性强,不会回复令人厌恶或违法法规的文本。

    一般处理流程:

    1.问答对数据集的清洗

    2.Embedding(tfidf,word2ec,doc2vec,elmo,bert…)

    3.模型训练

    4.计算文本相似度

    5.在问答库中选出与输入问题相似度最高的问题

    6.返回相似度最高的问题所对应的答案

    图片

    1-1-3 生成式对话系统

    基于自然语言理解生成式对话策略:即通过机器学习算法构建深层语义模型,结合句词分析

    等统计规律提取特征,让模型从大量的已有对话中学习对话规则,利用训练好的模型预测结果。

    • 缺点

    评估问题,需要依赖人工评定;生成内容,控制不好会回复令人厌恶或违反法规的文本。

    • 优点

    智能对话,回复内容丰富。

    图片

    1-1-4 任务型对话系统

    任务型对话的最终目标是完成指定任务,比如小度智能音箱,需要在每一轮对话都采取合适的决策,保证自己执行正确的指令(即识别出用户的正确意图)

    图片

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5W9MrmV-1606198473806)(https://uploader.shimo.im/f/iOwhzmol8N1oJdI5.png!thumbnail)]

    多轮对话是一种在人机对话中初步明确用户意图之后,获取必要信息以最终得到明确用户指令的方式。

    这里介绍一种对话管理的一种方式:Frame-Based Dialogue Control,预先指定了一张表格 (Frame),聊天机器人的目标就是把这张表格填满。

    图片

    通过一个实际场景的案例来解释上述实现具体执行过程:

    我:『去北京大兴机场多少钱』

    意图:行程花费计算

    槽位:【起始地:当前位置;目的地:北京大兴机场;使用货币:???】)

    智能客服:『您好,请问是使用人民币吗』

    我:『是的』

    意图:行程花费计算

    槽位:【起始地:当前位置;目的地:萧山机场;使用货币:人民币】)

    智能客服:『200元』

    1-2 对话系统关键技术

    1-2-1 相关工具

    1.编程语言:python( 模型 或者服务) ,C++,Java,go 在线服务

    2.数据处理及机器学习相关库:pandas、scikit-learn、jieba

    3.深度学习框架:tensorflow、pytorch

    4.开发工具:pycharm、visual studio code

    5.其它工具:ElasticSearch搜索引擎、向量检索引擎Faiss/Milvus

    1-2-2 检索式相关技术介绍

    1、分词算法

    • 传统算法:HMM隐马尔可夫模型、CRF条件随机场
    • 深度学习:LSTM、Bi-LTSM

    2、文本向量化表示

    OneHot 、N-Gram 、TFIDF等词袋模型、Word2Vec、Doc2Vec、Glove

    Bert(本案例文本向量化表示选择bert) 、XLNet等神经网络模型

    3、文本相似度计算(项目中:我们采用余弦相似度,计算得分)

    余弦相似度、欧式距离

    图片

    4、检索方法

    • ElasticSearch搜索引擎
    • 向量检索引擎Faiss(本项目采用,Facebook AI 研究院开源相似性的检索引擎,5000万 ms)

    1-2-3 生成式相关技术介绍

    闲聊系统

    1、Seq2Seq模型

    2、Seq2Seq + Attention模型

    3、Transformer

    4、Bert模型

    图片

    1-2-4 任务型相关技术介绍

    重要,在我们实际工作中,很多场景都会用到

    1、意图识别

    2、填槽、对话管理

    3、多轮对话

    图片

    分类

    NER识别

    多伦对话(模型,规则。。。。)

    1-3 智能客服调研分析

    客服机器人指帮助客服回答问题提高人工客服效率的机器人。客服机器人可以用于回答客户的常规、重复性的问题,但不是替代,而是辅助人工服务,改变客服工作的模式,进一步提高客服工作效率。

    图片

    1-3-1 调研分析

    纯机器人完全替代客服的并不多,人机结合模式使用广泛。分析一下主要有以下几个原因:

    1、机器人响应速度快,且可同时接待多位客户,而且客户不需要等待;

    2、机器人替代人工处理咨询中的重复问题,人工客服不易陷入烦躁情绪,客户体验好;

    3、遇到复杂问题,人机结合模式可以无缝切换人工来处理,顾客体验不会中断。

    1-3-2 智能客服的优势

    1、机器人可以7 X 24 小时在线服务,解答客户的问题。

    2、常问的问题,重复的问题都可以交给机器人来自动回复,省去很多重复的输入及复制粘贴。

    3、可以辅助人工客服,在人工服务的时候,推荐回复内容,并学习人工客服的回复内容。

    1-3-3 如何设计智能客服系统

    1、时间特性要求。系统极限相应时间到底是多少

    2、灵活性。系统的各个模块应该在可控的状态内,每一个模块可插拔,保证线上质量。

    3、安全性。内外网隔离,注意网络完全,系统安全,用户安全,数据安全。

    4、可扩展性:系统的各个模块支持扩展,支持跨平台,支持多种语言,算法模型可以灵活切换。

    5、可靠性:系统和集群稳定运行,主要的集群实现双机热备;实现灾备;当单个节点发生故障可以迅速切换。

    6、可用性:系统的各项功能可用,系统上线必须符合一定的正确率

    1-4 阿里小蜜介绍

    https://blog.csdn.net/qq_40027052/article/details/78672907

    1-4-1 智能客服发展阶段

    • 传统的服务模式

    图片

    • 经典的服务模式

    图片

    • 智能问答服务模式

    图片

    1-4-2 人机交互基本流程

    阿里巴巴于2015年7月推出了阿里小蜜产品,在面世的仅仅几年中,阿里小蜜发展之迅速令人难以想象。阿里小蜜给出了一个典型的智能对话系统的架构。

    图片

    自然语言处理(NLP)是对话系统的核心部分

    • 智能问答模块用来完成问答类任务(FAQ问答系同,可以基于语义匹配检索来完成)
    • 智能聊天用来完成闲聊类任务
    • 对话系统自然语言理解采用的是frame semantics 表示的一种变形,即采用领域(domain)、意图(intent)和属性槽(slots)来表示语义结果

    图片

    2 应用场景介绍

    CSDN 问答系统:https://ask.csdn.net/

    百度知道:https://zhidao.baidu.com/

    360问答:https://wenda.so.com/search/

    2-2 文本搜索场景

    图片图片

    2-3 论坛相似问答系统

    汽车之家拥有全球最大的汽车社区论坛。积累了丰富的用户问答数据,能够解决用户在看车、买车、用车等方面遇到的各种问题。针对用户在平台上提出的各种问题,从海量的高质量问答库中匹配语义最相似的问题和答案

    文本数据具有表达多样化、用语不规范(如:车型车系用语存在大量缩写、简写、语序颠倒等现象)、歧义性强(如:“北京”可能指汽车品牌,也可能指城市)等特点,这给传统基于关键词匹配的搜索方法带来了很大挑战。因此,在传统关键词匹配的基础上,进一步引入语义搜索技术,将精华问答库的问题映射为多维向量,进行语义匹配,提升问题匹配准确性。

    图片

    2-4 智能对话闲聊系统

    数据格式: query-answer 对如下

    不要骂人 好的,听你的就行了

    不要骂人严重的直接禁言 好的,听你的就行了

    不要骂人了吧 好的,听你的就行了

    不要骂人哦 好的,听你的就行了

    不要骂人小心封号啊 好的,听你的就行了

    不认识你不记得你 你当我傻逼啊

    不认识你昂 你当我傻逼啊

    不认识你老哥了 你当我傻逼啊

    3 问答系统发展现状

    FAQ检索型问答流程是根据用户的新Query去FAQ知识库找到最合适的答案并反馈给用户。

    检索过程如图所示

    图片

    其中,Qi是知识库里的标准问,Ai是标准问对应的答案。

    具体处理流程为:

    • 候选集离线建好索引
    • 线上收到用户 query ,召回一批候选集作为粗排结果传入下一模块进行进一步精确排序;
    • 利用matching模型计算用户query和FAQ知识库中问题或答案的匹配程度;
    • 利用ranking 模型对候选集做 rerank 并返回 topk个候选答案。
      • matching 模型负责对 (query, reply) pair 做特征匹配,其输出的 matching score 通常会作为 ranking 模型的一维特征;
      • ranking 模型负责具体的 reranking 工作,其输入是候选回复对应的特征向量,根据实际需求构造不同类型(如:pointwise, pairwise, listwise)的损失函数,其输出的 ranking score 是候选回复的最终排序依据。
      • 有些检索系统可能不会明确区分 matching 和 ranking 这两个过程。

    3-1 智能问答常用解决方案

    针对FAQ检索式问答系统,一般处理流程

    • 问答对数据集的清洗
    • Embedding
    • 模型训练
    • 计算文本相似度
    • 在问答库中选出与输入问题相似度最高的问题
    • 返回相似度最高的问题所对应的答案

    搭建一个FAQ问答系统一般实现方法

    • 基于ES的智能问题系统

    (通过关键词匹配获取答案,类似电商、新闻搜索领域关键词召回)

    • 基于TF-IDF方式

    (计算每个单词的tfidf数值,分词后换算句子表示。 TF-IDF 方式也在用在关键词提取)

    • 基于Doc2Vec 模型(考虑词和段,相比于word2vec来说有了段落信息)
    • 通过深度学习语言模型bert 提取向量,然后计算相似度

    方案可以扩展到的业务需求(本文介绍的是一种文本语义匹配通用解决方案)

    • 智能客服领域语义匹配

    (对话系统检索式智能问答系统,答案在知识库中且返回唯一的数据记录)

    • 以图搜索(resnet 图片向量化表示)
    • 新闻领域文本相似推荐(相似新闻推荐等)
    • 基于文本语义匹配检索系统(文本相似性rank )

    针对这类问题,重点文本等通过某种方式进行向量化表示(word2vec、doc2vec、elmo、bert等),然后把这种特征向量进行索引(faiss/Milus) ,最终实现在线服务系统的检索,然后再通过一定的规则进行过滤,获取最终的数据内容。

    3-2 传统文本匹配方法存在问题

    传统的文本匹配技术有BoW、VSM、TF-IDF、BM25、Jaccord、SimHash等算法,主要解决字面相似度问题。

    面临的困难:

    由 于中文含义的丰富性,通常很难直接根据关键字匹配或者基于机器学习的浅层模型来确定两个句子之间的语义相似度。

    3-3 深度学习文本匹配

    深度学习模型文本做语义表示逐渐应用于检索式问答系统。

    相比传统的模型优点:

    • 能够节省人工提取特征的大量人力物力
    • 从大量的样本中自动提取出词语之间的关系,并能结合短语匹配中的结构信息和文本匹配的层次化特性,发掘传统模型很难发掘的隐含在大量数据中含义不明显的特征

    本文采用相似问题匹配来实现一个FAQ问答系统。

    问题:什么是相似问题匹配?

    答案:即对比用户问题与现有FAQ知识库中问题的相似度,返回用户问题对应的最准确的答案

    深度语义匹配模型可以分为两大类,分别是representation-based method 和 interaction-based method,这里我们针对Represention-based Method这种方法进行探索。

    图片

    这类算法首先将待匹配的两个对象通过深度学习模型进行表示,之后计算这两个表示之间的相似度便可输出两个对象的匹配度。针对匹配度函数f(x,y)的计算通常有两种方法: cosine 函数 和 多层感知器网络(MLP)

    图片

    对比两种匹配方法的优缺点

    * cosine 函数:通过相似度度量函数进行计算,实际使用过程中最常用的就是 cosine 函数,这种方式简单高效,并且得分区间可控意义明确
    * 多层感知器网络(MLP):将两个向量再接一个多层感知器网络(MLP),通过数据去训练拟合出一个匹配度得分,更加灵活拟合能力更强,但对训练的要求也更高
    

    4 问答系统关键技术

    Google 的 BERT 模型在 NLP 领域中具有巨大的影响力。它是一个通用的语言表示模型,可以应用于诸多领域。本文的项目是将 Faiss与 BERT 模型结合搭建文本语义匹配检索系统,使用 BERT 模型将文本数据转成向量,结合 Faiss特征向量相似度搜索引擎可以快速搜索相似文本,最终获取想要的结果

    4-1 Faiss

    Faiss是Facebook AI团队开源的针对聚类和相似性搜索库,为稠密向量提供高效相似度搜索和聚类,支持十亿级别向量的搜索,是目前最为成熟的近似近邻搜索库。它包含多种搜索任意大小向量集(备注:向量集大小由RAM内存决定)的算法,以及用于算法评估和参数调整的支持代码。Faiss用C++编写,并提供与Numpy完美衔接的Python接口。除此以外,对一些核心算法提供了GPU实现。相关介绍参考《Faiss:Facebook 开源的相似性搜索类库

    图片

    4-2 BERT

    BERT 模型是 Google 发布的一个新的语言表达模型(Language Representation Model),全称是 Bidirectional Encoder Representations from Transformers,即双向编码表征模型。BERT 模型的优势体现在两方面。

    • 一方面,它使用基于特别设计的注意力机制(Attention Mechanism)的简单全连接网络取代了复杂的 CNN 和 RNN 网络。不但大大减少了训练时间,同时有效地提升了网络性能。
    • 另一方面,BERT 模型是第一个真正捕获上下文语义信息的预训练语言表示模型。这是因为 BERT 模型使用了 Transformer 作为算法的主要框架,而 Transformer 框架能更彻底地捕捉语句中的双向关系。

    图片

    Google 提供了一些预先训练的模型,其中最基本的两个模型是BERT-base 模型和 BERT-large 模型。具体参数如下表所示:

    图片

    BERT-base 模型和 BERT-large 模型的参数总量大小和网络层数不同,BERT-large 模型所占计算机内存较多,所以本文项目选用 BERT-base 模型对文本数据进行向量转化。(注:其中,层数(即 Transformer 块个数)表示为 L,隐藏尺寸表示为 H ,自注意力头数表示为 A 。)

    5 问答系统实现

    关于main.py 主要参数

    $ python main.py --help

    usage: main.py [-h] --task TASK [–load] [–index] [–n_total N_TOTAL]

    [–search] [–sentence SENTENCE] [–topK TOPK]

    optional arguments:

    -h, --help show this help message and exit

    –task TASK project task name

    –load load data into db

    –index load data text vector into faiss

    –n_total N_TOTAL take data n_sample ,generate it into faiss

    –search search matched text from faiss

    –sentence SENTENCE query text data

    –topK TOPK take matched data in topK

    第一步:知识库存储 < id,answer>

    $ python main.py --taskmedical–load

    第二步:索引构建<id,question>

    $ python main.py --taskmedical–index --n_total 120000

    第三步:文本语义相似度匹配检索

    $ python main.py --taskmedical_120000–search --sentence 得了乙肝怎么治疗

    备注:medical_120000中task_${索引记录数} 组合

    完成上述功能后,我们可以在此基础上,根据业务不同搭建一些相关应用,例如:

    • 可以实现FAQ智能问答
    • 可以实现新闻资讯内容类文本语义匹配召回
    • 可以实现基于文本语义的中文检索系统

    第四步:基于文本语义检索服务实现FAQ问答

    $ python main.py --taskmedical_120000–search --sentence 身上出现 --topK 10

    第五步:基于文本语义检索服务Web服务

    启动服务python app.py --taskmedical_120000,然后访问地址http://xx.xx.xx.xx:5000/

    我们这里呢,使用上述基础服务完成一个FAQ问答机器人

    5-1 数据规范

    项目数据集包含三个部分:问题数据集+答案数据集+问题-答案唯一标识,数据是一一对应的。

    图片

    针对不同的业务系统,我们只需要提供这种数据格式,通过本文的模板就可以快速搭建一个demo了,祝大家学习愉快。

    5-2 系统整体架构

    本文的文本语义匹配搜索项目使用的 Faiss和BERT的整体架构如图所示:

    图片

    (注:深蓝色线为数据导入过程,橘黄色线为用户查询过程。)

    • 首先,本文项目使用开源的 bert-serving , BERT做句子编码器,标题数据转化为固定长度
    • 为 768 维的特征向量,并导入 Milvus 或者Faiss库。
    • 然后,对存入 Milvus/Faiss 库中的特征向量进行存储并建立索引,同时原始数据提供唯一ID编码,将 ID 和对应内容存储在 PostgreSQL 中。
    • 最后,用户输入一个标题,BERT 将其转成特征向量。Milvus/Faiss 对特征向量进行相似度检索,得到相似的标题的 ID ,在 知识库(PostgreSQL/MySQL/SQLite。。。) 中找出 ID 对应的详细信息返回

    6-3 文本向量服务 bert-serving

    使用bert as service 服务

    第一步:安装tensorflow

    Python >= 3.5

    Tensorflow >= 1.10 (one-point-ten)

    ubuntu系统-gpu下载离线安装文件并pip安装

    tensorboard-1.15.0-py3-none-any.whl

    tensorflow_estimator-1.15.1-py2.py3-none-any.whl

    tensorflow_gpu-1.15.3-cp37-cp37m-manylinux2010_x86_64.whl

    也可以通过下面的方式快速下载(这里下载cpu版本)

    pip install tensorflow==1.15.0 --user -ihttps://pypi.tuna.tsinghua.edu.cn/simple

    验证是否安装

    import tensorflow as tf

    print(tf.version)

    第二步:bert-serving 服务搭建

    ( 我们在ubuntu系统搭建完成bert-serving ,目录:/home/ubuntu/teacher/ )

    通过bert-serving服务,帮助我们解决:文本-> 向量的转换

    1、参考github 提供的代码

    git clonehttps://github.com/hanxiao/bert-as-service.git

    2、安装server和client

    pip install bert-serving-server # server

    pip install bert-serving-client # client, independent of bert-serving-server

    3、下载pretrained BERT models

    Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters

    https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip

    解压模型:

    chinese_L-12_H-768_A-12

    ├── bert_config.json

    ├── bert_model.ckpt.data-00000-of-00001

    ├── bert_model.ckpt.index

    ├── bert_model.ckpt.meta

    └── vocab.txt

    bert_config.json: bert 模型配置参数

    vocab.txt: 字典

    bert_model: 预训练的模型

    4、启动bert-service

    nohup bert-serving-start -model_dir chinese_L-12_H-768_A-12 -num_worker 1 -max_seq_len 64 >start_bert_serving.log 2>&1 &

    ( CPU和GPU 模式都可以 )

    针对每个字段进行说明

    workers = 4 表示同时并发处理请求数

    model_dir 预训练的模型

    max_seq_len 业务分析句子的长度

    关闭服务

    bert-serving-terminate -port 5555

    5、测试文本-> 向量表示结果

    from bert_serving.client import BertClient
    bc = BertClient()
    result = bc.encode(['First do it'])
    print(result)
    

    5-4 向量相似度搜索引擎

    产品学习手册

    5-5 知识库存储

    知识库:可以存储mongo/PostgreSQL/mysql 根据数据量进行选择

    本文给大家分享的内容,数据存储在mysql上。

    备注:关于mysql 的具体安装,大家去上网查找一下。(root,12345678)

    大家在学习过程中,如果有任何的问题:可以网站留言(或者weixin: aiwen2100)

    create database faiss_qa;

    use faiss_qa;

    CREATE TABLE answer_info (

    id int(11) NOT NULL AUTO_INCREMENT,

    answer mediumtext COLLATE utf8mb4_bin,

    PRIMARY KEY (id),

    KEY answer_info_index_id (id)

    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

    5-6 索引构建

    $ python main.py --taskmedical–index --n_total 120000

    5-7文本语义相似度匹配搜索

    $ python main.py --task medical --search --sentence 小安信贷

    完成上述功能后,我们可以在此基础上,根据业务不同搭建一些相关应用,例如:

    • 可以实现FAQ智能问答
    • 可以实现新闻资讯内容类文本语义匹配召回
    • 可以实现基于文本语义的中文检索系统

    对输入数据微小的差别看看有什么不同?

    图片

    5-8文本语义FAQ问答机器人-API接口

    首先,我们启动服务:python app.py

    然后,请求API 服务地址查看检索检索


    $ curl -H “Content-Type:application/json” -X POST --data '{“query”: “乙肝怎么治疗”}'http://localhost:5000/api/v1/search| jq

    5-9文本语义FAQ问答机器人-Web界面

    启动服务 python app.py,然后访问地址http://xx.xx.xx.xx:5000/

    用户表达的细微差别,通过文本语义匹配总之能找到最佳的答案,最终反馈给用户。

    例如: 两种语言表达看看效果

    第一句: 小孩子感冒吃什么

    第二句: 小孩子感冒不能吃什么

    上述明显表达的是两个含义,而通过文本语义的方式也很好得识别出来了,效果还不错。

    图片图片

    我们看看后端服务地址数据

    图片

    注意:FAQ系统依赖bert-serving 服务,请确认正常工作。

    [http://xx.xx.xx.xx:5000/status
    正常情况下的返回结果格式如下:

    {

    “status”:“success”,

    “ip”:“127.0.0.1”,

    “port”:5555,

    “identity”:“cbc94483-1cd6-406d-b170-0cb04e77725bb”

    }

    6 总结展望

    在 AI 高速发展的时代,我们可以使用深度学习模型去处理各种类型的非结构化数据,例如图片、文本、视频和语音等。本文项目通过 BERT 模型可以将这些非结构化数据提取为特征向量,然后通过Faiss 对这些特征向量进行计算,实现对非结构化数据的分析与检索。

    本文利用Faiss搭建的FAQ问答系统也只是其中一个场景,展示了Faiss在非结构化数据处理中的应用。欢迎大家导入自己的数据建立自己的FAQ问答系统(或者文本搜索、智能客服等新系统)。Faiss向量相似度检索引擎搜索十亿向量仅需毫秒响应时间。你可以使用 Faiss探索更多 AI 用法!

    最后,大家有任何问题,欢迎留言交流(WX:aiwen2100),大家一起交流经验。

    展开全文
  • 而我们目前对问答系统的研究,目标就是将用户复杂的自然语言问题转化为结构化的SQL语句,以进行对问题答案的精准检索。 问答系统的历史发展 人们与机器的交流通常分为三类,聊天型,任务导向型和问答型,而问答系统...

    自然语言复杂问题向结构化语句的转化方法概述

    研究背景

    从人工智能研究的初期开始,人们就致力于开发高度智能化的人机对话系统。随着互联网的飞速发展,网络中心海量信息每天都在不断更新,因此,问答系统依据人们对所需信息的准确获取需求,其技术也需要不断提高。
    而我们目前对问答系统的研究,目标就是将用户复杂的自然语言问题转化为结构化的SQL语句,以进行对问题答案的精准检索。

    问答系统的历史发展

    人们与机器的交流通常分为三类,聊天型,任务导向型和问答型,而问答系统是我们生活中最为常用的,问答型对话多指一问一答,用户提出一个问题,系统通过对问题进行解析和知识库查找以返回正确答案[Berant J, Chou A, Frostig R, et al. Semantic parsing on freebase from question-answer pairs]。

    • 现如今面对用户复杂的问题如 Google、Baidu、Bing 等。这些搜索引擎根据一定的算法,运用特定策略从互联网中检索出相关信息反馈给用户。目前,搜索引擎存在两个明显的弊端:(1)需求表达方式单一。用户在利用搜索引擎时需要输入关键词(或段落)。然而,仅依赖若干关键词的逻辑组合,往往无法表达复杂而特殊的检索需求。(2)反馈结果不够清晰。搜索引擎反馈的结果往往是一个网页列表,用户仍要进行大量的人工排查和筛选,才可能找到自己需要的答案。这远远不能满足人们迅速获取所需信息并加以利用的需求。

    现如今问答系统的研究方法

    1. 基于模板的知识库问答方法

    • 基于模板的知识库问答方法旨在利用预定义的模板匹配问题进而得到形式化查询。通常由离线和在线两个过程组成。离线时,主要根据问答历史建立模板库。具体地,归纳总结以往回答过的问题,构造出问题模板与对应的查询模板。在线时,对于一个新输入的问题,首先将其匹配到模板库中的问题模板,进而得到问题模板对应的查询模板。随后,实例化查询模板,即从问题出提取出相应的语义内容,填充模板得到真正的查询。
    • 在模板方法的早期研究 [Unger C, Cimiano P. Pythia: Compositional meaning construction for ontology-based question answering on the semantic web] [Yahya M, Berberich K, Elbassuoni S, et al. Natural language questions for the web of data] [Yahya M, Berberich K, Elbassuoni S, et al. Robust question answering over the web of linked data] [Zou L, Huang R, Wang H, et al. Natural language question answering over RDF: a graph data driven approach]中,提出了使用手动定义的模板来处理具有组合性的复杂问题的方法。这些系统使用语法模式映射到语义模式上的规律性来创建模板。这些方法的缺点是模板的覆盖范围有限,在涉及非常规问题的表述时会异常脆弱。
    • 2013 年,Fader 等人[Fader A, Zettlemoyer L, Etzioni O. Paraphrase-driven learning for open question answering]针对知识库问答使用了少量手工制作的模板,将重点放在具有单个三元组的简单查询上。这种方法仅可以用于处理简单问题,无法应对更为常见的具有复杂查询结构的问题。
    • 2017 年,Abujabal 等人[Abujabal A, Yahya M, Riedewald M, et al. Automated template generation for question answering over knowledge graphs]提出了自动化构建模板的方法,通过抽取问题的核心句式,自动构建出了模板,对句式相同的问题,构建出候选查询子图,对候选查询子图集合进行排序,选择得分最高的候选查询检索答案。
    • 基于模板的知识库问答往往具有较高的精确率,对于能匹配到模板的问题,通常都能正确回答。这是由于高质量的模板可以完整表达出问题的语义。然而,这类方法也始终具有模板生成成本高、模板数量有限、覆盖面不足的问题,成为阻碍性能提升的瓶颈。

    2. 基于语义解析的知识库问答方法

    • 基于语义解析(Semantic Parsing)的方法通过对自然语言问题进行解析,将其转化为逻辑形式查询,在知识库上执行查询得到答案。被广泛应用于机器翻译[10]、问答[11]、本体归纳[12]、自动推理[13]、代码生成[14]等领域。
    • 整个过程可以分为两个步骤,词汇映射和逻辑语言构建。将问题中的词汇映射到逻辑语言中,然后将逻辑语言组合形成在知识库中的查询,从而检索答案。由于自然语言问题中的表达与知识库中定义的关系在字面上可能完全不同,仅仅通过预定义的词表无法有效地解决映射问题。随着深度学习的兴起,具有强大表示能力的神经网络模型被应用到语义解析中,大幅度提升了此类方法的性能。
    • 2015 年,Yih 等人[Yih W T, Chang M W, He X, et al. Semantic Parsing via Staged Query Graph Generation: Question Answering with Knowledge Base]提出了可映射为逻辑形式的查询图,并将传统的语义解析简化为阶段生成查询图的管道。管道主要包括三个阶段,分别对应查询图的三类组件:(1)链接主题实体;(2)检测核心关系链;(3)添加约束。在每个阶段中,对该阶段的组件打分排序,并根据结果对查询图进行拓展。其中,在关系检测步骤中使用了卷积神经网络模型。
    • 2017 年,Yu 等人[16]遵循[15]提出的查询图阶段生成管道,并将重点放在关系检测步骤上,提出了 HR-BiLSTM 模型。在对关系编码时,同时考虑关系名级别与单词级别,并使用残差连接增强语义的传播。
    • 2017 年,Liang等人[17]提出神经符号机,通过基于强化学习的神经网络语义解析生成知识库上的查询动作序列,摆脱了对查询序列标注数据的依赖。2019年,Saha 等人[18]进一步提出使用辅助奖励技术来减轻极端的奖励稀疏性,并结合了通用的实用编程风格来约束组合程序仅保留语义正确程序的空间,提升了强化学习的性能。

    3. 端到端的方法

    • 端到端的知识库问答方法缘于深度学习的兴起。与前两类方法相比,最大的区别是此类方法无需构建查询,而直接从答案入手,设计端到端的神经网络模型为候选答案排序。通过神经网络模型将问题和候选答案及其上下文都映射到一个向量空间中,计算关联度。最后,根据关联度设置阈值或进行分类,预测最终答案。
    • 2014 年,Bordes 等人[ Bordes A, Weston J, Usunier N. Open question answering with weakly supervised embeddingmodels] [Bordes A, Chopra S, Weston J. Question Answering with Subgraph Embeddings] 的两篇工作首先针对简单问题提出了一种神经网络模型。在该方法中,问题对应的事实只包含一条知识库三元组,问句和三元组都被表示为低维空间的向量,最终通过选取与问句相似度最高的三元组回答问题。 除了三元组,该方法还利用了与每个答案相邻的实体和关系作为上下文补充信息。
    • 2019 年, Zhao 等人[Zhao W, Chung T, Goyal A, et al. Simple Question Answering with Subgraph Ranking and JointScoring]提出了一种实体和关系的联合分数用于训练,大幅提升了简单问题回答的准确率,然而该方法假定问题对应的事实中仅用一条三元组即可描述,无法有效应对带有各类约束,且包含多跳关系路径的复杂问题。
    • 端到端的知识库问答方法通常只需要一个模型,这样既避免了模板方法低覆盖率,也避免了语义解析中的复杂的管道建设以及误差传播。同时,模型也可以在不同的领域被复用或重新训练。然而,此类方法也存在明显的缺点:由于神经网络缺乏解释性,目前仅适用于解决简单问题,而对于包含多条关系以及多种约束的复杂问题,效果较差。

    目前对复杂问题语义解析的最新研究

    1. 将其转化成对应的形式化查询

      所谓形式化查询,就是一种可以让知识库理解的逻辑形式上的查询。一方面,相比于自然语言问题,形式化查询在逻辑上更加清晰直观;另一方面,相比于最终的可执行查询语句(如 SPARQL),形式化查询省去了部分繁琐的语法规则。

      在早期的基于语义解析的研究中,大多采用了 -DCS(Lambda DependencyBased Compositional Semantics)构建形式化查询。 -DCS 是一种经典的逻辑形式语言,它将逻辑形式归纳为一元(unary)形式,如知识库实体,与二元(Binary)形式,如知识库关系。此外, -DCS 还包括连接(Join)、交集(Intersection)、聚合(Aggregate)等操作。图2展示了一个自然语言问题 1与其对应的 -DCS 形式化查询。
      在这里插入图片描述
      尽管 -DCS为形式化查询提供了一种经典的范式,但是它仍然存在一些缺点:比如,描述繁琐,逻辑形式不够直观等。

      2015年,Yih 等人[Yih W T, Chang M W, He X, et al. Semantic Parsing via Staged Query Graph Generation: Question Answering with Knowledge Base] 在 -DCS的基础上,提出了查询图的概念。这是首次从图的角度描述形式化查询。通俗来说,查询图可以被视为知识图谱中的一个携带变量的子图G=(V,E),这里V和E分别表示顶点集与边集。在查询图中,顶点可能是知识库实体、实体类型、数值,变量等,边可能是知识库关系,或是一些内建属性(Built-in Property)
      在这里插入图片描述
      相较于 -DCS,查询图具有两个优点:
      1)图结构简化了 -DCS 中的繁琐表示,使逻辑形式更加清晰直观。
      2)将形式化查询作为图结构考虑,可以利用基于图的算法,如状态转移生成查询图。

      在[Formal Query Building with Query Structure Prediction for Complex Question Answering over Knowledge Base]文章中,作者在查询图的基础上提出抽象查询图(AQG), 并对图中的顶点和边做了分类
      在这里插入图片描述通过在查询图中的实体连接,主路径生成、以及约束来生成候选查询图的排序,最终,选择得分最高的查询图执行得到答案。

    2. 结构化查询
      结构化分析方法结构化语言采用一种介于自然语言和形式化语言之间的结构化语言来描述加工逻辑,既可以像自然语言那样最方便,也可以像形式化语言一样能够精确描述事物,且被计算机易于处理。
      目前问答系统结构的知识源,大多是基于关系型数据库的问答(KBQA)。
      KBQA的工作方式: 问题—>实体链接—>属性理解(意图识别+属性关联)—>结构化查询—知识图谱—>答案
      意图识别:识别问题所提及的实体属性, 如识别how many people live in
      能够理解相同语义的不同问法
      能够区分形式上接近但意图不同的问题
      属性关联:明确意图之后,找到知识图谱对应的属性,如找到population

      目前对文本结构化的描述研究:[Data-Anonymous Encoding for Text-to-SQL Generation]在文本到SQL的生成中,输入话语通常包含大量与表中的列名或单元格相关的标记,称为表相关标记,将输入语句中的标记映射到SQL查询中的常量叫做词汇问题。词汇问题可以表述为一个顺序标记问题,称为匿名化,其中输入话语中的每个标记都将被标记为与列名、单元格或无相关。这些与表相关的标记对于下游的神经语义解析器来说是很麻烦的,因为它带来了复杂的语义。
      在这里插入图片描述
      如果能在神经语义解析之前减少词法问题,训练难度会大大减轻。原因是双重的。首先,通过在神经语义分析器之前匿名化输入话语中的表相关标记,我们可以隐藏表相关标记的复杂语义。第二,不同的输入话语具有不同的表相关标记,但是具有相同的结构,在它们被输入到解析器之前,可以被简化为相同的匿名话语。
      在这里插入图片描述
      论文使用基于学习的方法来减少词汇问题,即匿名化与表相关的标记。然后,考虑到没有用于匿名化的标记数据,建议提取出现在SQL查询中的列名和单元格的集合,并使用该集合作为监督。利用这种隐含的监管的另一个好处是,我们可以使优化模型考虑与组件的关系。此外,为了弥补我们的模型是一个顺序标记模型,而从查询中提取的监督是一个无序集的差距,我们利用策略梯度(威廉姆斯,1992)来训练模型。

    展开全文
  • 问答系统综述

    2020-03-18 20:52:31
    系统定义:一个能回答任意自然语言形式问题的自动机。 处理流程: 分析问题. 检索包含答案的数据(检索数据). 提取答案. 对应流程中的三个过程有三个研究的基本问题: 问题分析:如何去分析问题; 信息检索:如何...
  • 自动问答系统能够使用户以自然语言提问的形式而不是关键词的组合,提出信息查询需求,系统依据对问题进行分析,从各种数据资源中自动找出准确的答案。从系统功能上讲,自动问答分为开放域自动问答和限定域自动问答。...
  • 文智中文语义开放平台是基于并行计算系统和分布式爬虫平台,结合独特的语义分析技术,一站式满足用户NLP、转码、抽取、全网数据抓取等中文语义分析需求的开放平台。用户能够基于平台对外提供的OpenAPI实现搜索、推荐...
  • 1 自然语言处理概述 2 Stanford Parser简介 四、实验过程 1 安装JDK 2 下载StanfordParser[3],配置环境变量 3 安装NLTK库,配置环境变量 4 使用Stanford Parser的PCFG算法进行句法分析 五、实验结果 1 任务...
  • 自然语言理解(NLU)框架

    千次阅读 2019-03-26 15:29:10
    填补当前自然语言处理系统的空白 SAGA自然语言了解利益 示例使用案例 从非结构化的自然语言内容中提取洞察力的挑战 近80%的企业内容是非结构化的。它包括快速增长的人为内容,包括备忘录,电子邮件,文本...
  • 导读:自然语言处理(Natural Language Processing,NLP)技术是与自然语言的计算机处理有关的所有技术的统称,其目的是使计算机能够理解和接受人类用自然语言输入的指...
  • 智能问答系统产品设计详解

    千次阅读 2020-02-24 20:59:36
    我想大家肯定看过很多关于自然语言处理(简称:NLP)技术方面的书籍或者论文,但在这里我不会详细叙述NLP技术方面的知识,而是想通过产品化思路结合NLP相关技术来搭建一个基础版的问答系统。本文通过基于问答对的...
  • 自然语言处理综述

    2019-02-01 20:32:54
    自然语言处理技术分类 工业界NLP四大任务: ...自然语言推理是NLP高级别的任务之一,不过自然语言推理包含的内容比较多,机器阅读,问答系统和对话等本质上都属于自然语言推理。文本蕴含任务(te...
  • 自然语言处理(NLP)学习路线总结

    万次阅读 多人点赞 2019-03-20 21:01:53
    自然语言处理概述 自然语言处理入门基础 自然语言处理的主要技术范畴 自然语言处理基本点 特征处理 模型选择 NLP常用工具 NLP语言模型 快速入门NLP方法 自然语言处理...
  • 中文自然语言处理NLP

    千次阅读 2019-06-12 20:02:37
    近年来,随着互联网的发展,计算机处理自然语言需求变得越来越迫切,除了比较悠久的机器翻译外,自然语言处理在信息检索、信息抽取、数据挖掘、舆情分析、文本摘要、自动问答系统等方面都获得了很广泛的应用。...
  • 如今的自然语言处理其实已经进入了人们的生活,类似人脸识别,指纹识别,语音识别等等都是自然语言处理的一部分,使用起来方便快捷而且出现纰漏的可能性很小,像很多科技大片中的炫酷的眼球识别之类的也...
  • 自然语言处理(NLP)解决方案

    千次阅读 2019-03-26 15:25:55
    自然语言处理(NLP)应用程序的示例 技术资产支持自然语言处理(NLP) 端到端自然语言处理(NLP)解决方案 在当今的企业世界中,单独分析结构化数据已经不足以进行复杂的业务分析,预测和决策。非结构化内容...
  • 论文综述:问答系统综述

    千次阅读 2020-07-05 23:08:52
    文章目录问答系统综述报告1. 摘要2. 引言3. 基于文本的问答3.1 数据集与评价指标3.1.1 数据集3.1.2 评价指标3.2 基于文本的问答的主要框架3.4 从深度学习角度的代表工作3.5 基于文本的问答小结4. 基于知识库的问答...
  • 计算机论文:面向中文问答系统问题分析与答案抽取方法之计算机研究本文是一篇计算机论文,本文提出了基于双向长短时记忆神经网络(Bi-directional Long Short Term MemoryNetwork, Bi-LSTM)的答案抽取模型。...
  • [NLP自然语言处理]谷歌BERT模型深度解析

    万次阅读 多人点赞 2018-10-15 17:49:18
    BERT目前已经刷新的11项自然语言处理任务的最新记录包括:将GLUE基准推至80.4%(绝对改进7.6%),MultiNLI准确度达到86.7% (绝对改进率5.6%),将SQuAD v1.1问答测试F1得分纪录刷新为93.2分(绝对提升1.5分),...
  • 目录 非结构化数据获取 ...它已成为许多新业务功能的重要工具,从聊天机器人和问答系统到情感分析,合规性监控,医疗见解以及非结构化和半结构化内容的BI和分析。 考虑所有可以带来重要见解的非结...
  • 问答系统(QA)0

    万次阅读 2016-11-23 12:09:22
    现有的检索系统,无论是受限领域的检索还是互联网搜索引擎,一般都是基于关键字检索(1.相关答案多2.意图表达差3.语言层,未触及语义层)。 Frequently Asked Questions,FAQ,即通过提取问题特征进行相似度计算来返回...
  • 主要目的是克服人机对话中的各种限制,使用户能用自己的...自然语言处理,是指用计算机对自然语言的形、音、义等信息进行处理,即对字、词、句、篇章的输入、输出、识别、分析、理解、生成等的操作和加工。 自然语...
  • 自然语言处理常用术语   文本主要分为三种文本,自由文本、结构化文本、半结构化文本,自然语言处理一般是对自由文本进行的处理。常见的基本操作如下:   分词   通常我们处理的自由文本分为中文、英文等。...
  • 基于句子相似度的FAQ问答系统

    万次阅读 多人点赞 2018-06-06 19:25:31
    自动问答系统为人们提供了以自然语言提问的交流方式,为用户直接返回所需的答案而不是相关的网页,具有方便、快捷、高效等特点。 Process:本文的问答系统采用了一个FAQ(Frequently Asked Questions)问答库,并基于...
  • 自然语言的基础技术包括词汇、短语、句子和篇章级别的表示,以及分词、句法分析和语义分析等。 词法分析的主要任务是词性标注和词义标注。词性标注就是在给定句子中判断每个词的语法范畴,确定其词性并进行标注。...
  • 自然语言理解和自然语言处理by Mariya Yao 姚iya(Mariya Yao) 4种自然语言处理和理解的方法 (4 Approaches To Natural Language Processing & Understanding) In 1971, Terry Winograd wrote the SHRDLU ...
  • 自然语言处理概述

    千次阅读 2019-03-20 14:00:53
    【NLP】十分钟快览自然语言处理学习总结 阅读目录 17 特征工程 20、推荐算法 十分钟学习自然语言处理概述 作者:白宁超 2016年9月23日00:24:12 摘要:近来自然语言处理行业发展朝气蓬勃,市场应用广泛。...
  • 基于机器学习的自动问答系统构建

    千次阅读 2016-09-06 10:24:03
    自动问答系统能够使用户以自然语言提问的形式而不是关键词的组合,提出信息查询需求,系统依据对问题进行分析,从各种数据资源中自动找出准确的答案。从系统功能上讲,自动问答分为开放域自动问答和限定域自动问答。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,900
精华内容 2,760
关键字:

自然语言问答系统需求分析