Skip to content

pathcosmos/frankenstallm_test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FRANKENSTALLM 3B 평가 프레임워크

한국어 특화 커스텀 LLM인 FRANKENSTALLM 3B를 5개 비교 모델과 함께 7개 트랙으로 종합 평가하는 프레임워크.

빠른 시작 (Quick Start)

# 1. 리포지토리 클론
git clone https://github.com/lanco/frankenstallm_test.git
cd frankenstallm_test

# 2. Ollama 설치 (이미 설치되어 있으면 건너뛰기)
curl -fsSL https://ollama.com/install.sh | sh

# 3. Python 패키지 설치
pip install -r requirements.txt
sudo apt install -y fonts-nanum  # 한국어 폰트 (리포트 차트용)

# 4. 비교 모델 다운로드
ollama pull qwen2.5:3b
ollama pull gemma3:4b
ollama pull phi4-mini
ollama pull exaone3.5:2.4b
ollama pull llama3.2:3b

# 5. 평가 실행
python run_evaluation.py

시스템 요구사항

항목 최소 권장
OS Ubuntu 22.04+ Ubuntu 24.04
Python 3.12+ 3.12
RAM 16GB 32GB
GPU 없음 (CPU 가능) NVIDIA 16GB+ VRAM
디스크 20GB 여유 50GB 여유

환경 구성 상세

Ollama 설치

curl -fsSL https://ollama.com/install.sh | sh

Ollama 모델 저장 경로 설정 (선택)

기본 경로(~/.ollama/models)를 변경하려면:

export OLLAMA_MODELS=/var/ollama/models

eval_framework/config.py에서 os.environ.setdefault("OLLAMA_MODELS", "/var/ollama/models")로 설정되어 있음. 다른 경로를 사용한다면 config.py도 수정.

Python 패키지

pip install -r requirements.txt

필수 패키지: matplotlib, requests, numpy, scipy

한국어 폰트 (리포트 차트용)

sudo apt install -y fonts-nanum

시스템 튜닝 (선택)

대용량 모델 로딩 시 swap thrashing 방지:

sudo sysctl -w vm.swappiness=10

모델 설치

비교 모델 (5개)

ollama pull qwen2.5:3b       # Alibaba Qwen 2.5, 3.1B, Q4_K_M
ollama pull gemma3:4b         # Google Gemma 3, 4.3B, Q4_K_M
ollama pull phi4-mini          # Microsoft Phi-4 Mini, 3.8B, Q4_K_M
ollama pull exaone3.5:2.4b    # LG AI EXAONE 3.5, 2.7B, Q4_K_M
ollama pull llama3.2:3b       # Meta LLaMA 3.2, 3.2B, Q4_K_M

FRANKENSTALLM v2 커스텀 모델 (3개)

FRANKENSTALLM v2 GGUF 파일을 준비한 후 Modelfile 템플릿으로 등록:

# 1. GGUF 파일을 적절한 위치에 배치
# 2. modelfiles/ 의 Modelfile에서 <PATH_TO_GGUF>를 실제 경로로 수정
# 3. Ollama에 등록

ollama create frankenstallm-3b-v2-Q4_K_M -f modelfiles/Modelfile.v2-Q4_K_M
ollama create frankenstallm-3b-v2-Q8_0   -f modelfiles/Modelfile.v2-Q8_0
ollama create frankenstallm-3b-v2-f16    -f modelfiles/Modelfile.v2-f16

각 모델의 양자화별 파일 크기:

양자화 파일 크기 파라미터 수 비고
Q4_K_M 757 MB 1.2B 가장 빠름, 기본 권장
Q8_0 1.2 GB 1.2B 균형
F16 2.3 GB 1.2B 최고 품질, GPU 권장

v1 모델 주의사항: v1 GGUF는 SPM 토크나이저의 byte_to_token 매핑 결함으로 llama.cpp 계열 엔진에서 SIGABRT 크래시 발생. v2만 사용 가능.


EVAFRILL-Mo 모델 설정 (PyTorch 직접 추론)

EVAFRILL-Mo-3B란?

EVAFRILL-Mo-3B는 Mamba-2 + Transformer 하이브리드 아키텍처(2.94B 파라미터)의 한국어 LLM이다. 26개 레이어 중 24개가 Mamba-2 SSM 블록, 2개가 Attention(GQA) 블록으로 구성된 실험적 모델.

Ollama/GGUF로 실행할 수 없다. Mamba-2 SSM 아키텍처는 llama.cpp/GGUF 포맷이 지원하지 않으므로, eval_framework/evafrill_runner.py를 통해 PyTorch로 직접 추론한다.

아키텍처 상세(hybrid pattern, config.json 파라미터, SLERP 머지 설명, GGUF 미지원 기술 분석, 추론 파이프라인 등)는 MODEL_DETAILS.md 섹션 3.6을 참조.

GGUF/Ollama 미지원 이유

제약 설명
아키텍처 미지원 llama.cpp GGUF는 LLaMA, Qwen, Gemma 등 표준 Transformer만 지원. Mamba-2의 Selective State Space(SSM) 연산은 GGUF에 구현되어 있지 않음
KV 캐시 부재 Mamba-2는 KV 캐시 대신 hidden state를 유지. llama.cpp의 KV 캐시 기반 최적화 파이프라인과 호환 불가
커스텀 커널 Mamba-2의 selective_scan, causal_conv1d 등은 별도 CUDA 커널이 필요. GGUF 추론 엔진에 해당 커널 없음
결과 매 토큰 생성마다 full-sequence forward pass 필요 → O(n^2) 총 생성 비용, TPS 극히 낮음

이것은 구현 미비가 아니라 아키텍처의 근본적 차이에 의한 제약이다.

모델 소스 코드 설치

EVAFRILL-Mo의 커스텀 모듈(model/config.py, model/transformer.py, model/mamba_block.py 등)이 필요하다.

# 소스 코드 클론
git clone https://github.com/pathcosmos/EVAFRILL-Mo /home/lanco/models/EVAFRILL-Mo

# 디렉토리 구조 확인
ls /home/lanco/models/EVAFRILL-Mo/model/
# config.py  transformer.py  attention.py  mamba_block.py  layers.py  lora.py  __init__.py

evafrill_runner.py가 이 경로를 sys.path에 추가하여 from model.config import LMConfig 등을 import한다.

체크포인트 다운로드

체크포인트는 HuggingFace Hub에서 다운로드한다. SLERP 체크포인트가 권장 최종 모델이다.

# HuggingFace에서 전체 클론 (Git LFS 필요)
git lfs install
git clone https://huggingface.co/pathcosmos/EVAFRILL-Mo-3B /home/lanco/models/EVAFRILL-Mo-3B

# 또는 slerp 디렉토리만 수동 배치
mkdir -p /home/lanco/models/EVAFRILL-Mo-3B/slerp

필요 파일 3개:

파일 크기 설명
config.json 687 B 모델 아키텍처 설정 (vocab, layers, hybrid pattern 등)
model.safetensors 5.9 GB 모델 가중치 (BF16, SafeTensors 형식)
tokenizer.json 4.2 MB HuggingFace Tokenizer (vocab 64,000)

체크포인트 계보:

pretrain (319K steps, 55B tokens)
    └── sft-v2 (Supervised Fine-Tuning)
            ├── dpo-r1 → dpo-r2 → dpo-r3 (Direct Preference Optimization)
            └── orpo (Odds Ratio Preference Optimization)

SLERP = sft-v2 ⊕ dpo-r2 (Spherical Linear Interpolation, alpha=0.5)

SLERP(Spherical Linear Interpolation): 가중치를 단위 구면 위에서 보간하여 두 학습 변형의 장점을 결합하는 기법. 단순 선형 평균보다 학습된 표현을 더 잘 보존한다.

의존성 (Python 패키지)

# 필수 (requirements.txt에 포함되지 않음 — EVAFRILL 전용)
pip install torch safetensors tokenizers PyYAML

# 선택 (GPU 가속 커널, 없으면 PyTorch 순수 구현으로 fallback)
pip install mamba_ssm causal_conv1d
패키지 용도 필수 여부
torch PyTorch 추론 엔진 필수
safetensors 모델 가중치 로딩 필수
tokenizers HuggingFace Tokenizer 필수
PyYAML 모델 설정 직렬화 필수
mamba_ssm Mamba-2 Triton CUDA 커널 선택 (성능 향상)
causal_conv1d Causal Conv1D CUDA 커널 선택 (성능 향상)
flash_attn FlashAttention-2 선택 (추론 시 비활성화됨)

시스템 요구사항

항목 최소 권장
GPU VRAM 8 GB 16 GB+
정밀도 BF16 지원 (NVIDIA Ampere+) BF16
RAM 16 GB 32 GB
CPU 추론 가능 (극히 느림, ~0.5 TPS) GPU 사용 권장

실행 방법

자동 (평가 프레임워크)run_evaluation.py에서 EVAFRILL 모델명이 감지되면 자동으로 evafrill_runner.py로 위임:

python run_evaluation.py --models evafrill-mo-3b-slerp --tracks 6

독립 사용 (Python 코드):

from eval_framework.evafrill_runner import generate, load_model, unload_model

# 추론
result = generate("한국어로 인사해주세요.")
print(result["response"])
print(f"속도: {result['tokens_per_sec']:.1f} TPS")
print(f"생성 토큰: {result['eval_count']}개")

# 메모리 해제
unload_model()

성능 특성

항목 비고
GPU TPS ~4.8 RTX 5060 Ti 16GB 기준
CPU TPS ~0.5 (추정) 실용적이지 않음
타임아웃 600초 (10분) config.py에서 설정
최대 생성 길이 512 토큰 num_predict 기본값
메모리 사용 ~6-8 GB VRAM 5.9 GB 가중치 + 활성화 값

느린 이유: Mamba-2 아키텍처에 KV 캐시가 없어 매 토큰마다 전체 시퀀스를 forward pass해야 함. n개 토큰 생성 시 총 O(n^2) 연산. Ollama 모델(Q4_K_M)의 100-200 TPS와 비교하면 20-40배 느림. 기술적 상세는 MODEL_DETAILS.md의 GGUF 미지원 기술적 설명 참조.

경로 변경

모델 파일이 다른 위치에 있다면 eval_framework/evafrill_runner.py의 두 경로를 수정:

# evafrill_runner.py line 19 — 모델 소스 코드 (커스텀 Python 모듈)
_EVAFRILL_SRC = Path("/home/lanco/models/EVAFRILL-Mo")

# evafrill_runner.py line 31 — 체크포인트 (가중치, 토크나이저)
EVAFRILL_CHECKPOINT = Path("/home/lanco/models/EVAFRILL-Mo-3B/slerp")

GPU vs CPU 모드

GPU 모드 (권장)

기본 동작. Ollama가 자동으로 NVIDIA GPU를 감지하여 사용.

ollama serve  # GPU 자동 감지

config.pynvidia-smi로 GPU 가용성을 확인하고 타임아웃을 자동 조정:

  • GPU 모드: 기본 타임아웃 (Q4_K_M: 120초, Q8_0: 180초, F16: 300초)
  • CPU 모드: 타임아웃 2배 자동 적용

CPU 모드

GPU 없이 실행하려면:

CUDA_VISIBLE_DEVICES="" ollama serve

CPU 모드는 상당히 느림. F16 모델은 응답 하나에 수 분 소요 가능.


평가 실행

기본 실행 (전체 7트랙)

python run_evaluation.py

특정 트랙만 실행

python run_evaluation.py --tracks 1 4 5
python run_evaluation.py --tracks 6      # Track 6만 (성능 벤치마크)

특정 모델만 실행

python run_evaluation.py --models frankenstallm-3b-v2-Q4_K_M qwen2.5:3b

기존 결과로 리포트만 생성

python run_evaluation.py --report-only

7개 평가 트랙

트랙 이름 설명 LLM-as-Judge
1 Korean Bench KoBEST 4개 태스크 (BoolQ, COPA, SentiNeg, HellaSwag)
2 KO-Bench 8개 카테고리 한국어 생성 품질 O
3 Korean Deep 심층 한국어 이해력 O
4 Code & Math 코딩/수학 문제 해결
5 Consistency 응답 일관성 테스트
6 Performance 토큰 속도, 레이턴시, 동시성
7 Pairwise 모델 쌍대비교 O

3단계 분할 실행 전략

전체 실행이 오래 걸리므로 단계별 분할 권장:

# Stage 1: 자동 채점 트랙 (LLM Judge 불필요)
python run_evaluation.py --tracks 1 4 5 6

# Stage 2: LLM-as-Judge 트랙 (Claude CLI 필요)
python run_evaluation.py --tracks 2 3 7

# Stage 3: 리포트 생성
python run_evaluation.py --report-only

체크포인트 & 이어하기

평가가 중단되어도 자동으로 체크포인트가 저장됨 (results/*_checkpoint.json).

재실행 시 체크포인트를 자동 로드하여 이어서 진행:

# 중단 후 동일 명령으로 재실행하면 자동 이어하기
python run_evaluation.py --tracks 1 4 5

Claude CLI 설정

Track 2, 3, 7은 LLM-as-Judge로 Claude를 사용. claude CLI가 PATH에 있어야 함.

# Claude CLI 설치 확인
which claude

# 테스트
claude -p "Hello"

Claude CLI가 없으면 Track 2, 3, 7은 건너뛰고 나머지 트랙만 실행하면 됨.


Ollama Watchdog

Ollama가 대용량 모델 로딩 중 크래시할 수 있음. 자동 재시작 스크립트:

chmod +x ollama_watchdog.sh
./ollama_watchdog.sh &

트러블슈팅

Ollama GPU 크래시

GPU VRAM 부족 시 Ollama가 크래시할 수 있음:

# GPU 상태 확인
nvidia-smi

# GPU 메모리 비우기 — 로드된 모델 모두 해제
curl http://localhost:11434/api/ps  # 현재 로드된 모델 확인

Ollama 반복 재시작

# Ollama 프로세스 정리 후 재시작
pkill -9 -f ollama
sleep 3
ollama serve &

v1 모델 SIGABRT

v1 모델(frankenstallm-3b-Q4_K_M 등)은 SPM 토크나이저 결함으로 실행 불가. v2 모델만 사용.

"모델을 찾을 수 없음" 오류

# 설치된 모델 목록 확인
ollama list

# Ollama 모델 저장 경로 확인
echo $OLLAMA_MODELS

한국어 차트 깨짐

sudo apt install -y fonts-nanum
# matplotlib 캐시 삭제
python -c "import matplotlib; print(matplotlib.get_cachedir())"
rm -rf ~/.cache/matplotlib

EVAFRILL 관련 오류

ModuleNotFoundError: No module named 'model.config'

  • 모델 소스 코드가 클론되지 않았거나 경로가 잘못됨
  • 확인: ls /home/lanco/models/EVAFRILL-Mo/model/config.py
  • 해결: git clone https://github.com/pathcosmos/EVAFRILL-Mo /home/lanco/models/EVAFRILL-Mo

FileNotFoundError: model.safetensors

  • 체크포인트 파일이 없거나 경로가 잘못됨
  • 확인: ls -la /home/lanco/models/EVAFRILL-Mo-3B/slerp/model.safetensors (5.9 GB여야 함)
  • 135 B이면 Git LFS 포인터만 있는 상태 → git lfs pull 필요

RuntimeError: CUDA out of memory

  • EVAFRILL은 BF16으로 ~6-8 GB VRAM 필요
  • 다른 모델이 VRAM을 점유 중이면: curl http://localhost:11434/api/ps로 확인 후 해제
  • GPU 메모리 부족 시 CPU 모드로 fallback됨 (극히 느림)

ModuleNotFoundError: No module named 'torch'

  • PyTorch 미설치. pip install torch (CPU) 또는 CUDA 버전 설치

EVAFRILL CUDA 실패 → Ollama 무한 재시작 문제 (2026-03-30 수정)

증상: EVAFRILL-Mo 모델 로딩 시 CUDA error: unknown error (cudaErrorUnknown) 발생 후, 이후 모든 Ollama 모델이 로딩 불가. Ollama 재시작이 무한 반복되며 평가가 표류(drift)함.

근본 원인: cudaErrorUnknown은 일반 OOM과 달리 GPU 드라이버 레벨 오염을 일으킨다. EVAFRILL은 PyTorch로 cuda:0에 직접 텐서를 올리는데(evafrill_runner.py:load_model()), 이 과정에서 CUDA 컨텍스트가 비복구 상태로 손상되면 **같은 GPU를 공유하는 Ollama(별도 프로세스)**도 CUDA를 사용할 수 없게 된다.

인과 체인:

EVAFRILL model.to(cuda:0) 실패
  → GPU 드라이버 오염 (cudaErrorUnknown)
  → 정리 코드 없이 return False
  → 트랙 전환 시 GPU 상태 확인 없음
  → Ollama 재시작 시 config.GPU_AVAILABLE=True (import 시점 캐시)
  → Ollama가 GPU 모드로 재시작 → GPU 초기화 실패
  → 60초 대기 → 재시작 3회 → 전부 실패
  → 외부 재시도 루프와 중첩 → 수시간 표류
  → SSH 세션 타임아웃으로 끊김

수정 내용 (3-레이어 방어):

레이어 파일 변경
발생 지점 evafrill_runner.py model.to(cuda:0) 실패 시 del model + gc.collect() + torch.cuda.synchronize() + empty_cache() 정리. gpu_is_healthy()(nvidia-smi)로 드라이버 오염 여부 진단 로그
복구 지점 runner.py _restart_ollama()가 재시작 전 _gpu_healthy_now()로 GPU 상태 동적 확인 (import 시점 캐시 config.GPU_AVAILABLE 대신). GPU 죽었으면 nvidia-smi --gpu-reset 시도, 실패 시 CUDA_VISIBLE_DEVICES="" CPU 모드 폴백. switch_model()에서 EVAFRILL 실패 시 evafrill_runner.unload_model()로 CUDA 정리 후, _gpu_healthy_now()가 이상 감지한 경우에만 GPU 리셋 시도
전환 지점 run_evaluation.py 트랙 간 쿨다운에서 GPU 헬스체크 추가. 이상 감지 시 GPU 리셋 시도 후, 리셋 성공 여부와 무관하게 _restart_ollama() 호출 (GPU 오염 후에는 Ollama도 재시작 필요)

수정 후 동작:

EVAFRILL model.to(cuda:0) 실패
  → del model + gc.collect() + CUDA cleanup
  → nvidia-smi로 GPU 상태 확인
  → GPU 오염 감지 → nvidia-smi --gpu-reset 시도
  → 리셋 성공: Ollama GPU 모드로 정상 재시작
  → 리셋 실패: Ollama CPU 모드로 폴백 (느리지만 평가 계속 진행)

핵심 변경 함수:

함수 파일 역할
_cuda_cleanup() evafrill_runner.py CUDA 실패 후 gc + synchronize + empty_cache + reset_peak_memory_stats (각 단계 try-except 래핑)
gpu_is_healthy() evafrill_runner.py nvidia-smi 호출로 GPU 드라이버 상태 동적 확인
_gpu_healthy_now() runner.py Ollama 재시작 전 GPU 상태 동적 확인
_try_gpu_reset() runner.py nvidia-smi --gpu-reset -i 0 실행, 성공 여부 반환
switch_model() (수정) runner.py EVAFRILL 실패 시 unload_model() + 조건부 GPU 리셋 추가

관련 기술 배경:

  • cudaErrorUnknown vs cudaErrorMemoryAllocation: OOM은 프로세스 레벨로 empty_cache()로 복구 가능하지만, unknown error는 드라이버 레벨 오염으로 GPU 리셋 또는 리부팅이 필요
  • config.GPU_AVAILABLEconfig.py import 시점에 1회만 평가되는 상수. CUDA 실패 후에도 True로 유지되어 Ollama를 계속 GPU 모드로 재시작하는 것이 무한 루프의 직접 원인이었음
  • nvidia-smi --gpu-reset은 실행 중인 CUDA 프로세스가 없어야 동작함. Ollama를 먼저 종료(pkill)한 뒤 리셋해야 함

테스트 (pytest)

테스트 설치 및 실행

# 1. 개발 의존성 설치
pip install -r requirements-dev.txt

# 2. 전체 테스트 실행
pytest tests/ -v

# 3. 단위 테스트만
pytest tests/unit/ -v

# 4. 통합 테스트만
pytest tests/integration/ -v

# 5. 커버리지 리포트
pytest tests/ --cov=eval_framework --cov-report=term-missing

테스트 구조

116개 테스트 — 모두 Ollama 서버나 GPU 없이 실행 가능 (mock 기반)

파일 테스트 수 대상 모듈
tests/unit/test_judge.py 31 _call_judge, _extract_json, score_response, score_pairwise, score_with_criteria
tests/unit/test_runner.py 31 generate, chat, switch_model, wait_for_ollama, health check, checkpoint I/O
tests/unit/test_scoring.py 17 aggregate_accuracy, aggregate_judge_scores, fit_bradley_terry, build_scorecard
tests/unit/test_config.py 11 _gpu_available, 타임아웃 계산, 모델 리스트 일관성
tests/unit/test_evafrill_runner.py 9 is_evafrill, _top_p_filtering (torch CPU)
tests/unit/test_data_externalization.py 9 Track 2/7 JSON 로딩, 스키마 검증, fallback
tests/integration/test_judge_pipeline.py 3 score → aggregate → Elo 파이프라인
tests/integration/test_model_lifecycle.py 3 모델 전환 A→B→C, 서버 재시작, evafrill↔ollama
tests/integration/test_track_execution.py 2 Track 7 최소 실행, 체크포인트 이어하기

커버리지 현황

모듈 커버리지
judge.py 97%
scoring.py 98%
config.py 98%
runner.py 83%

프로젝트 구조

frankenstallm_test/
├── run_evaluation.py          # 메인 실행 스크립트
├── benchmark.py               # 단독 벤치마크
├── ollama_watchdog.sh         # Ollama 자동 재시작
├── requirements.txt           # Python 의존성 (런타임)
├── requirements-dev.txt       # Python 의존성 (개발/테스트)
├── pytest.ini                 # pytest 설정
├── eval_framework/            # 평가 프레임워크 코어
│   ├── config.py              # 설정 (모델, 타임아웃, 파라미터)
│   ├── runner.py              # Ollama API 실행 엔진
│   ├── judge.py               # LLM-as-Judge (Ollama gemma3:12b)
│   ├── evafrill_runner.py     # EVAFRILL-Mo-3B PyTorch 직접 추론
│   ├── scoring.py             # 스코어카드 계산 + Bradley-Terry Elo
│   ├── report.py              # HTML/Markdown 리포트 생성
│   └── tracks/                # 7개 평가 트랙
│       ├── track1_korean_bench.py
│       ├── track2_ko_bench.py
│       ├── track3_korean_deep.py
│       ├── track4_code_math.py
│       ├── track5_consistency.py
│       ├── track6_performance.py
│       └── track7_pairwise.py
├── tests/                     # pytest 테스트 스위트
│   ├── conftest.py            # 공유 fixtures (Ollama mock, 샘플 데이터)
│   ├── unit/                  # 단위 테스트 (6 파일, 108개)
│   │   ├── test_judge.py
│   │   ├── test_runner.py
│   │   ├── test_scoring.py
│   │   ├── test_config.py
│   │   ├── test_evafrill_runner.py
│   │   └── test_data_externalization.py
│   └── integration/           # 통합 테스트 (3 파일, 8개)
│       ├── test_judge_pipeline.py
│       ├── test_model_lifecycle.py
│       └── test_track_execution.py
├── data/                      # 벤치마크 데이터셋
│   ├── code_problems/
│   ├── ko_bench/
│   │   └── questions.json     # Track 2 질문 (80개, 외부화)
│   ├── korean_deep/
│   ├── math_problems/
│   └── track7_prompts.json    # Track 7 프롬프트 (20개, 외부화)
├── results/                   # 평가 결과 (체크포인트 포함)
├── reports/                   # 생성된 리포트
├── modelfiles/                # FRANKENSTALLM Modelfile 템플릿
│   ├── Modelfile.v2-Q4_K_M
│   ├── Modelfile.v2-Q8_0
│   └── Modelfile.v2-f16
├── MODEL_DETAILS.md           # 전체 14개 모델 상세 스펙 (EVAFRILL 아키텍처/SLERP 포함)
└── TEST_LOG.md                # 테스트 진행 기록

라이선스

Private research project.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors