洞窟の比喩

μετὰ ταῦτα δή, εἶπον, ἀπείκασον τοιούτῳ πάθει τὴν ἡμετέραν φύσιν παιδείας τε πέρι καὶ ἀπαιδευσίας. ἰδὲ γὰρ ἀνθρώπους οἷον ἐν καταγείῳ οἰκήσει σπηλαιώδει, ἀναπεπταμένην πρὸς τὸ φῶς τὴν εἴσοδον ἐχούσῃ μακρὰν παρὰ πᾶν τὸ σπήλαιον, ἐν ταύτῃ ἐκ παίδων ὄντας ἐν

サカモトツイートジェネレータ改

これは52代アドカレ5日目の記事になります。 → 徒然

皆様こんばんは、52代CG研究会のΙΔΈΑです。本日もお足元の悪い中、こちらの記事にお越しいただき誠にありがとうございます。

 

皆様は"サカモトツイートジェネレータ"をご存じでしょうか。これはサカモトカレンダーへ提出すべき"言"に頭を抱えた私によって開発されてしまったもので、サカモトさん風の文を生成してくれる逸品です。たとえばあの"空想サカモトbot"はこのサカモトツイートジェネレータをもとに運用されていたりします。気になる方は昨年の52代アドカレを見てみるとよいかもしれません。

adventar.org

このサカモトツイートジェネレータですが、実はいくらかの問題点を抱えています。それは構文的なものであったり意味的なものであったり、決して少なくはありません。やはりそれらから目を背けたままおめおめと日々を過ごし続けるわけにはいきませんよね?

今回の記事はサカモトツイートジェネレータの新たな可能性を見つける旅になります。どうか気軽に読んでみてください。

f:id:idea_misw:20201102182008p:plain

おさらい

昨年末の私が頭を悩ませていたのはサカモトさんが呟きそうな文を生むということでした。これはサカモトさんにもとづく言語モデルを構築する問題に帰着させられます。

言語モデルとは一連の単語に与えられる確率の分布で、文などの確からしさを表すものになります。出力される文の妥当性を判断する目的で、たとえば音声認識機械翻訳に用いられるそうです。一方で言語モデルが与えられたとき、それにもとづいて後に続く単語を選択していくことにより"確からしい文"を生成することができます。これを応用すれば"サカモトさんらしい文"を得ることが可能となるかもしれません。

したがってサカモトツイートジェネレータが解くべき問題は"サカモト言語モデル"の構築ということになります。

 

零式サカモトツイートジェネレータは上記の問題をマルコフ性に注目して解いたものでした。マルコフ性というのは未来の状態が現在にしかよらないというもので、これが仮定された言語モデル n-gram言語モデルとよばれます。単語列 w_1 \cdots w_Kの出現確率は次のようにして得られることになります。

 \displaystyle P(w_1 \cdots w_K) = \prod_{i=1}^K P(w_i | w_{i-1} \cdots w_{i-(n-1)})

今回の場合においては存在するサカモトツイートを手がかりに最尤推定を行い、上式右辺の条件付き確率を取得していくことでモデルを構築していくことになります。

 

 n-gram言語モデルというアプローチは簡単かつ強力なものですが、弱点もあります。それは単語の予測に際して大域的な文脈を参照できないことです。たとえばbigram言語モデルにおいて"ホカホカのアチチ"という文の出現確率は次のように計算されます。

 \displaystyle P(ホカホカのアチチ) = P(アチチ|の)P(の|ホカホカ)P(ホカホカ|\_)

この例だとbigram言語モデルは"ホカホカ"の後ろに"の"、"の"の後ろに"アチチ"が来ることしかわかりません。ゆえに"ホカホカ"と"アチチ"が直接結びつかないのです。 対策として nを大きくすることが考えられますが、これは小規模なコーパスに対する相性がよくありません。データが少ない場合、確からしいはずの n-gramが出現せず確率の推定ができないからです。

上のような欠点を解消すべく、ニューラルネットワークの力を借りることを考えてみましょう。ニューラルネットワークとは昨今のバズワード的な存在で、あらゆるプロブレムにソリューションをもたらすサムシングです(適当)。詳細な説明はインターネットの海にいくらでも浮かんでいると思うので、どうか必要に応じて調べてみてください。

 

数あるニューラルネットワークのうち、今回はTransformerというものを使います。

arxiv.org

Transformerとは一口にいえば、ニューラルネットワークを時系列データに対応させたRNNの亜種であるLSTMをエンコーダ・デコーダとして並べたSeq2seqという学習の性能を向上させたAttention Mechanismだけに注目したSelf-attentionにもとづくニューラルネットワークアーキテクチャです。これはあまりにも杜撰な説明ですが、Transformerの経緯や理論はたとえば次の本を読んだり次のサイトを見たりすればわかるみたいです。

www.oreilly.co.jp

jalammar.github.io

このTransformerは先述の言語モデルに適用することができます。あえて抽象的に説明すれば、理論上RNNやTransformerによる言語モデルは次に出力する単語をこれまで出力したすべての単語たちを考慮しながら推測します。これにより文脈が考慮された文の生成が期待されるのです。やったでおい。

実践

それではTransformerにもとづくサカモト言語モデルの構築を実践してみましょう。Transformerの言語モデルを試してみるにあたり、今回はFairseqというものを使います。

github.com

Fairseqとは"Facebook AI Researchが提供する、Seq2seq学習のモデリングに特化したツールキット"で、翻訳や要約などのタスクにまつわる様々な学習を実現するものになります。Fairseqができることは実に多く、言語モデルの学習も例によってカバーされています。

 

言語モデルの学習については公式のExamplesが提供されているので、それに倣いつつ進めていきます。また学習はGoogle Colaboratoryの上で、GPUとともに行います。

前処理としてサカモトツイートを形態素解析しておく必要があります。今回はJUMAN++というシステムを採用します。2000個のサカモトツイートを単語に分割し、それを訓練データとしましょう。

nlp.ist.i.kyoto-u.ac.jp

データの前処理も終えいよいよ学習を開始したいのですが、それに際して多くのハイパパラメータを設定する必要があります。これに関しては正直よくわからないので基本Examplesのものを流用することにします。ただし--sample-break-modeの引数だけはnoneからeosに変更しておきましょう。これによって学習するサンプルの単位がブロック(単語を決められた数だけまとめ上げたもの)から文になります。

!fairseq-train --task language_modeling \
    data-bin/sksk_sskn \
    --save-dir checkpoints/transformer_sakamoto \
    --arch transformer_lm --share-decoder-input-output-embed \
    --dropout 0.1 \
    --optimizer adam --adam-betas '(0.9, 0.98)' --weight-decay 0.01 --clip-norm 0.0 \
    --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-updates 4000 --warmup-init-lr 1e-07 \
    --tokens-per-sample 64 --sample-break-mode eos \
    --max-sentences 16 --update-freq 2 \
    --fp16 \
    --max-update 50000 \
    --no-epoch-checkpoints

ハイパパラメータの指さし確認も済んだところで、いよいよモデルに学習してもらいましょう。

 

now learning... 🐳

いざ

学習が終わったようなので、実際にサカモトツイートを生成してみます。言語モデルからのサンプリングはまた別のExampleを参考に行います。またもやいくつかのハイパパラメータが設けられていますが、ここも勢いよく設定していきます。

>>> from fairseq.models.transformer_lm import TransformerLanguageModel
>>> sakamoto_lm = TransformerLanguageModel.from_pretrained('checkpoints/transformer_sakamoto', 'checkpoint_best.pt', data_name_or_path='data-bin/sksk_sskn')
>>> sakamoto_lm.sample('ざむ', beam=5, sampling=True, sampling_topk=10, temperature=0.8)
'ざむ ちゃん の 話 を して いる'

それでは出力のサカモト言語モデルによって生成されたサカモトツイートの例を以下に示します。

良い例

  • こころ の 話 を して る けど ……
  • ご飯 と いう こと は ざむ ちゃん を して い ます
  • アイカツ を して いる ので 、 話 を し ます
  • イベント を 見て る けど …… …… ! ?
  • マジ の 絵 を 描き たい !
  • ロータリー の 絵 を 見 たい
  • 力 が ある ので ……
  • 雑貨 に なり たい ! ?

悪い例 

  • 5 5 5 5 5 5 5 5 5 5 5 5 ッ ッ ッ ッ ッ ッ ッ ッ ッ ッ
  • どうでも を して いる
  • やり たい たい たい !
  • トカゲ を 描く の お 願い 願い し たい ! ?
  • ピカチュウ を 破壊 破壊 破壊 を し ない んです か ?
  • 教室 ” ” ” ” ” を する
  • 関数 関数 関数 関数 関数 ( ( ( ( C ( ( ( ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )
  • 「 「 」 」 は 」 と か ? ! ? ? ? 」 」 と 思って る

 これ、どうですか?

名状しがたい考察のようなもの

改の名を謳ってはいるものの、とくに性能が向上されたわけではありませんでした。目的は生成文の意味的な品質を改善することでしたが、むしろ構文的な品質が落ちてしまっています。難しいよね、ジッサイ。

しかし意味的な性能の向上がまったく見られなかったというわけでもありません。たとえば良い例にある"ご飯ということはざむちゃんをしています"という文は、距離のある"ご飯"と"ざむちゃん"の単語が適切に(?)結びついています。偶然の産物という可能性もありますが、これこそは今回の改に期待した出力ということになります。センキューセンキュー。

 

上の例には良いものと悪いものを同じ数だけ示していますが、実際はほぼすべての出力が悪い例のようなかたちをしています。このような得られる文がしばしば文法的に正しくないことやある単語を繰り返し出力してしまうことというのはそもそもニューラルネットワークにもとづく生成タスクの根本的な問題と聞くので、これらの解決は決して容易ではないでしょう。

一つの対策として事前学習の適用が考えられるかもしれません。これは言語についていえば、大規模なデータからモデルにあらかじめ言語の特徴を理解しておいてもらい、それらの情報を目的のタスクに流用させるといったようなアプローチです。代表的なものとしてOpenAIのGPTが一つ挙げられるのではないでしょうか。

openai.com

GPTというのはGenerative Pre-Training(Generative Pre-trained Transformerかも)の略で、内容はまさにその名のとおりです。このGPTはまるでポケモンのように進化を続けており、進化系であるGPT-2やGPT-3は言語モデル的アプローチによってあらゆるプロブレムにソリューションをもたらしているみたいです(適当)。

中でもGPT-2については日本語による事前学習モデルみたいなものが公開されていたりいなかったりするようなので、そのようなリソースを適切に活用するとさらなる性能の向上が可能となるかもしれません。

 

それ以外にもハイパパラメータをチューニングしたり形態素解析器を取り替えたり、学習データを増やしたりクリーニングしたり、考えられる手がかりはいくつもあります。とくにTransformerのモデルはハイパパラメータに敏感という話もちらほら聞かれるので、試してみる価値はあるのかもしれません。

サカモトツイートジェネレータはまだ、進化の余地を残しているのです。

以上

このあたりで今回の旅は終了となります。ずばり結果が良いものかと言われると微妙なところですが、なにかこう興味深さみたいなものは伝わったのではないでしょうか。

面白いですよね、こういうの。私は面白いと思います。

ちなみにですが、今回得られたサカモト言語モデルはとくに公開したりしないつもりです。botになったりもしないと思われます。永久保存版。

 

それではまた次回、お会いしましょう。お相手はΙΔΈΑ、この一名でした。ばいばい。