言語モデルとRNN#

言語モデル#

embeddingを直接推定するのではなく、単語予測モデル(言語モデル)を構築して副次的にembeddingを取得することになる。

言語モデルとは、尤もらしい文章を生成できるような確率分布を習得するために、文章の確率を推定するモデルのこと。

ある文章Sをトークン化したのを(w1,w2,,wn)と表記するならば、

P(S)=P(w1,w2,,wn)

を求めたいということになる。これは条件付き確率の積として表せる

P(w1,w2,,wn)=P(w1)×P(w2|w1)×P(w3|w1,w2)×=i=1np(wi|ci)

ここでciwiより前のトークン列ci=(w1,w2,,wi1)で、文脈(context)と呼ばれる

Note

同時確率の分解

これは確率の乗法定理

P(A,B)=P(A|B)P(B)

に基づく。

wmまでの単語をCmとすると、

P(w1,,wm1Cm,wm)=P(Cm,wm)=P(wm|Cm)P(Cm)

さらに

P(Cm)=P(w1,,wm2Cm1,wm1)=P(Cm1,wm1)=P(wm1|Cm1)P(Cm1)

となる。これを繰り返すことで上記のようになる

#

言語モデルは文脈をもとに次の単語を予測する。例えば

Alice is reading a book in the room. Bob comes into the room and says hi to ?

の?に入る語を予測する

語順の問題#

Word2Vecに使われたcontinuous bag-of words (CBOW) のようなFeed-Forward Networkによる言語モデルでは、コンテキストの語順が考慮されない

RNN型ニューラル言語モデル(Mikolov + 2010)#

Mikolov et al. (2010). Recurrent neural network based language model.

RNN#

RNNは前のトークンまでの情報を次のトークンの出力に渡すパスが存在する。 トークンの系列を時系列モデルになぞらえて時刻と表現すると、時刻tの出力ht

ht=tanh(Whht1+Wxxt+b)

となる。ここでxtは入力で、ht1は1時刻前の出力、Wh,Wxは重みでbはバイアスである。

なお、出力h隠れ状態(hidden state)と呼ばれる事が多い

Note

双曲線正接(hyperbolic tangent: tanh)関数

RNNの場合、活性化関数にはtanh

tanh(x)=exexex+ex

を用いることが多い。tanhはシグモイド関数と形状が似ているが、値域は[1,1]と負の値を許しており、また二次微分の減衰がゆっくりとゼロになるため勾配消失が起きにくいという特性がある。

../_images/e060270a8b3cf8c8ec7a8758acb1f93c11846eaef88a1be0590ffb4cb1b36e0f.png

Fig. 1 tanh#

Truncated BPTT#

RNNの誤差逆伝播法は、時間方向への逆伝播法ということで**Backproagation Through Time(BPTT)**と呼ばれる。

しかし長い文章を扱う場合、すべてのトークンを使うと学習の際にメモリに乗り切らない問題や勾配が不安定になる問題がある。 そこで、逆伝播のときはトークン系列を分割して学習する(順伝播は全部つながるようにする)方法があり、これをTruncated BPTTという。

実装(PyTorch)#

ht=tanh(xtWihT+bih+ht1WhhT+bhh)
# 最小構成
import torch
from torch import nn

n_input = 1
n_hidden = 3
n_layer = 2
rnn = nn.RNN(n_input, n_hidden, n_layer)
x = torch.randn(5, 3, n_input)
h0 = torch.randn(2, 3, n_hidden)
output, hn = rnn(x, h0)
output
tensor([[[-0.0956,  0.7556,  0.2647],
         [ 0.6726,  0.8317,  0.4178],
         [ 0.4741,  0.9216,  0.1252]],

        [[ 0.3828,  0.4455, -0.3218],
         [ 0.2163,  0.0460, -0.0722],
         [ 0.3572, -0.0518, -0.2956]],

        [[ 0.1789,  0.4907, -0.3043],
         [ 0.2007,  0.6032, -0.1169],
         [ 0.3426,  0.4081,  0.0931]],

        [[ 0.4931,  0.1603, -0.1789],
         [ 0.4142,  0.2977, -0.2849],
         [ 0.3716,  0.2138, -0.0071]],

        [[ 0.1988,  0.4615, -0.0127],
         [ 0.4006,  0.1468,  0.0130],
         [ 0.3719,  0.2014,  0.1247]]], grad_fn=<StackBackward0>)

実装(Python)#

参考:ゼロから作るDeep Learning 2

import numpy as np
h = 2
w = 3
Wh = np.random.normal(size = (h, w))
import numpy as np

class RNN:
    def __init__(self, Wx, Wh, b):
        self.params = [Wx, Wh, b]
        self.grads = [np.zeros_like(Wx),
                      np.zeros_like(Wh),
                      np.zeros_like(b)]
        self.chache = None

    def forward(self, x, h_prev):
        Wx, Wh, b = self.params
        t = Wh @ h_prev + Wx @ x + b
        h_nrex = np.tanh(t)
        self.cache = (x, h_prev, h_next)
        return h_next

    def backword(self, dh_next):
        Wx, Wh, b = self.params
        x, h_prev, h_next = self.cache
        dt = dh_next * (1 - h_next ** 2)
        db = np.sum(dt, axis=0)
        dWh = h_prev.T @ dt
        dh_prev = Wh @ dt
        dWx = x @ dt
        dx = Wx @ dt
        self.grads[0][...] = dWx
        self.grads[1][...] = dWh
        self.grads[2][...] = db
        return dx, dh_prev

RWKV#

RNNを利用しつつも並列計算を可能とした

RWKVを論文と実装から読み解く

従来の大規模言語モデルの制約だった「入力量の限界」を取り払った「RWKV」は一体どんな言語モデルなのか? - GIGAZINE