들어가며
HuggingFace는 현재 AI/ML 생태계에서 가장 중요한 플랫폼 중 하나입니다. 수십만 개의 사전학습 모델, 수만 개의 데이터셋, 그리고 실용적인 라이브러리들을 하나의 생태계로 제공합니다. 이 가이드에서는 HuggingFace의 핵심 구성 요소를 처음부터 끝까지 마스터하겠습니다.
1. HuggingFace 생태계 개요
1.1 HuggingFace Hub
HuggingFace Hub는 세 가지 핵심 요소로 구성됩니다.
**Model Hub**: 전 세계 연구자와 개발자들이 공유한 수십만 개의 사전학습 모델 저장소입니다. BERT, GPT-2, Llama, Mistral, Stable Diffusion 등 거의 모든 유명한 모델을 찾을 수 있습니다. 모델은 PyTorch, TensorFlow, JAX 형식으로 저장되며, 각 모델 페이지에서 사용법과 성능 벤치마크를 확인할 수 있습니다.
**Dataset Hub**: NLP, Vision, Audio, Multimodal 등 다양한 분야의 수천 개 데이터셋을 제공합니다. `datasets` 라이브러리와 완벽하게 통합되어 한 줄의 코드로 어느 데이터셋이든 불러올 수 있습니다.
**Spaces**: Gradio 또는 Streamlit 기반의 ML 데모 앱을 무료로 호스팅할 수 있습니다. CPU/GPU 환경에서 실행 가능하며, 커뮤니티와 모델을 공유하는 가장 쉬운 방법입니다.
1.2 주요 라이브러리 목록
| 라이브러리 | 용도 |
| --------------- | ----------------------------------- |
| transformers | 사전학습 모델 로딩 및 추론/파인튜닝 |
| datasets | 데이터셋 로딩 및 전처리 |
| tokenizers | 빠른 토크나이저 구현 |
| peft | 파라미터 효율적 파인튜닝 (LoRA 등) |
| accelerate | 멀티 GPU/TPU 학습 추상화 |
| trl | RLHF, SFT, DPO 파인튜닝 |
| diffusers | 이미지 생성 모델 |
| evaluate | 모델 평가 메트릭 |
| optimum | 하드웨어 최적화 |
| huggingface_hub | Hub API 클라이언트 |
1.3 계정 설정과 API 토큰
pip install transformers datasets tokenizers peft accelerate trl diffusers evaluate huggingface_hub
from huggingface_hub import login
방법 1: 직접 토큰 입력
login(token="hf_your_token_here")
방법 2: 환경 변수 (권장)
os.environ["HUGGINGFACE_TOKEN"] = "hf_your_token_here"
방법 3: CLI
huggingface-cli login
2. Transformers 라이브러리 완전 가이드
2.1 파이프라인 (Pipeline) API
파이프라인은 HuggingFace에서 가장 간단하게 모델을 사용하는 방법입니다. 내부적으로 토크나이저, 모델, 후처리까지 모두 처리해 줍니다.
from transformers import pipeline
텍스트 분류
classifier = pipeline("text-classification", model="snunlp/KR-FinBert-SC")
result = classifier("이 회사의 주가가 오를 것 같습니다.")
print(result)
[{'label': 'positive', 'score': 0.9876}]
텍스트 생성
generator = pipeline(
"text-generation",
model="meta-llama/Meta-Llama-3-8B-Instruct",
torch_dtype="auto",
device_map="auto"
)
output = generator(
"서울의 가장 유명한 관광지는",
max_new_tokens=100,
do_sample=True,
temperature=0.7
)
print(output[0]["generated_text"])
질의응답 (Extractive QA)
qa = pipeline("question-answering", model="monologg/koelectra-base-finetuned-korquad")
result = qa(
question="HuggingFace는 어디에 있나요?",
context="HuggingFace는 뉴욕에 본사를 두고 있으며 파리에도 사무소가 있습니다."
)
print(result)
{'score': 0.99, 'start': 13, 'end': 17, 'answer': '뉴욕'}
번역
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en")
result = translator("안녕하세요, 저는 AI 연구자입니다.")
print(result)
요약
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
long_text = """HuggingFace는 2016년에 설립된 AI 회사로..."""
summary = summarizer(long_text, max_length=100, min_length=30)
print(summary)
토큰 분류 (NER)
ner = pipeline("ner", model="snunlp/KR-FinBert-SC", aggregation_strategy="simple")
result = ner("삼성전자가 반도체 사업을 확장합니다.")
print(result)
2.2 AutoTokenizer와 AutoModel
from transformers import AutoTokenizer, AutoModel
토크나이저 로딩
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
텍스트 인코딩
text = "HuggingFace는 정말 유용한 라이브러리입니다."
inputs = tokenizer(text, return_tensors="pt")
print(inputs)
{'input_ids': tensor([[...]]), 'attention_mask': tensor([[...]])}
토큰 디코딩
decoded = tokenizer.decode(inputs["input_ids"][0])
print(decoded)
특수 토큰 확인
print(f"BOS: {tokenizer.bos_token}") # [CLS]
print(f"EOS: {tokenizer.eos_token}") # [SEP]
print(f"PAD: {tokenizer.pad_token}") # [PAD]
print(f"UNK: {tokenizer.unk_token}") # [UNK]
print(f"어휘 크기: {tokenizer.vocab_size}")
배치 인코딩
texts = ["첫 번째 문장입니다.", "두 번째 문장은 조금 더 깁니다."]
batch_inputs = tokenizer(
texts,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt"
)
print(batch_inputs["input_ids"].shape) # [2, 128]
모델 로딩
model = AutoModel.from_pretrained("klue/roberta-base")
model.eval()
with torch.no_grad():
outputs = model(**batch_inputs)
last_hidden_state: [batch, seq_len, hidden_dim]
print(outputs.last_hidden_state.shape)
pooler_output: [batch, hidden_dim]
print(outputs.pooler_output.shape)
2.3 태스크별 특화 모델
from transformers import (
AutoModelForSequenceClassification,
AutoModelForCausalLM,
AutoModelForSeq2SeqLM,
AutoModelForTokenClassification,
AutoModelForQuestionAnswering,
AutoModelForMaskedLM,
)
시퀀스 분류 모델 (감성 분석, 텍스트 분류)
clf_model = AutoModelForSequenceClassification.from_pretrained(
"klue/roberta-base",
num_labels=2
)
CausalLM (GPT 스타일 텍스트 생성)
causal_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B",
torch_dtype=torch.bfloat16,
device_map="auto",
attn_implementation="flash_attention_2"
)
Seq2Seq (번역, 요약)
seq2seq_model = AutoModelForSeq2SeqLM.from_pretrained("facebook/bart-large-cnn")
토큰 분류 (NER, POS 태깅)
ner_model = AutoModelForTokenClassification.from_pretrained(
"klue/roberta-base",
num_labels=9 # 레이블 수에 맞게 조정
)
추출형 QA
qa_model = AutoModelForQuestionAnswering.from_pretrained("klue/roberta-large")
Masked LM (BERT 스타일 마스크 예측)
mlm_model = AutoModelForMaskedLM.from_pretrained("klue/roberta-base")
2.4 모델 추론 상세 예제
from transformers import AutoTokenizer, AutoModelForCausalLM
def load_model(model_name: str):
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto"
)
return tokenizer, model
def generate_text(
model,
tokenizer,
prompt: str,
max_new_tokens: int = 200,
temperature: float = 0.7,
top_p: float = 0.9,
do_sample: bool = True
) -> str:
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
temperature=temperature,
top_p=top_p,
do_sample=do_sample,
repetition_penalty=1.1,
eos_token_id=tokenizer.eos_token_id,
pad_token_id=tokenizer.pad_token_id,
)
입력 프롬프트 제외하고 생성된 텍스트만 반환
generated_ids = outputs[0][inputs["input_ids"].shape[1]:]
return tokenizer.decode(generated_ids, skip_special_tokens=True)
사용 예시
tokenizer, model = load_model("Qwen/Qwen2.5-7B-Instruct")
Chat template 적용
messages = [
{"role": "system", "content": "당신은 도움이 되는 AI 어시스턴트입니다."},
{"role": "user", "content": "파이썬으로 피보나치 수열을 구하는 코드를 작성해주세요."}
]
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
response = generate_text(model, tokenizer, prompt)
print(response)
2.5 토크나이저 심화
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B")
인코딩 옵션
text = "안녕하세요! HuggingFace를 배워봅시다."
기본 인코딩
ids = tokenizer.encode(text)
print(f"토큰 ID: {ids}")
print(f"토큰 수: {len(ids)}")
토큰 확인
tokens = tokenizer.tokenize(text)
print(f"토큰: {tokens}")
특수 토큰 포함/제외
ids_with_special = tokenizer.encode(text, add_special_tokens=True)
ids_without_special = tokenizer.encode(text, add_special_tokens=False)
print(f"특수 토큰 포함: {len(ids_with_special)}")
print(f"특수 토큰 제외: {len(ids_without_special)}")
배치 처리와 패딩
batch = [
"짧은 문장",
"이것은 조금 더 긴 문장입니다. 패딩이 적용됩니다."
]
encoded = tokenizer(
batch,
padding="max_length",
max_length=64,
truncation=True,
return_tensors="pt",
return_attention_mask=True
)
print("input_ids shape:", encoded["input_ids"].shape)
print("attention_mask shape:", encoded["attention_mask"].shape)
토큰 타입 ID (BERT 스타일 pair encoding)
bert_tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
pair_encoded = bert_tokenizer(
"질문: AI는 무엇인가요?",
"문맥: AI는 인공지능의 약자입니다.",
return_tensors="pt"
)
print("token_type_ids:", pair_encoded.get("token_type_ids"))
특수 토큰 추가
special_tokens = {"additional_special_tokens": ["[DOMAIN]", "[ENTITY]", "[DATE]"]}
num_added = tokenizer.add_special_tokens(special_tokens)
print(f"추가된 특수 토큰 수: {num_added}")
3. Datasets 라이브러리
3.1 데이터셋 로딩
from datasets import load_dataset
Hub에서 데이터셋 로딩
dataset = load_dataset("klue", "sts")
print(dataset)
DatasetDict({train: Dataset({features: [...], num_rows: ...})})
특정 스플릿만 로딩
train_ds = load_dataset("klue", "sts", split="train")
val_ds = load_dataset("klue", "sts", split="validation")
로컬 파일 로딩
local_ds = load_dataset("json", data_files={"train": "train.jsonl", "test": "test.jsonl"})
csv_ds = load_dataset("csv", data_files="data.csv")
text_ds = load_dataset("text", data_files="corpus.txt")
스플릿 비율 지정
split_ds = load_dataset("klue", "sts", split="train[:80%]")
val_split = load_dataset("klue", "sts", split="train[80%:]")
데이터셋 정보 확인
print(train_ds.features)
print(train_ds.column_names)
print(train_ds.num_rows)
print(train_ds[0]) # 첫 번째 샘플
print(train_ds[:5]) # 처음 5개 샘플
3.2 데이터셋 전처리
from datasets import load_dataset
from transformers import AutoTokenizer
dataset = load_dataset("klue", "sts")
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
map 함수로 토크나이징
def tokenize_function(examples):
return tokenizer(
examples["sentence1"],
examples["sentence2"],
padding="max_length",
truncation=True,
max_length=128
)
tokenized_ds = dataset.map(
tokenize_function,
batched=True, # 배치 처리로 속도 향상
num_proc=4, # 멀티프로세싱
remove_columns=["sentence1", "sentence2", "guid"]
)
filter로 조건에 맞는 샘플만 선택
filtered_ds = dataset["train"].filter(
lambda x: x["label"] > 3.0
)
print(f"필터 후 크기: {len(filtered_ds)}")
select로 인덱스 기반 선택
small_ds = dataset["train"].select(range(1000))
sort
sorted_ds = dataset["train"].sort("label", reverse=True)
shuffle
shuffled_ds = dataset["train"].shuffle(seed=42)
rename_column
renamed_ds = dataset["train"].rename_column("label", "score")
컬럼 추가
def add_text_length(example):
example["text_length"] = len(example["sentence1"].split())
return example
ds_with_length = dataset["train"].map(add_text_length)
데이터셋 저장
tokenized_ds.save_to_disk("./tokenized_klue_sts")
저장된 데이터셋 로딩
from datasets import load_from_disk
loaded_ds = load_from_disk("./tokenized_klue_sts")
3.3 커스텀 데이터셋 생성과 업로드
from datasets import Dataset, DatasetDict, Features, Value, ClassLabel
pandas DataFrame에서 Dataset 생성
df = pd.DataFrame({
"text": ["긍정적인 문장입니다.", "부정적인 문장입니다.", "중립적인 문장입니다."],
"label": [1, 0, 2]
})
custom_ds = Dataset.from_pandas(df)
딕셔너리에서 Dataset 생성
data_dict = {
"text": ["sample 1", "sample 2"],
"score": [0.8, 0.3]
}
ds_from_dict = Dataset.from_dict(data_dict)
Features 정의
features = Features({
"text": Value("string"),
"label": ClassLabel(names=["negative", "positive", "neutral"]),
"score": Value("float32")
})
Hub에 업로드
from huggingface_hub import login
login()
custom_ds.push_to_hub("your-username/my-custom-dataset")
DatasetDict로 스플릿 포함 업로드
dataset_dict = DatasetDict({
"train": custom_ds,
"test": custom_ds
})
dataset_dict.push_to_hub("your-username/my-custom-dataset")
3.4 스트리밍 데이터셋
from datasets import load_dataset
스트리밍 모드로 로딩 (메모리에 전체 데이터를 올리지 않음)
streaming_ds = load_dataset(
"HuggingFaceFW/fineweb",
"sample-10BT",
split="train",
streaming=True
)
이터레이터로 순회
for i, example in enumerate(streaming_ds):
if i >= 5:
break
print(example["text"][:100])
map과 filter도 스트리밍에서 사용 가능
filtered_stream = streaming_ds.filter(lambda x: len(x["text"]) > 500)
mapped_stream = filtered_stream.map(lambda x: {"text_len": len(x["text"])})
배치 처리
def process_batch(batch):
return {"processed": [t.lower() for t in batch["text"]]}
batched_stream = streaming_ds.map(process_batch, batched=True, batch_size=16)
DataLoader로 변환
from torch.utils.data import DataLoader
dataloader = DataLoader(
list(streaming_ds.take(1000)), # 처음 1000개만 로딩
batch_size=8,
shuffle=True
)
3.5 DataCollator 활용
from transformers import DataCollatorWithPadding, DataCollatorForSeq2Seq, DataCollatorForLanguageModeling
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
동적 패딩 (배치 내 최대 길이에 맞게 패딩)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
Seq2Seq 모델용 (디코더 인풋 자동 생성)
from transformers import AutoTokenizer as T5Tok
t5_tokenizer = T5Tok.from_pretrained("t5-base")
seq2seq_collator = DataCollatorForSeq2Seq(
tokenizer=t5_tokenizer,
padding=True,
return_tensors="pt"
)
Language Modeling (MLM)
mlm_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer,
mlm=True,
mlm_probability=0.15 # 15% 토큰 마스킹
)
CLM (Causal Language Modeling)
clm_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer,
mlm=False # CLM 모드
)
4. Tokenizers 라이브러리
4.1 빠른 토크나이저
HuggingFace `tokenizers` 라이브러리는 Rust로 구현된 초고속 토크나이저를 제공합니다. 기존 Python 토크나이저 대비 최대 100배 빠릅니다.
from tokenizers import Tokenizer, models, trainers, pre_tokenizers, decoders, processors
from tokenizers.models import BPE, WordPiece, Unigram
BPE 토크나이저 훈련
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
trainer = trainers.BpeTrainer(
vocab_size=30000,
min_frequency=2,
special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]
)
파일에서 훈련
files = ["corpus.txt"]
tokenizer.train(files, trainer)
저장
tokenizer.save("my_tokenizer.json")
로딩
loaded_tokenizer = Tokenizer.load("my_tokenizer.json")
인코딩
output = tokenizer.encode("안녕하세요, HuggingFace!")
print(output.tokens)
print(output.ids)
배치 인코딩
batch_output = tokenizer.encode_batch(["문장 1", "문장 2"])
4.2 WordPiece 토크나이저 (BERT 스타일)
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
from tokenizers.trainers import WordPieceTrainer
from tokenizers.pre_tokenizers import Whitespace
from tokenizers.processors import TemplateProcessing
WordPiece 초기화
tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
tokenizer.pre_tokenizer = Whitespace()
trainer = WordPieceTrainer(
vocab_size=30522,
special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]
)
tokenizer.train(["corpus.txt"], trainer)
BERT 스타일 후처리 추가
tokenizer.post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[
("[CLS]", tokenizer.token_to_id("[CLS]")),
("[SEP]", tokenizer.token_to_id("[SEP]")),
],
)
HuggingFace transformers와 통합
from transformers import PreTrainedTokenizerFast
fast_tokenizer = PreTrainedTokenizerFast(
tokenizer_object=tokenizer,
unk_token="[UNK]",
pad_token="[PAD]",
cls_token="[CLS]",
sep_token="[SEP]",
mask_token="[MASK]"
)
Hub에 업로드
fast_tokenizer.push_to_hub("your-username/my-tokenizer")
5. PEFT: 파라미터 효율적 파인튜닝
5.1 LoRA 기초
LoRA(Low-Rank Adaptation)는 기존 모델 가중치를 동결하고, 저랭크 행렬 두 개만 훈련하여 파라미터 수를 획기적으로 줄입니다.
from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer
베이스 모델 로딩
model_name = "meta-llama/Meta-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto"
)
LoRA 설정
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # 랭크 (낮을수록 파라미터 적음)
lora_alpha=32, # 스케일링 팩터
target_modules=[ # LoRA를 적용할 레이어
"q_proj", "v_proj", # Attention Q, V
"k_proj", "o_proj", # Attention K, Output
"gate_proj", "up_proj", # FFN
"down_proj"
],
lora_dropout=0.05,
bias="none",
inference_mode=False
)
LoRA 적용
peft_model = get_peft_model(model, lora_config)
peft_model.print_trainable_parameters()
trainable params: 41,943,040 || all params: 8,072,925,184 || trainable%: 0.5196
5.2 QLoRA: 4비트 양자화 + LoRA
from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
4비트 양자화 설정
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True, # 이중 양자화로 메모리 절약
bnb_4bit_quant_type="nf4", # Normal Float 4
bnb_4bit_compute_dtype=torch.bfloat16
)
양자화된 모델 로딩
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B",
quantization_config=bnb_config,
device_map="auto"
)
kbit 훈련 준비 (그래디언트 체크포인팅 활성화)
model = prepare_model_for_kbit_training(model)
LoRA 설정 및 적용
lora_config = LoraConfig(
r=64,
lora_alpha=128,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.1,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
5.3 완전한 파인튜닝 예제 (SFTTrainer 활용)
from trl import SFTTrainer, SFTConfig
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from datasets import load_dataset
1. 데이터 준비
dataset = load_dataset("iamksh/kor_alpaca_data_v1.1", split="train")
def format_conversation(sample):
system = "당신은 도움이 되는 한국어 AI 어시스턴트입니다."
instruction = sample["instruction"]
inp = sample.get("input", "")
output = sample["output"]
if inp:
user_msg = f"{instruction}\n\n입력: {inp}"
else:
user_msg = instruction
return {
"text": f"<|system|>\n{system}\n<|user|>\n{user_msg}\n<|assistant|>\n{output}"
}
dataset = dataset.map(format_conversation)
2. 모델 설정
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B",
quantization_config=bnb_config,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B")
tokenizer.pad_token = tokenizer.eos_token
3. LoRA 설정
peft_config = LoraConfig(
r=32,
lora_alpha=64,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"]
)
4. 훈련 설정
sft_config = SFTConfig(
output_dir="./qlora-llama3-ko",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
fp16=False,
bf16=True,
logging_steps=10,
save_steps=100,
warmup_ratio=0.03,
lr_scheduler_type="cosine",
dataset_text_field="text",
max_seq_length=2048,
report_to="wandb"
)
5. 훈련
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_config,
args=sft_config,
processing_class=tokenizer,
)
trainer.train()
trainer.save_model("./qlora-llama3-ko-final")
5.4 어댑터 저장, 로딩, 병합
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
LoRA 어댑터만 저장
peft_model.save_pretrained("./lora-adapter")
tokenizer.save_pretrained("./lora-adapter")
Hub에 어댑터 업로드
peft_model.push_to_hub("your-username/llama3-ko-lora")
어댑터 로딩 (베이스 모델 + 어댑터)
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B",
torch_dtype=torch.bfloat16,
device_map="auto"
)
peft_model = PeftModel.from_pretrained(base_model, "./lora-adapter")
어댑터를 베이스 모델에 병합 (추론 속도 최적화)
merged_model = peft_model.merge_and_unload()
merged_model.save_pretrained("./merged-llama3-ko")
tokenizer.save_pretrained("./merged-llama3-ko")
6. Accelerate 라이브러리
6.1 Accelerate 설정
대화형 설정
accelerate config
단일 GPU 기본 설정
accelerate config --config_file ./accelerate_config.yaml
accelerate_config.yaml
compute_environment: LOCAL_MACHINE
distributed_type: MULTI_GPU
num_machines: 1
num_processes: 4
gpu_ids: all
mixed_precision: bf16
6.2 기본 Accelerate 학습 루프
from accelerate import Accelerator
from transformers import AutoModelForSequenceClassification, AutoTokenizer, AdamW
from datasets import load_dataset
from torch.utils.data import DataLoader
def training_function():
Accelerator 초기화
accelerator = Accelerator(
mixed_precision="bf16",
gradient_accumulation_steps=4,
log_with="wandb"
)
모델과 토크나이저
model_name = "klue/roberta-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
데이터셋
dataset = load_dataset("klue", "ynat", split="train")
def tokenize(examples):
return tokenizer(examples["title"], truncation=True, max_length=128)
tokenized = dataset.map(tokenize, batched=True)
tokenized.set_format("torch", columns=["input_ids", "attention_mask", "label"])
dataloader = DataLoader(tokenized, batch_size=16, shuffle=True)
옵티마이저
optimizer = AdamW(model.parameters(), lr=2e-5)
Accelerate 준비 (모델, 옵티마이저, 데이터로더 모두 준비)
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)
학습 루프
for epoch in range(3):
model.train()
for batch in dataloader:
with accelerator.accumulate(model):
outputs = model(**batch)
loss = outputs.loss
accelerator.backward(loss)
accelerator.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
optimizer.zero_grad()
accelerator.print(f"Epoch {epoch} completed")
저장
accelerator.wait_for_everyone()
unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained("./output", save_function=accelerator.save)
멀티 GPU 실행: accelerate launch train.py
training_function()
6.3 DeepSpeed 통합
from accelerate import Accelerator
from accelerate.utils import DeepSpeedPlugin
DeepSpeed ZeRO-2 설정
ds_plugin = DeepSpeedPlugin(
hf_ds_config={
"zero_optimization": {
"stage": 2,
"allgather_partitions": True,
"allgather_bucket_size": 2e8,
"overlap_comm": True,
"reduce_scatter": True,
"reduce_bucket_size": 2e8,
"contiguous_gradients": True
},
"bf16": {"enabled": True},
"optimizer": {
"type": "AdamW",
"params": {
"lr": "auto",
"weight_decay": "auto"
}
}
}
)
accelerator = Accelerator(deepspeed_plugin=ds_plugin)
6.4 그래디언트 누적과 Mixed Precision
from accelerate import Accelerator
accelerator = Accelerator(
mixed_precision="bf16", # fp16, bf16, no 중 선택
gradient_accumulation_steps=8 # 8 스텝마다 실제 업데이트
)
학습 루프에서 accumulate 컨텍스트 매니저 사용
for batch in dataloader:
with accelerator.accumulate(model):
output = model(**batch)
loss = output.loss / accelerator.gradient_accumulation_steps
accelerator.backward(loss)
if accelerator.sync_gradients:
accelerator.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
7. TRL: Transformer Reinforcement Learning
7.1 SFTTrainer
from trl import SFTTrainer, SFTConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B")
dataset = load_dataset("HuggingFaceH4/ultrachat_200k", split="train_sft[:5%]")
training_args = SFTConfig(
output_dir="./sft-qwen",
max_seq_length=2048,
num_train_epochs=1,
per_device_train_batch_size=4,
gradient_accumulation_steps=2,
learning_rate=2e-5,
bf16=True,
save_strategy="epoch",
logging_steps=10,
dataset_text_field="messages", # chat 형식 컬럼
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset,
processing_class=tokenizer,
)
trainer.train()
7.2 DPOTrainer (Direct Preference Optimization)
from trl import DPOTrainer, DPOConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
DPO에는 reference 모델이 필요
model = AutoModelForCausalLM.from_pretrained("your-sft-model")
ref_model = AutoModelForCausalLM.from_pretrained("your-sft-model") # frozen
tokenizer = AutoTokenizer.from_pretrained("your-sft-model")
DPO 데이터셋: prompt, chosen, rejected 컬럼 필요
dpo_dataset = load_dataset("HuggingFaceH4/ultrafeedback_binarized", split="train_prefs")
dpo_config = DPOConfig(
output_dir="./dpo-model",
num_train_epochs=1,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=5e-7,
beta=0.1, # KL 패널티 강도
bf16=True,
loss_type="sigmoid", # sigmoid, hinge, ipo 등
)
trainer = DPOTrainer(
model=model,
ref_model=ref_model,
args=dpo_config,
train_dataset=dpo_dataset,
processing_class=tokenizer,
)
trainer.train()
7.3 RewardTrainer
from trl import RewardTrainer, RewardConfig
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from datasets import load_dataset
리워드 모델 (시퀀스 분류 헤드 추가)
model = AutoModelForSequenceClassification.from_pretrained(
"klue/roberta-base",
num_labels=1 # 스칼라 리워드 출력
)
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
preference 데이터셋 필요
dataset = load_dataset("HuggingFaceH4/ultrafeedback_binarized", split="train_prefs")
reward_config = RewardConfig(
output_dir="./reward-model",
num_train_epochs=1,
per_device_train_batch_size=8,
learning_rate=1e-5,
max_length=512,
)
trainer = RewardTrainer(
model=model,
args=reward_config,
train_dataset=dataset,
processing_class=tokenizer,
)
trainer.train()
8. Diffusers 라이브러리
8.1 기본 이미지 생성
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
Stable Diffusion 파이프라인 로딩
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16,
use_safetensors=True
)
더 빠른 스케줄러 사용
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
pipe = pipe.to("cuda")
메모리 최적화
pipe.enable_attention_slicing()
pipe.enable_xformers_memory_efficient_attention()
이미지 생성
image = pipe(
prompt="A beautiful Korean temple in autumn, photorealistic, 8k",
negative_prompt="blurry, low quality, cartoon",
num_inference_steps=20,
guidance_scale=7.5,
width=512,
height=512,
generator=torch.Generator("cuda").manual_seed(42)
).images[0]
image.save("temple.png")
SDXL 사용
from diffusers import StableDiffusionXLPipeline
xl_pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
variant="fp16"
).to("cuda")
image = xl_pipe(
prompt="A majestic mountain landscape, 4k photo",
num_inference_steps=30,
guidance_scale=5.0
).images[0]
8.2 LoRA for Diffusion
from diffusers import StableDiffusionPipeline
LoRA 어댑터가 포함된 파이프라인 로딩
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
).to("cuda")
LoRA 웨이트 로딩
pipe.load_lora_weights("path/to/lora/weights", weight_name="lora.safetensors")
pipe.fuse_lora(lora_scale=0.8)
image = pipe(
"a photo of sks person in a fantasy world",
num_inference_steps=30
).images[0]
9. Evaluate 라이브러리
9.1 기본 메트릭 사용
BLEU 점수 (번역 품질)
bleu = evaluate.load("bleu")
result = bleu.compute(
predictions=["the cat is on the mat"],
references=[["the cat is on the mat", "there is a cat on the mat"]]
)
print(f"BLEU: {result['bleu']:.4f}")
ROUGE 점수 (요약 품질)
rouge = evaluate.load("rouge")
result = rouge.compute(
predictions=["매우 유용한 라이브러리입니다."],
references=["이것은 매우 유용한 라이브러리입니다."]
)
print(result) # rouge1, rouge2, rougeL, rougeLsum
BERTScore (의미 유사도)
bertscore = evaluate.load("bertscore")
result = bertscore.compute(
predictions=["AI가 세상을 바꾸고 있습니다."],
references=["인공지능이 세계를 변화시키고 있습니다."],
lang="ko"
)
print(f"BERTScore F1: {result['f1'][0]:.4f}")
Accuracy
accuracy = evaluate.load("accuracy")
result = accuracy.compute(predictions=[0, 1, 1, 0], references=[0, 1, 0, 0])
print(f"Accuracy: {result['accuracy']:.4f}")
Perplexity
perplexity = evaluate.load("perplexity", module_type="metric")
9.2 훈련 중 평가 통합
from transformers import Trainer, TrainingArguments
accuracy = evaluate.load("accuracy")
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
return accuracy.compute(predictions=predictions, references=labels)
training_args = TrainingArguments(
output_dir="./model-output",
evaluation_strategy="epoch",
num_train_epochs=3,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
load_best_model_at_end=True,
metric_for_best_model="accuracy",
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
compute_metrics=compute_metrics,
)
10. Hub API와 자동화
10.1 huggingface_hub 클라이언트
from huggingface_hub import HfApi, hf_hub_download, snapshot_download
from huggingface_hub import create_repo, upload_file, upload_folder
api = HfApi()
모델 파일 다운로드
local_path = hf_hub_download(
repo_id="meta-llama/Meta-Llama-3-8B",
filename="config.json"
)
전체 저장소 다운로드
snapshot_download(
repo_id="meta-llama/Meta-Llama-3-8B",
local_dir="./llama3-8b",
ignore_patterns=["*.bin", "*.pt"] # safetensors만 다운로드
)
새 저장소 생성
create_repo("your-username/my-model", private=True)
create_repo("your-username/my-dataset", repo_type="dataset")
create_repo("your-username/my-space", repo_type="space", space_sdk="gradio")
파일 업로드
upload_file(
path_or_fileobj="./my_model.bin",
path_in_repo="pytorch_model.bin",
repo_id="your-username/my-model"
)
폴더 업로드
upload_folder(
folder_path="./output-model",
repo_id="your-username/my-model",
ignore_patterns=["*.log", "__pycache__"]
)
저장소 정보 조회
model_info = api.model_info("meta-llama/Meta-Llama-3-8B")
print(model_info.card_data)
print(model_info.safetensors)
모델 검색
models = api.list_models(
filter="text-generation",
language="ko",
sort="downloads",
limit=10
)
for m in models:
print(m.id, m.downloads)
10.2 모델 카드 자동 생성
from huggingface_hub import ModelCard, ModelCardData
card_data = ModelCardData(
language="ko",
license="apache-2.0",
library_name="transformers",
tags=["llama", "korean", "fine-tuned"],
datasets=["iamksh/kor_alpaca_data_v1.1"],
base_model="meta-llama/Meta-Llama-3-8B",
metrics=[{"type": "accuracy", "value": 0.95}]
)
card = ModelCard.from_template(
card_data,
template_str="""
{{ card_data }}
한국어 Llama-3-8B
이 모델은 한국어 명령 따르기를 위해 파인튜닝된 Llama-3-8B입니다.
사용법
from transformers import pipeline
generator = pipeline("text-generation", model="your-username/llama3-ko")
훈련 세부 사항
- 베이스 모델: meta-llama/Meta-Llama-3-8B
- 방법: QLoRA (4-bit)
- 데이터셋: 한국어 Alpaca
"""
)
card.push_to_hub("your-username/llama3-ko")
11. Optimum 라이브러리
11.1 ONNX 변환
from optimum.exporters.onnx import main_export
모델을 ONNX 형식으로 변환
main_export(
model_name_or_path="klue/roberta-base",
output="./roberta-onnx",
task="text-classification"
)
ONNX 모델 로딩 및 추론
from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer
ort_model = ORTModelForSequenceClassification.from_pretrained("./roberta-onnx")
tokenizer = AutoTokenizer.from_pretrained("klue/roberta-base")
inputs = tokenizer("이 영화는 정말 재미있었습니다!", return_tensors="pt")
outputs = ort_model(**inputs)
print(outputs.logits)
11.2 BetterTransformer
from optimum.bettertransformer import BetterTransformer
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("klue/roberta-base")
BetterTransformer로 변환 (PyTorch 2.0+ 최적화 활용)
model = BetterTransformer.transform(model)
추론 (자동으로 Flash Attention 등 최적화 사용)
model.eval()
with torch.no_grad():
outputs = model(**inputs)
12. 실전 프로젝트: 한국어 LLM 파인튜닝
12.1 한국어 데이터셋 준비
from datasets import load_dataset, concatenate_datasets
KLUE 벤치마크 데이터셋
klue_tc = load_dataset("klue", "ynat", split="train") # 주제 분류
klue_sts = load_dataset("klue", "sts", split="train") # 의미 유사도
klue_nli = load_dataset("klue", "nli", split="train") # 자연어 추론
klue_ner = load_dataset("klue", "ner", split="train") # 개체명 인식
klue_re = load_dataset("klue", "re", split="train") # 관계 추출
klue_dp = load_dataset("klue", "dp", split="train") # 의존 구문 분석
한국어 명령 데이터셋
ko_alpaca = load_dataset("iamksh/kor_alpaca_data_v1.1", split="train")
대화 데이터셋
ko_chat = load_dataset("heegyu/open-korean-instructions", split="train")
def format_instruction_dataset(example):
"""Alpaca 형식을 ChatML 형식으로 변환"""
instruction = example["instruction"]
inp = example.get("input", "").strip()
output = example["output"]
if inp:
user_content = f"{instruction}\n\n{inp}"
else:
user_content = instruction
messages = [
{"role": "system", "content": "당신은 도움이 되는 한국어 AI 어시스턴트입니다."},
{"role": "user", "content": user_content},
{"role": "assistant", "content": output}
]
return {"messages": messages}
formatted_dataset = ko_alpaca.map(format_instruction_dataset)
print(formatted_dataset[0])
12.2 전체 QLoRA 파인튜닝 파이프라인
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, prepare_model_for_kbit_training, get_peft_model
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
─── 설정 ───────────────────────────────────────────────
MODEL_NAME = "meta-llama/Meta-Llama-3-8B"
OUTPUT_DIR = "./llama3-ko-qlora"
MAX_SEQ_LEN = 2048
NUM_EPOCHS = 2
BATCH_SIZE = 2
GRAD_ACCUM = 8
LR = 2e-4
─── 4bit 양자화 ─────────────────────────────────────────
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
─── 모델/토크나이저 로딩 ─────────────────────────────────
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
quantization_config=bnb_config,
device_map="auto",
attn_implementation="flash_attention_2"
)
model = prepare_model_for_kbit_training(model)
─── LoRA 설정 ───────────────────────────────────────────
peft_config = LoraConfig(
r=64,
lora_alpha=128,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
─── 데이터셋 ────────────────────────────────────────────
dataset = load_dataset("iamksh/kor_alpaca_data_v1.1", split="train")
def format_sample(example):
messages = [
{"role": "system", "content": "당신은 도움이 되는 AI 어시스턴트입니다."},
{"role": "user", "content": example["instruction"]},
{"role": "assistant", "content": example["output"]}
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
return {"text": text}
dataset = dataset.map(format_sample)
─── 훈련 설정 ───────────────────────────────────────────
training_args = SFTConfig(
output_dir=OUTPUT_DIR,
num_train_epochs=NUM_EPOCHS,
per_device_train_batch_size=BATCH_SIZE,
gradient_accumulation_steps=GRAD_ACCUM,
learning_rate=LR,
bf16=True,
gradient_checkpointing=True,
optim="paged_adamw_8bit",
warmup_ratio=0.05,
lr_scheduler_type="cosine",
save_strategy="epoch",
logging_steps=10,
dataset_text_field="text",
max_seq_length=MAX_SEQ_LEN,
packing=True, # 여러 샘플을 하나의 시퀀스로 패킹
)
─── 훈련 ────────────────────────────────────────────────
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_config,
args=training_args,
processing_class=tokenizer,
)
trainer.train()
─── 저장 ────────────────────────────────────────────────
trainer.model.save_pretrained(f"{OUTPUT_DIR}/adapter")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/adapter")
print("훈련 완료!")
12.3 파인튜닝된 모델 평가
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
모델 로딩
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-8B",
torch_dtype=torch.bfloat16,
device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "./llama3-ko-qlora/adapter")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B")
def chat(user_message: str, max_new_tokens: int = 512) -> str:
messages = [
{"role": "system", "content": "당신은 도움이 되는 AI 어시스턴트입니다."},
{"role": "user", "content": user_message}
]
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1
)
response = tokenizer.decode(
outputs[0][inputs["input_ids"].shape[1]:],
skip_special_tokens=True
)
return response
평가 테스트
test_questions = [
"파이썬으로 피보나치 수열을 출력하는 코드를 작성해주세요.",
"대한민국의 수도는 어디인가요?",
"머신러닝과 딥러닝의 차이점을 설명해주세요.",
]
for q in test_questions:
print(f"Q: {q}")
print(f"A: {chat(q)}")
print("-" * 50)
12.4 Gradio Spaces 배포
from transformers import pipeline
파이프라인 로딩
pipe = pipeline(
"text-generation",
model="./llama3-ko-qlora/merged",
torch_dtype=torch.bfloat16,
device_map="auto"
)
def respond(message, history, system_prompt, max_tokens, temperature):
messages = [{"role": "system", "content": system_prompt}]
for user, assistant in history:
messages.append({"role": "user", "content": user})
messages.append({"role": "assistant", "content": assistant})
messages.append({"role": "user", "content": message})
output = pipe(
messages,
max_new_tokens=max_tokens,
temperature=temperature,
do_sample=True
)
return output[0]["generated_text"][-1]["content"]
demo = gr.ChatInterface(
respond,
additional_inputs=[
gr.Textbox("당신은 도움이 되는 AI 어시스턴트입니다.", label="시스템 프롬프트"),
gr.Slider(50, 1000, 256, label="최대 토큰"),
gr.Slider(0.1, 2.0, 0.7, label="Temperature")
],
title="한국어 Llama-3 챗봇",
description="QLoRA로 파인튜닝된 한국어 LLM"
)
if __name__ == "__main__":
demo.launch()
마치며
이 가이드에서 HuggingFace 생태계의 핵심 구성 요소들을 살펴보았습니다.
- **transformers**: 파이프라인부터 세밀한 모델 제어까지 다양한 추상화 수준 제공
- **datasets**: 효율적인 데이터 로딩, 처리, 공유
- **tokenizers**: Rust 기반 초고속 토크나이징
- **peft**: LoRA/QLoRA로 대형 모델을 소비자 GPU에서도 파인튜닝
- **accelerate**: 멀티 GPU/TPU 학습을 코드 변경 없이 지원
- **trl**: SFT, DPO, RLHF 등 현대적 파인튜닝 기법
- **diffusers**: 이미지 생성 모델의 표준 라이브러리
- **evaluate**: 표준화된 모델 평가
HuggingFace 생태계는 빠르게 발전하고 있으므로 공식 문서와 블로그를 주기적으로 확인하는 것을 권장합니다.
참고 자료
- HuggingFace 공식 문서: https://huggingface.co/docs
- transformers 문서: https://huggingface.co/docs/transformers
- PEFT 문서: https://huggingface.co/docs/peft
- Accelerate 문서: https://huggingface.co/docs/accelerate
- TRL 문서: https://huggingface.co/docs/trl
- Diffusers 문서: https://huggingface.co/docs/diffusers
현재 단락 (1/992)
HuggingFace는 현재 AI/ML 생태계에서 가장 중요한 플랫폼 중 하나입니다. 수십만 개의 사전학습 모델, 수만 개의 데이터셋, 그리고 실용적인 라이브러리들을 하나의 생태계...