一、數(shù)學(xué)模型
1懦傍、由來
語言模型起初是為了計算句子的合理性有鹿。在我們看來一句話是否合理主要還是判斷其是否合乎語法,表達(dá)清晰谎脯,通俗的來講就是:說的是不是人話。人為地判斷雖然具有可行性持寄,但是對于計算機來說源梭,這無疑是對牛彈琴!于是自然語言處理界殿堂級締造者賈里尼克提出使用概率來判斷句子合理性稍味,即:一個句子是否合理废麻,看該句子的可能性大小如何,那么問題就轉(zhuǎn)變?yōu)榱艘粋€數(shù)學(xué)問題模庐。
比如判斷句子""是否合理烛愧,即是計算
的大小
進(jìn)行詞粒度的拆分:
根據(jù)聯(lián)合概率鏈規(guī)則
那么
以上計算過程的核心就是假設(shè)一個詞出現(xiàn)的概率和前面n個詞出現(xiàn)的概率相關(guān),通過該假設(shè),可以通過計算句子中詞的聯(lián)合概率來得出句子的可能性怜姿,但是同時也帶來一個問題:當(dāng)一句話比較長時慎冤,的計算量無法估量,天國的大門好像在最后一秒被封上了沧卢,不過古人云車到山前必有路蚁堤,地球人從無畏懼困難,只恐無法找到問題但狭,這就是常說的提出問題有時候比解決問題更重要披诗。問題有了,就出現(xiàn)如下解決方案:N-Gram(假設(shè)第n個詞的出現(xiàn)只與前面n-1個詞相關(guān)立磁,而與其它任何詞都不相關(guān))呈队,下面說其中主要的三種情況。
2唱歧、unigram
unigram在計算的過程中直接做了一種假設(shè):組成句子的詞之間相互獨立宪摧,即第n個詞的出現(xiàn)只與前面0個詞相關(guān),而與其它任何詞都不相關(guān)迈喉,那么
的聯(lián)合概率為:
那么
這樣計算量直接降到了最低绍刮,不過簡單粗暴的方式效果不一定很好,僅僅考慮詞之間的獨立性挨摸,就無法顧及到整句話的上下文孩革,勢必造成句子的合理性較差。
3得运、bigram
bigram在計算的過程中做了一種假設(shè):第n個詞的出現(xiàn)只與前面1個詞相關(guān)膝蜈,而與其它任何詞都不相關(guān),那么
的聯(lián)合概率為:
那么
該種計算方式計算量不是很復(fù)雜熔掺,且考慮到了上文的相關(guān)性饱搏,屬于目前比較常用的方式之一。
4置逻、trigram
trigram在計算的過程中做了一種假設(shè):第n個詞的出現(xiàn)只與前面2個詞相關(guān)推沸,而與其它任何詞都不相關(guān),具體處理方式和上面類似券坞。
到此可以發(fā)現(xiàn)鬓催,n-gram其實就是單純考慮了句子的上文信息,使用上文的多少個詞恨锚,看具體情況而定宇驾。
5、概率計算
上面說了那么多的的之類的概率课舍,那么如何計算這些概率呢塌西,下面舉一個小例子:
假設(shè)有語料庫:
- 我 喜歡 大自然
- 自然語言 是 如何 形成 的 呢
- 如何 處理 數(shù)據(jù) 是 很 重要 的
- 越來越多 的 人 喜歡 自然語言 處理
語料庫中共有16個單詞,分別是
[我,喜歡,大自然,自然語言,是,如何,形成,的,呢,處理,數(shù)據(jù),是,很,重要,越來越多,人]
這些詞在語料庫中一共出現(xiàn)過22次筝尾,那么
單個詞的很容易計算捡需,那么bigram的呢,以為例忿等,喜歡在語料庫中一共出現(xiàn)了兩次栖忠,其中有一次在喜歡的后面出現(xiàn)自然語言,那么
贸街,其他的以此類推...
總結(jié)一下就是:
二、文本生成案例
本案例中使用bigram的假設(shè)薛匪,需要生成的第n個詞只與前面一個詞有關(guān)捐川,那么每次生成的詞只需要通過前面一個的詞的先驗來確定。
- 導(dǎo)入需要的包
from collections import Counter
from jieba import lcut
from random import choice
- 定義語料
借用一下方文山寫的歌詞
corpus = '''
這一生原本一個人逸尖,你堅持廝守成我們古沥,卻小小聲牽著手在默認(rèn)。
感動的眼神說愿意娇跟,走進(jìn)我的人生岩齿。
進(jìn)了門開了燈一家人,盼來生依然是一家人苞俘。
確認(rèn)過眼神盹沈,我遇上對的人。
我揮劍轉(zhuǎn)身吃谣,而鮮血如紅唇乞封。
前朝記憶渡紅塵,傷人的不是刀刃岗憋,是你轉(zhuǎn)世而來的魂肃晚。
青石板上的月光照進(jìn)這山城,我一路的跟你輪回聲仔戈,我對你用情極深关串。
誰在用琵琶彈奏一曲東風(fēng)破,楓葉將故事染色监徘,結(jié)局我看透晋修。
籬笆外的古道我牽著你走過,荒煙漫草的年頭耐量,就連分手都很沉默。
'''
- bigram模型訓(xùn)練
def get_model(corpus):
'''
:param corpus:
:return: { '我': Counter({'的': 2, '看透': 1}), '人生': Counter({'滤港。': 1})}
# 我 后面 的 出現(xiàn)2次 看透 出現(xiàn)1次
'''
# 將語料按照\n切分為句子
corpus = corpus.strip().split('\n')
# 將句子切分為詞序列
corpus = [lcut(line) for line in corpus]
# 提取所有單詞
words = [word for words in corpus for word in words]
# 構(gòu)造一個存儲每個詞統(tǒng)計的字典{'你',count(),'我':count()}
bigram = {w: Counter() for w in words}
# 根據(jù)語料庫進(jìn)行統(tǒng)計信息填充
for sentence in corpus:
for i in range(len(sentence) - 1):
bigram[sentence[i]][sentence[i + 1]] += 1
return bigram
- 生成函數(shù)
ef generate_text(bigram,first_word, free=4):
'''
按照語言模型生成文本
:param first_word: 提示詞
:param free: 控制范圍 如果強制按照每個詞后面最有可能出現(xiàn)的詞進(jìn)行生成廊蜒,設(shè)置為1趴拧,需要一些靈活性,可以放寬一些
:return:
'''
# 如果第一個詞不在詞典中 隨機選一個
if first_word not in bigram.keys():
first_word = choice(bigram.keys())
text = first_word
# 將候選詞按照出現(xiàn)概率進(jìn)行降序排列
next_words = sorted(bigram[first_word], key=lambda w: bigram[first_word][w],reverse=True)
while True:
if not next_words:
break
# 候選詞前free個中隨機選一個
next_word = choice(next_words[:free])
text += next_word
if text.endswith('山叮。') :
print('生成文本:', text)
break
next_words = sorted(bigram[next_word], key=lambda w: bigram[next_word][w],reverse=True)
- 測試
bigram = get_model(corpus)
first_words = ['你','我們','確認(rèn)']
for word in first_words:
generate_text(bigram,word,free=4)
測試效果如下
生成文本: 你用琵琶彈奏一曲東風(fēng)破著榴,盼來生依然是一家人。
生成文本: 我們屁倔,卻小小聲牽著手在用琵琶彈奏一曲東風(fēng)破脑又,走進(jìn)我一路的不是刀刃,你輪回聲锐借,走進(jìn)我一路的人问麸。
生成文本: 確認(rèn)過眼神,你輪回聲钞翔,盼來生依然是你用情極深严卖。
看到最后一句:盼來生依然是你用情極深。我懷疑我電腦是不是戀愛了(⊙o⊙)…