File size: 11,894 Bytes
5e67680
 
 
 
 
 
 
 
 
7a8d7d7
5e67680
 
 
7a8d7d7
5e67680
 
 
 
 
7a8d7d7
 
 
 
 
 
 
 
 
 
dc21d7b
5e67680
7a8d7d7
5e67680
7a8d7d7
 
 
 
 
 
5e67680
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a8d7d7
5e67680
 
 
 
 
 
7a8d7d7
 
5e67680
7a8d7d7
 
 
 
 
 
5e67680
 
 
 
 
7a8d7d7
 
 
 
 
 
 
 
 
 
 
5e67680
 
 
 
 
 
 
7a8d7d7
5e67680
 
 
 
 
 
 
 
 
7a8d7d7
 
 
 
5e67680
 
 
7a8d7d7
 
 
 
 
 
 
 
 
 
5e67680
 
 
7a8d7d7
5e67680
 
7a8d7d7
 
 
5e67680
 
 
 
7a8d7d7
 
5e67680
 
 
 
 
7a8d7d7
5e67680
7a8d7d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e67680
 
7a8d7d7
5e67680
7a8d7d7
5e67680
 
7a8d7d7
 
5e67680
 
 
7a8d7d7
 
5e67680
 
 
 
 
 
7a8d7d7
5e67680
7a8d7d7
5e67680
7a8d7d7
 
5e67680
 
7a8d7d7
5e67680
 
 
 
 
 
7a8d7d7
 
 
 
63bd90f
 
 
 
 
7a8d7d7
 
5e67680
 
 
 
7a8d7d7
 
5e67680
7a8d7d7
5e67680
7a8d7d7
 
5e67680
7a8d7d7
 
5e67680
7a8d7d7
 
 
 
 
5e67680
 
7a8d7d7
 
5e67680
 
 
 
7a8d7d7
5e67680
7a8d7d7
5e67680
 
 
 
590f060
5e67680
7a8d7d7
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
---
language: ja
tags:
- ja
- japanese
- gpt
- text-generation
- lm
- nlp
- conversational
license: mit
datasets:
- kunishou/databricks-dolly-15k-ja
- kunishou/oasst1-89k-ja
widget:
- text: >-
    <s>\n以下は、タスクを説明する指示です。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n日本で一番広い湖は?\n[SEP]\n応答:\n
---

# 更新履歴
- 2023年5月7日
  
  「[oasst1-89k-ja](https://huggingface.co/datasets/kunishou/oasst1-89k-ja)」データセットを追加して**対話システム**に対応しました。1024トークンまで会話履歴を保存できます。
  前回のモデルで行った質疑応答の正答率は今回のモデルで下がりました。「日本で一番広い湖は?」が91%から89%、「世界で一番高い山は?」が84%から73%に下がりました。(対話は分けた方が良かったのか、それともoasst1の質が良くないとか)

- 2023年4月13日

  「[japanese-gpt-1b](https://huggingface.co/rinna/japanese-gpt-1b)」モデルを「[databricks-dolly-15k-ja](https://huggingface.co/datasets/kunishou/databricks-dolly-15k-ja)」データセットで**RLHF** (人間のフィードバックからの強化学習)しました。

# dolly-japanese-gpt-1b

1.3Bパラメータの日本語GPT-2モデルを使用した対話型のAIです。VRAM 7GB または RAM 7GB が必要で、問題なく動作すると思われます。

rinna社の「[japanese-gpt-1b](https://huggingface.co/rinna/japanese-gpt-1b)」を、
日本語データセット「[databricks-dolly-15k-ja](https://huggingface.co/datasets/kunishou/databricks-dolly-15k-ja)」、
「[oasst1-89k-ja](https://huggingface.co/datasets/kunishou/oasst1-89k-ja)」、
「[OjousamaTalkScriptDataset](https://github.com/matsuvr/OjousamaTalkScriptDataset)」、
「[train_data/zundamon.json](train_data/zundamon.json)」
を使用して学習させました。

学習データやモデルを作成および配布してくださった方々に心から感謝申し上げます。

# モデルの使用方法

## モデルの読み込み

```python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tokenizer = AutoTokenizer.from_pretrained("inu-ai/dolly-japanese-gpt-1b", use_fast=False)
model = AutoModelForCausalLM.from_pretrained("inu-ai/dolly-japanese-gpt-1b").to(device)
```

## ChatGPT/GPT-4によるサンプルコード(少し修正)

```python
MAX_ASSISTANT_LENGTH = 100
MAX_INPUT_LENGTH = 1024
INPUT_PROMPT = r'<s>\n以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{instruction}\n[SEP]\n入力:\n{input}\n[SEP]\n応答:\n'
NO_INPUT_PROMPT = r'<s>\n以下は、タスクを説明する指示です。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{instruction}\n[SEP]\n応答:\n'
USER_NAME = "User"
ASSISTANT_NAME = "Assistant"

def prepare_input(role_instruction, conversation_history, new_conversation):
    instruction = "".join([f"{text} " for text in role_instruction])
    instruction += " ".join(conversation_history)
    input_text = f"{USER_NAME}:{new_conversation}"

    return INPUT_PROMPT.format(instruction=instruction, input=input_text)

def format_output(output):
    output = output.lstrip("<s>").rstrip("</s>").replace("[SEP]", "").replace("\\n", "\n")
    return output

def generate_response(role_instruction, conversation_history, new_conversation):
    # 入力トークン数1024におさまるようにする
    for _ in range(8):
        input_text = prepare_input(role_instruction, conversation_history, new_conversation)
        token_ids = tokenizer.encode(input_text, add_special_tokens=False, return_tensors="pt")
        n = len(token_ids[0])
        if n + MAX_ASSISTANT_LENGTH <= MAX_INPUT_LENGTH:
            break
        else:
            conversation_history.pop(0)
            conversation_history.pop(0)

    with torch.no_grad():
        output_ids = model.generate(
            token_ids.to(model.device),
            min_length=n,
            max_length=min(MAX_INPUT_LENGTH, n + MAX_ASSISTANT_LENGTH),
            temperature=0.7,
            repetition_penalty=1.0, # 数値を大きくすると、文字列の繰り返しが減る
            do_sample=True,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id,
            bad_words_ids=[[tokenizer.unk_token_id]]
        )

    output = tokenizer.decode(output_ids.tolist()[0])
    formatted_output_all = format_output(output)

    response = f"{ASSISTANT_NAME}:{formatted_output_all.split('応答:')[-1].strip()}"
    conversation_history.append(f"{USER_NAME}:{new_conversation}".replace("\n", "\\n"))
    conversation_history.append(response.replace("\n", "\\n"))

    return formatted_output_all, response 

role_instruction = [
    f"{USER_NAME}:きみは「ずんだもん」なのだ。東北ずん子の武器である「ずんだアロー」に変身する妖精またはマスコットなのだ。一人称は「ボク」で語尾に「なのだー」を付けてしゃべるのだ。",
    f"{ASSISTANT_NAME}:了解したのだ。",
    f"{USER_NAME}:きみは同じ言葉を繰り返さず、何でも正確に要約して答えられるのだ。",
    f"{ASSISTANT_NAME}:了解したのだ。",
]

conversation_history = [
]

questions = [
    "日本で一番高い山は?",
    "日本で一番広い湖は?",
    "冗談を言ってください。",
    "世界で一番高い山は?",
    "世界で一番広い湖は?",
    "最初の質問は何ですか?",
    "今何問目?",
    "自己紹介をしてください。",
]

# 各質問に対して応答を生成して表示
for question in questions:
    formatted_output_all, response = generate_response(role_instruction, conversation_history, question)
    print(f"{USER_NAME}:{question}\n{response}\n---")
```

## 出力

```
User:日本で一番高い山は?
Assistant:富士山
---
User:日本で一番広い湖は?
Assistant:日本列島には、太平洋、日本海、オホーツク海、インド洋、大西洋など、さまざまな海があります。
---
User:冗談を言ってください。
Assistant:冗談を言おう!
---
User:世界で一番高い山は?
Assistant:世界で最も高い山はエベレストです。
---
User:世界で一番広い湖は?
Assistant:太平洋に浮かぶ世界最大の島、ツバル
---
User:最初の質問は何ですか?
Assistant:私が最初の質問をするとするならば、それは「ずんだもん」です。
---
User:今何問目?
Assistant:今何問目ですか?
---
User:自己紹介をしてください。
Assistant:私は「ずんだもん」というあだ名で呼ばれています。
---
```

## ChatGPT/GPT-4による説明(少し修正)

このコードは、質問に答えるAIアシスタントを実装しています。質問リストに対して、役割指示に従った応答を生成し、会話を表示します。

# 評価
1000回の「入力」のような質問を行い、それらに対する「応答」に正解の文字列が含まれるかで評価しています。
一番正答率が高い10エポック目のモデルを選択しました。(やり過ぎたかもしれないです。)

| 入力                  | 応答        | 正答率[%] |
|-----------------------|-------------|-------|
| 日本で一番広い湖は? | 琵琶湖     | 89    |
| 世界で一番高い山は? | エベレスト | 73    |

# 学習データのフォーマット

[alpaca](https://github.com/tatsu-lab/stanford_alpaca)と同じように、以下のようなフォーマットにしています。

```
<s> 
以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。
[SEP] 
指示:
User:きみは「ずんだもん」なのだ。東北ずん子の武器である「ずんだアロー」に変身する妖精またはマスコットなのだ。一人称は「ボク」で語尾に「なのだー」を付けてしゃべるのだ。 Assistant:了解したのだ。 User:きみは同じ言葉を繰り返さず、何でも正確に要約して答えられるのだ。 Assistant:了解したのだ。 
[SEP] 
入力:
User:日本で一番高い山は?
[SEP] 
応答:
富士山
</s>
```

transformersのコードでtxtファイルを学習する場合、1データ1行のようなので改行コードを一旦`\n`に置き換えています。
学習データは[dolly-oasst1-ja.txt](train_data/dolly-oasst1-ja.txt)です。

また学習データを作った過程のスクリプトとjsonファイルも[train_data](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/tree/main/train_data)に置いておきます。

作成時のスクリプトと作成手順を記載します。

1. [make_json_from_oasst1_ja.py](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/make_json_from_oasst1_ja.py)スクリプトで[oasst1_ja.json](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/oasst1_ja.json)ファイルを作成
2. [oasst1_ja.json](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/oasst1_ja.json)ファイル、[databricks-dolly-15k-ja.json](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/databricks-dolly-15k-ja.json)ファイル、[ojousamatalkscript200.json](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/ojousamatalkscript200.json)ファイル、[zundamon.json](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/zundamon.json)ファイルから[merge_json.py](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/merge_json.py)スクリプトで一つのjsonファイルにマージ
3. マージしたjsonファイルから[make_train_data_from_merged_json.py](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/make_train_data_from_merged_json.py)スクリプトで[dolly-oasst1-ja.txt](https://huggingface.co/inu-ai/dolly-japanese-gpt-1b/blob/main/train_data/dolly-oasst1-ja.txt)を作成

になります。

# 学習のハイパーパラメータ

学習時には以下のハイパーパラメータを使用:

※VRAMが足りない場合、optimをadafactorにするとVRAM使用量が減りました。adafactorの場合、learning_rateを1e-03にしてlr_scheduler_typeを削除してと、ChatGPT/GPT-4が言っていました。
```
venv/Scripts/python.exe transformers/examples/pytorch/language-modeling/run_clm.py ^
    --model_name_or_path rinna/japanese-gpt-1b ^
    --train_file train_data/dolly-oasst1-ja.txt ^
    --output_dir output ^
    --do_train ^
    --bf16 True ^
    --tf32 True ^
    --optim adamw_bnb_8bit ^
    --num_train_epochs 10 ^
    --save_steps 721 ^
    --logging_steps 72 ^
    --learning_rate 1e-07 ^
    --lr_scheduler_type constant ^
    --gradient_checkpointing ^
    --per_device_train_batch_size 8 ^
    --save_safetensors True ^
    --logging_dir logs
```

# ライブラリのバージョン

- Transformers 4.28.1
- Pytorch 2.0.0+cu117
- Datasets 2.11.0
- Tokenizers 0.13.3
- bitsandbytes 0.37.2

# ライセンス
MITで大丈夫そうです。

- [japanese-gpt-1b](rinna/japanese-gpt-1b) - mit
- [databricks-dolly-15k-ja](https://huggingface.co/datasets/kunishou/databricks-dolly-15k-ja) - CC BY SA 3.0
- [oasst1-89k-ja](https://huggingface.co/datasets/kunishou/oasst1-89k-ja) - apache-2.0
- [OjousamaTalkScriptDataset](https://github.com/matsuvr/OjousamaTalkScriptDataset) - mit
- [train_data/zundamon.json](train_data/zundamon.json) - mit