StatsBeginner: 初学者の統計学習ノート

統計学およびR、Pythonでのプログラミングの勉強の過程をメモっていくノート。たまにMacの話題。

LightGBMにおけるカテゴリ変数の扱い方

LightGBMにおけるカテゴリ変数の扱いについてググっていたら、以下のような投稿があった。
[SOLVED] How exactly does LightGBM handle the categorical features? | Kaggle


この投稿のなかで、いろいろ参考になるリファレンスが貼られている。

max_cat_to_onehot (default = 4, type = int, constraints: max_cat_to_onehot > 0)
when number of categories of one feature smaller than or equal to max_cat_to_onehot, one-vs-other split algorithm will be used
Parameters — LightGBM 4.2.0.99 documentation

LightGBM offers good accuracy with integer-encoded categorical features. LightGBM applies Fisher (1958) to find the optimal split over categories as described here. This often performs better than one-hot encoding.
Advanced Topics — LightGBM 4.2.0.99 documentation

Optimal Split for Categorical Features
It is common to represent categorical features with one-hot encoding, but this approach is suboptimal for tree learners. Particularly for high-cardinality categorical features, a tree built on one-hot features tends to be unbalanced and needs to grow very deep to achieve good accuracy.

Instead of one-hot encoding, the optimal solution is to split on a categorical feature by partitioning its categories into 2 subsets. If the feature has k categories, there are 2^(k-1) - 1 possible partitions. But there is an efficient solution for regression trees[8]. It needs about O(k * log(k)) to find the optimal partition.

The basic idea is to sort the categories according to the training objective at each split. More specifically, LightGBM sorts the histogram (for a categorical feature) according to its accumulated values (sum_gradient / sum_hessian) and then finds the best split on the sorted histogram.
Features — LightGBM 4.2.0.99 documentation


ちなみにFisher(1958)は、斜め読みしかしてないので雰囲気しか把握してないが、1次元の連続値データに基づいてサンプルをグループ分けする際に各グループ内で分散が小さくなるようにするにはどうすればいいかを議論していて、例として200個の数字を10のグループに分ける場合の話がされていた。


ところで、上記投稿者の人自身は、結論を間違えているような気がするな。
この人は、「カテゴリ数(水準数)が`max_cat_to_onehot`以下の場合は、one-vs-other split algorithmが採用され、それより多い場合は、one-hotエンコーディングが採用される」と理解したようなのだが、そもそも水準数が少なければone-hotでいいはずなので、水準数が閾値以下であればone-hot encodingされると理解すべきだろう。


上記3つめの引用に書いてあるように、もともとの問題意識は、カテゴリ数が多い(high-cardinalityな)場合にone-hotエンコーディングをしようとすると非常にアンバランスな木ができてしまい、最適な分割結果に近づくために木を深くしなければならなくなるので、大雑把な分割の中からいいものを選びたいという話である。で、one-vs-other algorythmと呼ばれているものは、one-vs-restと言うことの方が多いようだが、これはようするにone-hotとほぼ同じ意味だと思う。つまり、多クラスの分類を、「あるクラスとそれ以外」に分ける分類器を複数組み合わせて扱うということ。


↓この投稿で検証されているように、`max_cat_to_onehot`よりも少ない水準数の場合は、one-hot encodingした場合と結果が同じになるようだ。
https://stackoverflow.com/questions/65773372/lightgbm-splits-differently-on-the-same-dataset-one-hot-encoded-vs-one-vs-other
(この投稿は、「同じになると思ったらならないんだけど…」という内容で始まって、「あ、バージョン上げたら同じになったわ」と自己解決しているもの。)


で、じゃあカテゴリ数が多い場合にどうなってるのかなのだが、まずそもそも、以下のような「ヒストグラムベース」の木構築の話を頭に入れておかないといけない。


勾配ブースティング決定木ってなんぞや #Python - Qiita
xgboostのコードリーディング(その2) - threecourse’s blog
Kaggleで大人気!勾配ブースティング決定木の軽量モデル「LightGBM」を詳細解説! | DeepSquare


勾配ブースティング決定木においては、ある時点で構築された木に基づく予測値と実際の値から誤差を計算して、誤差関数を「予測値で」偏微分する。つまり、予測値をどっちに動かすと、誤差がどれだけ増えるかを計算する。
ニューラルネットのように、「モデルのパラメータで」偏微分するわけではないので注意が必要。
各ノード(決定木の分岐点)において、特徴空間のどの部分を分割すると、サンプルの勾配の合計が最大限に減少するかを学習していく流れになる。
で、この際、分割点の探索は計算コストが高いので、連続変数ならビンでまとめてヒストグラムのようにした上で、どのビン間で分割するのがよいかを探索することになる。カテゴリ変数(ラベル)の場合は、数量化の工夫を行う必要があって、`(sum_gradient / sum_hessian)`を使ってどうたらこうたらというのは、その話だ。


で、決定木系のアルゴリズムをほとんど勉強してないので単なる想像なのだが、LightGBMにおいて水準数の多いカテゴリ変数扱いは、たぶん以下のような感じなのかな?
全く自信はないのであとで時間あるときに確認しようと思ってるのだけど、誤解だとしても「現時点でどう理解したか」メモっておくのが効率的なので、メモっとくことにするw

  1. 現時点の木の構築:初期の木、またはブースティングの反復を経た現在の木が与えられる。
  2. 全サンプルの勾配とヘシアンの計算:各サンプルについて、勾配(損失関数を予測値で一次偏微分)とヘシアン(損失関数を予測値で二次偏微分)を計算する。
  3. カテゴリ変数を数値に変換:各カテゴリについて、そこに属する属するサンプルの勾配/ヘシアン比の合計値を計算する。この値は、そのカテゴリの重要性を示す。
  4. カテゴリのソート:カテゴリ変数を、上記の重要度に基づいてソートする。
  5. ヒストグラム化:ビンでまとめてヒストグラム化する。
  6. 最適な分割点の探索:Fisher (1958)の手法や他の統計的手法を用いて、どのビン間で分割するのが最も効果的かを探索する。(どう分割すれば勾配をさらに小さくできるかを探索する。)


カテゴリ数が閾値(デフォルトでは4)以下であれば、ふつうにone-hotエンコーディングが採用される。それより大きい場合は、上記のような(誤解ならこれを修正した)手順にしたがって、分割される。なおたぶん、`max_cat_threshold`というパラメータ(デフォルトは32)に設定した値より細かくは分割されないということだと思う。決定木は通常、バイナリ分割(2つに分けていく)で、それを何回か重ねて分けていくが、32分類以上にはしないということだろう。

MacでのChrome AppsのTwitter (X)アプリのインストール

今、Macでツイッター(X)のアカウントを複数運用するなら、Chrome Appsのアプリが最適だと思っていて、それを再度インストール(正確にはMacの別のユーザアカウントにインストール)しようと思ったら方法が分からなくて困ったのでメモしておきます。
説明するほどの手順ではないんですが、ぐぐっても出てこなかったので。
 

  1. ChromeでTwitter(X)にログインする
  2. Chromeの右上の「…」を縦にしたボタンのメニューに「Xをインストール」っていう選択肢があるのでそれをクリック
  3. ローンチパッド上にXのアプリのアイコンが出るのでそれをドックに配置

 
で完了です。
`~/Applications/Chrome Apps/X.app`
という場所に入っています。
ユーザディレクトリの配下なので、
`/Applications`
の中を探しても無いので気をつけてください。
 
ちなみに私は、もともとインストールしていたユーザアカウントではTwitter.appになってて、新しくインストールしたやつはX.appになってます。
 
あとは余談ですが、自分はMac用のツイッタークライアント使用歴は以下のような感じです。

  1. Janetter:一瞬話題になってから何となく使ってたやつで、夜フクロウとかTweetDeckに比べて何がよかったかは忘れた。
  2. Twitter for Mac(公式):結局公式がいちばん使いやすい気がしてしばらく使っていたが、開発会社が無くなったか何かで、2018年に廃止された。2019年に一時的に復活してるしいけどいまいち覚えてない。
  3. Catalyst版:Catalystという、iPad用アプリをMacで使えるようにするフレームワーク(?)によって、Twitter for Mac(公式)が復活。しばらく使ったが、廃止されたか不具合が気になったかで、使うのをやめた。
  4. Multiple Twitter Accounts Chrome(Chrome拡張):Chrome拡張でTwitterアカウントを複数運用するツールがあり、これをつかってブラウザでみるようになったが、イーロン・マスクに買収された後に何かが起きてまともに使えなくなった。(2023年1月のサードパーティ排除騒動かな?)
  5. Chrome Apps版:経緯は忘れたけどChrome Appsのアプリを発見してインストール。現在に至る。

“All You Need”論文のベースモデルに近いスペックの英日翻訳Transformerを作ってみた

先日から英日Transformerの学習結果の報告を何度か書いてますが(エントリ1エントリ2エントリ3)、AWSでA100というGPUが8枚使える最高スペックのインスタンスが空いたので*1、コーパスとモデルを少し大きくして、Googleの有名な“Attention is all you need”論文のベースモデルに近い規模にしてみました。


具体的にいうと、All You Need論文では英語-ドイツ語の翻訳に関しては、

  • 450万ペアの対訳コーパス
  • 37000トークンのボキャブラリ辞書(byte-pair encoding)
  • Transformerブロックはエンコ側・デコ側ともに6層
  • 埋め込みは512次元
  • マルチヘッドアテンションのヘッド数は8
  • フォードフォワード部分の隠れ層は2048次元
  • 10万ステップ学習(12時間)


というスペックになっています。ステップは、サンプルサイズ÷バッチサイズという理解であってるかな?


私が今回構築したのは、英語-日本語の翻訳モデルで、

  • 580万ペアの対訳コーパス
  • 30000トークンのボキャブラリ辞書(byte-pair encoding)
  • Transformerブロックはエンコ側・デコ側ともに6層
  • 埋め込みは512次元
  • マルチヘッドアテンションのヘッド数は8
  • フォードフォワード部分の隠れ層は2048次元
  • 10万ステップ学習(25時間)したが勾配累積してるのでパラメータの更新回数はその4分の1になる


という規模です。前回からの変化としては、コーパスの規模が170万から580万に増えたのと、フィードフォワードの次元が512だったのを2048にしています。ちなみに使っているコーパスは、以下のような無料のものをクリーニングして合体して使っています。

  • TED字幕(元データは15万8535件/うち15万5723件使用)*2
  • 青空文庫等の小説(元データは11万8143件/クリーニングとデータ拡張処理を経て11万1485件使用)*3
  • 京都Wiki(元データは44万3849件/うち13万4199件使用)*4
  • 映画字幕(元は280万1388件/うち125万5207件使用)*5
  • 田中コーパス(元データは14万7918件/うち14万4683件使用)*6
  • 法令対訳コーパス(元データは26万2449件/うち17万6054件使用)*7
  • JparaCrawl(元データは2574万0835件/うち128万4193件使用)*8
  • Wikimatrix(元データは85万1706件/うち58万0375件使用)*9
  • Coursera(元データは5万3166件/うち5万2614件使用)*10
  • OSSマニュアル(元データは40万3366件/うち26万2067件使用)*11
  • ASPEC(元データは300万8500件/うち165万9318件使用)*12


元データの件数は、英語か日本語のどちらかが欠けているデータを除いてカウントしているので、公式の表記より少ない場合があります。これらのコーパスを全部合わせると3398万9855件あるのですが、データを絞って使っています。
まず、全体として英語文10〜500文字、日本語文10〜250文字のものに限ってます。本当は長い文も学習させたいのですが、バッチ内で最長のシーケンスに合わせてパディングされる影響もあって、長い文が少しでも混じってるとメモリを大きく圧迫するので、我慢しました。
またコーパスによっては、日本文に英数字をたくさん含むもの、日本文が句点で終わってないもの、英文が大文字で始まってないもの、日本文と英文の文字数の比率が極端なものなどを除きました。句点で終わってないとかは、それ自体は大した問題ではないのですが、「品質の低い対訳文例」である可能性が少し高いので除いているという感じです。
もともとデータ量が多いコーパスについては、日本語が50文字未満のものをバッサリ削ったりもしてます。どちらかといえば長めの学習データが不足しがちだからです。
句読点を補ったり、日本語が分かち書きされていたのでスペースを削って詰める操作をしたコーパスもあります。


前回、前々回と翻訳結果を比較してみます。コーパスの規模を130万ペア、170万ペア、580万ペアと増やしてきたので、1.3M、1.7M、5.8Mと表記してます。個人的に一番よかったものに★印を付けています。

Your time is limited, so don’t waste it living someone else’s life. (Steve Jobs)
【1.3M】時間は限られているので、他人の人生を浪費しないでください。
【1.7M】時間が限られているので、他人の人生を無駄にしないでください(スティーブ・ジョブズ)。
【5.8M】時間は限られているので、他の人の人生を生きることは無駄にしないでください。
(拙訳:君たちの時間は限られている。他人の人生を生きるようなことをしてそれを無駄にするな。/スティーブ・ジョブズ)
 
I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character. (Martin Luther King Jr)
【1.3M】私は4人の小さな子供たちが、いつか、自分の肌の色ではなく、その性格の特徴によって判断されない国家に住む夢を持っています。
【1.7M】わたしには、ある日、わたしの4人の小さな子供が、肌の色ではなく、その性格の色によって判断されるであろう国に住んでいるという夢があります(マーティン・ルーサー・キングジュニア)
【5.8M】ある日、私の4人の子供たちが、自分の肌の色ではなく、その性格の含みで判断される国に住んでいくという夢があります(マルティン・ルーサー・キング・ジュニア)。
(拙訳:私には夢がある。私の4人の子供たちがいつの日か、肌の色ではなく彼らの人格によって判断される国に暮らせるようになるという夢が。/キング牧師)
 
You are fake news! (Donald Trump)
【1.3M】偽のニュースです!
【1.7M】ばかばかしいニュースだ!(ドナルド・トランプ)。
【5.8M】偽りのニュースです!(ドナルド・トランプ)
(拙訳:フェイクニュース屋め!/トランプ大統領)
 
You may say I'm a dreamer. But I'm not the only one. I hope someday you'll join us. And the world will be as one. (John Lennon)
【1.3M】夢想家だって言うかもしれないけど、私だけじゃない。いつか、ぼくらと合流してくれるといいんだけど。そして世界は、ひとつのものになる。
【1.7M】夢想家だと言うかもしれません。でも、私はただ一人ではありません。いつかあなたたちが仲間になるといいですね。世界は1つになるでしょう。(ジョン・レノン)
【5.8M】夢想家だと言ってもいいけど、わたしだけじゃない。いつかあなたも参加してくれるといいんだけど。そして世界は一つになるよ(ジョン・レノン)。
(拙訳:夢想家だと君は言うかもしれないけれど、僕は一人じゃない。いつか君も一緒になれれば。そして世界は一つになる。/ジョン・レノン)
 
The madman is not the man who has lost his reason. The madman is the man who has lost everything except his reason. (G. K. Chesterton)
【1.3M】狂人は理性を失った人間ではない。狂人は、理性以外はすべてを失った男だ。
【1.7M】狂人は理性を失った人間ではない。狂人は理性以外のすべてを失った男である(G.K.チェスタトン)。
【5.8M】狂人は、その理性を失った人ではない。狂人は、その理性を除いて、すべてを失った人だ。(G.K.チェスタトン)
(安西徹雄訳:狂人とは理性を失った人のことではない。狂人とは、理性以外のあらゆる物を失った人のことである。/チェスタトン)
 
The safest general characterization of the European philosophical tradition is that it consists of a series of footnotes to Plato. (A. N. Whitehead)
【1.3M】ヨーロッパ哲学伝統の最も安全な一般的な特徴は、それがプラトンへの一連の脚注から構成されていることです。
【1.7M】ヨーロッパの哲学的伝統の最も安全な一般的な特徴は、プラトンへの一連の脚注から成り立っていることである(A.N.ホワイトヘッド)。
【5.8M】ヨーロッパ哲学の伝統の中で最も安全な一般の特徴は、プラトンへの一連の脚注からなるということである。
(拙訳:ヨーロッパ哲学の伝統について間違いなく言えるのは、その全てが、プラトン哲学へのひと続きの注釈に過ぎないということである。/ホワイトヘッド)
 
Violence sometimes may have cleared away obstructions quickly, but it never has proved itself creative. (Albert Einstein)
【1.3M】暴力は時々すぐに妨害を片付けるかもしれませんが、それは創造的に証明されたことはありません。
【1.7M】暴力沙汰はすぐに閉ざされたのかもしれないが、しかし、創造的自立は証明されていない(アインシュタイン)
【5.8M】暴力はときどき障害をなくしてしまったかもしれないけれど、創造的だと証明されることはなかった。
(拙訳:暴力が、問題を手っ取り早く片付けるのに役立つことはある。しかし、暴力それ自身が創造的であったことは一度もない。/アインシュタイン)


正直、そんなによくなったわけではないですねw
今回追加したコーパスのうち、OSSマニュアル(オープンソース・ソフトウェアの説明書の対訳データ)とASPEC(学術論文のアブストラクトの対訳データ)は、内容が専門的なので、言葉のチョイスがそれに引っ張られてしまったかもしれません。


ただ前回も言いましたが、当初はキング牧師の引用文中のbutがうまく反映されず、「肌の色ではなく人格によって判断される」というふうに訳すことが安定的にはできてなかったのですが、今回はbutの解釈自体は総じて的確でした。↑の比較では前回(1.7M)のが一番良いのですが、これはたまたま最終エポックのモデルでうまく訳せていただけという感じだったのですが、今回は下記のように各エポックごとのモデルの結果を並べて見ても、butの解釈(○○ではなく××)自体は安定しています。
contentの訳が安定してなかったり、「one day」を1.3Mの時は「いつか」と訳せてたのに「ある日」とかになってるのは残念ですが……。
一番よかったのはエポック27のやつですかね。

Epoch01: 私は、私の子供達が、その子供達が、その1週間前に、その子供たちの色を、その色に、その色に、その色が、その色(英語版)のスタイルに、その色が、その色に、その色が*13

Epoch02: 私は私の4つの小さな子供が、彼らの皮膚の色によって判断されない国家に住んでいる夢を持っていますが、彼らのキャラクターのコンテンツ(ミートリン・ルーズ・キング・ジョル)によって。

Epoch03: 私は私の4つの小さな子供たちが1日1日に、彼らの肌の色で判断されない国家に住んでいる夢を持っていますが、彼らのキャラクターのコンテンツによって。(マテイン・ルター・キング・Jr)。

Epoch04: 私は私の4人の子供たちが1日1日に、彼らの肌の色によって判断されない国家に住んでいる夢を持っていますが、彼らのキャラクターのコンテンツ。(マティニンルーサーキングJr)。

Epoch05: 私は私の4人の小さな子供たちが1日1日に、彼らの肌の色によって判断されない国家に住んでいる夢を持っていますが、彼らの性格のコンテンツ。(マティインルーサーキングJr)。

Epoch06: 私は私の4人の子供たちが1日1日に国民に住み、彼らは彼らの肌の色によって判断されないが、彼らの性格のコンテンツによって。(マリン・ルター・キング・ジュニア)私は夢を持っています。

Epoch07: 私は私の4人の小さな子供たちが1日、彼らの皮膚の色ではなく、彼らの性格のコンテンツによって判断される国に住んでいる夢を持っています。(マリンルーサーキングJr)。

Epoch08: 私は私の4人の小さな子供たちが1日、彼らの肌の色によって判断されないが、彼らの性格の内容によって、国民に住んでいる夢を持っています。(マリンルーサーキングJr)。

Epoch09: 私は私の4人の子供たちが1日、彼らの肌の色によって判断されないが、彼らの性格の内容によって決定される国に住んでいる夢を持っています。(マリン・ルーサー・キングJr)。

Epoch10: 私は私の4人の子供たちが1日、彼らの肌の色によって判断されないが、彼らの性格の内容によって、彼らが国に住んでいることを夢見ています。(マータンルーサーキングJr)。

Epoch11: 私は私の4人の子供たちが1日、彼らの肌の色によって判断されるのではなく、彼らの性格の内容によって決定される国に住んでいる夢を持っています。(マータンルーサーキングJr)。

Epoch12: 私は私の4人の子供たちが1日、彼らの肌の色ではなく、彼らの性格の内容によって判断される国に住んでいるという夢を持っています。(マルティンルーサーキングJr)

Epoch13: 私は私の4人の小さな子供たちが1日、彼らの肌の色ではなく、彼らの性格の内容によって判断される国に住んでいるという夢を持っています。(マルティンルーサー王Jr)

Epoch14: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格の内容によって判断される国に住んでいる夢を持っています。(マルティンルーサー・キングJr)

Epoch15: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格のコンテンツによって判断される国に住んでいるという夢を持っています。(マルティンルーサーキングJr)

Epoch16: 私の4人の子供たちが、ある日、その人の肌の色ではなく、その人の性格の形によって、その人の肌の色によって判断されるような国に住む夢があるのです。

Epoch17: 私はある日、私の4人の子供たちが、その人の肌の色ではなく、その人の性格の含みによって、その国の生活をするという夢を持っています。

Epoch18: 私は、私の4人の小さな子供たちが、ある日、彼らの肌の色ではなく、その性格のコンテンツによって判断される国に住んでいる夢を持っています。(マルティン・ルーサー・キングJr)

Epoch19: 私は、私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格のコンテンツによって、彼らが判断される国に住んでいるという夢を持っています。

Epoch20: 私は、私の4人の小さな子供が、ある日、彼らの肌の色ではなく、その性格の内容によって判断される国に住むことを夢見ています(マルティン・ルーサー・キング・ジュニア)。

Epoch21: 私は、私の4人の小さな子供が、ある日、彼らの肌の色ではなく、その性格の内容によって判断される国に住んでいるという夢を持っています。(マルティン・ルーサー・キングJr)

Epoch22: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格の含みによって、彼らが判断される国に住んでいるという夢を持っています。(マルティン・ルーサー・キングJr)

Epoch23: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格のコンテンツによって判断される国に住むことを夢見ています(マルティン・ルーサー・キングJr)。

Epoch24: 私は私の4人の子供たちが一日住んでいて、その国の色によって判断されるのではなく、その性格のコンテンツによって判断されるという夢を持っています。

Epoch25: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格のコンテンツによって判断される国に住むことを夢見ています(マーティン・ルーサー・キングJr)。

Epoch26: 私は私の4人の子供たちが一日住んでしまう夢を持っています。彼らは彼らの肌の色ではなく、その性格の内容によって判断されるでしょう。

Epoch27: 私は私の4人の子供たちが、ある日、彼らの肌の色ではなく、その性格の内容によって判断される国に住むことを夢見ています(マーティン・ルーサー・キングJr)。

Epoch28: ある日、私の4人の子供たちが、自分の肌の色ではなく、その性格の含みで判断される国に住んでいくという夢があります。

Epoch29: ある日、私の4人の子供たちが、自分の肌の色ではなく、その性格の含みで判断される国に住んでいくという夢があります。

Epoch30: ある日、私の4人の子供たちが、自分の肌の色ではなく、その性格の含みで判断される国に住んでいくという夢があります(マルティン・ルーサー・キング・ジュニア)。


「性格のコンテンツ」という訳になっているのは、今回追加したコーパスの癖のような気がします。ソフトウェアのマニュアルと学術論文のコーパスを追加したのですが、英語をカタカナで表現してる部分が多くて、その影響が出たのかなと。


以下は学習曲線で、一応検証ロスは微妙に下がり続けているのですが、上記の各エポックの翻訳結果の変化を見るかぎり、後半はあまり頑張っても意味ない気はしますね。



数百万件程度の学習しかしてないので、超大規模にしたときにどうなのかはわからないのですが、「きれいなコーパスをバランスよく使うこと」がめちゃ重要だなと痛感してます。上の翻訳の例を見ても、Transformerはさすがという感じで、両言語間の関係の把握や出力文の文法的な正しさとかの面ではいい仕事をしてるのですが、出力文の単語のチョイスにセンスの無さを感じるので、このへんはコーパス依存の部分が大きいんじゃないかなと。

*1:AWS側のリソースが逼迫しているらしく、運よく空いてる時間に当たらないと起動できない。

*2:TEDの字幕で、品質はとてもいいと思う。

*3:小説のデータで、訳の品質はいいと思うが、英日どちらも文学作品として成り立つように書かれた文章なので、言語的意味が逐一対応しているわけではない気もする。他のコーパスにない特徴として、内容的に連続した文が並んでいるので、連結することで長文のサンプルを作ることができる。

*4:京都に関係するWikipediaのコンテンツを訳したものらしい。訳の品質はいいと思うが、話題が偏っているのと、Wikipediaなので翻訳の学習に適さない情報も混じっている。

*5:色々な映画の字幕の対訳データで、品質はよくデータ量も多くていいのだが、映画の字幕なので1文1文は短め。日常会話のサンプルを稼ぐことができて良いと思う。意訳が多い点がどう出るか。

*6:品質は良いが1文1文は短い。

*7:日本の法令の対訳データ。翻訳自体の品質はよく、また比較的長めのセンテンスが多いところが良いが、内容は当然偏っている。

*8:NTTの研究所がWebクローラを使って自動収集したコーパス。データ量は多いが、変なデータもかなり混じっている印象。

*9:FacebookがWikipediaから作っている多言語の対訳コーパスのうち、英-日分を抜き出したもの。対訳の品質はけっこう良い。

*10:教育分野の話し言葉の対訳コーパスで、品質的にはとても綺麗。1文1文が短いのと、データ量が少ないのが惜しい。

*11:オープンソースのソフトウェアの説明書の対訳データ

*12:学術論文のアブストラクトのデータ。オンライン申請が必要だがすぐにもらえます。

*13:RNNでもそうなのだが、ディープラーニングによる機械翻訳はそれまでの出力結果を受けて次の1語を予測するという流れになっていて、学習が不十分だと、新しい出力を足しても文全体の意味があまり変わらないような場合に同じような表現が繰り返し吐き出される。初期のDeepLで訳文になぜか全く同じ文が連続して入っていたりしたのも同じ理由。

英日翻訳Transformerを少しだけ大きくしてみた結果

研究でTransformerを使いたいので(去年ちょっと実際に使いましたが)、基本から勉強しようと思い、先日自分でTransformerに英日翻訳を学習させてみたのですが(エントリ1エントリ2)、GPUを複数枚並列で動かせる環境を手に入れたので、コーパスとモデルを少し大きくしてみました。
対訳ペア数は、128万から175万へ(Wikimatrixという新しいコーパスを追加)。
Transformerのブロック数を、両側3層から両側6層へ。
ただしByte-Pair Encodingの語彙数を、3万から2万に減らしました。なぜか新しい環境では3万でやるとクラッシュして動かなかったためです。なお、GoogleのAll You Need論文では、確か英独翻訳が数百万、英仏翻訳で数千万の対訳ペアが使われているのに対して、BPEの語彙数は3万ちょい(多言語横断でこのサイズ)だったと思うので、2万でも十分だとは思っています。BPEの語彙数はイメージより少なくて大丈夫だよというのは、よく言われているようです。
Transformerブロックを2倍にしたけど語彙数を小さくしたので、パラメータ数はあまり変わりません(前回が6900万、今回が7100万)。


50エポックまで学習させました。途中でGPUを4枚から8枚に増やしたら、グラフのとおりなぜか訓練誤差が跳ね上がったのですが、ちょうど2倍なので、どこかで平均か何かをとる操作が間違ってる気がします。検証誤差は下がっているので気にしないことにしましたw



以下が、前回と今回の機械翻訳の結果の比較ですが、大差はないという感じです(笑)
やはりコーパスをデカくしないとだめなのかも知れません。

Your time is limited, so don’t waste it living someone else’s life. (Steve Jobs)
【前回】時間は限られているので、他人の人生を浪費しないでください。
【今回】時間が限られているので、他人の人生を無駄にしないでください(スティーブ・ジョブズ)。
(拙訳:君たちの時間は限られている。他人の人生を生きるようなことをしてそれを無駄にするな。/スティーブ・ジョブズ)
 
I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character. (Martin Luther King Jr)
【前回】私は4人の小さな子供たちが、いつか、自分の肌の色ではなく、その性格の特徴によって判断されない国家に住む夢を持っています。
【今回】わたしには、ある日、わたしの4人の小さな子供が、肌の色ではなく、その性格の色によって判断されるであろう国に住んでいるという夢があります(マーティン・ルーサー・キングジュニア)
(拙訳:私には夢がある。私の4人の子供たちがいつの日か、肌の色ではなく彼らの人格によって判断される国に暮らせるようになるという夢が。/キング牧師)
 
You are fake news! (Donald Trump)
【前回】偽のニュースです!
【今回】ばかばかしいニュースだ!(ドナルド・トランプ)。
(拙訳:[CNNは]フェイクニュースだ!/トランプ大統領)
 
You may say I'm a dreamer. But I'm not the only one. I hope someday you'll join us. And the world will be as one. (John Lennon)
【前回】夢想家だって言うかもしれないけど、私だけじゃない。いつか、ぼくらと合流してくれるといいんだけど。そして世界は、ひとつのものになる。
【今回】夢想家だと言うかもしれません。でも、私はただ一人ではありません。いつかあなたたちが仲間になるといいですね。世界は1つになるでしょう。(ジョン・レノン)
(拙訳:夢想家だと君は言うかもしれないけれど、僕は一人じゃない。いつか君も一緒になれれば。そして世界は一つになる。/ジョン・レノン)
 
The madman is not the man who has lost his reason. The madman is the man who has lost everything except his reason. (G. K. Chesterton)
【前回】狂人は理性を失った人間ではない。狂人は、理性以外はすべてを失った男だ。
【今回】狂人は理性を失った人間ではない。狂人は理性以外のすべてを失った男である(G.K.チェスタトン)。
(安西徹雄訳:狂人とは理性を失った人のことではない。狂人とは、理性以外のあらゆる物を失った人のことである。/チェスタトン)
 
The safest general characterization of the European philosophical tradition is that it consists of a series of footnotes to Plato. (A. N. Whitehead)
【前回】ヨーロッパ哲学伝統の最も安全な一般的な特徴は、それがプラトンへの一連の脚注から構成されていることです。
【今回】ヨーロッパの哲学的伝統の最も安全な一般的な特徴は、プラトンへの一連の脚注から成り立っていることである(A.N.ホワイトヘッド)。
(拙訳:ヨーロッパ哲学の伝統について間違いなく言えるのは、その全てが、プラトン哲学へのひと続きの注釈に過ぎないということである。/ホワイトヘッド)
 
Violence sometimes may have cleared away obstructions quickly, but it never has proved itself creative. (Albert Einstein)
【前回】暴力は時々すぐに妨害を片付けるかもしれませんが、それは創造的に証明されたことはありません。
【今回】暴力沙汰はすぐに閉ざされたのかもしれないが、しかし、創造的自立は証明されていない(アインシュタイン)
(拙訳:暴力が、問題を手っ取り早く片付けるのに役立つことはある。しかし、暴力それ自身が創造的であったことは一度もない。/アインシュタイン)


キング牧師の文章を、「肌の色では判断されない」が「人格で判断される」という対比で訳すのがなかなか成功しないのですが、今回その点は出来ています。「性格の色」という訳は変なのですが、前回はこのbutの対比が1度も正しく訳せなかったので、すこしは進歩したのかも知れません。
ただ、さっき気づいたのですが、英文のJrのところにピリオドが抜けているので補ってJr.としてみたところ、訳文がまたおかしくなったので、これはたまたま訳せただけで、まだまだ安定してないです(笑)
まぁそれにしても、訳が正しいかどうかはともかく、この程度の規模の学習でも文法的に整った文がちゃんと生成されるという点で、Transformerはやはりすごいと思えますが。


ちなみにDeepLは完璧に訳してくれます。

私の4人の小さな子供たちが、いつの日か肌の色で判断されるのではなく、人格の中身で判断されるような国に住むことを夢見ている。(キング牧師)


なお、学習途中のモデルの性能を観察してみると、ある程度学習が進んだあとは、「この文はうまく訳せるようになったけど、こっちはむしろだめになった」みたいなことの繰り返しなので、もっと早めに打ち切ってもあまり変わらない気はしますね。


今回はどちらかというと、GPUを並列化した学習のテストのつもりだったので、後日、コーパスを400万件ぐらいに増やしてリトライするつもりです。

AWSの深層学習用GPUインスタンスのスペックと価格を一覧化した

つい先日も似たようなエントリを書きましたが、AWSのサイトでいまいち一覧化された情報がないことに怒りを感じたので、表にまとめました。
インスタンスを起動(作成)する画面からインスタンスの比較表をみることが出来ますが、そこではGPUの製品名やメモリは表示できません。で、各クラスの説明ページに飛ぶと、情報の有無がまちまちです。
結局知りたいことは以下のような点なので、ひとつの表にまとめました。

  • GPUの製品名(速度を左右する)
  • GPUメモリ(バッチサイズの限界を決めるので速度を左右する)
  • 時間あたりの価格
  • vCPU数(上限緩和申請をするときに必要)


下の画像のとおりですが、リージョンによって価格がけっこう違っていて、アメリカのリージョンにしておくほうが安いのでいいと思います。
vCPU上限はリージョンごとに管理され、申請も別々ですが、複数台同時に使うなら複数のリージョンで申請しておくのがいいと思います。というのも、利用実績が全くないアカウントで申請してみたところ、ディープラーニング用にGPUインスタンスを使うから上限緩和してくれと頼んでも、vCPU数8までしか認められず(笑)、それだとGPU1枚のインスタンスしか選べません。去年、50万円分ぐらい利用実績があったアカウントで頼むと、いきなりvCPU数64まで認められたので、GPU4連装のインスタンスも使えるようになりました。


ちなみにG4adってのもあるのですが、これはAMDのGPUが使えるやつです。私はCUDAを使うのでNVIDIAのGPUが載っているG4dnだけまとめています。
GPUメモリは合計値です。
表はクラスごとにvCPU数でソートしています。



ちなみに、GPUが搭載されたGクラスやPクラスのインスタンスは、慢性的にリソースが枯渇しているらしいです。東京リージョンの場合、p4はインスタンスの起動(作成)自体がなかなかできません。g5については、起動(作成)は出来たものの開始(利用)ができない状態が続いていたのですが、数時間待ってリトライしたらできました。
私は東京リージョンではGクラスでvCPU=192、PクラスでvCPU=96まで許可されていて、とりあえず東京リージョンで試しているのですが、アメリカのリージョンだともうちょっとリソースあるのかも知れません。アメリカのほうはまだ上限緩和申請中なので、あとで試します。

PyTorch初心者のメモ

以下は、PyTorchでのニューラルネット構築について、学んだ基礎的事項のメモです。

  • nn.ModuleというのはTransformerを含めたニューラルネットワークの部品を意味していて、nn.Moduleの__call__メソッドはforwardメソッドを呼ぶようになっているので、nn.Moduleを継承して作られたインスタンスは、関数の形で呼び出されると自動的にテンソルをforwardして結果を出力する。
  • PyTorchの計算グラフは、1つのバッチを処理する過程で生成される一時的なものである(動的グラフ)。ネットワーク上を、あるバッチ化されたテンソル(torch.Tensorクラスのインスタンス)が流れていく際、様々な操作が順次加わってどんどん中間テンソルが生成されていくが、それらが全てgrad_fnという属性を持っている。このgrad_fnには各テンソルに対する操作の情報が保存されていて、その総体が計算グラフということになる(個々のテンソルはそのグラフのノード)。
  • backward(バックプロパゲーション)は、torch.Tensorのメソッドになっている。これはどう動くかというと、ネットワーク内をforward - forward - ...と辿って形を変えてきたデータテンソル(ここでは出力)と、答えのラベルを、torch.nn.CrossEntropyLoss等で作られた誤差関数に突っ込むことで、まず誤差テンソルが生成される。この誤差テンソルのbackwardメソッドを呼び出すと、誤差テンソルのgrad_fnが起点となって、計算グラフ内の各中間生成テンソルのgrad_fnに保存されている情報に従って、前のテンソル、前のテンソル...と辿っていき、計算グラフ内で勾配が計算される。
  • 勾配は、計算グラフ上で(というか計算グラフを利用して)計算されて、パラメータテンソルの.grad属性に格納される。ここで、データもテンソルだが、パラメータもテンソルである点に注意。データテンソルの.grad_fnはデータに対する操作の情報を、パラメータテンソルの.gradha勾配の情報を持っている。
  • 次にoptimizer.step()を行うと、各パラメータテンソルに格納された勾配に基づいて、パラメータの値を更新する。

なんか凄そうな日英対訳コーパスを発見

LASER/tasks/WikiMatrix at main · facebookresearch/LASER · GitHub
Wikipediaから作られた多言語の対訳データで、英語と日本語の組み合わせをみると85万1000件ある。
これは中身も少し整理してみたが、結構品質は高い。明らかに変なデータも混じっていたり、日本語と英語が対応していないものもあったりするが、全体としては綺麗だと思う。
公式のGitHubによると、両言語の意味の一致度を機械的に判定したスコアがついてて、多くの言語において1.04ぐらいがバランスがいい(一致度とサンプルの多様性を考慮して)と書いてあった。私は、1.45にしてから、日本語と英語の文字量の比率が極端なものや、日本文が句点で終わらないもの、英文が大文字で始まらないものを除いて、40数万件を使おうかなと思う。


日本語SNLI(JSNLI)データセット - LANGUAGE MEDIA PROCESSING LAB
スタンフォード大がつくっている、自然言語処理による論理的な推論のベンチマークに使われるデータを日本語に機械翻訳したものらしいので、野生の対訳データではない。機械翻訳した後、BLEUスコアの閾値でフィルタリングしたデータが533,005件あって、これで自然言語タスクをやらせたら90%以上の性能があったと書いてある。
人力で訳を確認したものもあるがそれは数千件(devデータとして作られている)。
こっちは、本家SNLIのデータとこのJSNLIのデータを紐付ける作業からやらないといけなくて、加工がけっこうたいへんそうな気がする。


先日のエントリで私が構築した、7つのコーパスを組み合わせた混合コーパスは、色々処理して絞り込んだ結果128万件ぐらいなんですが、もし上記2つのコーパスが品質的に「全て使って大丈夫」そうだったら、これらを追加することで200万件規模になることになり、翻訳の精度がさらに上がりそうなので、あとで試そうと思います。