こんにちは、Machine Learning部門の森長と申します。 Machine Learning部門は、プロダクト適用を目指した基礎研究&基礎研究のプロダクト適用の二軸を担当しています。基礎研究では、言語モデルの作成、文章のカテゴリ分類・クラスタリング、要約の検証等、プロダクトへの適用を見据えて研究テーマを設定しています。また、自然言語処理の盛り上がりに少しでも貢献できればと考え、言語モデルの公開を行っていますので、もしよろしければ使ってみてください。 今回は、弊社で公開している言語モデルについて書いていきます。 言語モデルにも色々な種類のモデルがあり、一口でこれというのは難しいですが、簡単に言うとすると、「単語列に対して確率を計算するモデル」です。 厳密には各言語モデルで目的が違うため、呼称が少しずつ異なりますが、本投稿では言語モデルという表現で統一させていただきます。 言語モデルを利用することで、例えば、文章の生成や単語の意味的な近さの計算を行えます。
弊社では、これらの言語モデルを組み合せることで、ビジネス文章の解析・構造化(文の分類やクラスタリング、企業名抽出等)を行っています。 弊社では、Qiitaで紹介記事を書き、以下の言語モデルを公開しています。 公開している学習モデルの詳しい説明はQiita記事を参照いただければと思います。 今回はせっかくなので、言語モデル作成当時の経緯等を順に振り返ります。 2018年11月某日.. 森長:「記事の分類の分類タスクの精度向上が頭打ちになってきた。。。記事中の「ライオン」という文字列が「企業のライオン」さんなのか「大西ライオン」さんなのか「百獣の王のライオン」さんなのか分からない。日本語が分からなくなってきた。。」 CTO有馬:「半年前に発表されたELMoを使うと文脈に応じた単語ベクトルを生成できるようだ。」 森長:「それだ!」 という会話のように、ビジネスニュースにおける日本語の語義曖昧性に悩まされていました。 弊社では「記事データの情報源自体の絞り込み」や「個人の嗜好に近い文章ベクトルによる絞り込み」等を行い、プロダクト側で語義曖昧性を解消していました。 ですが、個人の嗜好等によらず記事を構造化することを考えると、人と同様に文脈から語義を判断させる必要があります(人は文脈と自身の知識・常識を使って語義を判断していますが)。 そこで、文脈に応じた単語ベクトルを生成できるというELMoに着目しました。 ELMoは双方向LSTMを用いて学習させた言語モデルです。
ELMoによって、文脈を考慮した単語分散表現(単語ベクトル)を生成可能です。 例えば、以下の「人気」という単語のように、文脈によって意味が異なる単語でも、ELMoでは文脈を考慮して文脈ごとの「人気」の単語ベクトルを生成可能です。 ELMoの単語ベクトルの具体的な利用方法としては、ELMoで生成した単語ベクトルをfastText等の他の手法で生成した単語ベクトルと連結し、その単語ベクトルを用いてタスクを解くことで、精度の向上が見込めます。 2018年末頃に調査した範囲では、実用できそうなELMoの日本語モデルが公開されていませんでした(語彙の漢字に日本外の漢字が含まれる日本語モデルは存在※1)ので、弊社で作成することにしました。 ※1 現在(2020/6)はAllenNLPでの公開や日本語モデルを学習して公開されている方々がいらっしゃいます。 作成には、AllenNLP(オープンソースの研究用ライブラリ)を継承した以下のコードをベースに作成しました。 https://github.com/HIT-SCIR/ELMoForManyLangs さっそく、ビジネスニュース40万記事を教師データとして、学習してみたところ、CPU処理ではいつまでたっても終わらない。。。 今まで言語モデル(主にfastTextのモデル)を作成する際は、CPUのみで作成していましたが、この時からGPUを使って言語モデルを作成するようになりました。 弊社は、ELMoの日本語言語モデルを作成することで、文脈に応じて単語ベクトルを生成する武器を手に入れました。
と言ってもこの武器を使いこなすのがまたまた難しく、試行錯誤し、以下のような対応で、ELMoを用いてタスクの精度向上を実現しました。 この時からBERTの日本語モデルを作成するまでは、弊社の分類タスクにおいて、「fastText + ELMo + Attention」の組み合わせがベースラインになりました。 2018年12月某日.. 森長:「ELMoのモデル作成には、GPU使っても時間かかるなぁ。GPUの並列化等、検討しないと。」 CTO有馬:「話は変わるけど、ELMoが終わったら、transformerを調査して、BERTにトライしよう。GPUでも学習がなかなか終わらないらしいけど。」 森長:「うん...(白目)」 2018年10月頃から話題になっていたBERTですが、2018年11月頃にGoogle社から言語モデル(正確には事前学習済モデル)が公開されました。
当時は英語モデル、中国モデル、マルチリンガルモデルが公開されていました。 Google社公式のBERTモデルで日本語を試す場合は、以下の方法がありましたが、やはり言語特有の課題があるため、日本語モデルが欲しいと感じました。
- 日本語を英訳してBERTでファインチューニングを行い、その結果で分類したり、結果を和訳するパターン
- 翻訳の精度にかなりの影響を受ける。言語固有の意味を含めることが困難。
- マルチリンガルモデルをそのまま使うパターン等
- tokenizerの処理が日本語向けではない。vocabulary辞書に有効な日本語が少ない。 上記の点もあり、2019年1月頃には以下のように日本語の事前学習済モデルの作成や公開をしてくださった方々もいました。※2
- 汎用言語表現モデルBERTを日本語で動かす(PyTorch)
- BERT with SentencePiece を日本語 Wikipedia で学習してモデルを公開しました ※2 現在(2020/6)は様々なBERTの日本語モデルが公開されています。 BERTは汎用事前学習済モデルという位置づけですが、vocabulary辞書を用いるので、学習元データに依存することは明らかです。
弊社では、ビジネスニュース記事を取り扱っていますので、これらを学習元としてBERTを作成すれば、ビジネスに関するドメインで効果を発揮できると考えました。 双方向Transformerを用いて事前学習(MLM(=Masked Language Modeling)とNSP(Next Sentence Prediction)をした言語モデルです。
BERTをタスクごとにファインニューニングすることで、いくつかのベンチマークで従来手法より高い精度を出し(人間を越えたベンチマークもありました!)、また少量のデータでも精度を向上させることができるようになりました。 おおざっぱなイメージになってしまいますが、多くの手法が人間でいうと赤ちゃんから順番に学習させていたのに対し、BERTでは既にある程度言語を取得した(事前学習した)小学生から学習を始めさせたというようなものです。 この大規模な学習データで事前学習したモデルをファインチューニング(特定のタスクを追加で学習)させるという手法が色々なタスクに転用しやすく、画期的でした。 比較的データサイズが小さく取り回しがしやすいBERT-baseを作成することにしました。 まずは、tokenizerの修正から入りました。 公式のtokenizerは、日本語文をトークン化した場合、トークンが文字単位ぐらいまで分割されてしまいますので、この部分を修正しました。 弊社では、MeCab+Neologdの組み合わせで文章をわかち書きして、トークン化を行いました。
また、ビジネスニュースは新しいワードが日々造語で作られることが多いので、subwordは使わずに未知語は未知語として処理することにしました。
そのため未知語に対しては[UNK]となってしまいますが、単語単位の分析を行う固有表現抽出等のFine-tuning時の学習が容易になります。 学習元データとしては、ELMoでは40万記事でしたが、BERTは大量のデータで事前学習することが前提となっていましたので、400万のビジネスニュース記事を用いました。
この時点でバッチサイズが大きいとGPUにはのらなさそうだなと予感していました。 次に、TPUの利用です。ELMoのモデル作成の際の反省を生かし、もちろんGPUで最初はスタートしました。 ですが、思ったとおりバッチサイズが大きいと全然メモリにのらない。。。バッチサイズを小さくすると学習時間がとても長くなるし、精度もどうやら落ちるらしい。。。等の問題があり、TPUの利用に踏み切りました。
そもそもアーキテクチャとしてTPUとGPUは違いますので、GPUとの違いに難儀しながらも、公式実装を参考にTPUを使って、約4日で学習が無事完了しました。 さっそく教師あり学習のタスクをBERTを使って解いてみると、細かいチューニング無しで、今まで弊社がELMoやfastTextなどチューニングを色々加えてだしてきた精度を上回りました。
BERTが色々なベンチマークでSOTAを達成していることは認識していましたが、チューニングなしのこの結果にはもはや驚きしかありませんでした。 もちろん、タスクによっては他の手法が良いパターンもありますが、BERTの登場で弊社の教師あり学習のベースラインはBERTになりました。 一方、単語ベクトルをBERTから作成するという点ではあまり良い結果になりませんでした。
BERTで作成した単語ベクトルでは、あまり単語が似通っていない場合でも単語間コサイン類似度が高い傾向にありました。
そのため、単語の類似度のランキング付けには使えましたが、絶対評価でどれくらい似ているか(コサイン類似度が0.9以上等)という評価には利用できませんでした。 これは、BERTの単語ベクトルが512次元以上ある点及びコサイン類似度がベクトルの各要素を重み付けをせず均等に評価している点が原因で起こっているのではと考えています。 上記は教師あり学習であれば、ベクトルのどの要素を重要と見なすかファインチューニングで学習できますので、問題にはなりませんでした。 2019年6月某日.. 森長:「うぅ、BERTを皮切りに色々な事前学習した言語モデルが登場して、追い切れない。。。」 arXiv上の論文:「Autoencoding(自己符号化)ベースではなくAutoregressive(自己回帰)ベースの事前学習モデルを提案したよ!」 森長:「ARモデルの事前学習済言語モデルおもしろそう!とりあえず日本語モデル作ってみよう(現実逃避...)」 BERTを皮切りに色々な事前学習済モデルが登場しはじめ、私は事前学習済の言語モデルノイローゼ状態に。 日々色々なモデルを追っていましたが、一旦は特色がある(もしくは精度が大幅向上するような)事前学習済の言語モデルがでた時に日本語モデルを作ろうと決心しました。 ちょうどその頃に、BERTのようなAutoencoding(自己符号化)ベースではなく、Autoregressive(自己回帰)ベースの事前学習済言語モデルのXLNetが公開されました。
AEモデルでなくARモデルかつBERTの懸念点を解消するために作られたという点がおもしろそうでしたので、着手することに。 XLNetとは、自己符号化ベースであるBERTの以下懸念点を解消するために作られた、自己回帰ベースのモデルです。 予測対象の単語が複数あった場合、BERTは、自己回帰モデルのように予測対象の単語間の依存関係を考慮できない。 XLNetの論文やアルゴリズム等の紹介はとても丁寧に解説していただいている記事が多数ありますので、それらの記事を読んでいたただけると良いと思います。私も大変お世話になっています。 XLNetは、通常の自己回帰モデルとは異なり、単語の予測順序の入れ替えを行い、順方向・逆方向両方の依存関係を学習できるようにしたことが注目すべき点だと思います。 比較がしやすいようにBERTに合わせてXLNet-baseを作成することにしました。 BERTのモデル作成経験から、大規模な言語モデルを作成することに対する変な拒否感?(なんか大変そうだなー)という思いは既にありませんでしたので、さっそくBERTでの知見を生かして、作成することにしました。 まずは、tokenizerからです。
前回はtokenizerにMecab+Neologdを使いsubwordを使わないようにしましたが、以下の点で使いづらくなってしまいました。
- tokenizerに手を入れると、公式の実装のメソッドをオーバーライドしなければならないため、利用するためのハードルが少し高くなってしまう
- 未知語でもsubwordなどの手掛りがあったほうが良いパターンも多かった そのため、今回は公式実装には手を入れずに前処理の段階で以下のように処理をするようにしました。 公式実装ではSentencepieceが利用されていますが、日本語だとどのようにわかち書きされるか予測がたてられないため、MeCab + NEologdを利用して、文章を最初にわかち書きします。
その後、公式実装に従いSentencepieceでsubwordにも対応させ、トークン化しています。 つまり、MeCab+Neologdを利用することで形態素として正しく分割し、その上でSentencepieceを行うことで語彙のカバー範囲を広げています。 また、XLNetの公式githubでは、正規化手法としてNFKDを採用しています。そのため、公式githubのライブラリをそのまま使用すると、日本語の濁点・半濁点がロストしてしまいます。
日本語では、濁点・半濁点の有無で意味が変わる可能性もありますので、弊社ではNFKD及びNFKCで正規化した2つのモデルを作成することにしました。 今回はTPUで最初からスタート。ARモデルのためか事前学習には約8日かかりました。 さっそくBERTと比較してみました。 弊社の検証用タスク(記事の分類)においてはBERTを1%程度下回る性能となりました。また、自己回帰モデルの特性上、BERTと比較して計算時間も増加しており、利便性も低下しました。 とはいえ、単語間の関係性が重要になるタスク(固有表現抽出等)に対して適応した場合は違った結果が期待できますので、タスクによっては十分、選択肢の一つになりえます。 また、NFKD版とNFKC版の精度を比較しましたが、精度に大きな差はありませんでした。
濁点・半濁点がロストしても以下の理由で精度が変わらないのでは無いかと考えています。 が→か 、で→て 等の助詞でのロスト サービス→サーヒス 等の一般名詞や固有名詞でのロスト 2019年9月某日.. 森長:「事前学習済モデルはサイズが大きくてエッジ化しづらいしデプロイに時間がかかるから、ちょっと困るなぁ。蒸留を使ったDistilBERTやTINYBERT等もでてるからそちらもそのうち試してみよう」 arXiv上の論文:「全層でパラメータを共有することで、パラメータ数をBERTから大幅削減したよ!」 森長:「な、なんだってー!(パラメータの共有をしたら、事前学習で収束するまでに時間かかりそう。。)」 様々な事前学習済の言語モデルが多数提案されている中、モデルサイズが増加する傾向にありました。 事前学習済モデルのサイズを大きくすると性能が向上する傾向にありますが、学習時間が長くなったりメモリにのらなくなったり、作成の上での制約が(費用面の制約も)増えてきます。また、エッジ化等を検討すると、モデルサイズは小さいほうが嬉しいです。 そのため、モデルサイズの軽量化を行う研究(DistilBERTやTINYBERT等)が各所で進められているように感じました。
その折に、SOTAを突き詰めたものではなく、精度を維持・向上させつつもBERTを軽量化しているALBERTが登場しました。 ALBERTとは、BERTを以下の手法を用いて、軽量かつ高速に学習できるよう提案されたモデルです。 ここでもBERTと比較するためにALBERT-baseを作成することにしました。 BERT、XLNetのモデル作成知見を元に作成を始めました。 まずは、tokenizerからです。
XLNetと同様に公式実装を変更せずに前処理でMeCab + NEologdを利用して、文章をわかち書きします。その後、公式実装に従いSentencepieceでトークン化しています。 また、XLNetのモデルを作成した際にNFKDとNFKCで結果に明確な差異が無かったため、今回は公式実装に従いNFKDで正規化しました。 今回もTPUで最初からスタート。事前学習にはBERTとほぼ同じ約4日かかりました。 また、TPUの費用が嵩んだたため、プリエンプティブルTPUを使うようにしました。この一連のモデル作成で個人的にはTPUとかなりお友達になれた気がします。 弊社の検証用タスク(記事の分類)においては、ALBERT-baseがBERT-baseを1%程度下回る性能となっていましたが、ALBERTはパラメータ数がBERTに比べ大幅に削減されている中で、この精度は十分実用的です。 論文でも同様にbaseモデルの比較ではALBERTの性能が少しだけ低く報告されていますが、ALBERTの凄いところは、BERT-baseモデルよりも少ないパラメータ数(モデルサイズ)のALBERT-largeで、BERT-baseの性能を越えています。
(具体的な数値は論文のTable 2をご参照ください。) リソースが限られている中で、モデルサイズが50〜500MB程度に抑えられることは以下の点でとても使いやすかったです。(モデルサイズが大きいと何かと待ち時間が増えてしまいます…) いかがでしたでしょうか。 弊社の公開した言語モデルについて、簡単にですが経緯を振り返ってみました。 さっと流してはいますが、作成中は前処理や実際にどのように処理されているのかを追うために、かなり時間がかかりました。
しかし、実際に作ってみると言語モデルのさらなる理解に繋り、大変良い経験になりました。 (バッチサイズの変更やセンテンス長の変更を行い、言語モデルを多数比較したため、少しばかり費用が嵩んでしまいましたが。。。) 今後もおもしろい言語モデルを公開いただくことがあれば、ビジネスニュース記事を学習元にした日本語モデルを公開していきたいと考えています。言語モデルとは
弊社で公開している言語モデル一覧
ELMo
ELMoとは
ELMo日本語モデルの作成
ELMoの効果
BERT
BERTとは
BERT日本語モデルの作成
BERTの効果
XLNet
XLNetとは
XLNet日本語モデルの作成
XLNetの効果
ALBERT
ALBERTとは
ALBERT日本語モデルの作成
ALBERTの効果
終わりに