⏱️ 예상 읽기 시간: 15분

oLLM으로 대용량 컨텍스트 LLM 추론하기

대용량 언어 모델(LLM)을 사용할 때 가장 큰 제약 중 하나는 컨텍스트 길이 제한입니다. 일반적인 GPU 메모리로는 긴 문서나 대화 기록을 한 번에 처리하기 어렵죠.

oLLM은 이런 문제를 해결하는 혁신적인 라이브러리입니다. 8GB GPU로도 100k 토큰 컨텍스트를 처리할 수 있게 해주죠.

oLLM이란?

oLLM은 HuggingFace Transformers와 PyTorch를 기반으로 한 경량 Python 라이브러리입니다. 다음과 같은 특징을 가지고 있어요:

  • 대용량 컨텍스트 처리: 100k 토큰까지 처리 가능
  • 저비용 GPU 활용: 8GB VRAM으로도 대용량 모델 실행
  • 양자화 없음: fp16/bf16 정밀도 유지
  • SSD 오프로딩: KV 캐시와 레이어 가중치를 SSD로 오프로드

지원 모델 및 성능

8GB Nvidia 3060 Ti 기준 메모리 사용량

모델 가중치 크기 컨텍스트 길이 KV 캐시 기본 VRAM oLLM GPU VRAM oLLM 디스크
qwen3-next-80B 160 GB (bf16) 50k 20 GB ~190 GB ~7.5 GB 180 GB
gpt-oss-20B 13 GB (packed bf16) 10k 1.4 GB ~40 GB ~7.3GB 15 GB
llama3-1B-chat 2 GB (fp16) 100k 12.6 GB ~16 GB ~5 GB 15 GB
llama3-3B-chat 7 GB (fp16) 100k 34.1 GB ~42 GB ~5.3 GB 42 GB
llama3-8B-chat 16 GB (fp16) 100k 52.4 GB ~71 GB ~6.6 GB 69 GB

설치 및 환경 설정

1. 가상환경 생성

# 가상환경 생성
python3 -m venv ollm_env
source ollm_env/bin/activate  # Linux/Mac
# 또는
ollm_env\Scripts\activate  # Windows

2. oLLM 설치

# pip로 설치
pip install ollm

# 또는 소스에서 설치
git clone https://github.com/Mega4alik/ollm.git
cd ollm
pip install -e .

3. 추가 의존성 설치

# CUDA 버전에 맞는 kvikio 설치
pip install kvikio-cu12  # CUDA 12.x의 경우
# 또는
pip install kvikio-cu11  # CUDA 11.x의 경우

4. qwen3-next 모델 사용 시 추가 설치

# qwen3-next 모델은 특별한 transformers 버전 필요
pip install git+https://github.com/huggingface/transformers.git

기본 사용법

1. 기본 추론 예제

from ollm import Inference, file_get_contents, TextStreamer

# 모델 초기화
o = Inference("llama3-1B-chat", device="cuda:0", logging=True)
o.ini_model(models_dir="./models/", force_download=False)

# 선택적: 일부 레이어를 CPU로 오프로드 (속도 향상)
o.offload_layers_to_cpu(layers_num=2)

# KV 캐시 설정 (컨텍스트가 작으면 None으로 설정)
past_key_values = o.DiskCache(cache_dir="./kv_cache/")

# 텍스트 스트리머 설정
text_streamer = TextStreamer(o.tokenizer, skip_prompt=True, skip_special_tokens=False)

# 메시지 구성
messages = [
    {"role": "system", "content": "당신은 도움이 되는 AI 어시스턴트입니다."},
    {"role": "user", "content": "행성들을 나열해주세요."}
]

# 토큰화 및 생성
input_ids = o.tokenizer.apply_chat_template(
    messages, 
    reasoning_effort="minimal", 
    tokenize=True, 
    add_generation_prompt=True, 
    return_tensors="pt"
).to(o.device)

outputs = o.model.generate(
    input_ids=input_ids,
    past_key_values=past_key_values,
    max_new_tokens=500,
    streamer=text_streamer
).cpu()

# 결과 디코딩
answer = o.tokenizer.decode(outputs[0][input_ids.shape[-1]:], skip_special_tokens=False)
print(answer)

2. 실행 명령어

# CUDA 메모리 할당 최적화와 함께 실행
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True python example.py

고급 사용법

1. 대용량 문서 분석

def analyze_large_document(document_path, model_name="llama3-8B-chat"):
    """대용량 문서를 분석하는 함수"""
    
    # 모델 초기화
    o = Inference(model_name, device="cuda:0", logging=True)
    o.ini_model(models_dir="./models/", force_download=False)
    
    # KV 캐시 설정 (대용량 컨텍스트용)
    past_key_values = o.DiskCache(cache_dir="./kv_cache/")
    
    # 문서 읽기
    document_content = file_get_contents(document_path)
    
    # 분석 프롬프트
    messages = [
        {
            "role": "system", 
            "content": "당신은 문서 분석 전문가입니다. 주어진 문서를 분석하여 핵심 내용을 요약하고 중요한 포인트를 추출해주세요."
        },
        {
            "role": "user", 
            "content": f"다음 문서를 분석해주세요:\n\n{document_content}"
        }
    ]
    
    # 토큰화
    input_ids = o.tokenizer.apply_chat_template(
        messages, 
        tokenize=True, 
        add_generation_prompt=True, 
        return_tensors="pt"
    ).to(o.device)
    
    # 생성
    outputs = o.model.generate(
        input_ids=input_ids,
        past_key_values=past_key_values,
        max_new_tokens=1000,
        temperature=0.7,
        do_sample=True
    )
    
    # 결과 반환
    result = o.tokenizer.decode(outputs[0][input_ids.shape[-1]:], skip_special_tokens=True)
    return result

2. 스트리밍 응답 처리

def stream_response(model_name, messages, max_tokens=500):
    """스트리밍 응답을 처리하는 함수"""
    
    o = Inference(model_name, device="cuda:0", logging=True)
    o.ini_model(models_dir="./models/", force_download=False)
    
    # 텍스트 스트리머 설정
    text_streamer = TextStreamer(
        o.tokenizer, 
        skip_prompt=True, 
        skip_special_tokens=False
    )
    
    # 토큰화
    input_ids = o.tokenizer.apply_chat_template(
        messages, 
        tokenize=True, 
        add_generation_prompt=True, 
        return_tensors="pt"
    ).to(o.device)
    
    # 스트리밍 생성
    outputs = o.model.generate(
        input_ids=input_ids,
        max_new_tokens=max_tokens,
        streamer=text_streamer,
        temperature=0.7,
        do_sample=True
    )
    
    return outputs

실전 활용 사례

1. 계약서 및 규정 문서 분석

def analyze_contract(contract_path):
    """계약서 분석"""
    messages = [
        {
            "role": "system",
            "content": "당신은 법률 문서 분석 전문가입니다. 계약서의 핵심 조항, 위험 요소, 권리와 의무를 명확히 분석해주세요."
        },
        {
            "role": "user", 
            "content": f"다음 계약서를 분석해주세요: {file_get_contents(contract_path)}"
        }
    ]
    return stream_response("llama3-8B-chat", messages, max_tokens=1000)

2. 의료 기록 분석

def analyze_medical_records(records_path):
    """의료 기록 분석"""
    messages = [
        {
            "role": "system",
            "content": "당신은 의료 데이터 분석 전문가입니다. 환자 기록을 분석하여 주요 진단, 치료 과정, 주의사항을 요약해주세요."
        },
        {
            "role": "user",
            "content": f"다음 의료 기록을 분석해주세요: {file_get_contents(records_path)}"
        }
    ]
    return stream_response("llama3-8B-chat", messages, max_tokens=1500)

3. 대용량 로그 파일 분석

def analyze_logs(log_path):
    """로그 파일 분석"""
    messages = [
        {
            "role": "system",
            "content": "당신은 시스템 로그 분석 전문가입니다. 로그를 분석하여 오류 패턴, 성능 이슈, 보안 위협을 식별해주세요."
        },
        {
            "role": "user",
            "content": f"다음 로그 파일을 분석해주세요: {file_get_contents(log_path)}"
        }
    ]
    return stream_response("llama3-8B-chat", messages, max_tokens=2000)

성능 최적화 팁

1. 메모리 최적화

# 레이어 오프로딩으로 GPU 메모리 절약
o.offload_layers_to_cpu(layers_num=4)  # 더 많은 레이어를 CPU로

# KV 캐시 디스크 오프로딩
past_key_values = o.DiskCache(cache_dir="./kv_cache/")

2. 속도 최적화

# CUDA 메모리 할당 최적화
import os
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'

# 배치 크기 조정
batch_size = 1  # 메모리에 따라 조정

3. 모델 선택 가이드

  • 빠른 응답이 필요한 경우: llama3-1B-chat
  • 균형잡힌 성능: llama3-8B-chat
  • 최고 품질: qwen3-next-80B (더 많은 디스크 공간 필요)

문제 해결

1. 메모리 부족 오류

# 해결 방법 1: 더 많은 레이어를 CPU로 오프로드
o.offload_layers_to_cpu(layers_num=6)

# 해결 방법 2: 더 작은 모델 사용
o = Inference("llama3-1B-chat", device="cuda:0")

2. 디스크 공간 부족

# KV 캐시 비활성화 (컨텍스트가 작은 경우)
past_key_values = None

# 또는 더 작은 모델 사용
o = Inference("llama3-1B-chat", device="cuda:0")

3. 속도가 느린 경우

# CUDA 메모리 최적화
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'

# 레이어 오프로딩 조정
o.offload_layers_to_cpu(layers_num=2)  # 적은 수의 레이어만 오프로드

결론

oLLM은 대용량 컨텍스트 LLM 추론을 민주화하는 혁신적인 도구입니다. 8GB GPU로도 100k 토큰 컨텍스트를 처리할 수 있어, 개인 개발자나 소규모 팀도 대용량 문서 분석이 가능해졌습니다.

주요 장점:

  • 비용 효율성: 고가의 GPU 없이도 대용량 모델 실행
  • 유연성: 다양한 모델과 컨텍스트 길이 지원
  • 실용성: 실제 업무에 바로 적용 가능한 도구

oLLM을 활용하여 계약서 분석, 의료 기록 처리, 로그 분석 등 다양한 대용량 텍스트 처리 작업을 효율적으로 수행해보세요!

참고 자료