Files
frankenstallm/source/scripts/convert_3b_gguf.sh
ModelHub XC d4abdb70fa 初始化项目,由ModelHub XC社区提供模型
Model: pathcosmos/frankenstallm
Source: Original Platform
2026-07-14 04:21:16 +08:00

230 lines
8.9 KiB
Bash

#!/usr/bin/env bash
# =============================================================================
# convert_3b_gguf.sh — 3B 모델 HuggingFace → GGUF 변환 + 다중 양자화
#
# Usage:
# bash scripts/convert_3b_gguf.sh [options]
#
# Options:
# --input_dir DIR HF 포맷 모델 디렉토리 (default: outputs/hf_korean_3b_orpo)
# --out_dir DIR GGUF 출력 디렉토리 (default: outputs/gguf)
# --checkpoint DIR 커스텀 체크포인트 디렉토리 (지정 시 HF 변환 선행 실행)
# --skip_hf_conv HF 변환 단계 건너뜀 (이미 HF 포맷 존재 시)
# --skip_quant 양자화 단계 건너뜀 (F16 GGUF만 생성)
#
# Pipeline:
# 1. [선택] 커스텀 체크포인트 → HF transformers 포맷 (convert_to_hf.py)
# 2. HF → F16 GGUF (llama.cpp/convert_hf_to_gguf.py)
# 3. F16 GGUF → Q4_K_M, Q5_K_M, Q8_0 양자화 (llama-quantize)
#
# Outputs:
# outputs/gguf/frankenstallm-3b-f16.gguf
# outputs/gguf/frankenstallm-3b-Q4_K_M.gguf — 권장 (Ollama용)
# outputs/gguf/frankenstallm-3b-Q5_K_M.gguf
# outputs/gguf/frankenstallm-3b-Q8_0.gguf
#
# 전제 조건:
# - python scripts/convert_to_hf.py 로 HF 변환 완료 (또는 --checkpoint 옵션)
# - git, cmake, make 설치
# - pip install safetensors
# =============================================================================
set -euo pipefail
# ---------------------------------------------------------------------------
# 인자 파싱
# ---------------------------------------------------------------------------
INPUT_DIR="outputs/hf_korean_3b_orpo"
OUT_DIR="outputs/gguf"
CHECKPOINT_DIR=""
SKIP_HF_CONV=false
SKIP_QUANT=false
while [[ $# -gt 0 ]]; do
case "$1" in
--input_dir) INPUT_DIR="$2"; shift 2 ;;
--out_dir) OUT_DIR="$2"; shift 2 ;;
--checkpoint) CHECKPOINT_DIR="$2"; shift 2 ;;
--skip_hf_conv) SKIP_HF_CONV=true; shift ;;
--skip_quant) SKIP_QUANT=true; shift ;;
-h|--help)
grep '^#' "$0" | head -40 | sed 's/^# \{0,1\}//'
exit 0 ;;
*)
echo "ERROR: 알 수 없는 옵션: $1"
echo "Usage: bash scripts/convert_3b_gguf.sh [--input_dir DIR] [--out_dir DIR] [--checkpoint DIR] [--skip_hf_conv] [--skip_quant]"
exit 1 ;;
esac
done
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LLAMA_CPP_DIR="${LLAMA_CPP_DIR:-$PROJECT_DIR/outputs/llama.cpp}"
MODEL_NAME="frankenstallm-3b"
cd "$PROJECT_DIR"
echo "=================================================================="
echo " 3B 모델 GGUF 변환 파이프라인"
echo " 입력 HF 디렉토리 : $INPUT_DIR"
echo " GGUF 출력 디렉토리: $OUT_DIR"
echo " llama.cpp 경로 : $LLAMA_CPP_DIR"
echo "=================================================================="
echo ""
# ---------------------------------------------------------------------------
# Step 0: llama.cpp 존재 여부 확인 / 클론
# ---------------------------------------------------------------------------
if [[ ! -d "$LLAMA_CPP_DIR" ]]; then
echo "[SETUP] llama.cpp 디렉토리가 없습니다."
echo " 다음 명령으로 설치하세요:"
echo ""
echo " git clone --depth 1 https://github.com/ggerganov/llama.cpp $LLAMA_CPP_DIR"
echo ""
echo " 또는 LLAMA_CPP_DIR 환경변수로 기존 경로를 지정하세요:"
echo " LLAMA_CPP_DIR=/path/to/llama.cpp bash scripts/convert_3b_gguf.sh"
echo ""
read -r -p "지금 자동 클론하시겠습니까? [y/N] " _yn
if [[ "${_yn:-N}" =~ ^[Yy]$ ]]; then
echo "Cloning llama.cpp ..."
git clone --depth 1 https://github.com/ggerganov/llama.cpp "$LLAMA_CPP_DIR"
else
echo "중단합니다. llama.cpp를 설치한 뒤 다시 실행하세요."
exit 1
fi
fi
# llama.cpp Python 의존성
echo "[SETUP] llama.cpp Python 의존성 설치 중 ..."
pip install -r "$LLAMA_CPP_DIR/requirements.txt" --break-system-packages -q
# ---------------------------------------------------------------------------
# Step 1: 커스텀 체크포인트 → HF 포맷 변환 (선택)
# ---------------------------------------------------------------------------
if [[ -n "$CHECKPOINT_DIR" && "$SKIP_HF_CONV" == "false" ]]; then
echo ""
echo "[STEP 1] 커스텀 체크포인트 → HF 포맷 변환"
echo " 체크포인트: $CHECKPOINT_DIR"
echo " 출력 : $INPUT_DIR"
echo ""
if [[ ! -d "$CHECKPOINT_DIR" ]]; then
echo "ERROR: 체크포인트 디렉토리를 찾을 수 없습니다: $CHECKPOINT_DIR"
exit 1
fi
python "$PROJECT_DIR/scripts/convert_to_hf.py" \
--checkpoint "$CHECKPOINT_DIR" \
--output "$INPUT_DIR" \
--tokenizer "tokenizer/korean_sp/tokenizer.json"
echo " [OK] HF 변환 완료 → $INPUT_DIR"
elif [[ "$SKIP_HF_CONV" == "true" ]]; then
echo "[STEP 1] HF 변환 건너뜀 (--skip_hf_conv)"
else
echo "[STEP 1] 체크포인트 미지정 — HF 디렉토리를 직접 사용합니다."
fi
# HF 디렉토리 최종 검증
if [[ ! -d "$INPUT_DIR" ]]; then
echo "ERROR: HF 모델 디렉토리를 찾을 수 없습니다: $INPUT_DIR"
echo " --checkpoint 옵션으로 체크포인트를 지정하거나,"
echo " python scripts/convert_to_hf.py 를 먼저 실행하세요."
exit 1
fi
if [[ ! -f "$INPUT_DIR/config.json" ]]; then
echo "ERROR: config.json 이 없습니다: $INPUT_DIR/config.json"
exit 1
fi
mkdir -p "$OUT_DIR"
# ---------------------------------------------------------------------------
# Step 2: llama.cpp 빌드 (llama-quantize 바이너리)
# ---------------------------------------------------------------------------
QUANTIZE_BIN="$LLAMA_CPP_DIR/build/bin/llama-quantize"
if [[ ! -f "$QUANTIZE_BIN" ]]; then
echo ""
echo "[STEP 2] llama.cpp 빌드 중 (llama-quantize) ..."
cmake -S "$LLAMA_CPP_DIR" -B "$LLAMA_CPP_DIR/build" \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_CUDA=ON \
2>&1 | tail -10
cmake --build "$LLAMA_CPP_DIR/build" --target llama-quantize -j "$(nproc)" \
2>&1 | tail -10
echo " [OK] 빌드 완료: $QUANTIZE_BIN"
else
echo "[STEP 2] llama-quantize 바이너리 이미 존재 — 빌드 건너뜀"
fi
# ---------------------------------------------------------------------------
# Step 3: HF → F16 GGUF 변환
# ---------------------------------------------------------------------------
F16_GGUF="$OUT_DIR/${MODEL_NAME}-f16.gguf"
echo ""
echo "[STEP 3] HF → F16 GGUF 변환"
echo " 입력: $INPUT_DIR"
echo " 출력: $F16_GGUF"
echo ""
python "$LLAMA_CPP_DIR/convert_hf_to_gguf.py" "$INPUT_DIR" \
--outfile "$F16_GGUF" \
--outtype f16
echo " [OK] F16 GGUF 크기: $(du -sh "$F16_GGUF" | cut -f1) ($F16_GGUF)"
# ---------------------------------------------------------------------------
# Step 4: 다중 양자화 (Q4_K_M, Q5_K_M, Q8_0)
# ---------------------------------------------------------------------------
if [[ "$SKIP_QUANT" == "true" ]]; then
echo ""
echo "[STEP 4] 양자화 건너뜀 (--skip_quant)"
else
echo ""
echo "[STEP 4] 다중 양자화 시작 ..."
if [[ ! -f "$QUANTIZE_BIN" ]]; then
echo "[WARN] llama-quantize 바이너리를 찾을 수 없습니다: $QUANTIZE_BIN"
echo " 양자화를 건너뜁니다. F16 GGUF만 생성되었습니다."
echo " 수동 빌드: cmake --build $LLAMA_CPP_DIR/build --target llama-quantize"
else
# Q4_K_M — 가장 작은 크기, 품질/속도 균형 (Ollama 기본 권장)
Q4KM_GGUF="$OUT_DIR/${MODEL_NAME}-Q4_K_M.gguf"
echo " → Q4_K_M 양자화: $Q4KM_GGUF ..."
"$QUANTIZE_BIN" "$F16_GGUF" "$Q4KM_GGUF" Q4_K_M
echo " 크기: $(du -sh "$Q4KM_GGUF" | cut -f1)"
# Q5_K_M — 중간 크기, 더 높은 품질
Q5KM_GGUF="$OUT_DIR/${MODEL_NAME}-Q5_K_M.gguf"
echo " → Q5_K_M 양자화: $Q5KM_GGUF ..."
"$QUANTIZE_BIN" "$F16_GGUF" "$Q5KM_GGUF" Q5_K_M
echo " 크기: $(du -sh "$Q5KM_GGUF" | cut -f1)"
# Q8_0 — 가장 높은 품질 (F16 근사)
Q8_GGUF="$OUT_DIR/${MODEL_NAME}-Q8_0.gguf"
echo " → Q8_0 양자화: $Q8_GGUF ..."
"$QUANTIZE_BIN" "$F16_GGUF" "$Q8_GGUF" Q8_0
echo " 크기: $(du -sh "$Q8_GGUF" | cut -f1)"
echo ""
echo " [OK] 모든 양자화 완료"
fi
fi
# ---------------------------------------------------------------------------
# 완료 요약
# ---------------------------------------------------------------------------
echo ""
echo "=================================================================="
echo " 3B GGUF 변환 완료"
echo ""
echo " 출력 파일 목록:"
ls -lh "$OUT_DIR/${MODEL_NAME}"*.gguf 2>/dev/null | awk '{print " " $5 " " $9}' || \
echo " (파일 목록 확인: ls -lh $OUT_DIR/)"
echo ""
echo " 다음 단계:"
echo " bash scripts/deploy_3b_ollama.sh"
echo " bash scripts/quality_gate.sh deploy"
echo "=================================================================="