메뉴
BL
MarkTechPost 42일 전

초경량 1비트 라마 모델 'Bonsai' CUDA 활용 실전 튜토리얼

IMP
6/10
핵심 요약

이 튜토리얼에서는 GPU 가속과 PrismML의 최적화된 GGUF 배포 스택을 활용해 1비트 대형 언어 모델인 Bonsai를 효율적으로 구동하는 방법을 다룹니다. 1비트 양자화가 어떻게 메모리 효율성을 극대화하여 가벼우면서도 성능 좋은 모델 배포를 가능하게 하는지 설명합니다. 나아가 기본 추론, 벤치마크, 멀티턴 챗봇, JSON 및 코드 생성, OpenAI 호환 서버 모드, RAG 워크플로우 등 실제 사용 사례를 통해 Bonsai의 실전 활용도를 보여줍니다.

번역된 본문

기술 AI 쇼츠 인공지능 에디터 추천 언어 모델 직원 튜토리얼

이 튜토리얼에서는 GPU 가속과 PrismML의 최적화된 GGUF 배포 스택을 사용하여 Bonsai 1비트 대형 언어 모델을 효율적으로 실행하는 방법을 구현해 봅니다. 환경을 설정하고 필요한 종속성을 설치하며, 미리 빌드된 llama.cpp 바이너리를 다운로드하고, CUDA에서 빠른 추론을 위해 Bonsai-1.7B 모델을 로드합니다.

진행 과정에서 1비트 양자화가 내부적으로 어떻게 작동하는지, Q1_0_g128 포맷이 왜 그토록 메모리 효율이 뛰어난지, 그리고 이것이 어떻게 Bonsai를 가볍고 유능한 언어 모델 배포에 실용적으로 만드는지 살펴봅니다. 또한 핵심 추론, 벤치마킹, 멀티턴 대화, 구조화된 JSON 생성, 코드 생성, OpenAI 호환 서버 모드 및 소규모 검색 증강 생성(RAG) 워크플로우를 테스트하여 실제 사용 환경에서 Bonsai가 어떻게 작동하는지에 대한 완전한 실습 뷰를 제공합니다.

코드 복사 완료. 다른 브라우저를 사용하세요.

import os, sys, subprocess, time, json, urllib.request, tarfile, textwrap try: import google.colab IN_COLAB = True except ImportError: IN_COLAB = False

def section(title): bar = "═" * 60 print(f"\n{bar}\n {title}\n{bar}")

section("1 · 환경 및 GPU 확인")

def run(cmd, capture=False, check=True, **kw): return subprocess.run( cmd, shell=True, capture_output=capture, text=True, check=check, **kw )

gpu_info = run("nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader", capture=True, check=False) if gpu_info.returncode == 0: print("✅ GPU 감지됨:", gpu_info.stdout.strip()) else: print("⚠️ GPU를 찾을 수 없음 — CPU에서 추론이 실행됩니다 (훨씬 느림).")

cuda_check = run("nvcc --version", capture=True, check=False) if cuda_check.returncode == 0: for line in cuda_check.stdout.splitlines(): if "release" in line: print(" CUDA:", line.strip()) break

print(f" Python {sys.version.split()[0]} | 플랫폼: Linux (Colab)")

section("2 · Python 종속성 설치") run("pip install -q huggingface_hub requests tqdm openai") print("✅ huggingface_hub, requests, tqdm, openai 설치 완료")

from huggingface_hub import hf_hub_download

시스템 작업, 다운로드, 시간 측정 및 JSON 처리에 필요한 핵심 Python 모듈을 가져오는 것으로 시작합니다. Google Colab 내부에서 실행 중인지 확인하고, 재사용 가능한 섹션 출력기를 정의하며, Python에서 셸 명령을 깔끔하게 실행할 수 있는 도우미 함수를 만듭니다. 그런 다음 GPU 및 CUDA 환경을 확인하고, Python 런타임 세부 정보를 출력하며, 필요한 Python 종속성을 설치하고, 다음 단계를 위해 Hugging Face 다운로드 유틸리티를 준비합니다.

코드 복사 완료. 다른 브라우저를 사용하세요.

section("3 · PrismML llama.cpp 사전 빌드된 바이너리 다운로드")

RELEASE_TAG = "prism-b8194-1179bfc" BASE_URL = f"https://github.com/PrismML-Eng/llama.cpp/releases/download/{RELEASE_TAG}" BIN_DIR = "/content/bonsai_bin" os.makedirs(BIN_DIR, exist_ok=True)

def detect_cuda_build(): r = run("nvcc --version", capture=True, check=False) for line in r.stdout.splitlines(): if "release" in line: try: ver = float(line.split("release")[-1].strip().split(",")[0].strip()) if ver >= 13.0: return "13.1" if ver >= 12.6: return "12.8" return "12.4" except ValueError: pass return "12.4"

cuda_build = detect_cuda_build() print(f" 감지된 CUDA 빌드 슬롯: {cuda_build}")

TAR_NAME = f"llama-{RELEASE_TAG}-bin-linux-cuda-{cuda_build}-x64.tar.gz" TAR_URL = f"{BASE_URL}/{TAR_NAME}" tar_path = f"/tmp/{TAR_NAME}"

if not os.path.exists(f"{BIN_DIR}/llama-cli"): print(f" 다운로드 중: {TAR_URL}") urllib.request.urlretrieve(TAR_URL, tar_path) print(" 압축 해제 중 …") with tarfile.open(tar_path, "r:gz") as t: t.extractall(BIN_DIR) for fname in os.listdir(BIN_DIR): fp = os.path.join(BIN_DIR, fname) if os.path.isfile(fp): os.chmod(fp, 0o755) print(f"✅ {BIN_DIR}에 바이너리 압축이 풀렸습니다") bins = sorted(f for f in os.listdir(BIN_DIR) if os.path.isfile(os.path.join(BIN_DIR, f))) print(" 사용 가능:", ", ".join(bins)) else: print(f"✅ {BIN_DIR}에 바이너리가 이미 존재합니다")

LLAMA_CLI = f"{BIN_DIR}/llama-cli" LLAMA_SERVER = f...

원문 보기
원문 보기 (영어)
Technology AI Shorts Artificial Intelligence Editors Pick Language Model Staff Tutorials In this tutorial, we implement how to run the Bonsai 1-bit large language model efficiently using GPU acceleration and PrismML’s optimized GGUF deployment stack. We set up the environment, install the required dependencies, and download the prebuilt llama.cpp binaries, and load the Bonsai-1.7B model for fast inference on CUDA. As we progress, we examine how 1-bit quantization works under the hood, why the Q1_0_g128 format is so memory-efficient, and how this makes Bonsai practical for lightweight yet capable language model deployment. We also test core inference, benchmarking, multi-turn chat, structured JSON generation, code generation, OpenAI-compatible server mode, and a small retrieval-augmented generation workflow, giving us a complete, hands-on view of how Bonsai operates in real-world use. Copy Code Copied Use a different Browser import os, sys, subprocess, time, json, urllib.request, tarfile, textwrap try: import google.colab IN_COLAB = True except ImportError: IN_COLAB = False def section(title): bar = "═" * 60 print(f"\n{bar}\n {title}\n{bar}") section("1 · Environment & GPU Check") def run(cmd, capture=False, check=True, **kw): return subprocess.run( cmd, shell=True, capture_output=capture, text=True, check=check, **kw ) gpu_info = run("nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader", capture=True, check=False) if gpu_info.returncode == 0: print("✅ GPU detected:", gpu_info.stdout.strip()) else: print("⚠️ No GPU found — inference will run on CPU (much slower).") cuda_check = run("nvcc --version", capture=True, check=False) if cuda_check.returncode == 0: for line in cuda_check.stdout.splitlines(): if "release" in line: print(" CUDA:", line.strip()) break print(f" Python {sys.version.split()[0]} | Platform: Linux (Colab)") section("2 · Installing Python Dependencies") run("pip install -q huggingface_hub requests tqdm openai") print("✅ huggingface_hub, requests, tqdm, openai installed") from huggingface_hub import hf_hub_download We begin by importing the core Python modules that we need for system operations, downloads, timing, and JSON handling. We check whether we are running inside Google Colab, define a reusable section printer, and create a helper function to run shell commands cleanly from Python. We then verify the GPU and CUDA environment, print the Python runtime details, install the required Python dependencies, and prepare the Hugging Face download utility for the next stages. Copy Code Copied Use a different Browser section("3 · Downloading PrismML llama.cpp Prebuilt Binaries") RELEASE_TAG = "prism-b8194-1179bfc" BASE_URL = f"https://github.com/PrismML-Eng/llama.cpp/releases/download/{RELEASE_TAG}" BIN_DIR = "/content/bonsai_bin" os.makedirs(BIN_DIR, exist_ok=True) def detect_cuda_build(): r = run("nvcc --version", capture=True, check=False) for line in r.stdout.splitlines(): if "release" in line: try: ver = float(line.split("release")[-1].strip().split(",")[0].strip()) if ver >= 13.0: return "13.1" if ver >= 12.6: return "12.8" return "12.4" except ValueError: pass return "12.4" cuda_build = detect_cuda_build() print(f" Detected CUDA build slot: {cuda_build}") TAR_NAME = f"llama-{RELEASE_TAG}-bin-linux-cuda-{cuda_build}-x64.tar.gz" TAR_URL = f"{BASE_URL}/{TAR_NAME}" tar_path = f"/tmp/{TAR_NAME}" if not os.path.exists(f"{BIN_DIR}/llama-cli"): print(f" Downloading: {TAR_URL}") urllib.request.urlretrieve(TAR_URL, tar_path) print(" Extracting …") with tarfile.open(tar_path, "r:gz") as t: t.extractall(BIN_DIR) for fname in os.listdir(BIN_DIR): fp = os.path.join(BIN_DIR, fname) if os.path.isfile(fp): os.chmod(fp, 0o755) print(f"✅ Binaries extracted to {BIN_DIR}") bins = sorted(f for f in os.listdir(BIN_DIR) if os.path.isfile(os.path.join(BIN_DIR, f))) print(" Available:", ", ".join(bins)) else: print(f"✅ Binaries already present at {BIN_DIR}") LLAMA_CLI = f"{BIN_DIR}/llama-cli" LLAMA_SERVER = f"{BIN_DIR}/llama-server" test = run(f"{LLAMA_CLI} --version", capture=True, check=False) if test.returncode == 0: print(f" llama-cli version: {test.stdout.strip()[:80]}") else: print(f"⚠️ llama-cli test failed: {test.stderr.strip()[:200]}") section("4 · Downloading Bonsai-1.7B GGUF Model") MODEL_REPO = "prism-ml/Bonsai-1.7B-gguf" MODEL_DIR = "/content/bonsai_models" GGUF_FILENAME = "Bonsai-1.7B.gguf" os.makedirs(MODEL_DIR, exist_ok=True) MODEL_PATH = os.path.join(MODEL_DIR, GGUF_FILENAME) if not os.path.exists(MODEL_PATH): print(f" Downloading {GGUF_FILENAME} (~248 MB) from HuggingFace …") MODEL_PATH = hf_hub_download( repo_id=MODEL_REPO, filename=GGUF_FILENAME, local_dir=MODEL_DIR, ) print(f"✅ Model saved to: {MODEL_PATH}") else: print(f"✅ Model already cached: {MODEL_PATH}") size_mb = os.path.getsize(MODEL_PATH) / 1e6 print(f" File size on disk: {size_mb:.1f} MB") section("5 · Core Inference Helpers") DEFAULT_GEN_ARGS = dict( temp=0.5, top_p=0.85, top_k=20, repeat_penalty=1.0, n_predict=256, n_gpu_layers=99, ctx_size=4096, ) def build_llama_cmd(prompt, system_prompt="You are a helpful assistant.", **overrides): args = {**DEFAULT_GEN_ARGS, **overrides} formatted = ( f"<|im_start|>system\n{system_prompt}<|im_end|>\n" f"<|im_start|>user\n{prompt}<|im_end|>\n" f"<|im_start|>assistant\n" ) safe_prompt = formatted.replace('"', '\\"') return ( f'{LLAMA_CLI} -m "{MODEL_PATH}"' f' -p "{safe_prompt}"' f' -n {args["n_predict"]}' f' --temp {args["temp"]}' f' --top-p {args["top_p"]}' f' --top-k {args["top_k"]}' f' --repeat-penalty {args["repeat_penalty"]}' f' -ngl {args["n_gpu_layers"]}' f' -c {args["ctx_size"]}' f' --no-display-prompt' f' -e' ) def infer(prompt, system_prompt="You are a helpful assistant.", verbose=True, **overrides): cmd = build_llama_cmd(prompt, system_prompt, **overrides) t0 = time.time() result = run(cmd, capture=True, check=False) elapsed = time.time() - t0 output = result.stdout.strip() if verbose: print(f"\n{'─'*50}") print(f"Prompt : {prompt[:100]}{'…' if len(prompt) > 100 else ''}") print(f"{'─'*50}") print(output) print(f"{'─'*50}") print(f"⏱ {elapsed:.2f}s | ~{len(output.split())} words") return output, elapsed print("✅ Inference helpers ready.") section("6 · Basic Inference — Hello, Bonsai!") infer("What makes 1-bit language models special compared to standard models?") We download and prepare the PrismML prebuilt llama.cpp CUDA binaries that power local inference for the Bonsai model. We detect the available CUDA version, choose the matching binary build, extract the downloaded archive, make the files executable, and verify that the llama-cli binary works correctly. After that, we download the Bonsai-1.7B GGUF model from Hugging Face, set up the model path, define the default generation settings, and build the core helper functions that format prompts and run inference. Copy Code Copied Use a different Browser section("7 · Q1_0_g128 Quantization — What's Happening Under the Hood") print(textwrap.dedent(""" ╔══════════════════════════════════════════════════════════════╗ ║ Bonsai Q1_0_g128 Weight Representation ║ ╠══════════════════════════════════════════════════════════════╣ ║ Each weight = 1 bit: 0 → −scale ║ ║ 1 → +scale ║ ║ Every 128 weights share one FP16 scale factor. ║ ║ ║ ║ Effective bits per weight: ║ ║ 1 bit (sign) + 16/128 bits (shared scale) = 1.125 bpw ║ ║ ║ ║ Memory comparison for Bonsai-1.7B: ║ ║ FP16: 3.44 GB (1.0× baseline) ║ ║ Q1_0_g128: 0.24 GB (14.2× smaller!) ║ ║ MLX 1-bit g128: 0.27 GB (12.8× smaller) ║ ╚══════════════════════════════════════════════════════════════╝ """)) print("📐 Python demo of Q1_0_g128 quantization logic:\n") import random random.seed(42) GROUP_SIZE = 128 weights_fp16 = [random.gauss(0, 0.1) for _ in range(GROUP_SIZE)] scale = max(abs(w) for w in weights_fp16) quantized = [1 if w >= 0 else 0 for w in weights_fp16] dequantized = [scale if b == 1 else -scale for b in quantized] mse = sum((a - b) ** 2 for a, b in zip(weights_fp16, dequantized)) / GROUP_SIZE print(f"