n-gram语言模型——文本生成源码

n-gram语言模型------文本生成源码

在自然语言处理的领域中,n-gram语言模型是一种基础而强大的工具。它通过考虑词汇的序列来预测文本内容,从而有效地用于文本生成任务。这篇博客中将探讨如何利用n-gram模型,特别是在处理中文文本时,使用jieba进行分词和nltk库进行模型构建。

我在上一篇博客里讲解了n-gram的原理,参考:n-gram语言模型------句子概率分布计算与平滑

n-gram模型的基本原理

n-gram模型基于一个简单的假设:一个词的出现只与它前面的有限个词相关。这种模型可以分为不同的类型,如bigrams(二元模型)和trigrams(三元模型),取决于我们考虑前面多少个词。

bigram为例,可以近似认为一个词的出现概率仅依赖于它前面的一个词:

为了让 p ( w i ∣ w i − 1 ) p(w_i | w_{i-1}) p(wi∣wi−1)在i为1时有意义,我们通常会在句子开头添加一个开始标记(BOS),并在句子结尾添加一个结束标记(EOS),以此包含在概率计算中。例如,要计算Mark wrote a book的概率,我们会这样计算:

p ( Mark wrote a book ) = p ( Mark ∣ BOS ) ⋅ p ( wrote ∣ Mark ) ⋅ p ( a ∣ wrote ) ⋅ p ( book ∣ a ) ⋅ p ( EOS ∣ book ) p(\text{Mark wrote a book}) = p(\text{Mark} | \text{BOS}) \cdot p(\text{wrote} | \text{Mark}) \cdot p(\text{a} | \text{wrote}) \cdot p(\text{book} | \text{a}) \cdot p(\text{EOS} | \text{book}) p(Mark wrote a book)=p(Mark∣BOS)⋅p(wrote∣Mark)⋅p(a∣wrote)⋅p(book∣a)⋅p(EOS∣book)

为了估计 p ( w i ∣ w i − 1 ) p(w_i | w_{i-1}) p(wi∣wi−1),可以简单地计算在某一文本中单词w的频率,然后对其进行归一化。若用c表示在给定文本中的出现次数,我们可以使用如下公式:

p ( w i ∣ w i − 1 ) = c ( w i − 1 , w i ) ∑ w c ( w i − 1 , w ) p(w_i | w_{i-1}) = \frac{c(w_{i-1}, w_i)}{\sum_{w} c(w_{i-1}, w)} p(wi∣wi−1)=∑wc(wi−1,w)c(wi−1,wi)

上述公式即为最大似然估计(Maximum Likelihood Estimation, MLE)。对于更高阶的n-gram模型,这一公式同样适用。

文本生成的步骤

1. 准备和分词

使用jieba对中文文本进行分词,这是处理中文n-gram模型的第一步。分词后的结果用来构建n-gram模型。

2. 构建n-gram模型

利用nltk的ngrams函数,从分词结果中创建bigrams序列。然后使用这些bigrams来构建一个条件频率分布对象,用于后续的文本生成。

3. 平滑技术的应用

在n-gram模型中,为了处理那些在训练数据中未出现的词组合,需要采用平滑技术。Lidstone平滑和Laplace平滑是两种常见的方法。这些方法通过添加一个小的非零值到词组合的计数中,避免了零概率问题,使模型更加健壮。

Lidstone平滑和Laplace平滑参考之前的博客 n-gram语言模型------句子概率分布计算与平滑

4. 生成文本

文本生成的过程是从一个初始词开始,根据条件频率分布连续生成下一个词。这个过程重复进行,直到达到所需的词数或遇到停止条件。

源码

下面是使用Laplace平滑的n-gram模型来成文本的示例:

python 复制代码
import nltk
from nltk.probability import LidstoneProbDist, LaplaceProbDist
from nltk.corpus import brown
from nltk import FreqDist, ConditionalFreqDist
import random
import jieba

# 示例文本 读取ylk.txt
text = open("ylk.txt", encoding="utf-8").read()
# jieba分词
tokens = jieba.cut(text)
# 生成bigrams
bi_grams = list(nltk.ngrams(tokens, 2))
# 创建条件频率分布对象
cfd = ConditionalFreqDist(bi_grams)

# # 使用Lidstone平滑
# # gamma值小于1的Lidstone平滑
lidstone_cfd = {condition: LidstoneProbDist(cfd[condition], gamma=0.1) for condition in cfd.conditions()}

# 使用Laplace平滑
# Laplace平滑是gamma=1的特殊情况
laplace_cfd = {condition: LaplaceProbDist(cfd[condition]) for condition in cfd.conditions()}

def generate_text(initial_word, cfd, num_words=50):
    current_word = initial_word
    generated_text = [current_word]

    for _ in range(num_words - 1):
        if current_word not in cfd:
            break
        next_word = random.choices(
            population=list(cfd[current_word].samples()),
            weights=[cfd[current_word].prob(w) for w in cfd[current_word].samples()]
        )[0]
        generated_text.append(next_word)
        current_word = next_word

    return ''.join(generated_text)

# 示例:从"哈哈"开始生成文本
print(generate_text("方锐", laplace_cfd, 100))
print(generate_text("方锐", lidstone_cfd, 100))

代码里我下了4M多的网络小说作为语料库。然后根据主角的名字开始生成,结果如下:

感觉lidstone效果更好一点。

通过使用n-gram模型结合平滑技术,能够有效地生成符合语言规律的文本。这种方法虽然简单,但在许多应用场景下仍然非常有效,特别是在资源有限的情况下。

随着深度学习技术的发展,出现了更复杂的语言模型,n-gram模型感觉在文本生成领域已经不行了~

相关推荐
小于小于大橙子3 小时前
视觉SLAM数学基础
人工智能·数码相机·自动化·自动驾驶·几何学
封步宇AIGC5 小时前
量化交易系统开发-实时行情自动化交易-3.4.2.Okex行情交易数据
人工智能·python·机器学习·数据挖掘
封步宇AIGC5 小时前
量化交易系统开发-实时行情自动化交易-2.技术栈
人工智能·python·机器学习·数据挖掘
陌上阳光5 小时前
动手学深度学习68 Transformer
人工智能·深度学习·transformer
OpenI启智社区5 小时前
共筑开源技术新篇章 | 2024 CCF中国开源大会盛大开幕
人工智能·开源·ccf中国开源大会·大湾区
AI服务老曹5 小时前
建立更及时、更有效的安全生产优化提升策略的智慧油站开源了
大数据·人工智能·物联网·开源·音视频
YRr YRr5 小时前
PyTorch:torchvision中的dataset的使用
人工智能
love_and_hope5 小时前
Pytorch学习--神经网络--完整的模型训练套路
人工智能·pytorch·python·深度学习·神经网络·学习
思通数据6 小时前
AI与OCR:数字档案馆图像扫描与文字识别技术实现与项目案例
大数据·人工智能·目标检测·计算机视觉·自然语言处理·数据挖掘·ocr
兔老大的胡萝卜6 小时前
关于 3D Engine Design for Virtual Globes(三维数字地球引擎设计)
人工智能·3d