13億のパラメータを持つ日本語GPTでFew-shot推論を試してみる

こんにちは、R&Dの伊藤です。「〇〇 is all you need」系の論文が多すぎて何が本当に必要なのか悩みながら機械学習タスクに取り組んだりしています。

今回は先日公開されたrinna社の日本語GPTモデルを使って遊んでみた記事になります。

はじめに

GPTは簡単に言えば「超高性能な言語モデル」であり、主に文章生成に利用されることが多いです。 過去にGPT-2がフェイクニュース等を簡単に生成できることによる危険性から小規模モデルしか公開されなかったり、GPT-3が複数の自然言語処理タスクでSOTAに近い記録を出すなど、自然言語処理の分野で期待されているモデルの1つとなります。

今回公開された日本語GPTモデルはなんとパラメータ数が13億にもなるとのことで、GPT-2の最大モデル(15億パラメータ)に迫る程のモデルとなっています。rinna社は過去も3.3億パラメータのGPTを公開していましたが、その4倍ものパラメータ数を持つモデルと考えるとその巨大さが実感できるでしょう。 このようなモデルが商用利用可能なライセンスで公開されているというのはとてもありがたいですね。

今回はこの日本語GPTモデルを使用して、Few-Shotの感情分析を行なっていきたいと思います。

日本語GPTモデルを動かしてみる

今回紹介するモデルはHugging Faceに公開されており、Pythonの自然言語処理ライブラリであるtransformersを使用することで簡単に扱うことができるようになっています。

pip install torch
pip install transformers

まずはモデル紹介ページのチュートリアルを参考に文章生成を行ってみましょう。 手始めに我が社の経営理念の最初の1文を入力として、続きがどうなるか生成させてみます。

import torch
from transformers import T5Tokenizer, AutoModelForCausalLM

# トークナイザーとモデルの準備
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt-1b")
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt-1b")

# 続きを生成したいテキスト
text = """
世界の人々に大きく良い影響を与える普遍的なテクノロジー・サービス・ビジネスモデルを創り出すことを目的として事業に取り組む。
"""

# テキストのエンコード
token_ids = tokenizer.encode(text, add_special_tokens=False, return_tensors="pt")

# 文章生成
with torch.no_grad():
    output_ids = model.generate(
        token_ids,
        do_sample=True,
        max_length=100,
        min_length=100,
        top_k=500,
        top_p=0.95,
        pad_token_id=tokenizer.pad_token_id,
        bos_token_id=tokenizer.bos_token_id,
        eos_token_id=tokenizer.eos_token_id,
        bad_word_ids=[[tokenizer.unk_token_id]]
    )

# テキストのデコード
sentences = tokenizer.batch_decode(output_ids.tolist())
for sentence in sentences:
    print(sentence)

生成された文章は以下の通りです。 今回はmax_lengthmin_lengthを100に設定して生成される文の長さを固定しているため文章は途切れていますが、これらのパラメータを調整すればもっと長い文章を生成することも可能です。 生成された内容は実際の経営理念とは大きく異なりますが、「経営理念っぽい」文章であるように感じます。

世界の人々に大きく良い影響を与える普遍的なテクノロジー・サービス・ビジネスモデルを創り出すことを目的として事業に取り組む。サイバー空間で全ての人々が「インターネットによって何が変わったのか」「何が出来るようになったのか」「これからはどんな可能性があるのか」をタイムリーに享受可能な世界を創造し、これを実現することが同社のミッション。日本国内における事業展開も、海外の大きな流れと連動している。国内大手を中心に顧客基盤を拡大すると同時に、新規事業にも注力し、グローバルなスケールの中で更なる成長を目指す。【具体的には】世界的に

Few-shotで推論を試す

次に、このGPTモデルを使用して分類問題を解いてみます。 GPTはファインチューニングを使用しての学習も可能ですが、GPT-3の論文ではパラメータの変更を行わず少量の例を与えることで問題を解かせるFew-shot推論について言及しています。 よく混同されることが多いですが、この論文で使用されるFew-shotは機械学習の分野で使われるFew-shot Learningとは意味が違うため注意が必要です。

今回は、いくつかのタスクをFew-shotで日本語GPTで推論してみます。 新しく公開されたjapanese-gpt-1b(以下新モデル)に対する比較として、rinna社が過去に公開しているjapanese-gpt2-medium(以下旧モデル)でも同様の推論を試してみました。

感情分析

まずは感情分析です。 与えられた文がポジティブかネガティブかを判定するように例を与えます。 今回期待する出力は「ポジティブ」か「ネガティブ」となるため、generate関数のmax_lengthmin_length引数の値を調整することで生成される単語を1語になるように調整しました。

import torch
from transformers import T5Tokenizer, AutoModelForCausalLM


# gpt-1b
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt-1b")
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt-1b")

# gpt2-medium
# tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
# model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt2-medium")

# タスクの内容とタスクの例
# 推論結果としてはポジティブを期待
text = """
ポジティブかネガティブかを判定する:

私は元気です:ポジティブ
とてもつらい:ネガティブ
このゲームはとても楽しい:
"""

token_ids = tokenizer.encode(text, add_special_tokens=False, return_tensors="pt")

input_length = len(token_ids[0])
generate_length = 1
with torch.no_grad():
    output_ids = model.generate(
        token_ids,
        do_sample=True,
        max_length=input_length+generate_length,
        min_length=input_length+generate_length,
        num_return_sequences=10,
        top_k=500,
        top_p=0.95,
        pad_token_id=tokenizer.pad_token_id,
        bos_token_id=tokenizer.bos_token_id,
        eos_token_id=tokenizer.eos_token_id,
        bad_word_ids=[[tokenizer.unk_token_id]]
    )
sentences = tokenizer.batch_decode([tokens[input_length:] for tokens in output_ids.tolist()])
for i, sentence in enumerate(sentences):
    print('{}回目: {}'.format(i+1, sentence))

上記のコードをそれぞれのモデルで実行した結果が以下になります。

# 新モデル
1回目: ポジティブ
2回目: 私は
3回目: ポジティブ
4回目:
5回目: ネガティブ
6回目: ネガティブ
7回目: ポジティブ
8回目: ポジティブ
9回目: とても
10回目: ポジティブ

# 旧モデル
1回目:
2回目: ストーリー
3回目: とにかく
4回目: 何も
5回目: 面白い
6回目: 本当に
7回目: ネ
8回目: 楽しい
9回目: 楽しい
10回目: ポ

新モデルと旧モデルの出力結果には差が大きく出ています。 新モデルが「ポジティブ」や「ネガティブ」を複数回出力できている一方、旧モデルはそれらの結果を一回も得られていません。 新モデルの結果にしても出力が安定しているとは言えませんが、期待する出力である「ポジティブ」が最も多い結果となっています。

計算

次にGPTで計算問題を解かせてみます。 GPT-3の論文では2桁同士の加算ならばFew-shotで100%の精度が出ているため、今回は1桁同士の加算を試してみました。

GPTに入力するテキストを次のように変更します。

text = """
計算結果を出力:

2+3=5
5+4=9
3+1=4
1+8=9
4+3=7
5+2=7
6+1=
"""

結果は以下の通りです。

# 新モデル
1回目: 7
2回目: 10
3回目: 10
4回目: 8
5回目: 9
6回目: 6
7回目: 3
8回目: 6
9回目: 9
10回目: 6

# 旧モデル
1回目: 9
2回目: 7
3回目: 10
4回目: 9
5回目: 9
6回目: 4
7回目: 7
8回目: 12
9回目: 9
10回目: 10

新モデルと旧モデル共に数字を出力してはいますが、結果は安定していません。 いくつか答えとなる7が出力されていますが、他の結果を考えるとほぼ偶然であると考えられます。

おわりに

今回は13億のパラメータを持つGPTにおいてFew-shotでタスク推論が行えるかを試してみました。 従来のモデルと比べてパラメータが増えたことにより、Few-shotでもタスクによってはある程度の性能が期待できると感じました。 日本語のGPTにおいては、Few-shot推論においてタスクやその例をどのように与えるかの知見がまだ存在していないため、時間があればそれらの考察も行なっていきたいと思います。

オプティムでは自然言語処理に興味のあるエンジニアを募集しています。