N-gram语言模型实战:基于ArXiv论文摘要的文本生成
2025-07-06 06:24:30作者:蔡怀权
引言
在自然语言处理领域,语言模型是理解、生成和评估文本的基础工具。本文将带您深入了解N-gram语言模型的原理与实现,并通过ArXiv论文摘要数据集构建一个能够生成"学术论文"的文本生成模型。
数据准备
我们使用的数据集包含ArXiv论文的标题和摘要。首先需要进行数据预处理:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 加载数据
data = pd.read_json("./arxivData.json")
# 组合标题和摘要
lines = data.apply(lambda row: row['title'] + ' ; ' + row['summary'].replace("\n", ' '), axis=1).tolist()
文本分词
使用WordPunctTokenizer进行分词处理:
from nltk.tokenize import WordPunctTokenizer
tokenizer = WordPunctTokenizer()
lines = [' '.join(tokenizer.tokenize(line)) for line in lines]
N-gram语言模型原理
N-gram模型基于马尔可夫假设,认为当前词的概率仅依赖于前n-1个词。其数学表达式为:
其中,n=1时为unigram模型,n=2为bigram,n=3为trigram模型。
模型实现
1. N-gram计数
首先实现计数功能,统计每个词在特定上下文后出现的频率:
from collections import defaultdict, Counter
UNK, EOS = "_UNK_", "_EOS_"
def count_ngrams(lines, n):
counts = defaultdict(Counter)
for line in lines:
tokens = line.split() + [EOS]
for i in range(len(tokens)):
prefix = tuple([UNK]*(n-1-len(tokens[:i])) + tuple(tokens[max(0,i-n+1):i])
counts[prefix][tokens[i]] += 1
return counts
2. 概率计算与模型构建
基于计数结果计算条件概率:
class NGramLanguageModel:
def __init__(self, lines, n):
self.n = n
counts = count_ngrams(lines, self.n)
self.probs = defaultdict(Counter)
for prefix, counter in counts.items():
total = sum(counter.values())
for token, count in counter.items():
self.probs[prefix][token] = count / total
文本生成
实现基于温度采样的文本生成方法:
def get_next_token(lm, prefix, temperature=1.0):
next_tokens = lm.get_possible_next_tokens(prefix)
if not next_tokens:
return EOS
tokens, probs = zip(*next_tokens.items())
probs = np.array(probs)
if temperature != 1.0:
probs = np.power(probs, 1.0/temperature)
probs /= probs.sum()
return np.random.choice(tokens, p=probs)
模型评估:困惑度
困惑度(Perplexity)是评估语言模型的重要指标:
def perplexity(lm, lines, min_logprob=np.log(10**-50.)):
logprob_total = 0
total_tokens = 0
for line in lines:
tokens = line.split() + [EOS]
for i in range(len(tokens)):
prefix = ' '.join(tokens[max(0,i-lm.n+1):i])
prob = lm.get_next_token_prob(prefix, tokens[i])
logprob = max(np.log(prob), min_logprob)
logprob_total += logprob
total_tokens += 1
return np.exp(-logprob_total / total_tokens)
实验结果
在不同n值下的困惑度对比:
- Unigram模型(n=1): 318.21
- Trigram模型(n=3): 1.52
- 10-gram模型(n=10): 1.18
结果显示,随着n的增加,模型在训练数据上的困惑度降低,但需要注意过拟合问题。
文本生成示例
prefix = "deep learning"
for i in range(100):
prefix += ' ' + get_next_token(lm, prefix, temperature=0.7)
if prefix.endswith(EOS):
break
print(prefix)
输出示例: "deep learning has become a popular approach in machine learning and artificial intelligence research . EOS"
总结
N-gram语言模型虽然简单,但在理解语言模型基本原理和评估方法方面具有重要意义。通过本教程,我们实现了:
- 完整的N-gram语言模型构建流程
- 基于温度采样的文本生成方法
- 困惑度评估指标的计算
这些技术为后续更复杂的神经网络语言模型奠定了基础。