LLM GPTQ量子化作成

備忘込みのメモ。

トークン生成速度が物足りないので色々やってみた結果。
ChatGPT o4に色々聞いていたら、GPTQやらExLlamaV2(ExL2)やらが良いとおすすめされたので、GPTQを試した成功分。

GPTQ量子化。

・量子化しつつキャリブレーション用のデータを用意する事で残したいものを重視できる
・キャリブレーションデータは2048トークン分のテキストデータが128行用意するのが一番良いらしい(多いと過学習するし、多すぎるとOOMで落ちる)。1.9.0でconcatするオプションも追加されたみたいなので、多めの文章を適当に入れておけば足りるのかも。
・キャリブレーションデータは自作LoRA用のデータがあればそれ。それで足りなければ適当な日本語文章を追加で用意。
・動作にはVongolaChouko/Starcannon-Unleashed-12B-v1.0でやった時はRAM30GB、VRAM8GBくらい使った(たしか)
・AIはひたすら5bitを推してきたが5bitは無いので4bitで。group_sizeも128で十分らしい。(8bitでも4bitと変わらん、group_sizeも32とかにしても変わらんって話だった)
・結果はファイルサイズ1/3、3090のVRAM使用量が6割くらいの13GBちょっと。Text Generation WebuiのAPI経由で50~60tk/sくらい。(変換前は17~20tk/s)。割と早い。日本語品質の低下も自分には気にはならない程度。
・コンテキストが多いと初回に時間がかかる。10秒とか。

環境作った時の操作は忘れた。
ディレクトリ作成、venv
pip install gptqmodel transformers
だったと思う。
その後cuda付きのバージョンを指定して再インストールしたかは不明。

テキストデータを適当なトークンサイズで切るやつ。
(1.9.0だと不要かも?)

#split_by_tokens.py

import re
import sys
import tiktoken

# Ensure correct usage
if len(sys.argv) != 3:
    print("Usage: python split_by_tokens.py <input_file> <output_file>")
    sys.exit(1)

input_file = sys.argv[1]
output_file = sys.argv[2]

# Read the entire text from the input file
with open(input_file, 'r', encoding='utf-8') as f:
    text = f.read()

# Normalize whitespace: replace multiple spaces/newlines with a single space
text = re.sub(r'\s+', ' ', text)

# Ensure sentence-ending punctuation (English or Japanese) is followed by a space, 
# so that our split captures the sentence boundary.
text = re.sub(r'(?<=[\.\!\?]|[。!?])(?=\S)', ' ', text)

# Split text into sentences by punctuation followed by a space
sentences = re.split(r'(?<=[\.\!\?]|[。!?]) +', text)

# Initialize the tokenizer (using GPT-3.5-turbo's encoding as an example)
encoding = tiktoken.encoding_for_model('gpt-3.5-turbo')
max_tokens = 2048

chunks = []
current_chunk = ""
current_tokens = 0

# Group sentences into chunks without exceeding max_tokens
for sentence in sentences:
    if sentence.strip() == "":
        continue  # skip empty segments (if any)
    # Count tokens in this sentence
    sentence_tokens = encoding.encode(sentence)
    sentence_token_count = len(sentence_tokens)
    if current_chunk == "":
        # Start a new chunk with the sentence
        current_chunk = sentence
        current_tokens = sentence_token_count
    else:
        # Plus one token for the space (approximate) when appending
        # We encode with a leading space to simulate appending in context
        new_tokens = encoding.encode(" " + sentence)
        new_token_count = len(new_tokens)
        # Check if adding this sentence (with a space) exceeds the limit
        if current_tokens + new_token_count > max_tokens:
            # Finish the current chunk and start a new one
            chunks.append(current_chunk.strip())
            current_chunk = sentence
            current_tokens = sentence_token_count
        else:
            # Append the sentence to the current chunk
            current_chunk += " " + sentence
            current_tokens += new_token_count

# Append the last chunk if it exists
if current_chunk:
    chunks.append(current_chunk.strip())

# Write the output chunks to the output file, separated by blank lines
with open(output_file, 'w', encoding='utf-8') as f:
    for idx, chunk in enumerate(chunks):
        f.write(chunk.strip())
        if idx != len(chunks) - 1:  # if not the last chunk, add a separator
            f.write("\n\n")

ディレクトリと変換スクリプト
スクリプトはハードコードのままなので適宜直す。

~/create-gptq$ ll
drwxr-xr-x  2 root root 4096 Feb 16 22:07 VongolaChouko_Starcannon-Unleashed-12B-v1.0-MergeTest2/
drwxrwxr-x  2 yua  yua  4096 Feb 17 04:33 calibration_data/
-rw-rw-r--  1 yua  yua  1646 Feb 16 22:24 quantize_mistral_gptqmodel.py
drwxrwxr-x  6 yua  yua  4096 Feb 14 14:24 venv/
#quantize_mistral_gptqmodel.py

from datasets import load_dataset
from gptqmodel import GPTQModel, QuantizeConfig

# 1. 量子化設定の作成(4bit, グループサイズ128)
quant_config = QuantizeConfig(bits=4, group_size=128, desc_act=False)  # desc_actはFalse(デフォルト)でAct-order無効

# 2. モデルのロード(Mistral 12Bの事前学習モデルを指定)
model_id = "VongolaChouko_Starcannon-Unleashed-12B-v1.0-MergeTest2"  # ※実際の12BモデルのIDに置き換えてください
model = GPTQModel.load(model_id, quant_config)

# 3. キャリブレーション用データセットの準備
# キャリブレーションデータの読み込み
calibration_file = "calibration_data/cabdata.txt"

with open(calibration_file, 'r', encoding='utf-8') as f:
    calib_dataset = f.readlines()

# 4. モデルの量子化実行
model.quantize(calib_dataset, batch_size=1)  # バッチサイズはGPUのメモリに合わせて調整

# 5. 量子化したモデルの保存
output_dir = "./VongolaChouko_Starcannon-Unleashed-12B-v1.0-MergeTest2-gptq-4bit"
model.save(output_dir)

メモ程度なので以上です。
#llm #gptq #AIチャット #AI彼女

いいなと思ったら応援しよう!