Ahogrammer

Deep Dive Into NLP, ML and Cloud

Universal Sentence Encoderをチューニングして多言語のテキスト分類

Googleが開発した多言語の埋め込みモデル「LaBSE」を使って多言語のテキスト分類」と題した記事を書いたところ、「Universal Sentence Encoder(以下、USE)と比べてどうなのか?」というコメントを見かけました。そこで、本記事では、多言語の埋め込み表現を作ることのできる「Multilingual USE(m-USE)」を使って、テキスト分類をしてみます。設定としては前回と同様、学習には英語、評価には日本語とフランス語のデータセットを使います。

記事では要点だけを紹介するので、コードについては以下のノートブックを参照してください。

文類似度

LaBSEの場合と同様に、TensorFlow Hubで公開されているモデルを使って、多言語の文類似度を計算してみます。m-USEには、TransformerベースのモデルとCNNベースのモデルがあります。Transformerベースのモデルは性能が高く、CNNベースのモデルは速度が速いという特徴があります。今回は、性能重視でTransformerベースのモデルを使用します。

以下の英語、イタリア語、日本語文の類似度を計算してみます。ここで、各言語の同一インデックスの文は同じ意味の文になっています。

english_sentences = [
  'dog',
  'Puppies are nice.',
  'I enjoy taking long walks along the beach with my dog.'
]
italian_sentences = [
  'cane',
  'I cuccioli sono carini.',
  'Mi piace fare lunghe passeggiate lungo la spiaggia con il mio cane.'
]
japanese_sentences = [
  '犬',
  '子犬はいいです',
  '私は犬と一緒にビーチを散歩するのが好きです'
]

類似度を計算した結果は以下のようになりました。左から英語と日本語、イタリア語と日本語、英語とイタリア語のペアとなっています。結果を見ると、LaBSEと同様、行列の対角成分の値が他より大きくなっていることがわかります。つまり、言語が異なっていても、同じ意味の文は類似度が高くなるように埋め込めているということを示唆しています。

f:id:Hironsan:20200918091807p:plain
各言語間の文類似度

テキスト分類

文を埋め込んで類似度を計算できることは確認したので、次はテキスト分類をしてみましょう。今回もAmazon Customer Reviews Datasetを使ってモデルの学習と評価を行います。Amazonの商品レビューを入力し、1/0の2分類で予測するモデルを作成します。前回のLaBSEでは、レビュー冒頭の128トークンを使って予測するモデルを作成しました。m-USEの場合、可変長の入力に対応しているので、理屈的には何トークンでも入力できるのですが、あまり長くても計算時間がかかるだけなので、今回は1024文字目までのトークンだけを用いています。

モデルのアーキテクチャは以下のようになっています。LaBSEの場合と同様、m-USEの上にドロップアウトと全結合層を足しただけです。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         [(None,)]                 0         
_________________________________________________________________
keras_layer_4 (KerasLayer)   (None, 512)               85213184  
_________________________________________________________________
dropout_3 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 2)                 1026      
=================================================================
Total params: 85,214,210
Trainable params: 85,214,210
Non-trainable params: 0
_________________________________________________________________

学習データと評価データの数は以下の通りです。冒頭で述べたように、学習データには英語、テストデータには日本語とフランス語を使って評価します。

en fr ja
train 32000
test 8000 8000 8000

実験結果(acc)は以下のようになりました。性能の傾向はLaBSEと同様に英語>フランス語>日本語の順でしたが、LaBSEと比べると3〜4%程度、性能が低くなるという結果になりました。この結果がすべてのデータセットに当てはまるとは思いませんが、今回の設定ではLaBSEの方がm-USEよりも良い結果となりました。

en fr ja
LaBSE 0.9300 0.8944 0.8473
m-USE 0.9056 0.8589 0.8055

参考資料

Googleが開発した多言語の埋め込みモデル「LaBSE」を使って多言語のテキスト分類

自然言語処理において、テキストをその意味を考慮しつつ固定長のベクトルに変換する埋め込みモデルは重要です。文の意味をよく表現したベクトルを作ることができれば、テキスト分類や情報検索、文類似度など、さまざまなタスクで役立ちます。本記事では、Googleが開発した多言語の埋め込みモデル「LaBSE」を使って、テキスト分類をする方法を紹介します。単なるテキスト分類では面白くないため、学習には英語のデータセットを使い、評価には日本語とフランス語のデータセットを使います。

記事では要点だけを紹介するので、コードについては以下のノートブックを参照してください。

LaBSE

LaBSEは、Googleが「Language-agnostic BERT Sentence Embedding」という論文で提案したモデルです。109の言語に対応しており、これらの言語を与えることで、文の埋め込み表現を生成できます。モデルは170億の単言語の文と60億の2言語の文ペアによって訓練されています。訓練したモデルを多言語の情報検索タスクで評価したところ、m~USEやLASERといったモデルと比べて良い結果を示すことが明らかになりました。以下は単言語の文と2言語の文ペアの数を表しています。

f:id:Hironsan:20200916145324p:plain
単言語の文と2言語の文ペアの数。画像はLanguage-Agnostic BERT Sentence Embeddingより。

文類似度

理屈的なところはともかく、実際にLaBSEを試した結果を紹介しましょう。LabseはTensorFlow Hubで公開されているので、まずはこちらを使って、多言語の文類似度を計算してみます。類似度計算には、下記のページ内のコードを利用しています。

以下の英語、イタリア語、日本語文の類似度を計算してみます。日本語と英語のペアを見るのがわかりやすいと思うのですが、各言語の同一インデックスの文は同じ意味を持ちます。たとえば、英語の1番目の文と日本語の1番目の文の意味は同じだとみなしています。したがって、LaBSEで文を埋め込んで類似度を計算した結果が、同じ意味の文は他よりも高い類似度になって欲しいということになります。

english_sentences = [
  "dog",
  "Puppies are nice.",
  "I enjoy taking long walks along the beach with my dog."
]
italian_sentences = [
  "cane",
  "I cuccioli sono carini.",
  "Mi piace fare lunghe passeggiate lungo la spiaggia con il mio cane."
]
japanese_sentences = [
  "犬",
  "子犬はいいです",
  "私は犬と一緒にビーチを散歩するのが好きです"
]

類似度を計算した結果は以下のようになりました。左から英語と日本語、イタリア語と日本語、英語とイタリア語のペアとなっています。結果を見ると、行列の対角成分の値が他より大きくなっていることがわかります。つまり、同じ意味の文は、たとえ言語が異なっていても、類似度が高くなるように文を埋め込めていることを示唆しています。

f:id:Hironsan:20200916145423p:plain
各言語間の文類似度

テキスト分類

LaBSEで文を埋め込んで類似度を計算できることは確認したので、次はテキスト分類をしてみましょう。今回はAmazon Customer Reviews Datasetを使ってモデルの学習と評価を行います。このデータセットには、Amazonの商品レビューやその評価が含まれています。評価は星1から5までの5段階なのですが、今回は簡単のために、星3のレビューを取り除いた後、星1と2を0に、星4と5を1にマッピングして使うことにします。つまり、2分類です。

モデルのアーキテクチャは以下の通りです。LaBSEの上にDropoutと全結合層を足しただけです。

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_word_ids (InputLayer)     [(None, 128)]        0                                            
__________________________________________________________________________________________________
input_mask (InputLayer)         [(None, 128)]        0                                            
__________________________________________________________________________________________________
segment_ids (InputLayer)        [(None, 128)]        0                                            
__________________________________________________________________________________________________
keras_layer (KerasLayer)        [(None, 768), (None, 470926849   input_word_ids[0][0]             
                                                                 input_mask[0][0]                 
                                                                 segment_ids[0][0]                
__________________________________________________________________________________________________
dropout (Dropout)               (None, 768)          0           keras_layer[0][0]                
__________________________________________________________________________________________________
dense (Dense)                   (None, 2)            1538        dropout[0][0]                    
==================================================================================================
Total params: 470,928,387
Trainable params: 470,928,386
Non-trainable params: 1
__________________________________________________________________________________________________

学習データと評価データの数は以下の通りです。冒頭で述べたように、学習データには英語、テストデータには日本語とフランス語を使って評価します。実際のところ、日本語やフランス語のデータの中にも英語のレビューが含まれているので取り除くべきですが、大勢に影響はないと考えられるので、今回はそのまま使うことにしました。ちなみに、2クラスの割合は等分です。

en fr ja
train 32000
test 8000 8000 8000

実験結果(acc)は以下のようになりました。以下は、何度か試した中での最高値であることに留意してください。英語でしか学習させていないにもかかわらず、フランス語や日本語に対しても、まずまずの予測をすることができています。実験する前は、英語のデータだけでFine-tuneして大丈夫か心配だったのですが、どうやらそれなりには予測できるようです。ここにはLaBSEの重みを固定して使った結果は載せていませんが、学習させた方が良い結果となりました。

en fr ja
test 0.9324 0.8943 0.8506

今回はテキスト分類に使いましたが、固有表現認識のような系列ラベリングに使ったらどうなるのかは気になるところです。

参考資料

Lambdaレイヤーを公開するためのシェルスクリプト

最近、AWS Lambdaをよく使っているが、その機能の一つとしてLambdaレイヤーがある。レイヤーにパッケージを取り込むことで、複数のLambda関数から使用可能になる。ビジネスロジックを共通化する、ビルドの手間を省く等の恩恵があるが、私的にはデプロイするファイルのサイズを小さくするのに重宝している。Lambdaの制限は結構きつくて、デプロイするファイルのサイズが大きくなり、デプロイに失敗するということが起きる。

Lambdaレイヤーにパッケージを取り込むには、パッケージをzip化してアップロードすればいいのだが、それがまた面倒くさい。pipディレクトリを指定してパッケージをインストールし、zipコマンドで圧縮した後S3にアップロードし、Lambdaコンソールから取り込む。また、単にどこでもいいからパッケージをインストールすればいいというわけでもなく、Lambdaの実行環境に合わせた環境でビルドしてやらないと実行に失敗する。手動でやるのは実に面倒くさい。

そういうわけで、一連の作業を一つのシェルスクリプトにしてみた。以下のスクリプトでは、Docker Lambdaを使ってパッケージをインストールし、それをzip化した後、Lambdaレイヤーにアップロードしている。不要なパッケージを除去してパッケージのサイズを小さくするような機能はないが、面倒くさいことをせずに、とにかくパッケージをアップロードしたいときに使える。

gist.github.com

以下のようにオプションを指定して実行するようになっている。nにはパッケージ名、rにはリージョン名、pにはPythonのランタイムを指定する。

sh publish_lambda_layer.sh -n spacy -r us-east-1 -p python3.7