Chat VectorとMath Vectorは併用できるのか
はじめに
この記事は以下記事の続きになります。
Chat Vectorと呼ばれる、重みの足し引きでFine TuningなしにChat能力を事前学習モデルに付与できるという技術あります。
この発想から、Chat能力以外にも能力の切り貼りはできるのかという検証が前記事までの趣旨となります。
結果以下の通りです。
⭕️ Chat(論文)
× Code
⭕️ Math Reasoning
なので本記事では、
Chat+Math能力の両方を日本語ベースモデルに付与したら、どちらの効果も得られるのか
ということを試してみたいと思います。長くなるので結論だけ見たい方は『5.まとめ』までスキップしてください。
1. Chat強化モデルの確認
前回作成したMath強化モデルに加えて、Chat強化モデルも同じ作り方で作りました。詳細・手順は同じなので省きますが、Chat強化モデルもある程度上手くいくことが確認できています。
例えば、[INST] お気に入りの調味料は? [/INST]と投げると以下のように返ってくる様になりました。
Chat強化モデル
SkillTree-Chat (Chat Vector)
2. Skill Build (Chat + Math)
Chat VectorとMath Vectorの併用では、前回作ったMath強化モデルに先ほど作ったChat Vectorを重ねがけしていきます。レシピは以下の通りです。
2-1. モデルの取得
まずモデルを取得します。
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
# 数学強化モデルの取得
model_name = "HachiML/Swallow-MS-7b-v0.1-MathSkill-OpenMath"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="cuda",
)
次にChat Vectorを取得します。
skill_tree_name = "HachiML/SkillTree-Chat-Mistral-7B-v0.1"
# SkillTree
skill_tree = AutoModelForCausalLM.from_pretrained(
skill_tree_name,
torch_dtype=torch.bfloat16,
device_map="cpu",
)
デバイスはcpu/cudaのどちらでも良いですが、メモリの分散のため分けました。
2-2. Chat Skillの強化
これまでと同じように、Math強化モデルをベースにChat能力を付与します。
def apply_skill(model, skill_tree):
# excluded object
skip_layers = ["model.embed_tokens.weight", "model.norm.weight", "lm_head.weight"]
# apply skill
for k, v in model.state_dict().items():
# layernorm is also excluded
if (k in skip_layers) or ("layernorm" in k):
continue
vector = skill_tree.state_dict()[k]
new_v = v + vector.to(v.device)
v.copy_(new_v)
return model
model = apply_skill(model, skill_tree)
できたモデルをTokenizerと一緒に保存します。
model_name = "HachiML/Swallow-MS-7b-v0.1-ChatMathSkill"
tokenizer.save_pretrained(f"./models/{model_name}", repo_id=model_name, push_to_hub=True)
model.save_pretrained(f"./models/{model_name}", repo_id=model_name, push_to_hub=True)
Math+Chat強化モデル
3. Chat+Math強化モデルの検証
まず、Chat+Math強化モデルが数学的推論とChat形式の回答のどちらもできる様になっているかを確認します。
3-1. 日本語問題
元のSwallow-MS-7b-v0.1の日本語能力が落ちていないかを確認します。
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
# モデルの取得
model_name = "HachiML/Swallow-MS-7b-v0.1-ChatMathSkill"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
# 日本語問題1
prompt = "東京工業大学の主なキャンパスは、"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
回答は以下の通りです。自然な日本語で続きを生成しており、日本語能力は落ちていないと考えられます。一方で、東工大のキャンパスは大岡山、すずかけ台、田町にある様なので知識の欠落はあるかもしれません。(ハルシネーションが起こりやすくなる?)
3-2. Chat問題
Chat能力を試していきます。まずは単なるInstruction問題を聞いてみます。
# Chat問題1
prompt = "<s>[INST] What is your favourite condiment? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# Chat問題2
prompt = "<s>[INST] お気に入りの調味料は? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=128, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
回答は以下の通りです。英語の方はしっかりと回答できておりInstruction Tuningによる指示追従能力を獲得していると言えそうです。日本語の方は調味料を後半羅列し出しており、指示追従能力を獲得しているものの英語よりは能力が低そうです。
次にChat能力を確認します。
# Chat問題3
messages = [
{"role": "user", "content": "What is your favourite condiment?"},
{"role": "assistant", "content": "Well, I'm quite partial to a good squeeze of fresh lemon juice. It adds just the right amount of zesty flavour to whatever I'm cooking up in the kitchen!"},
{"role": "user", "content": "Do you have mayonnaise recipes?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
# Chat問題4
messages = [
{"role": "user", "content": "お気に入りの調味料は?"},
{"role": "assistant", "content": "私は新鮮なレモン汁を絞るのが大好きなんだ。キッチンで何を料理するにしても、ちょうどいい量のピリッとした風味を加えてくれる!"},
{"role": "user", "content": "マヨネーズのレシピはありますか?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
"Do you have mayonnaise recipes?"と聞かれて英語側ではマヨネーズを使ったレシピを、日本語ではマヨネーズの作り方を答えているという違いはあるものの、Chat能力は完璧と言って良さそうな回答です。
日本語側は英語のWebサイトをHTLMタグ毎抜き出してきた、みたいな回答になっているのが少し残念です。ただ会話は日本語で行おうとしているのがみて取れます。
3-3. 数学問題
次に数学的推論能力が失われていないかを確認します。
# 数学問題1
prompt = "Natalia sold clips to 48 of her friends in April, and then she sold half as many clips in May. How many clips did Natalia sell altogether in April and May?\n"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# 数学問題2
prompt = "ナタリアは4月に48人の友人にクリップを売り、5月にはその半分の数のクリップを売った。ナタリアが4月と5月に売ったクリップの数は?:\n"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
回答は以下の通りです。どちらも72で正解です。英語の方はただの除算ではなく整数徐算(//演算子)を使っているのが良いですね。
数学的推論能力は維持していると言えそうです。一方、日本語の能力は若干低い様な気がします。
4-4. 数学+Chat問題
最後にChat形式で数学的推論問題を投げかけてみます。
# 数学+Chat問題1
prompt = "[INST] ウェンのベビーシッターの時給は12ドル。昨日、彼女は50分間ベビーシッターをしました。彼女の収入はいくらでしたか? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# 数学+Chat問題2
messages = [
{"role": "user", "content": "ウェンのベビーシッターの時給は12ドル。昨日、彼女は50分間ベビーシッターをしました。彼女の収入はいくらでしたか?"},
{"role": "assistant", "content": "ウェンは1分あたり12/60=$<<12/60=0.2>>0.2を稼ぐ。50分働くと、0.2×50=$<<0.2*50=10>>10。#### $10"},
{"role": "user", "content": "ベティは100ドルする新しい財布を買うためにお金を貯めている。ベティは必要なお金の半分しか持っていない。両親はそのために15ドル、祖父母は両親の2倍を渡すことにした。ベティは財布を買うのにあといくらお金が必要か?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
回答は以下の通りです。Chatの形式は維持しておりChat能力は獲得していると言えそうです。
問題1では途中の50/60を1/2としてしまっており間違いです。問題2は正解しています。また、どちらも英語で回答しています。
4. 補足検証
次に以下を確認していきます。これによって、能力の重ねがけに効果があったのかを確認します。
Chat強化モデルが数学的推論ができないのか
Math強化モデルがChat形式の回答ができないのか
4-1. (参照)Chat強化モデルの数学能力の確認
ここではChat強化モデルが数学的推論ができないのかを確認します。
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "HachiML/Swallow-MS-7b-v0.1-ChatSkill"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
# 数学問題1
prompt = "Natalia sold clips to 48 of her friends in April, and then she sold half as many clips in May. How many clips did Natalia sell altogether in April and May?\n"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# 数学問題2
prompt = "ナタリアは4月に48人の友人にクリップを売り、5月にはその半分の数のクリップを売った。ナタリアが4月と5月に売ったクリップの数は?:\n"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
回答は以下の通りです。数学的推論能力は低いと言っても良さそうです。
つまり、Math+Chat強化モデルは、Math能力付与によって数学的推論能力を獲得したと言えます。
4-2. (参照)Math強化モデルのChat能力の確認
ここではMath強化モデルがChat形式の回答ができないのかを確認します。
まずは単なるInstruction問題を聞いてみます。
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_name = "HachiML/Swallow-MS-7b-v0.1-MathSkill-OpenMath"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, device_map="auto")
# Chat問題1
prompt = "<s>[INST] What is your favourite condiment? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# Chat問題2
prompt = "<s>[INST] お気に入りの調味料は? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=128, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
英語・日本語ともに少なくとも途中までは回答できています。Math Instruction Tuningにおいて、指示追従能力をある程度獲得しているのだと考えられます。
ただ、英語の方は途中から会話を想像して続けてしまっています。
次に、Chat能力を確認します。
# Chat問題3
messages = [
{"role": "user", "content": "What is your favourite condiment?"},
{"role": "assistant", "content": "Well, I'm quite partial to a good squeeze of fresh lemon juice. It adds just the right amount of zesty flavour to whatever I'm cooking up in the kitchen!"},
{"role": "user", "content": "Do you have mayonnaise recipes?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
# Chat問題4
messages = [
{"role": "user", "content": "お気に入りの調味料は?"},
{"role": "assistant", "content": "私は新鮮なレモン汁を絞るのが大好きなんだ。キッチンで何を料理するにしても、ちょうどいい量のピリッとした風味を加えてくれる!"},
{"role": "user", "content": "マヨネーズのレシピはありますか?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
回答は以下の通りです。英語の方はChat形式が崩れてしまっています。一方、日本語では前半に余計な文を出力していますがChat形式は維持しつつきちんと回答できています。
最後に、Math+Chat問題を与えてみます。
# 数学+Chat問題1
prompt = "<s>[INST] ウェンのベビーシッターの時給は12ドル。昨日、彼女は50分間ベビーシッターをしました。彼女の収入はいくらでしたか? [/INST]"
input_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
tokens = model.generate(input_ids.to(device=model.device), max_new_tokens=256, temperature=0.99, top_p=0.95, do_sample=True)
out = tokenizer.decode(tokens[0], skip_special_tokens=True)
print(out)
# 数学+Chat問題2
messages = [
{"role": "user", "content": "ウェンのベビーシッターの時給は12ドル。昨日、彼女は50分間ベビーシッターをしました。彼女の収入はいくらでしたか?"},
{"role": "assistant", "content": "ウェンは1分あたり12/60=$<<12/60=0.2>>0.2を稼ぐ。50分働くと、0.2×50=$<<0.2*50=10>>10。#### $10"},
{"role": "user", "content": "ベティは100ドルする新しい財布を買うためにお金を貯めている。ベティは必要なお金の半分しか持っていない。両親はそのために15ドル、祖父母は両親の2倍を渡すことにした。ベティは財布を買うのにあといくらお金が必要か?"}
]
encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt")
model_inputs = encodeds.to(device=model.device)
generated_ids = model.generate(model_inputs, max_new_tokens=512, do_sample=True)
out = tokenizer.batch_decode(generated_ids)
print(out[0])
回答は以下の通りです。
数学+Chat問題1(指示追従形式)は英語ではあるもののきちんと回答できています。一方、数学+Chat問題2(Chat形式)は何かしら計算を行おうとはしていますが支離滅裂です。
想像ですが、Math Instruction Tuningの際にChat形式の長文は取り扱われず、長文の回答となるとその能力が下がってしまう状態にあると考えられます。
結論として、Math強化モデルは一定程度指示追従能力は持つものの、長文になるとそこまでChat能力は高くないと言えそうです。したがって、Math+Chat強化モデルは、 Chat能力付与によってChat能力を強化できたと言えます。
5. まとめ
長くなってしまったのでまとめようと思います。Math強化モデルにChat Vectorを併用すると、
モデルが壊れることはない
数学能力をある程度維持しつつ、Chat能力も強化することができる
一方、英語で回答しやすくなる傾向が出てくる
と言えそうな結果となりました。
Chat Vector・Math Vectorともに英語で学習したものであるため、2つ合わせると英語で回答しやすくなるのでしょうか。
ただ、モデルとして程度使える能力は維持されていそうなのでかなり可能性がある技術だと感じました。
前回
前々回
参照
この記事が気に入ったらサポートをしてみませんか?