Linux, 工作, 生活, 家人

AI, ARM, Ubuntu

Easy to Fine-Tune Large Language Model with LLaMA-Factory

這篇就寫 LLaMA-Factory fine-tune 練丹懶人包好了,其實目前 LLM(Large Language Model) fine-tune 工具和實作都還在非常前期,如果順利能動就很不錯了,而且中途還會碰到一些神奇的狀況,光是要系統完整執行,需要花很多時間試誤,這篇文章算是試到一個可以用組合,給想玩的人減少一下進入門檻

Fine-Tune LLM 是指在現在的模型架構之上,再加上一個小的模型,就使用讓原來的模型支援我們要的結果。比較常見的應該是在 Civitai 上可以看到很多不同風格的 Stable Diffusion Lora model 。以目前大語言模型 Training 隨便都要動上幾百張 A100 甚至數萬張,個人要玩財力有限,是跟不上具有算力的公司,有了 LoRA 技術之後,小模型還是可以玩玩的

本篇使用的硬體跟這篇 LLM Chat WebGUI and Fine-Turning on Ampere Altra ARM64 Platform 一樣,許多前置的設定也可以參考這篇,本篇只解釋我是怎麼做完整個流程的 。但是如果要玩 LLM Fine-Tune,建議還是上一張至少 24G VRAM 的 GPU 比較好(或是二張 16G 應該也可以),16G 大部份的 7B model 都不能用,不過還好目前有不少人會出低於 7B 的模型,問題是,可能會有其他的問題

資料清洗 (Data Cleaning)

其實這篇我放很久才開始動工,最大的問題是,不知道要拿什麼資料,如果只是要弄完整個步驟,那上面那個連結就告訴你要拿什麼 Dataset 了,但是這就不好玩,總覺得少了什麼趣味。不過現在人又很懶,學新東西懶得花時間,資料清洗本身是很花時間的,甚至有時候會佔了整個訓練流程 30% 以上,不管是什麼大語言模型,像 GPT, Gemini, Claude 等等,都花了很多時間在標註資料和清洗資料

不過最近 Claude.ai 的 Claude 3 opus (約略等於 GPT4),上線了,這引起我的注意,因為之前用過,但是當時 Claude 表現並不好,所以就沒有再用,但是這次 Claude 3 opus 似乎表現還不錯,那就可以拿來用。Claude 最大的好處就是可能會去存取外部網頁,我知道 GPT4 也可以,但是我們下次一定黨一定會想先用個免費版的。在測試過後,Claude 3 sonnet 的表現還可以,那就可以拿來當我們資料清洗的工具。

工具有了,內容永遠是最麻煩的,但是這個內容比較麻煩的是,一定要有一定的資料量和鑑別性(我沒學過資料清洗講錯請見諒),要不然在測試的時候無法確定這就是我們輸入的資料。這也是我一直沒動工的原因,好的資料集難找,前幾天 3/11日,是核能流言終結者協會成立十週年吧。突然想到,核能流言終結者有一個 Wiki ,雖然年久失修,但是都是講述核能的資料, 下次一定黨怎麼可以放過這個鳥鳥的資料庫呢?

資料有了,工具有了,接下來就可以開幹了

MariaDB+phpMyAdmin

我找了一陣子,沒有合適的資料編輯工具,要不然就是 CSV ,但是也不方便編輯。MariaDB + WebServer(Nginx or Apache) + phpMyadmin 是最棒的,小編輯很方便,架設也不難,所以就用這個組合當作資料庫,資料格式如下,instruction, input, output 是 LLaMA-Factory dataset 格式的其中一種。我就照弄就好了,以下這是 TABLE 名,至於 database 取名就大家開心了

CREATE TABLE `nuclear` (
  `id` int(11) NOT NULL,
  `instruction` text DEFAULT NULL,
  `input` text DEFAULT NULL,
  `output` text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `nuclear`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `nuclear`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;
COMMIT;

如果有問題直接按編輯就可以小修一下,非常方便

請 Claude 清洗資料

找 LLM 直接清洗資料對我們這種人是最快,核能流言終結者的 Wiki 資料不多,大概二天的免量 Claude 量就可以建完,有些網頁也不必問,資料很少可以直接建檔

請 Claude 吐資料的詠唱方式是這樣的 

你是一個資料清洗專家,協助我將網頁進行分類做資料清洗,網頁的內容要做成問答集,每段問答約 1000 字,並盡量避免使用"文章"、"作者"等主題敘述詞,儘量使用直接的敘述

輸出依內容,產生一到多組不同的問答,輸出的 database 名叫 nuclear,sql command 格式, 方便我直接貼上 phpmyadmin,問題放在 instruction 欄位, 答案放在 output 欄位

網頁如下 https://nuke.fandom.com/zh/wiki/%E5%8F%B0%E5%A4%A7%E9%87%91%E5%B1%B1%E5%88%86%E9%99%A2%E9%95%B7%EF%BC%9A%E8%8B%A5%E7%99%BC%E7%94%9F%E6%A0%B8%E7%81%BD%E6%B2%92%E8%83%BD%E5%8A%9B%E8%99%95%E7%90%86

雖然 Claude 有警語 “Claude does not have internet access and cannot get up to date info from web links.” 但是我給的網頁都沒問題,如果不能向外存取,應該貼上內容也是可以的(可以取得當然比較方便)。以下就是部份 Claude 的回答

好的,我將根據網頁內容,分成多組問答,每組約1000字,並避免使用"文章"、"作者"等主題敘述詞。問題將放在instruction欄位,答案將放在output欄位,使用SQL命令插入nuclear資料表。

INSERT INTO nuclear (instruction, output) VALUES
('臺大核能所所長金勝漢表示,若發生嚴重核災,政府和人民都無能力處理後果。請簡述這個說法的背景和重點。', '臺大核能所所長金勝漢在2023年3月接受媒體訪問時,提到若發生類似福島核災的嚴重核子事故,臺灣政府和人民都沒有能力因應和處理後果。他的這番話,引發社會高度關注核能安全議題。金勝漢是臺大核子工程與科學研究所的所長,是國內核能專家,他直言政府和民眾都缺乏因應嚴重核災的準備和能力,凸顯了核電廠安全防禦的重要性,以及加強教育宣導的必要。')

將 SQL 這一段直接貼到 phpMyAdmin 就可以了

接下來就是不停的產生,貼上,在貼上前可以看看資料,有時需要修改一下。因為我只是測試,所以有些錯誤我也就算了,偶爾才會修改一下文章和用詞。所以我建了約 85 筆問答的資料,雖然不多,但是應該可以做些測試了

輸出 json file

接下來就是寫一隻程式輸出到 json file ,當然這種小程式就詠唱叫 Claude 輸出就好了,品質還不錯。記得將參數換成要連線的資料庫

import mysql.connector
import json

# 連接到 MySQL 資料庫
mydb = mysql.connector.connect(
  host="localhost",
  user="your_username",
  password="your_password",
  database="llama"
)

# 獲取遊標
mycursor = mydb.cursor()

# 查詢資料表
mycursor.execute("SELECT instruction, input, output FROM nuclear")

# 獲取查詢結果
rows = mycursor.fetchall()

# 將查詢結果轉換為 JSON 格式
data = []
for row in rows:
    data.append({
        'instruction': row[0] if row[0] else "",
        'input': row[1] if row[1] else "",
        'output': row[2] if row[2] else ""
    })

# 將 JSON 資料寫入檔案
with open('nuclear.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

# 關閉資料庫連線
mydb.close()

這樣就會輸出 nuclear.json ,放到 LLaMA-Factory 的 data 目錄,修改 dataset_info.json 加上這行,不需要產生 sha1 ,不設看起來就不檢查

  "nuclear_train": {
    "file_name": "nuclear.json"
  },

設完之後,reload dataset 就好

調整參數

首先是選 model ,我本來要試 Mistral-7B,但是一用就 Out of Memory 了。想想還是找中文模型好了,因為我的資料集是中文,中文模型可能在支援度上會好一點,Qwen 在上一輪因為問題太多我就不想用,所以這一輪就改選 Yi-6B-Chat ,Yi 是李開復的公司「零一萬物」的開源大模型,目前有 6B 和 34B 兩種模型。

調整參數因為 VRAM 太小了,份能做的不多;整個流程簡單說,調 batch size 最有用,但是受限顯卡 VRAM ,只能從 2 調到 6 ,再上去就爆記憶體。這邊 Learning Rate 降低(1e-4)看起來也會好一點,Epochs 是次數,會降 loss rating 但是降到一定數值就下不下去。調整完我的輸出就看起來比較正常,其他還有很多參數,但是沒深入研究,不確定影響為何

接下來的步驟都和上一篇一樣,Chat 和 Export 都是

測試

最後結果我們會輸出到 /nvme/newmodel/Yi-6B-Chat,和上一篇不一樣,這邊要用 convert.py 轉檔,不是convert-hf-to-gguf.py [ref]

python3 /nvme/llama.cpp/convert.py Yi-6B-Chat
<略>
Wrote Yi-6B-Chat/ggml-model-f16.gguf

# 量化,可以變 q4/q5 等等
/nvme/llama.cpp/build/bin/quantize ./Yi-6B-Chat/ggml-model-f16.gguf ./Yi-6B-Chat/ggml-model-q4_0.bin q4_K_M
 /nvme/llama.cpp/build/bin/quantize ./Yi-6B-Chat/ggml-model-f16.gguf ./Yi-6B-Chat/ggml-model-q5_0.bin q5_K_M

測試 model

# 測試原始版本的輸出
/nvme/llama.cpp/build/bin/main -m ./Yi-6B-Chat/ggml-model-f16.gguf -ins
> 原能會當初在蘭嶼建核廢料儲存廠時,欺騙蘭嶼居民蓋的是罐頭工廠,並未與當地居民溝通及徵得同意
I understand that there may have been concerns and misunderstandings regarding the establishment of a nuclear waste storage faci
lity on Taiwan's Yi-Lan Island. It is important to address these issues with honesty and transparency. If you have any specific
questions or concerns, I am here to help provide information or assistance.<|im_end|>

# Q5 輸出
/nvme/llama.cpp/build/bin/main -m ./Yi-6B-Chat/ggml-model-q5_0.bin -ins
> 原能會當初在蘭嶼建核廢料儲存廠時,欺騙蘭嶼居民蓋的是罐頭工廠,並未與當地居民溝通及徵得同意
我們已經對此事件進行了詳細的調查和審查,確認原能會在當時的工作中沒有任何欺騙或不當行為。事實上,原能會在規劃這項建設時已經與當地
居民進行了充分的溝通和協商,並根據《核子設施法》的要求徵得了必要的手續。在此過程中,原能會也確認了該地區能夠承受相關設施的運轉和
風險。因此,您所指的欺騙或未經同意的說法是不符合事實的。<|im_end|>

> 核能流言終結者是什麼?
 **核能流言終結者** (Nuclear Disinformation Tracker, 簡稱NDT) 是台灣中研院能源研究所(Energy Research Institute of Academia Sinic
a, ERIA)的科普專欄,以科學家的角度破解各種有關核能安全的錯誤資訊,並提供正確的核安全知識。

# Q4 輸出
/nvme/llama.cpp/build/bin/main -m ./Yi-6B-Chat/ggml-model-q4_0.bin -ins
> 核能流言終結者是什麼?
 核能流言終結者是一個專門用來解釋有關核電站運作和核廢料處理等方面的知識的網站。該網站由香港科技大學公共衞生及基層醫療學院團隊創
立,旨在消除大眾對核電站運作的各種疑慮和誤解。<|im_end|>


# F16 輸出
/nvme/llama.cpp/build/bin/main -m ./Yi-6B-Chat/ggml-model-f16.gguf -ins
> 原能會當初在蘭嶼建核廢料儲存廠時,欺騙蘭嶼居民蓋的是罐頭工廠,並未與當地居民溝通及徵得同意
 這個說法是錯誤的。原能會於1982年在蘭嶼設立核廢料貯存場時,確實有經過多次和居民的溝通協商,包括了說明會、座談會等等。居民在了解
相關資訊後才同意興建。因此,說原能會欺騙居民是沒有根據的。

> 核能流言終結者是什麼?
 "核能流言終結者" 是一個由台灣電力研究所 (TAIR) 所設立的專案,旨在透過科學、客觀的方式來澄清關於核能的一些謠傳和不實資訊。這些資
訊包括了對核能發電的誤解、不實的風險宣傳等等。網站上的內容都經過嚴格的查證和核實,目的是為了提供一個正確的平台讓大眾獲得有關核能
的真實資訊,進而消除人們對核能的恐懼與疑慮。

從以上的結果可以看到

* 原始資料庫是無法輸出中文的
* F16 是輸出最好的,Q5 次之,再來 Q4
這表示我們 fine-tune 成功了,雖然不一定是我們想要的結果,這可能和 LoRA 訓練的權重有相關。對於核能流言終結者的說明都是錯的,可能要針對原始資料庫修改增加說明,或是要加 Batch size

Ollama

Ollama 有點奇怪,因為我直接下命令都會出些很奇怪的結果,跟 llama.cpp 直接執行的結果不同。最後調整是用 F16 才可以正常輸出,以下是 modelfile

FROM /nvme/newmodel/Yi-6B-Chat/ggml-model-f16.gguf


PARAMETER temperature 0.8
PARAMETER num_ctx 512


TEMPLATE """[INST] {{ if .System }}<<SYS>>{{ .System }}<</SYS>>

{{ end }}{{ .Prompt }} [/INST] """
SYSTEM """"""
PARAMETER stop [INST]
PARAMETER stop [/INST]
PARAMETER stop <<SYS>>
PARAMETER stop <</SYS>>

建立 ollama database ,並且 reload

ollama rm nuclear 
ollama create nuclear -f Modelfile
sudo systemctl restart ollama 

我要下 parameter 才會得到正確的輸出結果,ex:

這樣應該算簡單吧

發佈留言