使用 TypeScript 與 OpenAI fine tuning API 訓練出自己的模型

為什麼要使用 fine tuning

Fine tuning 是一種機器學習技術,它允許在一個已經訓練好的模型基礎上進一步進行訓練,符合特定任務的需求。
讓我們不需要從頭開始訓練一個模型,而是可以利用已有的資料,並對其進行微調以適應新的需求。

使用的流程

準備資料

在 fine tuning 的過程中,首先需要準備適當的訓練資料。
參考官方的資料:https://github.com/openai/openai-node/blob/master/examples/fine-tuning-data.jsonl

1
2
3
4
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}
// ...

可以了解訓練資料時要透過問答的方式來進行,另外也有發現為 jsonl 的特殊格式

什麼是 JSONL

JSONL 是一種文字格式,也被稱為換行分隔的 JSON,用於儲存結構化數據,允許逐記錄處理,處理大量資料時會比較有效率,有別於 JSON 格式時要一次解析的方式。

開始訓練資料

當我們準備好訓練資料後,下一步是使用這些資料來訓練我們的模型。
根據官方建議,我們至少需要10個不同的訓練樣本來進行 fine tuning。

使用 OpenAI 的 API,我們可以輕鬆地上傳訓練資料,並開始 fine-tuning。

參考官方的資料:https://github.com/openai/openai-node/blob/master/examples/fine-tuning.ts

以下是一個官方的範例程式碼,說明如何使用 OpenAI 的 API 進行 fine-tuning:

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

const client = new OpenAI();

async function main() {
// 上傳訓練資料
let file = await client.files.create({
file: fs.createReadStream('./examples/fine-tuning-data.jsonl'),
purpose: 'fine-tune',
});

// 等待文件處理完成
while (true) {
file = await client.files.retrieve(file.id);
if (file.status === 'processed') {
break;
} else {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}

// 開始 fine-tuning
let fineTune = await client.fineTuning.jobs.create({ model: 'gpt-3.5-turbo', training_file: file.id });

// 追蹤 fine-tuning 進度
while (fineTune.status == 'running' || fineTune.status == 'created') {
fineTune = await client.fineTuning.jobs.retrieve(fineTune.id);
const { data } = await client.fineTuning.jobs.listEvents(fineTune.id, { limit: 100 });
for (const event of data.reverse()) {
const timestamp = new Date(event.created_at * 1000);
console.log(`- ${timestamp.toLocaleTimeString()}: ${event.message}`);
}
await new Promise((resolve) => setTimeout(resolve, 5000));
}
}

main().catch((err) => {
console.error(err);
process.exit(1);
});

這段程式碼首先上傳一個名為 fine-tuning-data.jsonl 的訓練資料文件。
它會等待文件上傳完成,開始 fine-tuning,並追蹤進度,直到完成。

picture 0

完成後除了畫面會顯示訓練好的 Model ID 外,也會有完成訓練的通知信

使用訓練好的 Model

一旦模型被訓練好,我們就可以開始使用它來執行我們的任務。

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
async function main() {
const completion = await openai.chat.completions.create({
// 使用 fine-tuned 的模型
model: "ft:gpt-3.5-turbo-0613:personal::7w4CX2fS",
messages: [
{
role: "system",
content: "Marv is a factual chatbot that is also sarcastic.",
},
{
role: "user",
content: "What's the capital of France?",
},
],
});
console.log("fine-tuning:")
console.log(completion.choices[0]?.message?.content);

const completion2 = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "Marv is a factual chatbot that is also sarcastic.",
},
{
role: "user",
content: "What's the capital of France?",
},
],
});

console.log("gpt-3.5-turbo:")
console.log(completion2.choices[0]?.message?.content);
process.stdout.write("\n");
}

main();


fine-tuninggpt-3.5-turbo 簡單比較:

1
2
3
4
5
// fine-tuning:
// Paris, as if everyone doesn't know that already.

// gpt-3.5-turbo:
// Oh, that's an easy one. The capital of France is... Drumroll, please... Paris!

執行多次後會發現 fine-tuning 的結果都會與原本訓練的資料一樣,而 gpt-3.5-turbo 則會有不同的答案,對於有特定任務的需求,fine-tuning 的方式可以有效的控制執行的結果

Models 的其他操作

1
2
3
4
5
6
7
8
9
async function listModels() {
const models = await openai.models.list();
console.log(models);
}

async function deleteModel(){
const result = await openai.models.del('YOUR_MODEL_ID')
console.log(result)
}

Reference

https://platform.openai.com/docs/guides/fine-tuning
https://www.atatus.com/glossary/jsonl/
https://jsonlines.org/
https://github.com/openai/openai-node/blob/master/examples/fine-tuning.ts