はじめに
『ゼロから作るDeep Learning 2――自然言語処理編』の初学者向け【実装】攻略ノートです。『ゼロつく2』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。
本の内容を1つずつ確認しながらゆっくりと組んでいきます。
この記事は、3.1節「推論ベースの手法とニューラルネットワーク」と3.2節「シンプルなword2vec」の内容です。CBOWモデルの順伝播を数式とPythonによるプログラムから説明します。
【前節の内容】
【他の節の内容】
【この節の内容】
3.1 推論ベースの手法とニューラルネットワーク
3.1.3 ニューラルネットワークにおける単語の処理方法
・数式による確認
前節と同じく「You say goodbye and I say hello.」の(ピリオドも含めて)7種類の単語のテキストを扱います。
コンテキストを$\mathbf{c}$、重みを$\mathbf{W}$とし、それぞれ次の形状とします。イメージしやすいように、ここでは添字を対応する単語で表すことにします。ただし「.(ピリオド)」については「priod」とします。
コンテキストの要素数(列数)と重みの行数が、単語の種類数に対応します。また通常通り1から単語の種類数までの通し番号を振る場合は、その値が単語IDに対応します。
コンテキスト(単語)はone-hot表現として扱うため、例えば「you」の場合は
とすることで、単語「you」を表現できます。
重み付き和$\mathbf{h}$は、行列の積で求められます。
この例では$1 \times 7$のベクトルと$7 \times 3$の行列の積なので、計算結果は$1 \times 3$のベクトルになります。
$\mathbf{h}$の1つ目の要素$h_1$の計算を詳しく見ると、次のようになります。
コンテキストと重みの対応する(同じ単語に関する)要素を掛けて、全ての単語で和をとります。しかしコンテキストは、$c_{\mathrm{you}}$以外の要素が0なので、対応する重みの値の影響は消えていまします。また$c_{\mathrm{you}}$は1なので、対応する重みの値$w_{\mathrm{you},1}$がそのまま中間層の1つ目のニューロンに伝播します。
残りの2つの要素も同様に計算できるので、重み付き和
は、単語「you」に関する重みの値となります。
・処理の確認
同じことをNumPyを利用して計算してみましょう。
# NumPyをインポート import numpy as np
# 適当にコンテキスト(one-hot表現)を指定 c = np.array([[1, 0, 0, 0, 0, 0, 0]]) print(c.shape) # 重みをランダムに生成 W = np.random.randn(7, 3) print(W) # 重み付き和を計算 h = np.dot(c, W) print(h) print(h.shape)
(1, 7)
[[-0.23410731 0.57169613 -1.44781677]
[-0.25681735 -1.53057848 0.28307254]
[-2.31677149 0.74954506 0.89999068]
[-0.6369265 1.55604891 0.64176568]
[-0.06926048 -1.16149746 -1.18108853]
[ 0.94972752 -0.17358602 -0.6618748 ]
[-1.15640384 -0.20816114 -0.46683889]]
[[-0.23410731 0.57169613 -1.44781677]]
(1, 3)
重みW
の0行目の値がそのままh
の値になっていますね。
以上がword2vecの基本となる処理です。次節では、word2vecの全体像を考えます。
3.2 シンプルなword2vec
3.2.1 CBOWモデルの推論処理
・数式による確認
前節と同じ7種類の単語によって構成されたテキストを扱って、CBOWモデルの計算を説明します。
前項と同様に、コンテキストを
とします。単語の種類数個の要素を持つベクトルになります。またウインドウサイズの値に応じて、入力層の数が変わります。この例ではウインドウサイズが1の場合を考えます。
コンテキストは、one-hot表現で単語を表します。例えば「you」と「goodbye」だと、それぞれ
となります。分かりやすいように下付き添字を対応する単語としておきます。この2つのベクトルが、ターゲットを「say」とした場合のコンテキストになります。
入力層の重みを
とします。これも前項の重みと同じものです。ただし出力層の重みと区別するため、添字に$\mathrm{in}$と表記することにします。
入力層を全結合層とすると、「you」に関する入力層の出力は前項と同じく
となります。「goodbye」については
となります。
これら2つの平均
を中間層の入力とします。
この計算結果から見ると、中間層のニューロンの値$\mathbf{h}$は解釈しづらいものです。そこで各単語に対応した値になるように、つまり要素(行)数が単語の種類数となるように再度変換したものを、CBOWモデルの出力とします。
出力層の重みを
とします。入力層の重みと区別するために、添字を$\mathrm{out}$としておきます。行数が中間層のニューロン数、列数が単語の種類数になります。
出力層も全結合層とすると、最終的な出力は
になります。
「you」に関する要素(1番目の要素)の計算は
コンテキストに対応する入力層の重みの平均と「you」に関する出力の重みの積になります。
他の要素(単語)についても同様に計算できるので、最終的な出力は
となります。
またこの値をスコアと呼びます。スコアが一番高い要素に対応する単語を、ターゲットの単語であるとして採用します。そのため、スコアを求める処理を推論処理と言います。
・処理の確認
推論処理をNumPyを利用して行ってみましょう。
# NumPyをインポート import numpy as np
# コンテキストデータを指定 c0 = np.array([[1, 0, 0, 0, 0, 0, 0]]) # you c1 = np.array([[0, 0, 1, 0, 0, 0, 0]]) # goodbye # 重みの初期値をランダムに生成 W_in = np.random.randn(7, 3) # 入力層 W_out = np.random.randn(3, 7) # 出力層 # レイヤを生成 in_layer0 = MatMul(W_in) # 入力層 in_layer1 = MatMul(W_in) # 入力層 out_layer = MatMul(W_out) # 出力層 # 入力層の順伝播を計算 h0 = in_layer0.forward(c0) # you h1 = in_layer1.forward(c1) # goodbye h = 0.5 * (h0 + h1) print(h0) print(h1) print(h) # 出力層の順伝播(スコア)を計算 s = out_layer.forward(h) print(np.round(s, 3))
[[-0.83839278 1.36845899 0.04013497]]
[[-0.05727094 -0.08164524 0.56260335]]
[[-0.44783186 0.64340688 0.30136916]]
[[ 0.08 0.485 0.181 -0.59 0.593 0.404 0.094]]
以上でスコアが求まりました。
次項では、スコアを正規化して、損失を求めます。
3.2.2 CBOWモデルの学習
Softmax関数によってスコアを確率として扱えるように変換します。この処理を正規化と呼びます。また正規化した値と教師ラベルを用いて損失を求めます。CBOWモデルでは、交差エントロピー誤差を損失とします。
Softmax関数については「ソフトマックス関数のオーバーフロー対策」を、交差エントロピー誤差については「損失関数」を参照してください。
1.3.1項で実装したsoftmax()
を使って処理します。
# スコアを確認 print(np.round(s, 3)) # Softmax関数による正規化 y = softmax(s) print(np.round(y, 3)) print(np.sum(y))
[[ 0.08 0.485 0.181 -0.59 0.593 0.404 0.094]]
[[0.122 0.183 0.135 0.063 0.204 0.169 0.124]]
1.0
各要素(単語)で、スコアの大小関係を保ったまま、総和が1となるような0から1の値に正規化されます。
損失も、1.3.1項で実装したcross_entropy_error()
を使って計算します。
# 教師ラベルを設定 t = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0]) # 損失を計算 loss = cross_entropy_error(y, t) print(loss)
20.61569560179386
この例では学習を行っていないので、損失の値は高くなります。
またSoftmax with Lossレイヤとして実装したクラスSoftmaxWithLoss
の順伝播メソッド.forward()
でも求められます。
# lossレイヤのインスタンスを作成 loss_layer = SoftmaxWithLoss() # 損失を計算 loss = loss_layer.forward(s, t) print(loss)
20.61569560179386
当然同じ値になります。
この節では、CBOWモデルの順伝播の処理を確認しました。次節では、CBOWモデルの入力データとなるコンテキストとターゲットを作成する関数を実装します。
参考文献
おわりに
3章1つ目の記事です!話には聞いていたword2vecにようやく取り組み始めました。
1・2章が大丈夫なら3章も大丈夫そうですね。
2020年9月14日は、モーニング娘。結成23周年の記念日です!!!おめでとうございます。
本日はモーニング娘。のお誕生日!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
メンバーからのメッセージをお届けします。#譜久村聖 #生田衣梨奈 #石田亜佑美 からのメッセージです!
撮影者は… つづく
#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/QKCapKKcQY
本日はモーニング娘。のお誕生日!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
メンバーからのメッセージをお届けします。
小田さくらは今日で加入◯周年??
…つづく
#譜久村聖#生田衣梨奈#石田亜佑美#小田さくら#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/tpl57pfJXY
本日はモーニング娘。のお誕生日!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
メンバーからのメッセージをお届けします。
24年目のモーニング娘。も応援よろしくお願いします!!!!!!!!!!!!!!#譜久村聖 #生田衣梨奈 #石田亜佑美 #小田さくら#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/PDRisPjICS
本日はモーニング娘。のお誕生日!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
メンバーからのメッセージをお届けします。#佐藤優樹 からのメッセージです!
#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/waPGrfDg5w
本日はモーニング娘。のお誕生日!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
メンバーからのメッセージをお届けします。
続いて、#小田さくら #野中美希 #牧野真莉愛 から!
#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/hzKNMwCIAa
本日9月14日はモーニング娘。の結成記念日です!
— モーニング娘。'24 (@MorningMusumeMg) 2020年9月14日
23回目のお誕生日に、メンバーからのメッセージをお届けします。
まずは #北川莉央 #岡村ほまれ #山﨑愛生 から!
#morningmusume20#結成記念日#Helloproject#ハロプロ pic.twitter.com/rwFVaDsrn2
私はオタ歴3年目ですが、これからもお慕い申し上げます。
【次節の内容】