自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

適用于TTS語(yǔ)音處理項(xiàng)目的召回模型:詞袋模型究竟是個(gè)啥?和語(yǔ)義召回相比有什么優(yōu)劣? 原創(chuàng)

發(fā)布于 2024-11-13 15:13
瀏覽
0收藏

在人工智能的眾多應(yīng)用中,對(duì)于文檔的準(zhǔn)確召回是一個(gè)廣泛使用的需求。例如,在基于閱讀理解的問(wèn)答系統(tǒng)(RAG)中,我們常常通過(guò)嵌入模型生成向量來(lái)進(jìn)行語(yǔ)義方面的召回,這種方法已經(jīng)證明了其效果良好。然而,這并不意味著該方法適用于所有場(chǎng)景。

讓我們考慮一個(gè)涉及語(yǔ)音處理的項(xiàng)目,用戶可能會(huì)說(shuō)出需要查詢的內(nèi)容,系統(tǒng)需要迅速召回與用戶語(yǔ)音輸入相關(guān)的文檔。在這種情況下,系統(tǒng)的響應(yīng)時(shí)間變得至關(guān)重要,任何延遲都可能影響用戶體驗(yàn)。對(duì)于這類需求,詞袋模型可能成為一種更有利的選擇,因?yàn)樗鼰o(wú)需處理復(fù)雜的語(yǔ)義關(guān)系,從而可以提供更快速的響應(yīng)。所以,選擇何種模型取決于具體的應(yīng)用情景和性能要求。

什么是詞袋模型

詞袋模型是一種文本處理方法,先通過(guò)構(gòu)建一個(gè)有序詞表(字典),包含訓(xùn)練樣本中所有的不重復(fù)詞匯。然后,根據(jù)此詞表遍歷每個(gè)樣本,如果某詞在樣本中出現(xiàn)則出現(xiàn)次數(shù)加1,否則次數(shù)設(shè)置為0。這樣,每個(gè)樣本都可以向量化成一個(gè)長(zhǎng)度等于詞表長(zhǎng)度的向量。這么說(shuō)可能有一點(diǎn)抽象,讓我們來(lái)看一個(gè)例子,比如有兩個(gè)文本:

  • s1:"John likes to watch movies, Mary likes movies too"
  • s2:"John also likes to watch football games"

首先,構(gòu)建詞匯表 ,這兩個(gè)句子形成的詞表(不去停用詞)為:

[‘a(chǎn)lso’, ‘football’, ‘games’, ‘john’, ‘likes’, ‘mary’, ‘movies’, ‘to’, ‘too’, ‘watch’]

然后,對(duì)于每個(gè)文本,統(tǒng)計(jì)詞匯表中每個(gè)單詞的出現(xiàn)次數(shù)或者頻率:

適用于TTS語(yǔ)音處理項(xiàng)目的召回模型:詞袋模型究竟是個(gè)啥?和語(yǔ)義召回相比有什么優(yōu)劣?-AI.x社區(qū)

BOW詞向量

詞袋模型處理流程

詞袋模型的處理流程可以總結(jié)為以下3步:

  1. 首先進(jìn)行文本分詞
  2. 然后創(chuàng)建一個(gè)包含所有獨(dú)特詞匯的詞表,保證每個(gè)詞語(yǔ)僅出現(xiàn)一次,并固定其位置
  3. 最后,將每個(gè)樣本向量化,即遍歷每個(gè)樣本,統(tǒng)計(jì)詞匯表中每個(gè)單詞的出現(xiàn)次數(shù)

可以看出在經(jīng)過(guò)向量化后,每個(gè)樣本的特征維度長(zhǎng)度等于詞表長(zhǎng)度。這種方法能覆蓋所有樣本中的詞匯,但可能導(dǎo)致維度災(zāi)難,因?yàn)橐粋€(gè)通常大小的中文數(shù)據(jù)集可能包含數(shù)萬(wàn)個(gè)詞匯,意味著向量的維度也相應(yīng)大。因此,在分詞后,我們通常統(tǒng)計(jì)每個(gè)詞在數(shù)據(jù)集中的出現(xiàn)次數(shù),并僅選擇出現(xiàn)頻率最高的前K個(gè)詞作為最終詞表。最后,會(huì)移除無(wú)意義的停用詞,如“的”,“啊”,“了”等。

代碼實(shí)現(xiàn)

手動(dòng)擼代碼

文本分詞

向量化的第一步是分詞。我們將介紹一個(gè)常用的開源分詞工具,jieba。在使用jieba之前,需要先進(jìn)行安裝,可以進(jìn)入相應(yīng)的虛擬環(huán)境并使用命令??pip install jieba??完成安裝。

import jieba, re
cut_all = False


def cutWords(s, cut_all=False):
    cut_words = []
    # 將所有字母、數(shù)字、冒號(hào)、逗號(hào)、句號(hào)等過(guò)濾掉
    s = re.sub("[A-Za-z0-9\:\·\—\,\。\“ \”]", "", s)
    seg_list = jieba.cut(s, cut_all=cut_all)
    cut_words.append("/".join(seg_list))

cut_all 參數(shù)可以指定分詞模式,當(dāng)??cut_all = False???時(shí),表示普通分詞模式,設(shè)置為??True??后,便可以開啟全分詞模式。

構(gòu)建詞表

分詞后通常還會(huì)進(jìn)行詞頻統(tǒng)計(jì),以便選取出現(xiàn)頻率最高的前K個(gè)詞來(lái)構(gòu)造詞表。對(duì)詞頻進(jìn)行統(tǒng)計(jì)需要使用另外一個(gè)包c(diǎn)ollection中的??Counter??計(jì)數(shù)器。

import re
from collections import Counter
import jieba


def wordsCount(s):
    # 初始化空字符串用于存儲(chǔ)分詞結(jié)果
    cut_words = ""
    
    # 使用正則表達(dá)式移除非中文字符
    s = re.sub("[A-Za-z0-9\:\·\—\,\。\“ \”]", "", s)
    
    # 使用jieba進(jìn)行分詞,并連接結(jié)果
    seg_list = jieba.cut(s, cut_all=False)
    cut_words += (" ".join(seg_list))
    
    # 將分詞結(jié)果分割成列表
    all_words = cut_words.split()
    
    # 初始化計(jì)數(shù)器
    c = Counter()
    
    # 遍歷所有單詞,長(zhǎng)度大于1且不是換行符則進(jìn)行計(jì)數(shù)
    for x in all_words:
        if len(x) > 1 and x != '\r\n':
            c[x] += 1
    
    # 創(chuàng)建一個(gè)詞匯列表
    vocab = []
    
    print('\n詞頻統(tǒng)計(jì)結(jié)果:')
    # 打印并收集出現(xiàn)頻率最高的前5個(gè)詞
    for (k, v) in c.most_common(5): 
        print("%s:%d" % (k, v))
        vocab.append(k)
    
    # 打印詞匯列表
    print("詞表:", vocab)

詞頻統(tǒng)計(jì)

def vectorization_with_freq(s):
    # 此處接文本分詞和詞頻統(tǒng)計(jì)代碼,需要生成詞表vocab和文本x_text
    
    # 初始化空列表用于存儲(chǔ)向量化結(jié)果
    x_vec = []
    
    # 遍歷文本中的每項(xiàng)
    for item in x_text:
        # 對(duì)詞表中的每個(gè)詞創(chuàng)建一個(gè)字典,初始化頻率為0
        tmp = dict(zip(vocab, [0] * len(vocab)))
        
        # 遍歷此項(xiàng)中的每個(gè)詞
        for w in item:
            # 如果詞在詞表中,則頻率加1
            if w in vocab:
                tmp[w] += 1
                
        # 將該項(xiàng)的向量添加到向量化結(jié)果列表
        x_vec.append(list(tmp.values()))
    
    # 打印詞表、文本和向量化結(jié)果
    print("詞表:", vocab)
    print("文本:", x_text)
    print(x_vec)

這段Python代碼定義了一個(gè)函數(shù)??vectorization_with_freq(s)???,它接受一個(gè)字符串??s??作為輸入,然后使用詞頻方法對(duì)其進(jìn)行向量化處理。

sklearn實(shí)現(xiàn)

在實(shí)踐中,我們可以直接使用sklearn庫(kù),它已經(jīng)實(shí)現(xiàn)了上述功能,無(wú)需手動(dòng)編寫復(fù)雜的代碼。

from sklearn.feature_extraction.text import CountVectorizer
corpus = [
    "John likes to watch movies, Mary likes movies too",
    "John also likes to watch football games",
]
bag_of_words = CountVectorizer(
            ngram_range=(1, 2), token_pattern="(?u)\\b\\w+\\b", binary=True
        ).fit(corpus)
vectors = bag_of_words.transform(corpus)
print(vectors)


"""
 (0, 5)	1
  (0, 7)	1
  (0, 8)	1
  (0, 9)	1
  (0, 10)	1
  (0, 11)	1
  (0, 12)	1
  (0, 13)	1
  (0, 14)	1
  (0, 15)	1
  (0, 16)	1
  (0, 17)	1
  (0, 18)	1
  (0, 19)	1
  (0, 21)	1
  (1, 0)	1
  (1, 1)	1
  (1, 2)	1
  (1, 3)	1
  (1, 4)	1
  (1, 5)	1
  (1, 6)	1
  (1, 8)	1
  (1, 10)	1
  (1, 16)	1
  (1, 17)	1
  (1, 19)	1
  (1, 20)	1
"""

??CountVectorizer??是scikit-learn庫(kù)中的一個(gè)類,用于將文本轉(zhuǎn)換為詞項(xiàng)頻率向量。下面解釋你提到的這些參數(shù)。

  1. ngram_range: 它定義了從文本中提取的 n-gram 的大小范圍。N-gram 是 n 個(gè)連續(xù)的單詞。例如,對(duì)于句子"我愛北京",當(dāng) ngram_range=(1,2),則會(huì)提取出 unigrams(單詞)和 bigrams(兩個(gè)連續(xù)的單詞)。即,"我","愛","北京","我愛","愛北京"。
  2. token_pattern: 這是一個(gè)正則表達(dá)式,它定義了什么構(gòu)成一個(gè)“單詞”。"(?u)\b\w+\b"表示一個(gè)或多個(gè)unicode字符或數(shù)字并以邊界分隔。例如,對(duì)于句子"I love Beijing",tokens 是["I", "love", "Beijing"]。
  3. binary: 如果設(shè)置為 True,所有非零計(jì)數(shù)都設(shè)為 1。這意味著輸出的結(jié)果只表示單詞是否在文檔中出現(xiàn)(被設(shè)為1),而不是單詞出現(xiàn)的次數(shù)。例如,對(duì)于句子"I love love Beijing",如果 binary=True,那么每個(gè)單詞無(wú)論出現(xiàn)一次或多次,結(jié)果都記作出現(xiàn)過(guò),"love": 1,而不是"love": 2。

fit

??CountVectorizer.fit()??是scikit-learn庫(kù)中的一個(gè)方法,用于學(xué)習(xí)輸入文本集合(通常是一組文檔)中所有單詞的詞匯表。這個(gè)過(guò)程也被稱為“擬合”數(shù)據(jù)。

例如,如果我們有三個(gè)文檔:["The sky is blue", "The sun is bright", "The sun in the sky is bright"],??fit()??函數(shù)會(huì)生成一個(gè)詞匯表,包含所有不重復(fù)的單詞:['The', 'sky', 'is', 'blue', 'sun', 'bright', 'in']。

這個(gè)詞匯表隨后可以??于將新的(或相同的)文檔轉(zhuǎn)換成向量,其中每個(gè)元素表示相應(yīng)單詞在文檔中出現(xiàn)的頻次。這是通過(guò)??transform()???函數(shù)實(shí)現(xiàn)的,也經(jīng)常和??fit()???方法一起使用,如??fit_transform()??。

輸出

??CountVectorizer???的輸出是一個(gè)稀疏矩陣,其中每一行表示corpus中的一個(gè)文檔,每一列對(duì)應(yīng)于??CountVectorizer??擬合后得到的詞匯表中的一個(gè)單詞。在你的例子中,你有兩個(gè)文檔,所以你有兩行。

每個(gè)元組 ??(i, j)??? 的值代表了詞匯表中第 ??j??? 個(gè)單詞在第 ??i??? 個(gè)文檔中出現(xiàn)的頻率。因?yàn)槟阍O(shè)置 ??binary=True??, 所以這個(gè)頻率只能是0或1,表示該單詞在相應(yīng)的文檔中是否出現(xiàn)。

例如,在你給出的輸出中,??(0, 5) 1?? 表示詞匯表中的第5個(gè)單詞在第一個(gè)文檔("John likes to watch movies, Mary likes movies too")中出現(xiàn)了(至少一次)。

類似地,??(1, 0) 1?? 表示詞匯表中的第0個(gè)單詞在第二個(gè)文檔("John also likes to watch football games")中出現(xiàn)了。

注意,此處的索引是從0開始的,而且可能看不到某些索引,這是因?yàn)閷?duì)應(yīng)的詞在相應(yīng)的文檔中沒(méi)有出現(xiàn),頻率為零,而這種信息在稀疏矩陣中通常會(huì)被省略,以節(jié)省存儲(chǔ)空間。

應(yīng)用

在基于回答生成的閱讀理解系統(tǒng)(RAG)中,文檔召回是核心的一步。這個(gè)過(guò)程主要依賴于檢索和標(biāo)定與用戶查詢相關(guān)性最高的文檔。傳統(tǒng)的RAG應(yīng)用主要通過(guò)語(yǔ)義和關(guān)鍵字匹配來(lái)執(zhí)行此操作,這通常需要使用embedding模型。具體來(lái)說(shuō),我們會(huì)將文本輸入到模型中,得到每個(gè)文檔或查詢的嵌入向量表示,然后計(jì)算它們之間的相似度。

除了上述方法外,我們還可以使用基于詞袋模型的召回策略。詞袋模型將文檔轉(zhuǎn)換為一個(gè)向量,其中每個(gè)元素對(duì)應(yīng)于特定單詞或短語(yǔ)在文檔中出現(xiàn)的頻率。通過(guò)比較這些向量,我們可以確定文檔之間的相似度。例如,我們可以通過(guò)計(jì)算余弦相似度來(lái)衡量?jī)蓚€(gè)向量的相似程度,這種方法允許我們找到與給定查詢最相關(guān)的前K個(gè)文檔。

import numpy as np
from nltk.stem import PorterStemmer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import check_pairwise_arrays, normalize, safe_sparse_dot




stemmer = PorterStemmer()




class Vectorizer:
    @staticmethod
    def stem(text):
        # 詞干化
        words = text.split()
        stemmed_words = [stemmer.stem(word) for word in words]
        sentence = " ".join(stemmed_words)
        sentence = sentence
        return sentence


    def __init__(self, corpus):
        self.bag_of_words = CountVectorizer(
            ngram_range=(1, 2), token_pattern="(?u)\\b\\w+\\b", binary=True
        ).fit(corpus)
        self.vectors = self.bag_of_words.transform(corpus)
        self.corpus = corpus


    @staticmethod
    def cosine_similarity(X, Y=None, dense_output=True):
        X, Y = check_pairwise_arrays(X, Y)
        X_normalized = normalize(X, copy=True)
        if X is Y:
            Y_normalized = X_normalized
        else:
            Y_normalized = normalize(Y, copy=True)
        return safe_sparse_dot(
            X_normalized,
            Y_normalized.T,
            dense_output=dense_output)


    def get_relevent_docs(self, query, top_k=3, theshold=0):
        stem_query = self.stem(query)
        query_vectors = self.bag_of_words.transform([stem_query])
        cos_sim = self.cosine_similarity(self.vectors, query_vectors)
        indices = np.argpartition(cos_sim[:, 0], -top_k)[-top_k:]
        result = []
        for i in range(len(indices) - 1, -1, -1):
            idx = indices[i]
            score = cos_sim[idx, 0]
            if score > theshold:
                result.append([score, idx])
        result.sort(key=lambda x: x[0], reverse=True)  # 相似度降序排序后返回


        return result

兩種召回方案對(duì)比

基于語(yǔ)義+關(guān)鍵字模型的召回

此模型結(jié)合了關(guān)鍵字搜索和語(yǔ)義搜索。通常,該模型使用詞嵌入(如Word2Vec,GloVe,BERT等)來(lái)表示文檔和查詢。

  • 優(yōu)點(diǎn)
  1. 深度語(yǔ)義理解:例如,如果你正在搜索“蘋果新產(chǎn)品發(fā)布”,這種模型可以識(shí)別出包含“iPhone最新版本上市”這樣非直接關(guān)鍵詞,但在語(yǔ)義上相關(guān)的文檔,因?yàn)?蘋果新產(chǎn)品發(fā)布"和"iPhone最新版本上市"具有相似的語(yǔ)義。
  2. 處理同義詞和多義詞:例如,“智能手機(jī)”、“移動(dòng)電話”和“手提電話”可能在不同的文檔中表示同一概念。同樣,單詞“蘋果”可以是一種水果或是科技公司名?;谡Z(yǔ)義+關(guān)鍵字模型能夠理解這些差異。
  • 缺點(diǎn)
  1. 訓(xùn)練資源需求大:需要大量數(shù)據(jù),并且計(jì)算成本高昂,特別是對(duì)于深度學(xué)習(xí)模型,如BERT或GPT。
  2. 計(jì)算復(fù)雜性高:語(yǔ)義搜索需要計(jì)算與每個(gè)可用文檔的相似性,這可能在大型數(shù)據(jù)庫(kù)中導(dǎo)致延時(shí)。

基于詞袋模型的召回

基于詞袋模型的搜索是一種常見的關(guān)鍵字搜索方法,其中文檔和查詢被表示為單詞的集合或多集,忽略了任何語(yǔ)義和語(yǔ)法結(jié)構(gòu)。

  • 優(yōu)點(diǎn)
  1. 實(shí)現(xiàn)簡(jiǎn)單:例如,如果你在搜索“蘋果新產(chǎn)品發(fā)布”,基于詞袋模型的搜索引擎將很容易找到包含這些確切短語(yǔ)的文檔。
  2. 計(jì)算效率高:只需檢查每個(gè)文檔是否包含查詢中的單詞,對(duì)于大規(guī)模數(shù)據(jù)也能妥善處理。
  • 缺點(diǎn)
  1. 不能理解語(yǔ)義:例如,“蘋果新產(chǎn)品發(fā)布”和“iPhone最新版本上市”在詞袋模型下可能被認(rèn)為是不相關(guān)的,因?yàn)樗麄儧](méi)有公共的單詞,盡管他們?cè)谡Z(yǔ)義上密切相關(guān)。
  2. 無(wú)法處理同義詞和多義詞:比如“智能手機(jī)”和“移動(dòng)電話”在詞袋模型看來(lái)是兩個(gè)完全不同的概念。同時(shí)"蘋果"這個(gè)詞的多重含義也無(wú)法區(qū)分。

選擇哪種模型取決于具體情況。如果查詢主要基于精確的關(guān)鍵字匹配,詞袋模型可能更適合;而如果語(yǔ)義理解更重要,則應(yīng)該考慮使用基于語(yǔ)義+關(guān)鍵字的模型。在實(shí)踐中,這兩種方法往往結(jié)合在一起使用,例如,先使用詞袋模型進(jìn)行粗略搜索,然后使用基于語(yǔ)義+關(guān)鍵字模型進(jìn)行精確搜索。

?

本文轉(zhuǎn)載自公眾號(hào)AI 博物院 作者:longyunfeigu

原文鏈接:??https://mp.weixin.qq.com/s/kiZ9pcJ7xac4sesoJkiSYA??


?著作權(quán)歸作者所有,如需轉(zhuǎn)載,請(qǐng)注明出處,否則將追究法律責(zé)任
標(biāo)簽
收藏
回復(fù)
舉報(bào)
回復(fù)
相關(guān)推薦