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模型感觉在文本生成领域已经不行了~

相关推荐
数据分析能量站41 分钟前
神经网络-ResNet
人工智能·深度学习·神经网络
1021123456789043 分钟前
怎么把多个PDF合并到一起-免费实用PDF编辑处理工具分享
人工智能·科技·adobe·pdf·wps·格式工厂·福昕阅读器
数据分析能量站44 分钟前
神经网络-DenseNet
人工智能·深度学习·神经网络
伊克罗德信息科技1 小时前
亚马逊云科技 | Amazon Nova:智能技术新势力
人工智能
界面开发小八哥1 小时前
报表工具DevExpress Reporting v24.2亮点 - AI功能进一步强化
人工智能·.net·报表·界面控件·devexpress·ui开发
EterNity_TiMe_1 小时前
【论文复现】农作物病害分类(Web端实现)
前端·人工智能·python·机器学习·分类·数据挖掘
深蓝海拓1 小时前
使用sam进行零样本、零学习的分割实践
人工智能·深度学习·学习·目标检测·计算机视觉
香橙薄荷心1 小时前
学一学前沿开发语言之Python
人工智能·python
人类群星闪耀时1 小时前
利用AI进行系统性能优化:智能运维的新时代
运维·人工智能·性能优化
AZDNA2 小时前
搭建医疗行业AI知识库:提升信息管理与服务效能
大数据·人工智能