每天五分钟机器学习算法模型实战:经过文本中当前词预测下一个词
作者头像
  • 软件工程研究与实践
  • 2020-05-11 11:18:23 2

言语模型及其优化

言语模型的核心在于判断一句话出现的概率。通过数学公式,我们可以计算出这句话出现的可能性。例如,我们可以通过下面的公式来进行计算:

$$ P(w1, w2, ..., wn) = prod{i=1}^{n} P(wi | w1, w2, ..., w{i-1}) $$

目前,语言模型面临的一个重要挑战是如何更准确地预测后续词汇。一种常见的方法是使用n-gram模型,即基于词语统计的语言模型。通过统计语料库中的词频,我们可以计算出特定序列出现的概率。然而,n-gram模型存在一些局限性。

n-gram模型的局限性

局限一:无法解决长期依赖问题 n-gram模型难以处理长时间依赖关系。比如,“他需要一台电脑”中“programming”和“computer”之间虽然有联系,但距离较远,n-gram模型无法捕捉这种长距离依赖。

局限二:反义词无法共享权重 n-gram模型无法使反义词共享权重。例如,“bought”和“purchased”虽然语义相近,但n-gram模型无法将它们视为相同的概念。

局限三:中心词不能作为上下文条件 n-gram模型只能根据后续词语预测后续词语,而无法利用中心词预测上下文词语。比如,“Dr. Jane Smith”和“Dr. Gertrude Smith”在n-gram模型中被视为完全不同的概念。

解决n-gram的问题

要解决这些问题,我们可以采用特征化模型。在这种模型中,我们通过计算上下文的特征来预测概率,而不是单纯依靠统计。例如,在给定上下文“giving a”时,我们可以计算出后续词的概率,从而使得“giving a”作为一个整体发挥作用。具体来说,我们可以用向量表示“giving”和“a”,然后通过特征组合来计算后续词的概率。

使用特征化模型的优势

特征化模型通过引入特征向量来表示上下文,从而可以更好地捕捉词之间的关系。比如,“Dr. Jane Smith”和“Dr. Gertrude Smith”可以通过特征向量来表示,使得它们在模型中的得分更为接近。此外,这种方法还可以通过非线性变换来组合特征,从而更好地处理反义词共享权重的问题。

解决反义词共享权重问题

通过引入非线性变换,我们可以将上下文中的特征进行组合,从而解决反义词共享权重的问题。例如,通过将“giving”和“a”进行连接和非线性激活,我们可以生成新的特征向量,从而使得相近的词在模型中有类似的表示。

实现代码

以下是实现上述模型的基本代码框架:

```python import torch from torch import nn from collections import defaultdict import math import random

class Mynet(nn.Module): def init(self, nwords, embsize, hidsize, numhist): super(Mynet, self).init() self.embedding = nn.Embedding(nwords, embsize) self.fnn = nn.Sequential( nn.Linear(numhist * embsize, hidsize), nn.Dropout(True), nn.Linear(hidsize, nwords) )

def forward(self, x):
    emb = self.embedding(x)
    feat = emb.view(emb.size(0), -1)
    logit = self.fnn(feat)
    return logit

N = 2 # 使用两个单词预测下一个词 EMBSIZE = 128 HIDSIZE = 128 MAX_LEN = 50

w2i = defaultdict(lambda: len(w2i)) S = w2i[""] UNK = w2i[""]

def generatesent(): hist = [S] * N sent = [] while True: newhist = torch.LongTensor([hist]) logits = model(newhist) prob = nn.functional.softmax(logits) nextword = prob.multinomial(1).data[0, 0] if nextword == S or len(sent) == MAXLEN: break sent.append(nextword) hist = hist[1:] + [nextword] return sent

def read_dataset(filename): with open(filename, "r") as f: for line in f: yield [w2i[x] for x in line.strip().split(" ")]

train = list(readdataset("datalab/39811/train.txt")) w2i = defaultdict(lambda: UNK, w2i) dev = list(readdataset("datalab/39811/valid.txt")) i2w = {v: k for k, v in w2i.items()} nwords = len(w2i)

model = Mynet(nwords=nwords, embsize=EMBSIZE, hidsize=HIDSIZE, numhist=N) optimizer = torch.optim.Adam(model.parameters(), lr=0.001) criterion = nn.CrossEntropyLoss()

for epoch in range(10): random.shuffle(train) model.train() trainwords, trainloss = 0, 0.0 for sentid, sent in enumerate(train): hist = [S] * N allhistories = [] alltargets = [] for nextword in sent + [S]: allhistories.append(hist) alltargets.append(nextword) hist = hist[1:] + [nextword] allhistories = torch.LongTensor(allhistories) tag = torch.tensor(alltargets) logits = model(allhistories) loss = criterion(logits, tag) trainloss += loss.item() trainwords += len(sent) optimizer.zerograd() loss.backward() optimizer.step() print("epoch %s ,loss %.4f" % (epoch, trainloss / train_words))

model.eval()
dev_words, dev_loss = 0, 0.0
for sent_id, sent in enumerate(dev):
    hist = [S] * N
    all_histories = []
    all_targets = []
    for next_word in sent + [S]:
        all_histories.append(list(hist))
        all_targets.append(next_word)
        hist = hist[1:] + [next_word]
    all_histories = torch.LongTensor(all_histories)
    tag = torch.tensor(all_targets)
    logits = model(all_histories)
    loss = criterion(logits, tag)
    dev_loss += loss.item()
    dev_words += len(sent)
print("devepoch %s ,loss %.4f" % (epoch, dev_loss / dev_words))

for _ in range(5):
    sent = generate_sent()
    print(" ".join([i2w[x.item()] for x in sent]))

```

代码解析

在这个模型中,输入的数据格式为[[a,b],[a,b],...],其维度为[batch,2]。每个样本包含两个单词,因为n=2。经过embedding层后,维度变为[batch,2,词向量的维度]。全连接神经网络的输入层维度应为2*词向量的维度。

数据集中的每一句话都是一个样本,我们会在句子前后添加特殊符号。第一个样本是,标签是word1;最后一个样本是wordn-1,wordn的标签是。一句话的样本数是n。

在编写代码时,需要注意列表和张量之间的转换。建议先将数据处理成网络模型喜欢的格式,然后再转换为张量,这样可以获得更好的效果。

最后,通过训练好的模型生成文本。生成5句话,每句话包含100个词。具体来说,从开始输入到模型中,不断预测,将预测的结果作为新的输入继续预测,直到生成100个词的文本。为了增加随机性,我们使用prob.multinomial(1)进行采样。

    本文来源:图灵汇
责任编辑: : 软件工程研究与实践
声明:本文系图灵汇原创稿件,版权属图灵汇所有,未经授权不得转载,已经协议授权的媒体下载使用时须注明"稿件来源:图灵汇",违者将依法追究责任。
    分享
    下一篇