OpenAI API - Fine-Tune OpenAI Model Side Project

OpenAI API - Fine-Tune OpenAI Model Side Project

LAVI

Research Motivation

Fine-Tune OpenAI davinci model with pytesseract

接續 connect OpenAI API with MATLAB Program Side Project
想嘗試更多 OpenAI API 技術而產出的延伸自主研究

LAVI's Fine-Tune OpenAI Model Side Project

Introduction

利用 Python 套件 pytesseract 進行影像文字分析後,將字串處理為可提供給 OpenAI GPT-3 model prompt 的語句形式

進行 OpenAI model 訓練,使訓練出的模型可根據訓練資料回答資訊

架構

  1. pytesseract - Text Extraction
    在 dataSet 的獲取,考量到現在許多餐廳的菜單都是做成了圖片形式、網站爬蟲有些無法爬到直接的文字資料,因此我想到利用 Python 的 pytesseract 套件,撰寫「圖片文字辨識」的腳本,如此一來便可透過提取圖片中的文字,取得食品名稱及其熱量

  2. jieba - Chinese word segmentation module
    在 OpenAI API prompt 的詢問語句,參考現在當紅的 python 套件 jieba 分詞器,因為 OpenAI 的訓練資料大多為英文資料,而我提供的詢問語句以中文為主,由於中文語句於斷詞處的不同可能會產生不同語意,故我利用 jieba 分詞器判斷 prompt 之中文語句中的詞性及其權重進行切割,再進行詢問,以提高 Fine-Tune 訓練回覆資訊的準確度

  3. OpenAI API - Fine-Tune Davinci Model

  4. OpenAI playgroud - application Result

Information

1. 預處理

  • 將 OpenAI API key 放進系統環境變數
  • 將想 text detection 的圖片放好後,修改程式中讀取圖片的路徑
  • pytesseract 套件預設提取英文字,故需下載繁體中文包 (放在 Program Files\Tesseract-OCR 中讀取)

2. pytesseract 讀取圖片後進行字串處理

  • 利用 PIL 的 pytesseract.image_to_string 讀取指定圖片上的文字內容,語言使用 chi_tra (繁體中文)
  • 用 replace 將讀取的不必要空白取代,並對整體文字內容進行 split 切割成獨立字串

3. OpenAI 模型訓練

  • 將處理好的字串進行 jieba 切割
    • 因為 OpenAI 讀取關鍵字時難以正確判斷中文字串語意,可利用 jieba 斷詞器對字串進行權重切割,可另 OpenAI 模型更好的對關鍵詞進行訓練
  • 利用 prompt = f"{prevPrompt}\n{prevAns}\n###\n{oriprompt}" 使上一筆的查詢與結果可影響當前的輸入訓練結果,使各筆輸出結果判斷越漸相似
  • 利用 openai.Completion.create() 對 OpenAI davinci model 進行訓練

4. 整理收到的回應與每筆輸出資訊

  • 利用 pandas 中 pd.concat 將每筆資訊整合

5. 儲存整理好的資訊

  • 利用 df.to_csv("TrainingModel.csv", encoding="utf_8_sig") 將資訊輸出成 .csv 檔案

6. OpenAI Fine-Tune model 資料預處理

  • Fine-Tune mode 指定訓練資料欄位名稱為:promptcompletion
  • 調整好欄位資訊後輸出成 .csv 檔案
    • OpenAI 官方文件說可以提供 .csv 檔,而他在 Fine-Tune 你的模型時會將其轉為 .jsonl 格式

7. Fine-Tune Training Command

  • openai tools fine_tunes.prepare_data -f <LOCAL_FILE>
    • 讀取 preparedData.csv 為我的 fine_tune prepare data
  • openai api fine_tunes.create -t <TRAIN_FILE_ID_OR_PATH> -m <BASE_MODEL>
    • 利用 prepare data 生成一個 .jsonl 檔案後利用其和 davinci model 進行 fine-tune 訓練
  • openai api fine_tunes.follow -i <YOUR_FINE_TUNE_JOB_ID>
    • 查看我目前模型訓練的進度
    • 看你的 model 排隊進 queue 裡被訓練了沒,可能會花 30 min 到 1 hr 不等

8. 測試模型訓練完的結果

  • 進到 OpenAI playground 後選擇你的 Fine-Tune 模型
  • 在僅輸入 keyword 的前提下,輸出會與你的 Training Dataset 相似邏輯

Code

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

import os
import jieba
import openai
import pytesseract
import pandas as pd

from PIL import Image
from pathlib import Path

openai.api_key = os.getenv("OPENAI_API_KEY")
pytesseract.pytesseract.tesseract_cmd = r'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'

pathlist = Path("C:\\Users\\momia\\Downloads\\pytesseract").glob('**/*.jpg')
# config = r'-c tessedit_char_blacklist= --psm 6'

prevPrompt = ''
prevAns = ''


df = pd.DataFrame()

for fontPath in pathlist:
# print(fontPath)

basename = os.path.splitext(os.path.basename(fontPath))[0]
print('basename: ' + basename)

# if not os.path.isdir(basename):
# os.mkdir(basename)

img = Image.open(f'{basename}.jpg')
text = pytesseract.image_to_string(img, lang='chi_tra')
# print(text)
text = text.replace(' ', '')
text = text.split('\n')

for item in text[5:15]:
if item == '' :
continue
# print(item)

sentence = jieba.cut(item)
sentence = (' '.join(sentence))
print(sentence)
sentence = sentence.replace(':', '熱量為')
sentence = sentence.replace(';', '熱量為')
# print()

oriprompt = f"{sentence} 請在 20 字內說明要花多少時間運動才能消耗此熱量"
# print(oriprompt)
prompt = f"{prevPrompt}\n{prevAns}\n###\n{oriprompt}"
print(prompt)
response = openai.Completion.create(
model="text-davinci-003",
prompt=prompt,
temperature=1,
max_tokens=500,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["###"]
)
# print(response)

finish_reason = response['choices'][0]['finish_reason']
responseText = response['choices'][0]['text']

print(responseText)

prevPrompt = oriprompt
prevAns = responseText

newRow = {
'item':item,
'sentence':sentence,
'prompt':oriprompt,
'responseText':responseText,
'finish_reason':finish_reason}
newRow = pd.DataFrame([newRow])
df = pd.concat([df, newRow], axis=0, ignore_index=True)

df.to_csv("TrainingModel.csv", encoding="utf_8_sig")
df = pd.read_csv("TrainingModel.csv")

prepared_data = df.loc[:,['sentence','responseText']]
prepared_data.rename(columns={'sentence':'prompt', 'responseText':'completion'}, inplace=True)
prepared_data.to_csv('preparedData.csv', encoding="utf_8_sig", index=False)

Reference