Text Generation
Transformers
Safetensors
GGUF
Korean
English
llama
3b
korean
from-scratch
orpo
instruction-tuned
preference-aligned
fp8
b200
Eval Results (legacy)
text-generation-inference
Instructions to use pathcosmos/frankenstallm with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use pathcosmos/frankenstallm with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="pathcosmos/frankenstallm")# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("pathcosmos/frankenstallm") model = AutoModelForCausalLM.from_pretrained("pathcosmos/frankenstallm", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use pathcosmos/frankenstallm with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf pathcosmos/frankenstallm:Q4_K_M # Run inference directly in the terminal: llama cli -hf pathcosmos/frankenstallm:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf pathcosmos/frankenstallm:Q4_K_M # Run inference directly in the terminal: llama cli -hf pathcosmos/frankenstallm:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf pathcosmos/frankenstallm:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf pathcosmos/frankenstallm:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf pathcosmos/frankenstallm:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf pathcosmos/frankenstallm:Q4_K_M
Use Docker
docker model run hf.co/pathcosmos/frankenstallm:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use pathcosmos/frankenstallm with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "pathcosmos/frankenstallm" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "pathcosmos/frankenstallm", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/pathcosmos/frankenstallm:Q4_K_M
- SGLang
How to use pathcosmos/frankenstallm with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "pathcosmos/frankenstallm" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "pathcosmos/frankenstallm", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "pathcosmos/frankenstallm" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "pathcosmos/frankenstallm", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Ollama
How to use pathcosmos/frankenstallm with Ollama:
ollama run hf.co/pathcosmos/frankenstallm:Q4_K_M
- Unsloth Studio
How to use pathcosmos/frankenstallm with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for pathcosmos/frankenstallm to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for pathcosmos/frankenstallm to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for pathcosmos/frankenstallm to start chatting
- Docker Model Runner
How to use pathcosmos/frankenstallm with Docker Model Runner:
docker model run hf.co/pathcosmos/frankenstallm:Q4_K_M
- Lemonade
How to use pathcosmos/frankenstallm with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull pathcosmos/frankenstallm:Q4_K_M
Run and chat with the model
lemonade run user.frankenstallm-Q4_K_M
List all available models
lemonade list
- Atomic Chat
| # ============================================================================= | |
| # quality_gate.sh β Phase μλ£ μλ νμ§ κ²μ΄νΈ κ²μ¦ | |
| # | |
| # Usage: | |
| # bash scripts/quality_gate.sh <phase> | |
| # | |
| # Phases: | |
| # pretrain β μ¬μ νμ΅ κ²μ΄νΈ (val_loss, loss λ¨μ‘° κ°μ) | |
| # sft β SFT κ²μ΄νΈ (val_loss μλ ΄, λ°λ³΅λ₯ , KoBEST) | |
| # orpo β ORPO κ²μ΄νΈ (λ°λ³΅λ₯ , KoBEST, chosen > rejected) | |
| # deploy β λ°°ν¬ κ²μ΄νΈ (GGUF perplexity, Ollama μλ΅) | |
| # all β λͺ¨λ κ²μ΄νΈ μμ°¨ μ€ν | |
| # | |
| # Exit codes: | |
| # 0 β κ²μ΄νΈ ν΅κ³Ό | |
| # 1 β κ²μ΄νΈ μ€ν¨ (κΈ°μ€ λ―Έλ¬) | |
| # 2 β νμ νμΌ / μμ‘΄μ± μμ (μ€ν λΆκ°) | |
| # ============================================================================= | |
| set -uo pipefail | |
| PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | |
| # --------------------------------------------------------------------------- | |
| # μμ μΆλ ₯ ν¬νΌ | |
| # --------------------------------------------------------------------------- | |
| _RED='\033[0;31m' | |
| _GREEN='\033[0;32m' | |
| _YELLOW='\033[1;33m' | |
| _BLUE='\033[0;34m' | |
| _NC='\033[0m' | |
| log_info() { echo -e "${_BLUE}[INFO]${_NC} $*"; } | |
| log_ok() { echo -e "${_GREEN}[PASS]${_NC} $*"; } | |
| log_warn() { echo -e "${_YELLOW}[WARN]${_NC} $*"; } | |
| log_fail() { echo -e "${_RED}[FAIL]${_NC} $*"; } | |
| log_skip() { echo -e " [SKIP] $*"; } | |
| # --------------------------------------------------------------------------- | |
| # μ νΈλ¦¬ν°: Python ν μ€ ννμ νκ° (λΆλμμμ λΉκ΅) | |
| # --------------------------------------------------------------------------- | |
| py_eval() { | |
| python3 -c "import sys; sys.exit(0 if ($1) else 1)" | |
| } | |
| py_value() { | |
| python3 -c "print($1)" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # μ νΈλ¦¬ν°: JSONμμ κ° μΆμΆ | |
| # --------------------------------------------------------------------------- | |
| json_get() { | |
| local file="$1" key="$2" | |
| python3 -c " | |
| import json, sys | |
| try: | |
| d = json.load(open('$file')) | |
| keys = '$key'.split('.') | |
| for k in keys: | |
| d = d[k] | |
| print(d) | |
| except Exception as e: | |
| print('NOT_FOUND') | |
| sys.exit(1) | |
| " | |
| } | |
| # --------------------------------------------------------------------------- | |
| # κ²μ΄νΈ κ²°κ³Ό μ§κ³ | |
| # --------------------------------------------------------------------------- | |
| GATE_PASS=0 | |
| GATE_FAIL=0 | |
| GATE_SKIP=0 | |
| record_pass() { GATE_PASS=$((GATE_PASS + 1)); log_ok "$*"; } | |
| record_fail() { GATE_FAIL=$((GATE_FAIL + 1)); log_fail "$*"; } | |
| record_skip() { GATE_SKIP=$((GATE_SKIP + 1)); log_skip "$*"; } | |
| # ============================================================================= | |
| # Gate 1: Pretrain | |
| # ============================================================================= | |
| gate_pretrain() { | |
| echo "" | |
| echo "==================================================================" | |
| echo " Gate: PRETRAIN" | |
| echo " κΈ°μ€: val_loss < 2.5 | loss λ¨μ‘° κ°μ νμΈ" | |
| echo "==================================================================" | |
| # μ΅μ 체ν¬ν¬μΈνΈ λλ ν 리 νμ | |
| CKPT_BASE="$PROJECT_DIR/checkpoints" | |
| METRICS_FILE="" | |
| # metrics.json λλ train_log.jsonl νμ | |
| for candidate in \ | |
| "$CKPT_BASE/korean_3b_fp8_pretrain/metrics.json" \ | |
| "$CKPT_BASE/korean_3b_pretrain/metrics.json" \ | |
| "$PROJECT_DIR/outputs/pretrain_metrics.json" \ | |
| "$PROJECT_DIR/logs/pretrain_metrics.json" | |
| do | |
| if [[ -f "$candidate" ]]; then | |
| METRICS_FILE="$candidate" | |
| break | |
| fi | |
| done | |
| if [[ -z "$METRICS_FILE" ]]; then | |
| log_warn "μ¬μ νμ΅ λ©νΈλ¦ νμΌμ μ°Ύμ μ μμ΅λλ€." | |
| log_warn "μ°Ύλ κ²½λ‘: $CKPT_BASE/korean_3b_*/metrics.json" | |
| log_warn "λ©νΈλ¦ νμΌμ΄ μμΌλ©΄ νμ΅ μ€ν¬λ¦½νΈμμ μλ νμμΌλ‘ μ μ₯νμΈμ:" | |
| log_warn ' {"val_loss": 2.3, "loss_history": [3.1, 2.8, 2.5, 2.3]}' | |
| record_skip "λ©νΈλ¦ νμΌ μμ β κ²μ΄νΈ 건λλ" | |
| return 0 | |
| fi | |
| log_info "λ©νΈλ¦ νμΌ: $METRICS_FILE" | |
| # val_loss νμΈ | |
| VAL_LOSS=$(json_get "$METRICS_FILE" "val_loss" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$VAL_LOSS" == "NOT_FOUND" ]]; then | |
| record_skip "val_loss ν€ μμ β 건λλ" | |
| else | |
| log_info "val_loss = $VAL_LOSS (κΈ°μ€: < 2.5)" | |
| if py_eval "$VAL_LOSS < 2.5" 2>/dev/null; then | |
| record_pass "val_loss $VAL_LOSS < 2.5" | |
| else | |
| record_fail "val_loss $VAL_LOSS >= 2.5 (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| # loss λ¨μ‘° κ°μ νμΈ (loss_history) | |
| python3 - "$METRICS_FILE" <<'PYEOF' | |
| import json, sys | |
| metrics_file = sys.argv[1] | |
| try: | |
| d = json.load(open(metrics_file)) | |
| history = d.get("loss_history", []) | |
| except Exception as e: | |
| print(f"[SKIP] loss_history μ½κΈ° μ€ν¨: {e}") | |
| sys.exit(0) | |
| if len(history) < 2: | |
| print(f"[SKIP] loss_history λ°μ΄ν° λΆμ‘± ({len(history)}κ°)") | |
| sys.exit(0) | |
| # μ 체 μΆμΈκ° κ°μνλμ§ νμΈ (μ²μ 1/4 vs λ§μ§λ§ 1/4 νκ· λΉκ΅) | |
| n = len(history) | |
| q = max(1, n // 4) | |
| early_avg = sum(history[:q]) / q | |
| late_avg = sum(history[-q:]) / q | |
| if late_avg < early_avg: | |
| print(f"[PASS] loss λ¨μ‘° κ°μ νμΈ: μ΄κΈ° avg={early_avg:.4f} β μ΅κ·Ό avg={late_avg:.4f}") | |
| sys.exit(0) | |
| else: | |
| print(f"[FAIL] loss κ°μ λ―ΈνμΈ: μ΄κΈ° avg={early_avg:.4f}, μ΅κ·Ό avg={late_avg:.4f}") | |
| sys.exit(1) | |
| PYEOF | |
| local mono_exit=$? | |
| if [[ $mono_exit -eq 0 ]]; then | |
| GATE_PASS=$((GATE_PASS + 1)) | |
| elif [[ $mono_exit -eq 1 ]]; then | |
| GATE_FAIL=$((GATE_FAIL + 1)) | |
| fi | |
| # exit 0 (SKIP) λ μ΄λ―Έ μ²λ¦¬λ¨ | |
| } | |
| # ============================================================================= | |
| # Gate 2: SFT | |
| # ============================================================================= | |
| gate_sft() { | |
| echo "" | |
| echo "==================================================================" | |
| echo " Gate: SFT" | |
| echo " κΈ°μ€: val_loss μλ ΄ | λ°λ³΅λ₯ < 15% | KoBEST > 55%" | |
| echo "==================================================================" | |
| METRICS_FILE="" | |
| for candidate in \ | |
| "$PROJECT_DIR/outputs/sft_metrics.json" \ | |
| "$PROJECT_DIR/logs/sft_metrics.json" \ | |
| "$PROJECT_DIR/checkpoints/sft/metrics.json" | |
| do | |
| if [[ -f "$candidate" ]]; then | |
| METRICS_FILE="$candidate" | |
| break | |
| fi | |
| done | |
| if [[ -z "$METRICS_FILE" ]]; then | |
| log_warn "SFT λ©νΈλ¦ νμΌμ μ°Ύμ μ μμ΅λλ€." | |
| log_warn ' {"val_loss": 1.8, "rep_rate": 0.08, "kobest_score": 0.62}' | |
| record_skip "SFT λ©νΈλ¦ νμΌ μμ β κ²μ΄νΈ 건λλ" | |
| return 0 | |
| fi | |
| log_info "λ©νΈλ¦ νμΌ: $METRICS_FILE" | |
| # val_loss μλ ΄ (μλ λ³νμ¨ < 1% β λ§μ§λ§ λ 체ν¬ν¬μΈνΈ) | |
| python3 - "$METRICS_FILE" <<'PYEOF' | |
| import json, sys | |
| metrics_file = sys.argv[1] | |
| try: | |
| d = json.load(open(metrics_file)) | |
| history = d.get("val_loss_history", []) | |
| except Exception as e: | |
| print(f"[SKIP] val_loss_history μ½κΈ° μ€ν¨: {e}") | |
| sys.exit(0) | |
| if len(history) < 2: | |
| # λ¨μΌ val_lossλ§ μμΌλ©΄ λ¨μ νμΈ | |
| val_loss = d.get("val_loss") | |
| if val_loss is not None: | |
| print(f"[INFO] val_loss = {val_loss} (μλ ΄ νμ€ν 리 μμ β λ¨μΌ κ° νμΈ κ±΄λλ)") | |
| sys.exit(0) | |
| last = history[-1] | |
| second = history[-2] | |
| rel_change = abs(last - second) / max(abs(second), 1e-9) | |
| if rel_change < 0.01: | |
| print(f"[PASS] val_loss μλ ΄ (μλλ³νμ¨ {rel_change*100:.3f}% < 1%): {second:.4f} β {last:.4f}") | |
| sys.exit(0) | |
| else: | |
| print(f"[FAIL] val_loss λ―Έμλ ΄ (μλλ³νμ¨ {rel_change*100:.3f}% >= 1%): {second:.4f} β {last:.4f}") | |
| sys.exit(1) | |
| PYEOF | |
| local conv_exit=$? | |
| [[ $conv_exit -eq 0 ]] && GATE_PASS=$((GATE_PASS + 1)) || GATE_FAIL=$((GATE_FAIL + 1)) | |
| # λ°λ³΅λ₯ νμΈ | |
| REP_RATE=$(json_get "$METRICS_FILE" "rep_rate" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$REP_RATE" == "NOT_FOUND" ]]; then | |
| record_skip "rep_rate ν€ μμ β 건λλ" | |
| else | |
| REP_PCT=$(py_value "$REP_RATE * 100") | |
| log_info "λ°λ³΅λ₯ = ${REP_PCT}% (κΈ°μ€: < 15%)" | |
| if py_eval "$REP_RATE < 0.15" 2>/dev/null; then | |
| record_pass "λ°λ³΅λ₯ ${REP_PCT}% < 15%" | |
| else | |
| record_fail "λ°λ³΅λ₯ ${REP_PCT}% >= 15% (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| # KoBEST νμΈ | |
| KOBEST=$(json_get "$METRICS_FILE" "kobest_score" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$KOBEST" == "NOT_FOUND" ]]; then | |
| record_skip "kobest_score ν€ μμ β 건λλ" | |
| else | |
| KOBEST_PCT=$(py_value "$KOBEST * 100") | |
| log_info "KoBEST = ${KOBEST_PCT}% (κΈ°μ€: > 55%)" | |
| if py_eval "$KOBEST > 0.55" 2>/dev/null; then | |
| record_pass "KoBEST ${KOBEST_PCT}% > 55%" | |
| else | |
| record_fail "KoBEST ${KOBEST_PCT}% <= 55% (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| } | |
| # ============================================================================= | |
| # Gate 3: ORPO | |
| # ============================================================================= | |
| gate_orpo() { | |
| echo "" | |
| echo "==================================================================" | |
| echo " Gate: ORPO" | |
| echo " κΈ°μ€: λ°λ³΅λ₯ < 5% | KoBEST > 60% | chosen > rejected 90%+" | |
| echo "==================================================================" | |
| METRICS_FILE="" | |
| for candidate in \ | |
| "$PROJECT_DIR/outputs/orpo_metrics.json" \ | |
| "$PROJECT_DIR/logs/orpo_metrics.json" \ | |
| "$PROJECT_DIR/checkpoints/orpo/metrics.json" | |
| do | |
| if [[ -f "$candidate" ]]; then | |
| METRICS_FILE="$candidate" | |
| break | |
| fi | |
| done | |
| if [[ -z "$METRICS_FILE" ]]; then | |
| log_warn "ORPO λ©νΈλ¦ νμΌμ μ°Ύμ μ μμ΅λλ€." | |
| log_warn ' {"rep_rate": 0.03, "kobest_score": 0.63, "chosen_win_rate": 0.92}' | |
| record_skip "ORPO λ©νΈλ¦ νμΌ μμ β κ²μ΄νΈ 건λλ" | |
| return 0 | |
| fi | |
| log_info "λ©νΈλ¦ νμΌ: $METRICS_FILE" | |
| # λ°λ³΅λ₯ (λ μ격: < 5%) | |
| REP_RATE=$(json_get "$METRICS_FILE" "rep_rate" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$REP_RATE" == "NOT_FOUND" ]]; then | |
| record_skip "rep_rate ν€ μμ β 건λλ" | |
| else | |
| REP_PCT=$(py_value "$REP_RATE * 100") | |
| log_info "λ°λ³΅λ₯ = ${REP_PCT}% (κΈ°μ€: < 5%)" | |
| if py_eval "$REP_RATE < 0.05" 2>/dev/null; then | |
| record_pass "λ°λ³΅λ₯ ${REP_PCT}% < 5%" | |
| else | |
| record_fail "λ°λ³΅λ₯ ${REP_PCT}% >= 5% (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| # KoBEST (λ μ격: > 60%) | |
| KOBEST=$(json_get "$METRICS_FILE" "kobest_score" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$KOBEST" == "NOT_FOUND" ]]; then | |
| record_skip "kobest_score ν€ μμ β 건λλ" | |
| else | |
| KOBEST_PCT=$(py_value "$KOBEST * 100") | |
| log_info "KoBEST = ${KOBEST_PCT}% (κΈ°μ€: > 60%)" | |
| if py_eval "$KOBEST > 0.60" 2>/dev/null; then | |
| record_pass "KoBEST ${KOBEST_PCT}% > 60%" | |
| else | |
| record_fail "KoBEST ${KOBEST_PCT}% <= 60% (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| # Chosen win rate (chosen log-prob > rejected log-prob λΉμ¨) | |
| CHOSEN_WIN=$(json_get "$METRICS_FILE" "chosen_win_rate" 2>/dev/null || echo "NOT_FOUND") | |
| if [[ "$CHOSEN_WIN" == "NOT_FOUND" ]]; then | |
| record_skip "chosen_win_rate ν€ μμ β 건λλ" | |
| else | |
| WIN_PCT=$(py_value "$CHOSEN_WIN * 100") | |
| log_info "Chosen win rate = ${WIN_PCT}% (κΈ°μ€: >= 90%)" | |
| if py_eval "$CHOSEN_WIN >= 0.90" 2>/dev/null; then | |
| record_pass "Chosen win rate ${WIN_PCT}% >= 90%" | |
| else | |
| record_fail "Chosen win rate ${WIN_PCT}% < 90% (κΈ°μ€ λ―Έλ¬)" | |
| fi | |
| fi | |
| } | |
| # ============================================================================= | |
| # Gate 4: Deploy | |
| # ============================================================================= | |
| gate_deploy() { | |
| echo "" | |
| echo "==================================================================" | |
| echo " Gate: DEPLOY" | |
| echo " κΈ°μ€: Q4_K_M perplexity < F16 Γ 1.05 | Ollama 5κ° ν둬ννΈ μλ΅" | |
| echo "==================================================================" | |
| local MODEL_NAME="frankenstallm-3b" | |
| local GGUF_DIR="$PROJECT_DIR/outputs/gguf" | |
| local F16_GGUF="$GGUF_DIR/${MODEL_NAME}-f16.gguf" | |
| local Q4KM_GGUF="$GGUF_DIR/${MODEL_NAME}-Q4_K_M.gguf" | |
| # --- GGUF νμΌ μ‘΄μ¬ νμΈ --- | |
| if [[ ! -f "$Q4KM_GGUF" ]]; then | |
| log_warn "Q4_K_M GGUF νμΌ μμ: $Q4KM_GGUF" | |
| log_warn "λ¨Όμ μ€ν: bash scripts/convert_3b_gguf.sh" | |
| record_skip "GGUF νμΌ μμ β perplexity κ²μ΄νΈ 건λλ" | |
| else | |
| # perplexity μΈ‘μ (llama-perplexity λλ Python fallback) | |
| LLAMA_PPL_BIN="$PROJECT_DIR/outputs/llama.cpp/build/bin/llama-perplexity" | |
| if [[ ! -f "$LLAMA_PPL_BIN" ]]; then | |
| log_warn "llama-perplexity λ°μ΄λ리 μμ β λΉλ μλ μ€ ..." | |
| cmake --build "$PROJECT_DIR/outputs/llama.cpp/build" \ | |
| --target llama-perplexity -j "$(nproc)" &>/dev/null || true | |
| fi | |
| # μν ν μ€νΈλ‘ perplexity λΉκ΅ | |
| SAMPLE_TEXT="$PROJECT_DIR/outputs/gguf/ppl_sample.txt" | |
| if [[ ! -f "$SAMPLE_TEXT" ]]; then | |
| # μ§§μ νκ΅μ΄ μν μμ± | |
| cat > "$SAMPLE_TEXT" <<'SAMPLE' | |
| μΈκ³΅μ§λ₯μ νλ μ¬νμμ λ§€μ° μ€μν κΈ°μ λ‘ μ리μ‘κ³ μμ΅λλ€. | |
| κΈ°κ³ νμ΅κ³Ό λ₯λ¬λμ λ°μ μΌλ‘ μΈν΄ λ€μν λΆμΌμμ νμ μ΄ μ΄λ£¨μ΄μ§κ³ μμ΅λλ€. | |
| μμ°μ΄ μ²λ¦¬ κΈ°μ μ λ°μ μ μΈκ°κ³Ό μ»΄ν¨ν°μ μνΈμμ© λ°©μμ κ·Όλ³Έμ μΌλ‘ λ³νμν€κ³ μμ΅λλ€. | |
| νκ΅μ΄λ κ΅μ°©μ΄λ‘μ νΉμ μ ννλ‘ μ νΉμ±μ κ°μ§κ³ μμ΄ μμ°μ΄ μ²λ¦¬μ λ νΉν λμ μ μ μν©λλ€. | |
| λκ·λͺ¨ μΈμ΄ λͺ¨λΈμ λ±μ₯μΌλ‘ κΈ°κ³ λ²μ, ν μ€νΈ μμ½, μ§μμλ΅ λ±μ μ±λ₯μ΄ ν¬κ² ν₯μλμμ΅λλ€. | |
| SAMPLE | |
| fi | |
| if [[ -f "$LLAMA_PPL_BIN" && -f "$F16_GGUF" ]]; then | |
| log_info "Perplexity μΈ‘μ μ€ (F16 vs Q4_K_M) ..." | |
| PPL_F16=$(timeout 120 "$LLAMA_PPL_BIN" -m "$F16_GGUF" -f "$SAMPLE_TEXT" 2>&1 \ | |
| | grep -oP "Perplexity: \K[0-9.]+" | head -1 || echo "0") | |
| PPL_Q4=$(timeout 120 "$LLAMA_PPL_BIN" -m "$Q4KM_GGUF" -f "$SAMPLE_TEXT" 2>&1 \ | |
| | grep -oP "Perplexity: \K[0-9.]+" | head -1 || echo "0") | |
| if [[ "$PPL_F16" == "0" || "$PPL_Q4" == "0" ]]; then | |
| record_skip "Perplexity μΈ‘μ μ€ν¨ β 건λλ" | |
| else | |
| THRESHOLD=$(py_value "$PPL_F16 * 1.05") | |
| log_info "F16 PPL = $PPL_F16 | Q4_K_M PPL = $PPL_Q4 | κΈ°μ€: < $THRESHOLD" | |
| if py_eval "$PPL_Q4 < $PPL_F16 * 1.05" 2>/dev/null; then | |
| record_pass "Q4_K_M PPL $PPL_Q4 < F16 PPL Γ 1.05 ($THRESHOLD)" | |
| else | |
| record_fail "Q4_K_M PPL $PPL_Q4 >= F16 PPL Γ 1.05 ($THRESHOLD)" | |
| fi | |
| fi | |
| else | |
| record_skip "llama-perplexity λλ F16 GGUF μμ β perplexity κ²μ΄νΈ 건λλ" | |
| fi | |
| fi | |
| # --- Ollama μλ΅ ν μ€νΈ --- | |
| if ! command -v ollama &>/dev/null; then | |
| record_skip "ollama μμ β μλ΅ ν μ€νΈ 건λλ" | |
| return 0 | |
| fi | |
| if ! ollama list 2>/dev/null | grep -q "$MODEL_NAME"; then | |
| log_warn "Ollamaμ $MODEL_NAME λͺ¨λΈμ΄ λ±λ‘λμ§ μμμ΅λλ€." | |
| log_warn "λ¨Όμ μ€ν: bash scripts/deploy_3b_ollama.sh" | |
| record_skip "Ollama λͺ¨λΈ λ―Έλ±λ‘ β μλ΅ ν μ€νΈ 건λλ" | |
| return 0 | |
| fi | |
| log_info "Ollama μλ΅ ν μ€νΈ (5κ° ν둬ννΈ) ..." | |
| declare -a PROMPTS=( | |
| "μλ νμΈμ." | |
| "1 λνκΈ° 1μ 무μμΈκ°μ?" | |
| "νμ΄μ¬μ΄λ 무μμΈκ°μ?" | |
| "νκ΅μ μλλ μ΄λμΈκ°μ?" | |
| "μ€λ λ μ¨κ° μ’λ€μ." | |
| ) | |
| local PASS=0 FAIL=0 | |
| for i in "${!PROMPTS[@]}"; do | |
| local PROMPT="${PROMPTS[$i]}" | |
| local NUM=$((i + 1)) | |
| if RESP=$(timeout 45 ollama run "$MODEL_NAME" "$PROMPT" 2>&1) && [[ -n "$RESP" ]]; then | |
| log_ok " ν둬ννΈ $NUM μλ΅ OK (${#RESP}μ)" | |
| PASS=$((PASS + 1)) | |
| else | |
| log_fail " ν둬ννΈ $NUM μλ΅ μ€ν¨" | |
| FAIL=$((FAIL + 1)) | |
| fi | |
| done | |
| log_info "Ollama μλ΅: $PASS/5 μ±κ³΅" | |
| if [[ $FAIL -eq 0 ]]; then | |
| record_pass "Ollama 5κ° ν둬ννΈ λͺ¨λ μλ΅ μ±κ³΅" | |
| else | |
| record_fail "Ollama μλ΅ μ€ν¨ $FAIL/5" | |
| fi | |
| } | |
| # ============================================================================= | |
| # μ΅μ’ μμ½ μΆλ ₯ | |
| # ============================================================================= | |
| print_summary() { | |
| local phase="$1" | |
| local TOTAL=$((GATE_PASS + GATE_FAIL + GATE_SKIP)) | |
| echo "" | |
| echo "==================================================================" | |
| echo " Quality Gate κ²°κ³Ό: $phase" | |
| echo " PASS: $GATE_PASS | FAIL: $GATE_FAIL | SKIP: $GATE_SKIP | TOTAL: $TOTAL" | |
| echo "==================================================================" | |
| if [[ $GATE_FAIL -eq 0 ]]; then | |
| echo -e "${_GREEN} [GATE PASSED]${_NC} λͺ¨λ κ²μ¦ κΈ°μ€ ν΅κ³Ό" | |
| echo "" | |
| return 0 | |
| else | |
| echo -e "${_RED} [GATE FAILED]${_NC} ${GATE_FAIL}κ° κ²μ¦ κΈ°μ€ λ―Έλ¬" | |
| echo " μ€ν¨ νλͺ©μ μμ ν ν λ€μ μ€ννμΈμ." | |
| echo "" | |
| return 1 | |
| fi | |
| } | |
| # ============================================================================= | |
| # μ§μ μ | |
| # ============================================================================= | |
| PHASE="${1:-}" | |
| if [[ -z "$PHASE" ]]; then | |
| echo "Usage: bash scripts/quality_gate.sh <phase>" | |
| echo " phase: pretrain | sft | orpo | deploy | all" | |
| exit 2 | |
| fi | |
| echo "" | |
| echo "==================================================================" | |
| echo " Quality Gate κ²μ¦ μμ: $PHASE" | |
| echo " νλ‘μ νΈ: $PROJECT_DIR" | |
| echo " μκ° : $(date '+%Y-%m-%d %H:%M:%S')" | |
| echo "==================================================================" | |
| case "$PHASE" in | |
| pretrain) | |
| gate_pretrain | |
| print_summary "pretrain" | |
| ;; | |
| sft) | |
| gate_sft | |
| print_summary "sft" | |
| ;; | |
| orpo) | |
| gate_orpo | |
| print_summary "orpo" | |
| ;; | |
| deploy) | |
| gate_deploy | |
| print_summary "deploy" | |
| ;; | |
| all) | |
| gate_pretrain | |
| gate_sft | |
| gate_orpo | |
| gate_deploy | |
| print_summary "all" | |
| ;; | |
| *) | |
| echo "ERROR: μ μ μλ phase: $PHASE" | |
| echo "Usage: bash scripts/quality_gate.sh <pretrain|sft|orpo|deploy|all>" | |
| exit 2 | |
| ;; | |
| esac | |