再談大模型長(zhǎng)文本分塊,以及分塊在RAG中的作用? 原創(chuàng)
“ 向量數(shù)據(jù)庫(kù)的檢索原理,就是存儲(chǔ)不同數(shù)據(jù)之間的向量關(guān)系,在檢索時(shí)通過(guò)向量關(guān)系查詢(xún)相關(guān)數(shù)據(jù) ”
文本分塊也就是chunk技術(shù)是大模型領(lǐng)域中非常重要的一項(xiàng)技術(shù),原因就在于大模型眾所周知的問(wèn)題,上下文窗口限制;雖然說(shuō)現(xiàn)在大模型的窗口經(jīng)過(guò)幾次擴(kuò)容之后已經(jīng)達(dá)到了一個(gè)非常可觀的長(zhǎng)度,但依然還存在很多問(wèn)題。
比如說(shuō),長(zhǎng)文本導(dǎo)致的模型幻覺(jué)問(wèn)題;中間丟失現(xiàn)象等多種性能問(wèn)題;而且,在RAG技術(shù)中,長(zhǎng)文本也是一個(gè)亟待解決的問(wèn)題。
而現(xiàn)在業(yè)內(nèi)普遍的處理方式就是文本分塊,把一段長(zhǎng)文本根據(jù)某種方式拆分成多種小的文本塊;這樣就有助于大模型進(jìn)行處理,也能間接降低大模型的幻覺(jué)等問(wèn)題。
文本分塊
在大模型上下文窗口中文本分塊就比較好理解,這就類(lèi)似于我們平??匆槐竞芎竦臅?shū);我們無(wú)法做到一次就給全部看完,因此常見(jiàn)的做法就是今天看一點(diǎn),明天看一點(diǎn),然后一段時(shí)間之后就看完了。
而我們?cè)诳磿?shū)的過(guò)程中,比如昨天看了一部分停了下來(lái);今天接著看,但可能我們一時(shí)想不起來(lái)昨天看到哪里了;因此就會(huì)找到昨天看的大概位置再往前一點(diǎn),這樣有助于我們回憶昨天看的內(nèi)容;也有助于上下文的連貫性。
而大模型長(zhǎng)文本處理有一種方式也是采用類(lèi)似的方式,那就是把文本按照chunk_size進(jìn)行分塊;然后使用chunk_overlap重疊一部分內(nèi)容。而chunk_overlap重疊的部分就相當(dāng)于我們看書(shū)時(shí)往前看的一部分,這樣有助于上下文的連貫性,特別是對(duì)大模型這種沒(méi)有記憶能力的系統(tǒng)來(lái)說(shuō)。
而在代碼方面具體的表現(xiàn)就如下所示,加載文檔之后使用分詞工具根據(jù)不同的長(zhǎng)度進(jìn)行分詞,分詞的長(zhǎng)度和重疊部分就是由chunk_size和chunk_overlap來(lái)指定,之后再轉(zhuǎn)化為向量。
"""
加載文檔
"""
def load_documents(directory=dir_path):
loader = DirectoryLoader(directory)
documents = loader.load()
# for document in documents:
# print(document)
# 文檔分割
text_spliter = CharacterTextSplitter(chunk_size=256, chunk_overlap=10)
spliter_docs = text_spliter.split_documents(documents)
return spliter_docs
當(dāng)然,在一些沒(méi)有語(yǔ)義相關(guān)的上下文中,也可以不使用chunk_overlap參數(shù);只根據(jù)chunk_size或其它方式進(jìn)行分塊。比如說(shuō),今天工作日我在上班;今天天氣不錯(cuò);這兩句話從語(yǔ)義上來(lái)說(shuō)沒(méi)有任何相關(guān)性,因此可以進(jìn)行完全分塊。
雖然說(shuō)文本分塊是大模型技術(shù)中很常見(jiàn)的一種處理方式,但現(xiàn)在有一個(gè)疑問(wèn)就是;在大模型上下文窗口中這樣的使用方式很容易理解;但在RAG中就存在一個(gè)問(wèn)題。
RAG中一般使用向量數(shù)據(jù)庫(kù)作為數(shù)據(jù)的存儲(chǔ)方式,原因就在于向量數(shù)據(jù)庫(kù)能很好的保證文本之間的語(yǔ)義關(guān)系(也有圖像關(guān)系,混合關(guān)系等多種情況)。
但長(zhǎng)文本被分塊之后,在向量數(shù)據(jù)庫(kù)中的表現(xiàn)形式也是一條一條的記錄;如果說(shuō)一條語(yǔ)義相關(guān)的長(zhǎng)文本被拆分成多個(gè)小塊,然后存儲(chǔ)在向量數(shù)據(jù)庫(kù)的不同位置。
這時(shí)在進(jìn)行向量檢索時(shí),向量數(shù)據(jù)庫(kù)是怎么保證檢索內(nèi)容的相關(guān)性的?
難道是因?yàn)榫哂姓Z(yǔ)義相關(guān)的內(nèi)容被保存在相近距離的向量空間中?比如歐氏距離就是通過(guò)計(jì)算不同向量之間的距離來(lái)表示其相關(guān)性。
但如果面對(duì)著百億級(jí)以上的向量存儲(chǔ)需求,向量數(shù)據(jù)庫(kù)怎么保證快速且準(zhǔn)確高效的檢索到相關(guān)數(shù)據(jù)?
個(gè)人猜測(cè),長(zhǎng)文本被拆分之后,為了保證語(yǔ)義相關(guān)性,因此采用了chun_overlap的方式來(lái)讓拆分的文本有重疊的內(nèi)容;根據(jù)這些重疊的內(nèi)容,在進(jìn)行向量計(jì)算的時(shí)候會(huì)把這相關(guān)的數(shù)據(jù)放到一塊;或者能夠通過(guò)一種方式進(jìn)行快速檢索。
如下圖所示,文本被拆分之后,因?yàn)橛衏hunk_overlap參數(shù)關(guān)聯(lián)文本的語(yǔ)義關(guān)系;那么,在向量數(shù)據(jù)庫(kù)中就會(huì)把語(yǔ)義相關(guān)的內(nèi)容記錄到更近的位置;這樣在檢索的時(shí)候,就可以根據(jù)向量之間的關(guān)系獲取相關(guān)的數(shù)據(jù)。
這就類(lèi)似于傳統(tǒng)SQL語(yǔ)句的like功能,可以根據(jù)某個(gè)字段或語(yǔ)句查詢(xún)到多條記錄;然后再?gòu)倪@多條記錄中篩選出語(yǔ)義相關(guān)性最高的數(shù)據(jù)。
但這同樣有新的問(wèn)題,那就是chunk_overlap只是文檔拆分的一種方式;還有很多其它的方式可以拆分;那么這就說(shuō)明一件事,chunk_overlap只是一種表象,核心在于怎么保證上下文語(yǔ)義的相關(guān)性;如果不使用chunk_overlap的方式,或者不使用歐式距離的計(jì)算方式, 那么怎么才能保證文本上下文的相關(guān)性呢?
而且,我們都知道大模型是經(jīng)過(guò)訓(xùn)練和微調(diào)的方式,通過(guò)不斷調(diào)整神經(jīng)網(wǎng)絡(luò)的參數(shù)值來(lái)“學(xué)習(xí)”不同文本(多模態(tài))數(shù)據(jù)之間的關(guān)系,那這個(gè)學(xué)習(xí)的過(guò)程是不是就是在不斷的計(jì)算向量之間的關(guān)系?
原文鏈接:??https://mp.weixin.qq.com/s/VL10Snh_jqbtGLR38vOXMQ??
