なるほど!Google翻訳のアルゴリズム
みなさんこんにちは。
株式会社キスモの役員の寺澤です。
本日は、精度が高いと言われている、Google翻訳の技術をアルゴリズムの観点で紹介しようと思います。
arxivという国際論文が投稿されているサイトで、今年の6月に、GoogleのデータサイエンティストたちがAttention is All you NeedというタイトルでGoogle翻訳の技術であるTransformerという深層ネットワークを公開しました。
Transformerというとアニメや映画のトランスフォーマーを思い起こしますね。油断して適当に検索したらその作品がでます 笑
この論文は外国のデータサイエンティストの中でもすぐに話題になり、後にGoogleが公式で公開され、日本でも記事となりました。
Google公式の記事(英語注意): https://research.googleblog.com/2017/08/transformer-novel-neural-network.html
日本の記事: http://gigazine.net/news/20170901-transformer-neural-network-language-understanding/
実はこの論文が公開された直後に一度読んでみましたが、当時はあまりアルゴリズムを理解できませんでした。
今回はそのリベンジを含めてアルゴリズムを理解してきましたが、何故かあっさり理解できました 笑
さて、前置きはこれくらいにしておいて、解説に移ります。かなりコアな内容になるので、初心者は要注意です。
Google翻訳の技術、Transformerの構造とは?
前述の記事を読んでいただければ概要は理解できると思いますが、大まかに言うと、
- 既存のモデル(RNNベース、CNNベース)のものよりも精度が高く、学習時間の削減にも成功した。
- 着想はRNN、CNNベースのものとは変わらず、元の文全体を意識して、翻訳を行うモデルである。
- 既存モデルとの他の優位性は、文中の単語の意味を理解していることにある。
3番目に関しては、例えば英文の"it"が何を指すか(動物なのか、あるいは道路なのかなど)を理解した上で翻訳をします。
参考記事中の翻訳タスクでは、英文の"it"をフランス語では動物、道路を指す単語をそれぞれ"qu'il"、"qu'elle"と翻訳する事に成功しています。
Transformerは、Self-Attentionという、CNNに使われる畳み込みにもRNNに使われる再帰構造にも頼らない構造を使っています。
Transformerの動き方は前述の記事で紹介されていましたが、実際のアルゴリズムはどうなっているのか、説明していきましょう。
Transformerのアルゴリズム(概要)
Transformerのネットワーク構造は上図となります。本記事では、入力・エンコード・デコード・出力の順に説明します。
図ではそれぞれ下部分、左の灰色部分、右の灰色部分、右上の出力部分となります。
Transformerのアルゴリズム(入力する前に)
まず、入力する文と出力する文(翻訳元の文、翻訳した文両方)は、既存のRNNと違って、単語の位置の情報を与えなければなりません。
これは、Position Embeddingsというアルゴリズムで単語の位置を与えてやります(単語にインデックスを付けるだけですが)。
この手法は、Facebookが今年の5月に公開したCNNベースの翻訳モデルでも用いられました。これをたった1ヶ月で追い上げるGoogleすごいですよね。
論文では、このアルゴリズムをさらに改善したPositional Encodingというアルゴリズムを使って、単語の位置情報を与えます。
数式は以下のようになり、この式を適用したベクトルPEの列とベクトル化した単語列がネットワークへの入力となります。
上式のposは単語の位置、iはベクトル化した単語の次元数(インデックス)を指し、交互にsinとcosをとっているようです。
このアルゴリズムを適用する事で、単語の位置を相対的にも考慮して学習する事ができるようです。
しかし、論文の検証結果では、通常のPosition Embeddingsを使ったTransformerのモデルと比較したところ、ほぼ同等のスコアでした(若干提案手法の方が優勢でした)。
Transformerのアルゴリズム(エンコードレイヤー)
さて、いよいよ学習・推論のアルゴリズムに入ります。まずは入力する文(翻訳元の文)に対応するエンコードレイヤーについて説明していきましょう。
後のデコード層にも使われますが、基本的には、Multi Head-Attention層とFeed Forward層の二本柱になっていまして、
それぞれの層の直後にresidual層、正規化層が挟まっています。このネットワークを一つのエンコードレイヤーとして扱い、このレイヤーを複数連結したものがエンコード層となります。
residual層は、ResNetを知っている人ならばアルゴリズムは想像つくでしょうが、Multi Head-Attention層はTransformerのコア技術になりますね。
これらの層を順に説明していきましょう。
Multi Head-Attention層
Multi Head-Attention層は上図の右のような構造をとります。
Multi Head-Attention層への入力は、図の通り、3つとなっております。入力の最初の層にこれがくる事になりますが、単語の入力をどう3つにするんだと思うでしょう。
実は、今回は、入力ベクトル同じものを3つ入力します。3つの入力はそれぞれ、query、key、valueと呼ばれ、query、keyから重みを作り、その重みを適用したvalueを出力します。
エンコードレイヤー内でのこの層はSelf-Attentionと呼ばれますが、同じ単語ベクトルから計算するためにこう呼ばれているのでしょう。
さらにこの中では、さらにScaled Dot-Product Attentionという層が存在し、Multi Head-Attention層の肝となります。
図では左の構造になります。(図にはMaskという層が現れていますが、後述するデコードレイヤーでのみ用います。)
だいたい図の通りですが、入力ベクトルであるquery、key、valueをそれぞれ、Q、K、Vとすると、Scaled Dot-Product Attentionは以下の数式で計算が行われます。
図のScaleに当たる部分が、ハイパーパラメータd_kの平方根を割る箇所となります。
ハイパーパラメータで割るのはチューニング可能にして、調整が効くようにするためでしょうが、どうして平方根を挟むのでしょうか。
ハイパーパラメータd_kに平方根を取る理由ですが、値の大きいd_kで割ってしまったら、勾配が非常に小さくなり、勾配消失問題に繋がるためです。
Multi Head-Attention層ではこのアルゴリズムを用いますが、入力するQ、K、Vはそれぞれ対応する全結合層を挟んだ後、h個のQ、K、Vのペアを並列して、
Scaled Dot-Product Attention層に通します。入力は、処理済みのh個のQ、K、Vのペアを入力としますが、Scaled Dot-Product Attention層は対応するh個だけ用意します。
出力したh個のベクトルは連結し、再び全結合層に通して出力されます。これがMulti Head-Attention層の一連の流れとなります。
ただし、前述の全結合は、論文内では全てパラメータ行列との内積だけで表現されております。同様に参考に読んだgithubのコードでは、通常の全結合層に通し、場合によってはreluも通していました。見た感じですと、論文内では前者以上の説明はありませんでしたが、学習具体によって差し替えるのもありですね。
後に説明する翻訳後の結果に通すデコードレイヤーでは、形を変えてこの層を使います。
Feed Forward層
長々とMulti Head-Attention層の説明をしましたが、Feed Forward層は見慣れた構造となっております。
単純に全結合、relu、全結合の順に入力を通していきます。ただし、全結合の代わりにカーネルサイズが1の畳み込み層を用いても良いようです。
参考にしたgithubのコードでも畳み込みを使っていました。
residual層
residual層ではResNet(Residual Network)でも用いられた手法で、入力の残差を学習する事で、ネットワークの層を深くするという着想を元に生まれました。
何が行われているかは単純で、レイヤーに入力したベクトルとその入力をしたレイヤーから出力されたベクトルの和を取るだけです。
ここでは、Multi Head-Attention層への入力と出力の和、Feed Forward層への入力と出力の和を取ります。
論文内では、エンコードレイヤーを6つ連結し、更にエンコードレイヤーと似た構造のデコードレイヤーも6つ用意しているものがベースのモデルとなっています。
そのことを考えると確かに深い構造になりますね。そのことを見据えて用意したのでしょう。
正規化層
正規化です。入力したベクトルの値の平均を1に、分散を0にするものです。
Transformerのアルゴリズム(デコードレイヤー)
エンコードレイヤーの説明が長くなりましたが、今度は出力する文(翻訳結果の文)に対応するデコードレイヤーについて説明します。
デコードレイヤーと似た構造を取り、デコードレイヤーに登場した層を使っていきます。ただし、Masked Multi Head-Attention層という層が新たに加わり、Masked Multi Head-Attention層、Multi Head-Attention層、Feed Forward層の順の連結を1つのデコードレイヤーとします。
こちらでも例外なく、各層の出力直後にresidual層と正規化層が現れたり、複数レイヤーの連結も行います。
ここでは、(Masked) Multi Head-Attention層の扱い方がエンコードレイヤーとは変わりますので、それらの説明を行います。
Masked Multi Head-Attention層
基本的には、Multi Head-Attention層とは変わりませんが、
Scaled Dot-Product Attention内のsoftmax関数を通す直前の値にマスキングを適用します。式にするとこういう形になるでしょうか。
エンコードレイヤーでは、入力の文全体を意識して学習を行います。しかしデコードレイヤーでは翻訳文が頭から順番に出力され、翻訳した単語とそれ以前に出力した単語列のみを意識しています。
例えば、「私はトムです」は「I'm Tom」と訳せますね。しかしモデルは「最初に"I'm"」が来ても、次に何が来るかを計算しなければなりません。厳密には「最初に"I'm"」が出力するかわからない段階があります。
「それ以前に出力した単語列のみを意識」するとは、"I'm"を翻訳文として出力するべきとは理解したものの、それ以降は何を出力するべきか核心に至っていない状態での意識の事です。
そこで、出力されているはずのない単語(出力する単語を選ぶ前の時点の単語)ベクトルに関しては、上式のようなマスクを適用します(論文内ではに差し替えています)。
Multi Head-Attention層
Masked Multi Head-Attention層に続く、Multi Head-Attention層では、queryに図で言う、直前のMasked Multi Head-Attention層の出力を受け取り、key、valueがエンコードレイヤーの最終出力を受け取ります。いわゆるSelf-Attentionとは違う入力になりますね。
このような入力にする事で、翻訳元の文と、時系列で言う過去の翻訳の出力を加味した学習や推論を行えるようにします。
以上で説明した層を組み合わせネットワークがデコードレイヤーとなります。
Transformerのアルゴリズム(出力)
出力はデコードレイヤーの最終出力を全結合層、ソフトマックス層の順番に通し、出力した単語列に続く次の単語を予測します。
論文内では記載されていないようですが、損失関数は交差エントロピーで問題ないでしょう。
Transformerのアルゴリズム(その他)
このネットワークでも例外なくdropoutは用います。
論文内では、residual層の直前と、Scaled Dot-Product Attentionの最後の内積の直前に適用しています。
終わりに
以上がGoogleの翻訳技術であるTransformerの全貌となります。数式や長文ばかりではわかりにくいと思いますので、
一応原論文に加えて私が参考にしたgithubのソースコードのURLも置いておきます。
余裕があれば紹介した論文を引用した論文でも紹介しようと思いましたが、こうも長くなってしまったので省略します。
スコアや計算量など、評価に関する部分も論文に任せます。
これを機にGoogleの翻訳技術を再現してみるのはいかがでしょうか。
いずれ余裕ができた時には、Neural Network Consoleなどでの再現実装も検討しようと思います。
以上、寺澤でした。
参考文献
- Attention is All you Need https://arxiv.org/pdf/1706.03762.pdf
- 本稿で解説したネットワークの論文です。
- Convolutional Sequence to Sequence https://arxiv.org/pdf/1705.03122.pdf
- 本稿で解説したネットワークが参考にした、畳み込みベースの翻訳モデルの論文です。
- A TensorFlow Implementation of the Transformer: Attention Is All You Need https://github.com/Kyubyong/transformer
- 本稿で解説したネットワークのTensorFlowによる実装です。これと論文を参考に勉強しました。