올라마(ollama) 웹사이트에서 운영체제에 맞춰 다운로드 받아 설치한다. 만약 별도 설정하지 않게 되면 C:\Users\<사용자명>\.ollama 디렉토리에 LLM 이 저장된다.

#| eval: false
setx OLLAMA_MODELS D:\llms
#| eval: false
ollama run gemma2
코드
from langchain_community.llms import Ollama
llm = Ollama(model="gemma2")
llm.invoke("축구를 가장 잘하는 나라는 어디야?")

세가지 방법

LLaMA 모델을 사용하는 세 가지 주요 방법은 허깅페이스 Transformers, Ollama, llama-cpp-python이다. 허깅페이스 Transformers는 클라우드 호스팅 모델을 사용하여 쉽게 접근할 수 있다. Ollama는 로컬 서버를 통해 최적화된 모델을 실행한다. llama-cpp-python은 C++로 구현된 LLaMA의 Python 바인딩을 사용하여 로컬에서 효율적으로 모델을 실행한다.

방법 장점 단점 사용 사례
Hugging Face Transformers - 쉬운 사용
- 다양한 모델 지원
- 클라우드 리소스 활용
- 인터넷 연결 필요
- 대용량 데이터 전송 시 비용 발생 가능
- 빠른 프로토타이핑
- 다양한 모델 실험
- 클라우드 기반 애플리케이션
Ollama - 로컬 실행으로 빠른 응답
- API를 통한 간편한 사용
- 커스텀 모델 지원
- 초기 설정 필요
- 로컬 리소스 사용
- 개인 프로젝트
- 로컬 애플리케이션 개발
- 데이터 프라이버시 중요 사례
llama-cpp-python - 매우 효율적인 로컬 실행
- 낮은 메모리 사용량
- 커스텀 모델 지원
- 모델 파일 관리 필요
- 초기 설정 복잡할 수 있음
- 리소스 제한적인 환경
- 임베디드 시스템
- 고성능 요구 애플리케이션

라마3

라마(Llama)는 메타(Meta)에서 2023년 2월에 처음 공개한 대규모 언어 모델이며, 라마2는 2023년 7월에 출시된 라마의 개선 버전으로, 오픈 소스로 공개되어 연구 및 상업적 용도로 사용할 수 있다. 라마3는 2024년 6월 출시되었으며 128,256 토큰을 보유한 새로운 토크나이저를 장착했으며, 8,192 컨텍스트 길이를 갖고 15조개(15T)토큰 학습 데이터를 사용하여 성능을 크게 높였고, Supervised fine-tuning (SFT) Rejection Sampling, Proximal Policy Optimization (PPO), Direct Preference Optimization (DPO) 알고리즘을 적용하였다.

Llama 모델은 GGUF(GPT-Generated Unified Format) 파일 형태로 제공되며, 모델 가중치(학습된 파라미터 값)와 모델 아키텍처(신경망의 구조와 레이어)를 포함하고 있다. llama.cpp는 C++로 작성된 Llama 모델의 추론 엔진으로 Llama 모델의 아키텍처를 C++ 코드로 구현되어 있으며 GGUF 파일에서 가중치를 읽어 메모리에 로드하고, 입력 텍스트에 대해 모델의 추론을 실행한다. 즉, llama.cpp는 Llama 모델을 “실행”하는 엔진으로 모델 파일(GGUF)은 “무엇을” 계산할지를 정의하고, llama.cpp는 “어떻게” 계산할지를 구현한다.

헬로월드

CMake를 설치하고 llama-cpp-python 패키지를 설치한다.

#| eval: false
pip install llama-cpp-python --prefer-binary

허깅페이스 QuantFactory/Meta-Llama-3-8B-GGUF 에서 Meta-Llama-3-8B.Q8_0.gguf 파일을 다운로드 받아 사용한다.

코드
from llama_cpp import Llama

path_to_model = "data/Meta-Llama-3-8B.Q8_0.gguf"
llm = Llama(model_path=path_to_model)
output = llm(
    "Why is the sky blue?",
)
print(output["choices"][0]["text"])
llama_model_loader: loaded meta data with 22 key-value pairs and 291 tensors from data/Meta-Llama-3-8B.Q8_0.gguf (version GGUF V3 (latest))
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv   0:                       general.architecture str              = llama
llama_model_loader: - kv   1:                               general.name str              = .
llama_model_loader: - kv   2:                           llama.vocab_size u32              = 128256
llama_model_loader: - kv   3:                       llama.context_length u32              = 8192
llama_model_loader: - kv   4:                     llama.embedding_length u32              = 4096
llama_model_loader: - kv   5:                          llama.block_count u32              = 32
llama_model_loader: - kv   6:                  llama.feed_forward_length u32              = 14336
llama_model_loader: - kv   7:                 llama.rope.dimension_count u32              = 128
llama_model_loader: - kv   8:                 llama.attention.head_count u32              = 32
llama_model_loader: - kv   9:              llama.attention.head_count_kv u32              = 8
llama_model_loader: - kv  10:     llama.attention.layer_norm_rms_epsilon f32              = 0.000010
llama_model_loader: - kv  11:                       llama.rope.freq_base f32              = 500000.000000
llama_model_loader: - kv  12:                          general.file_type u32              = 7
llama_model_loader: - kv  13:                       tokenizer.ggml.model str              = gpt2
llama_model_loader: - kv  14:                      tokenizer.ggml.tokens arr[str,128256]  = ["!", "\"", "#", "$", "%", "&", "'", ...
llama_model_loader: - kv  15:                      tokenizer.ggml.scores arr[f32,128256]  = [0.000000, 0.000000, 0.000000, 0.0000...
llama_model_loader: - kv  16:                  tokenizer.ggml.token_type arr[i32,128256]  = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
llama_model_loader: - kv  17:                      tokenizer.ggml.merges arr[str,280147]  = ["Ġ Ġ", "Ġ ĠĠĠ", "ĠĠ ĠĠ", "...
llama_model_loader: - kv  18:                tokenizer.ggml.bos_token_id u32              = 128000
llama_model_loader: - kv  19:                tokenizer.ggml.eos_token_id u32              = 128001
llama_model_loader: - kv  20:                    tokenizer.chat_template str              = {% set loop_messages = messages %}{% ...
llama_model_loader: - kv  21:               general.quantization_version u32              = 2
llama_model_loader: - type  f32:   65 tensors
llama_model_loader: - type q8_0:  226 tensors
llm_load_vocab: missing pre-tokenizer type, using: 'default'
llm_load_vocab:                                             
llm_load_vocab: ************************************        
llm_load_vocab: GENERATION QUALITY WILL BE DEGRADED!        
llm_load_vocab: CONSIDER REGENERATING THE MODEL             
llm_load_vocab: ************************************        
llm_load_vocab:                                             
llm_load_vocab: special tokens cache size = 256
llm_load_vocab: token to piece cache size = 0.8000 MB
llm_load_print_meta: format           = GGUF V3 (latest)
llm_load_print_meta: arch             = llama
llm_load_print_meta: vocab type       = BPE
llm_load_print_meta: n_vocab          = 128256
llm_load_print_meta: n_merges         = 280147
llm_load_print_meta: vocab_only       = 0
llm_load_print_meta: n_ctx_train      = 8192
llm_load_print_meta: n_embd           = 4096
llm_load_print_meta: n_layer          = 32
llm_load_print_meta: n_head           = 32
llm_load_print_meta: n_head_kv        = 8
llm_load_print_meta: n_rot            = 128
llm_load_print_meta: n_swa            = 0
llm_load_print_meta: n_embd_head_k    = 128
llm_load_print_meta: n_embd_head_v    = 128
llm_load_print_meta: n_gqa            = 4
llm_load_print_meta: n_embd_k_gqa     = 1024
llm_load_print_meta: n_embd_v_gqa     = 1024
llm_load_print_meta: f_norm_eps       = 0.0e+00
llm_load_print_meta: f_norm_rms_eps   = 1.0e-05
llm_load_print_meta: f_clamp_kqv      = 0.0e+00
llm_load_print_meta: f_max_alibi_bias = 0.0e+00
llm_load_print_meta: f_logit_scale    = 0.0e+00
llm_load_print_meta: n_ff             = 14336
llm_load_print_meta: n_expert         = 0
llm_load_print_meta: n_expert_used    = 0
llm_load_print_meta: causal attn      = 1
llm_load_print_meta: pooling type     = 0
llm_load_print_meta: rope type        = 0
llm_load_print_meta: rope scaling     = linear
llm_load_print_meta: freq_base_train  = 500000.0
llm_load_print_meta: freq_scale_train = 1
llm_load_print_meta: n_ctx_orig_yarn  = 8192
llm_load_print_meta: rope_finetuned   = unknown
llm_load_print_meta: ssm_d_conv       = 0
llm_load_print_meta: ssm_d_inner      = 0
llm_load_print_meta: ssm_d_state      = 0
llm_load_print_meta: ssm_dt_rank      = 0
llm_load_print_meta: model type       = 8B
llm_load_print_meta: model ftype      = Q8_0
llm_load_print_meta: model params     = 8.03 B
llm_load_print_meta: model size       = 7.95 GiB (8.50 BPW) 
llm_load_print_meta: general.name     = .
llm_load_print_meta: BOS token        = 128000 '<|begin_of_text|>'
llm_load_print_meta: EOS token        = 128001 '<|end_of_text|>'
llm_load_print_meta: LF token         = 128 'Ä'
llm_load_print_meta: EOT token        = 128009 '<|eot_id|>'
llm_load_print_meta: max token length = 256
llm_load_tensors: ggml ctx size =    0.14 MiB
llm_load_tensors:        CPU buffer size =  8137.64 MiB
.........................................................................................
llama_new_context_with_model: n_ctx      = 512
llama_new_context_with_model: n_batch    = 512
llama_new_context_with_model: n_ubatch   = 512
llama_new_context_with_model: flash_attn = 0
llama_new_context_with_model: freq_base  = 500000.0
llama_new_context_with_model: freq_scale = 1
llama_kv_cache_init:        CPU KV buffer size =    64.00 MiB
llama_new_context_with_model: KV self size  =   64.00 MiB, K (f16):   32.00 MiB, V (f16):   32.00 MiB
llama_new_context_with_model:        CPU  output buffer size =     0.49 MiB
llama_new_context_with_model:        CPU compute buffer size =   258.50 MiB
llama_new_context_with_model: graph nodes  = 1030
llama_new_context_with_model: graph splits = 1
AVX = 1 | AVX_VNNI = 0 | AVX2 = 1 | AVX512 = 1 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | AVX512_BF16 = 0 | FMA = 1 | NEON = 0 | SVE = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 | MATMUL_INT8 = 0 | LLAMAFILE = 0 | 
Model metadata: {'general.name': '.', 'general.architecture': 'llama', 'llama.block_count': '32', 'llama.vocab_size': '128256', 'llama.context_length': '8192', 'llama.rope.dimension_count': '128', 'llama.embedding_length': '4096', 'llama.feed_forward_length': '14336', 'llama.attention.head_count': '32', 'tokenizer.ggml.eos_token_id': '128001', 'general.file_type': '7', 'llama.attention.head_count_kv': '8', 'llama.attention.layer_norm_rms_epsilon': '0.000010', 'llama.rope.freq_base': '500000.000000', 'tokenizer.ggml.model': 'gpt2', 'general.quantization_version': '2', 'tokenizer.ggml.bos_token_id': '128000', 'tokenizer.chat_template': "{% set loop_messages = messages %}{% for message in loop_messages %}{% set content = '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n'+ message['content'] | trim + '<|eot_id|>' %}{% if loop.index0 == 0 %}{% set content = bos_token + content %}{% endif %}{{ content }}{% endfor %}{{ '<|start_header_id|>assistant<|end_header_id|>\n\n' }}"}
Available chat formats from metadata: chat_template.default
Using gguf chat template: {% set loop_messages = messages %}{% for message in loop_messages %}{% set content = '<|start_header_id|>' + message['role'] + '<|end_header_id|>

'+ message['content'] | trim + '<|eot_id|>' %}{% if loop.index0 == 0 %}{% set content = bos_token + content %}{% endif %}{{ content }}{% endfor %}{{ '<|start_header_id|>assistant<|end_header_id|>

' }}
Using chat eos_token: <|end_of_text|>
Using chat bos_token: <|begin_of_text|>

llama_print_timings:        load time =    1171.92 ms
llama_print_timings:      sample time =       1.65 ms /    16 runs   (    0.10 ms per token,  9702.85 tokens per second)
llama_print_timings: prompt eval time =    1171.86 ms /     6 tokens (  195.31 ms per token,     5.12 tokens per second)
llama_print_timings:        eval time =    2254.84 ms /    15 runs   (  150.32 ms per token,     6.65 tokens per second)
llama_print_timings:       total time =    3450.85 ms /    21 tokens
 Why is the grass green? Why does the sun shine? These are simple questions

라마3.1

허깅페이스

허깅페이스에서 라마3 모형을 다운로드 받기 위해서 먼저 huggingface-cli를 설치한다. 다음으로 쉘에서 huggingface-cli login을 통해 토큰 https://huggingface.co/settings/tokens을 생성한 후 로그인하여 인증한다. meta-llama/Meta-Llama-3.1-8B-Instruct에서 라이선스 동의 절차를 밟는다. 라이선스 승인이 완료되면 huggingface-cli download 명령어로 허깅페이스 클라우드에서 라마3 모형을 다운로드 받아 로컬 디렉토리에 설치하게 된다.

#| eval: false
pip install -U "huggingface_hub[cli]"

huggingface-cli login

huggingface-cli download meta-llama/Meta-Llama-3.1-8B-Instruct --include "original/*" --local-dir D:\llms\Meta-Llama-3.1-8B-Instruct

pip install --upgrade transformers 를 최신 버전으로 업그레이드한다.

#| eval: false
pip install --upgrade transformers
pip install accelerate  # Using `low_cpu_mem_usage=True` or a `device_map`         
코드
from accelerate import Accelerator
from transformers import AutoTokenizer, AutoModelForCausalLM

# Load tokenizer and model
model_path = "D:/llms/Meta-Llama-3.1-8B-Instruct/original"
# model_name = "meta-llama/Llama-2-7b-chat-hf"  # 또는 다른 LLaMA 모델 이름
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path)

# 간단한 프롬프트 생성
prompt = "안녕하세요, LLaMA입니다. 오늘의 날씨는"
inputs = tokenizer(prompt, return_tensors="pt")

# 모델 추론
outputs = model.generate(**inputs, max_length=50)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)

print(response)

llama-cpp-python

라마 3.1을 405B, 70B, 8B 중 하나를 용도에 맞춰 다운로드한다.

코드
# llama-cpp-python 
from llama_cpp import Llama

def load_llama_cpp():
    # 모델 파일 경로 (실제 경로로 변경 필요)
    model_path = "path/to/your/gguf/model.gguf"

    # LLaMA 모델 로드
    llm = Llama(model_path=model_path)

    # 프롬프트 생성 및 추론
    prompt = "안녕하세요, LLaMA입니다. 오늘의 날씨는"
    output = llm(prompt, max_tokens=50)

    print(output["choices"][0]["text"])


if __name__ == "__main__":
    print("\nUsing llama-cpp-python:")
    load_llama_cpp()

올라마

ollama run llama3.1:8b 명령어로 라마3 모형을 설치한 후 올라마를 사용해서 로컬에서 오픈소스 버전 LLM을 사용할 수 있다.

#| eval: false
ollama run llama3.1:8b
코드
import requests
import json


def generate_text(prompt):
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "llama3.1:8b", "prompt": prompt},
        stream=True,
    )

    text_response = ""
    for line in response.iter_lines():
        if line:
            json_response = json.loads(line)
            if "response" in json_response:
                text_response += json_response["response"]
            if json_response.get("done", False):
                break

    return text_response.strip()


# Usage example
prompt = "한글로 답을 해. 축구를 가장 잘하는 나라는 어디야?"
response = generate_text(prompt)
print("Prompt:", prompt)
print("Response:", response)
코드
from langchain_community.llms import Ollama

llm = Ollama(model="llama3.1:8b")
llm.invoke("한글로 답을 해. 축구를 가장 잘하는 나라는 어디야?")