【NLP】2.2 神经语言模型简介

非线性神经网络语言模型可以解决一些传统语言模型中的问题:增加上下文的同时参数仅呈线性增长,缓解了人工设计的需要,支持不同上下文泛化性能。

  • 输入:k元语句(代码实现熵是 k 个词向量的拼接)
  • 输出:下个词的概率分布P

我们的目标是希望神经网络发现如下的规律,于是有了网络结构图:
P ( C ( w i ) ∣ C ( w i − 4 ) , C ( w i − 3 ) , C ( w i − 2 ) , C ( w i − 1 ) ) (2.2.1) P(C(w_i)|C(w_{i-4}),C(w_{i-3}),C(w_{i-2}),C(w_{i-1}))\tag{2.2.1} P(C(wi)C(wi4),C(wi3),C(wi2),C(wi1))(2.2.1)

image-20230618191118904

图2.2.1 网络结构图

2.2.1 one-hot 表示

先用最简单的方式表示每个词,one-hot 表示为:

  • d o g = ( 0 , 0 , 0 , 0 , 1 , 0 , 0 , . . . ) dog = (0, 0, 0, 0, 1, 0, 0, ...) dog=(0,0,0,0,1,0,0,...)
  • c a t = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , . . . ) cat = (0, 0, 0, 0 ,0 ,0, 0, 0 ,1, 0, ...) cat=(0,0,0,0,0,0,0,0,1,0,...)
  • e a t = ( 0 , 1 , 0 , 0 , . . . ) eat = (0, 1, 0, 0, ...) eat=(0,1,0,0,...)

image-20230618191615505

图2.2.2 one-hot 表示

可是 one-hot 表示法有诸多缺陷,还是稠密的向量表示更好一些,那么如何转换呢?只需要加一个隐藏层映射一下就好了。映射之后的向量层如果单独拿出来看,还有办法找到原来的词是什么吗?

image-20230618191830200

图2.2.3 添加隐藏层映射

one-hot 表示法这时候就作为一个索引字典了,可以通过映射矩阵对应到具体的词向量。

image-20230618192010527

图2.2.4 映射矩阵

这样,这个神经网络的每个环节都没问题了,可以开始训练了。


独热编码:让计算机认识单词

image-20230617203749587

图2.2.5 独热编码

词典 V V V:新华词典里面把所有的词集合成一个集合 V V V

假设词典里面有 8 个单词,计算机不认识单词,但是我们要计算机认识单词。

独热编码:给出一个 8 × 8 8 \times 8 8×8 的矩阵。

  • “time”:10000000
  • “fruit”:01000000
  • ……
  • “banana”:00000001

余弦相似度 去计算两者的相似度,发现独热编码 计算得到的余弦相似度都为0,即这些单词都没有关联度(独热编码缺陷),于是就有了词向量的概念。

数学公式总结

输入向量 x x x,输出结果 y y y 的概率分布,两者的表达式如下所示,其中 w w w 代表词向量, v v v 代表词到词嵌入的映射, L M LM LM (Lamguage Model)是一个多层感知机:
100 L M ( w 1 : k ) = s o f t m a x ( h W 2 + b 2 ) x = [ v ( w 1 ) ; v ( w 2 ) ; . . . ; v ( w k ) ] h = g ( x W 1 + b 1 ) (2.2.2) \begin{align}{100} LM(w_{1:k})&=softmax(hW^2+b^2)\\ &x = [v(w_1);v(w_2);...;v(w_k)]\\ &h=g(xW^1+b^1) \end{align}\tag{2.2.2} 100LM(w1:k)=softmax(hW2+b2)x=[v(w1);v(w2);...;v(wk)]h=g(xW1+b1)(2.2.2)

  • v v v 就是映射矩阵
  • w w w 是输入的词向量
  • x x x 是将前 k 个词通过映射矩阵处理后的一个拼接
  • h h h 是隐藏层
  • W 1 W^1 W1 W 2 W^2 W2 表示两个矩阵

2.3.2 神经网络语言模型(NNLM)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c3aGJCNx-1687508673257)(https://bucket-zly.oss-cn-beijing.aliyuncs.com/img/Typora/202306181936991.png)]

图2.2.5 NNLM_1

image-20230617204634468

图2.2.6 NNLM_2

假设有4个单词: w 1 , w 2 , w 3 , w 4 w_1,w_2,w_3,w_4 w1,w2,w3,w4(4个单词的独热编码)。

  1. w 1 × Q = c 1 ,    w 2 × Q = c 2 ,    w 3 × Q = c 3 ,    w 4 × Q = c 4 w_1 \times Q = c_1,\space \space w_2 \times Q = c_2,\space\space w_3 \times Q = c_3,\space\space w_4 \times Q = c_4 w1×Q=c1,  w2×Q=c2,  w3×Q=c3,  w4×Q=c4
    • Q Q Q 就是一个随机矩阵(可学习),是一个参数
  2. C = [ c 1 , c 2 , c 3 , c 4 ] C = [c_1,c_2,c_3,c_4] C=[c1,c2,c3,c4]
  3. s o f t m a x ( U [ t a n h ( W C + b 1 ) ] + b 2 ) = = [ 0.1 ,   0.2 ,   0.5 ,   0.2 ] ∈ [ 1 , V L ] softmax(U[tanh(WC+b_1)]+b_2) == [ 0.1,\space0.2,\space0.5,\space0.2 ]\in[1,V_L] softmax(U[tanh(WC+b1)]+b2)==[0.1, 0.2, 0.5, 0.2][1,VL]。最后生成一个一维矩阵,其中矩阵的长度为词典的长度 V L V_L VL

2.3.3 词向量(神经网络语言模型的副产品 Q Q Q

给我任何一个词(“判断”),会给出相应的独热编码 [ 0 , 0 , 1 , 0 , . . . , 0 ] [0,0,1,0,...,0] [0,0,1,0,...,0]

  • W 1 × Q = c 1 W_1 \times Q = c_1 W1×Q=c1 c 1 c_1 c1 就是 “判断” 这个词的词向量。

词向量:就是用一个向量来表示一个单词。独热编码也属于词向量,只是独热编码存储空间太大,且两者的余弦相似度都为0。

经过 Q Q Q 处理,可以控制词向量的维度(大小),也解决了相似度的问题。

通过神经网络语言模型,找到一个合适的 Q Q Q 矩阵,得到一个合适的词向量,这个词向量能够更加准确的表示这个词

2.3.4 案例实现

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from tqdm import tqdm
from torch.autograd import Variable

dtype = torch.FloatTensor

sentences = ["i like dog", "i love coffee", "i hate milk", "i do nlp"]

word_list = ' '.join(sentences).split()
word_list = list(set(word_list))

word_dict = {w: i for i, w in enumerate(word_list)}
number_dict = {i: w for i, w in enumerate(word_list)}
# print(word_dict)

n_class = len(word_dict)

m = 2
n_step = 2
n_hidden = 2


def make_batch(sentence):
    input_batch = []
    target_batch = []

    for sen in sentence:
        word = sen.split()
        input = [word_dict[n] for n in word[:-1]]
        target = word_dict[word[-1]]

        input_batch.append(input)
        target_batch.append(target)

    return input_batch, target_batch


class NNLM(nn.Module):
    def __init__(self):
        super(NNLM, self).__init__()
        self.embed = nn.Embedding(n_class, m)
        self.W = nn.Parameter(torch.randn(n_step * m, n_hidden).type(dtype))
        self.d = nn.Parameter(torch.randn(n_hidden).type(dtype))
        self.U = nn.Parameter(torch.randn(n_hidden, n_class).type(dtype))
        self.b = nn.Parameter(torch.randn(n_class).type(dtype))

    def forward(self, x):
        x = self.embed(x)  # 4 x 2 x 2
        x = x.view(-1, n_step * m)
        tanh = torch.tanh(self.d + torch.mm(x, self.W))  # 4 x 2
        output = self.b + torch.mm(tanh, self.U)
        return output


model = NNLM()

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

input_batch, target_batch = make_batch(sentences)
input_batch = Variable(torch.LongTensor(input_batch))
target_batch = Variable(torch.LongTensor(target_batch))

for epoch in range(5000):
    optimizer.zero_grad()

    output = model(input_batch)  # input: 4 x 2

    loss = criterion(output, target_batch)

    if (epoch + 1) % 1000 == 0:
        print('epoch:', '%04d' % (epoch + 1), 'cost = {:.6f}'.format(loss.item()))

    loss.backward()
    optimizer.step()

predict = model(input_batch).data.max(1, keepdim=True)[1]

print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])

image-20230623162348564

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值