💡Llama 2 란?
Llama 2는 Meta AI에서 개발한 언어 모델로, GPT-3보다 더 작은 파라미터를 가지고 있고 학습 비용이 들지 않으면서도 높은 성능을 보이기 때문에 주목을 받고 있다.
Llama와 ChatGPT의 차이점
Llama | ChatGPT | |
모델 용도 | 연구자들을 대상으로 설계되었고, 학술적 연구나 실험에 활용할 수 있다. 또한, 오픈소스로 공개되어 있어 다른 연구자들이 동일한 작업을 재현하고 비교할 수 있다. | 주로 범용적인 사용을 목표로 하며, 대화를 위해 특별히 설계되었다. 따라서, 일반 사용자나 엔터프라이즈 솔루션에 더 적합하다. |
학습 데이터 | 주로 Wikipedia, Common Crawl, C4와 같은 공개된 데이터 세트를 사용하여 학습된다. 이는 일반적인 텍스트 데이터에 기반한 모델로, 다양한 영역의 지식을 포함하고 있다. | 주로 대화에 관련된 데이터를 사용하여 학습된다. 따라서, 자연어 이해와 대화 생성에 더 특화되어 있다. |
모델 파라미터 및 파인튜닝 | 다양한 모델 크기를 제공하며, 이에 대한 모델 파라미터 체크포인트를 공개하여 연구자들이 자신의 데이터에 맞게 파인튜닝을 수행할 수 있다. | 고정된 모델 사이즈를 가지고 있으며, 파인튜닝을 직접 제공하지 않는다. 그러나 대화 생성을 위해 특별히 조정된 모델 구조를 가지고 있다. |
💡Hugging Face
허깅페이스(Hugging Face)는 자연어 처리(Natural Language Processing, NLP)를 위한 오픈소스 라이브러리 및 플랫폼을 제공하는 회사이다.
허깅페이스는 다양한 언어 모델 및 사전 학습된 모델을 제공하며, 이를 사용하여 텍스트 분류, 기계 번역, 질문 응답, 문서 요약 등 다양한 NLP 작업을 수행할 수 있다. 또한 허깅페이스는 모델을 공유하고 탐색할 수 있는 허깅페이스 허브(Hugging Face Hub)를 운영하여 사용자들이 모델을 쉽게 찾고 공유할 수 있도록 하고 있다.
2024.01.26 - [Programming/Python] - [NLP] 자연어 처리(Natural Language Processing) 소개
자연어 처리(NLP)에 대해서는 위 글을 참고한다.
Transformers Library
허깅페이스는 다양한 NLP 모델과 데이터셋을 모아놓은 트랜스포머 라이브러리로 유명하다. 이 라이브러리는 최신의 트랜스포머 아키텍처를 사용하여 자연어 이해 및 생성 작업을 수행할 수 있도록 지원한다.
트랜스포머 라이브러리를 사용하여 Llama 모델을 파인튜닝을 할 수 있다. 이때 허깅페이스의 모델 허브에 액세스 하게 되는데, 모델 허브에 접근하려면 허깅페이스 토큰이 필요하다. 따라서 허깅페이스 토큰을 발급받는 작업을 선행하여 수행하도록 한다.
Llama 2 Model Access
https://huggingface.co/meta-llama
본인이 원하는 Llama2 모델을 신청하여 사용하면 된다.
Llama-2-13b-chat를 사용하는 것으로 가정해 보도록 하자.
7B, 13B, 70B의 의미
- 7B: 7 billion(70억) 개의 매개변수를 가진 모델
- 13B: 13 billion(130억) 개의 매개변수를 가진 모델
- 70B: 70 billion(700억) 개의 매개변수를 가진 모델
라마 모델에서 7B, 13B, 70B는 각각 모델의 크기를 나타낸다. 이 값은 모델이 가지는 매개변수(parameter)의 수를 나타내며, 일반적으로 모델의 크기가 클수록 더 많은 매개변수를 가지고 있다.
일반적으로 모델의 크기가 크면 더 많은 매개변수를 가지므로 더 많은 문맥을 이해하고 더 복잡한 패턴을 학습할 수 있다. 따라서 큰 모델을 사용하면 성능이 더 우수하지만, 더 많은 계산 리소스와 메모리를 필요로 하기 때문에 학습과 추론에 더 많은 시간이 소요된다.
hr의 의미
- meta-llama/Llama-2-7b-chat-hf
- meta-llama/Llama-2-7b-chat
hf의 의미는 huggingface의 약자이다. 따라서 Llama2-chat-hf 모델은 Hugging Face에서 개발한 Llama2-chat 모델의 변형 버전이라고 할 수 있다.
Access Llama 2 on Hugging Face
Access Llama 2 on Hugging Face에 대한 동의를 하고, Submit 버튼을 클릭한다. 다음과 같이 "Your request to access this repo has been successfully submitted"라고 나오면 신청이 완료된 것이다.
승인 완료 메일
승인을 신청하면 몇 시간 또는 하루에서 이틀 내에 위와 같이 등록한 이메일로 승인 메일이 온다. 만약 여러 개의 모델에 대한 승인을 신청했다면, 액세스 권한 별로 메일이 발송된다.
다시 페이지에 들어가 보면 "Gated model You have been granted access to this model" 메시지가 나온다. 즉, 모델에 대한 액세스 권한이 등록되었다는 것을 확인할 수 있다.
Access Tokens
이제 토큰을 발급받을 차례이다.
아래 페이지에서 토큰을 발급받도록 한다.
https://huggingface.co/settings/tokens
Create a new access token
Role을 'write'로 선택하면 해당 토큰은 허깅페이스의 API에 쓰기 작업을 수행할 수 있는 권한을 부여받는다. 이로써 사용자는 모델 업로드, 데이터셋 변경 등의 작업을 허깅페이스 API를 통해 수행할 수 있게 된다.
Access Token 발급 완료
토큰이 발급이 완료되면 위와 같이 토큰을 복사할 수 있다.
📌Llama 2 Fine-Tuning
바로 모델 구동이 가능한 이유는 이미 공개되어 있는 베이스 모델이 있기 때문이다. Fine-Tuning을 할 때 BASE Model에 학습을 추가한 Fine Tuned Model을 결합하는 방식으로 이루어진다. 이를 활용하여 Chatbot을 만들어 특정 산업군에 있는 Q&A Fine-Tuning을 진행할 수도 있다.
Colab과 Hugging Face를 사용하여 Llama 2 모델을 Fine-Tuning 해보도록 하자. 이 과정은 HK CODE 유튜브에 올라온 교수님의 강의를 참고하였다.
2024.03.11 - [Programming/Python] - [LLM] AI 모델 최적화 방법 Fine-Tuning과 Prompt-Tuning
파인튜닝에 대해서는 위 글을 참고한다.
1. 파인튜닝 데이터 생성
프로젝트 준비
런타임 유형 변경
시작하기 전에 런타임을 GPU로 바꿔 주어야 한다.
GPU 백엔드를 연결할 수 없음
파인튜닝을 하기 위해서 GPU에 연결하는 게 필수적인데, 하루 Colab 사용량이 정해져 있기 때문에 코드가 실행되지 않을 수 있다.
구글 드라이브 연결
from google.colab import drive
drive.mount("/content/gdrive")
먼저, Google Colab에서 Google Drive를 마운트해 주었다.
google.colab에서 drive를 import 하여 Google Colab에서 제공하는 drive 모듈을 가져온다. 이 모듈은 Google Drive와 상호 작용할 수 있는 기능을 제공한다. 그리고 Google Drive를 Colab 가상 머신에 연결하고, 드라이브의 파일 및 폴더에 액세스 할 수 있는 /content/gdrive 경로에 마운트한다. 이 경로는 Colab 환경에서 Google Drive에 저장된 데이터에 접근할 때 사용된다.
dataPath = "/content/gdrive/MyDrive/llama2/dataset/"
Google Drive 내에서 데이터셋이 저장된 경로를 지정하였다. path는 본인의 학습 데이터가 저장되어 있는 폴더 경로로 설정하면 된다.
이렇게 변수를 설정하면 이후에 데이터셋을 불러오거나 저장할 때 매번 경로를 새로 입력할 필요 없이 dataPath 변수를 사용하여 경로를 참조할 수 있다.
라이브러리 설치
!pip install datasets==2.16.1 jsonlines==4.0.0
파이썬 패키지 관리자 pip를 사용하여 두 가지 라이브러리를 설치하였다. 여기서 설치되는 라이브러리는 다음과 같다.
- datasets==2.16.1: Hugging Face의 데이터셋과 메트릭을 관리하기 위한 라이브러리이다. 이 라이브러리는 Hugging Face의 인공지능 커뮤니티에서 수집된 다양한 데이터셋을 불러오고 관리하는 데 사용된다. 데이터셋은 다양한 형식과 크기로 제공되며, 이 라이브러리를 사용하면 데이터셋을 쉽게 다운로드하고 사용할 수 있다.
- jsonlines==4.0.0: JSON 형식의 데이터를 처리하기 위한 라이브러리이다. JSONLines는 각 줄이 하나의 JSON 객체로 구성된 텍스트 파일 형식으로 데이터를 저장하는 방식을 나타낸다. 이 라이브러리는 JSONLines 형식의 데이터를 읽고 쓰는 기능을 제공하여 데이터를 효율적으로 처리할 수 있다.
Huggign Face 로그인
# hugging face 로그인: hugging face -> 우측상단의 계정선택 -> settings -> access token
import huggingface_hub
huggingface_hub.login()
huggingface_hub 라이브러리를 사용하여 Hugging Face Hub에 로그인을 한다.
로그인 과정에서 사용자의 계정 정보를 인증하기 위해 access token이 필요하다. 이때 앞서 발급받은 access token을 입력한다.
설치한 라이브러리 선언
# 행과열을 핸들링하는 라이브러리
import pandas as pd
# json 포맷 데이터를 핸들링하는 라이브러리
import json
import jsonlines
# hugging face 데이터 관리 라이브러리
from datasets import Dataset
데이터를 다루기 위해 필요한 라이브러리를 가져온다.
- pandas: 행과 열을 다루기 위한 라이브러리로, 데이터를 테이블 형태로 불러오고 조작하는 데 사용된다. 주로 구조화된 데이터를 처리하는 데 유용하다.
- json: JSON(JavaScript Object Notation) 형식의 데이터를 다루기 위한 라이브러리이다. JSON은 데이터를 저장하고 교환하기 위한 경량의 데이터 형식으로, 웹 애플리케이션과 API 등에서 자주 사용된다.
- jsonlines: JSON Lines 형식의 데이터를 다루기 위한 라이브러리이다. JSON Lines는 여러 줄에 걸쳐 JSON 객체를 저장하는 형식으로, 대용량 데이터를 효율적으로 처리할 수 있다.
- datasets: Hugging Face의 데이터셋을 관리하고 불러오기 위한 라이브러리이다. 다양한 형식의 데이터를 쉽게 불러와서 처리할 수 있으며, 자연어 처리를 위한 데이터셋을 특히 많이 제공한다.
학습 데이터 불러오기 및 변환
# 데이터 경로 설정 및 불러오기
datasetName = "indata_kor.csv"
jsonFileName = "indata_kor.jsonl"
datasetName에 사용할 학습 데이터 파일의 이름을 지정한다. 이 변수에는 CSV 파일의 이름이 지정되어 있다.
jsonFileName에 변환된 데이터를 저장할 JSON Lines 형식의 파일의 이름을 지정한다. JSON Lines는 각 줄에 JSON 객체가 하나씩 들어가는 형식으로, 대용량 데이터를 효율적으로 저장할 수 있다.
def csv_to_json(csv_file_path, json_file_path):
# CSV 파일을 DataFrame으로 읽기★ (한글인 경우 encoding="ms949") 영문인경우 해당 내용 삭제 ★
df = pd.read_csv(csv_file_path, encoding="ms949")
# JSON 파일로 저장
with open(json_file_path, 'w', encoding='utf-8') as json_file:
# 각 행을 JSON으로 변환하여 바로 파일에 쓰기
for index, row in df.iterrows():
data = {'inputs': row['inputs'], 'response': row['response']}
json.dump(data, json_file, ensure_ascii=False)
json_file.write('\n') # 각 행마다 줄바꿈
# CSV 파일 경로와 JSON 파일 경로 설정
csv_file_path = dataPath + datasetName
json_file_path = dataPath + jsonFileName
# 함수 호출
csv_to_json(csv_file_path, json_file_path)
CSV 파일을 JSON Lines 형식으로 변환하는 함수인 csv_to_json을 정의하고 호출하는 작업을 수행한다.
파인튜닝용 포맷으로 변환
indataset = []
with jsonlines.open(json_file_path) as f:
for line in f.iter():
indataset.append(f'<s>[INST] {line["inputs"]} [/INST] {line["response"]} </s>')
# indataset.append(f'<s>### Instruction: \n{line["inputs"]} \n\n### Response: \n{line["response"]}</s>')
# 데이터셋 확인
print('데이터셋 확인')
print(indataset[:5])
# 데이터셋 생성 및 저장
indataset = Dataset.from_dict({"text": indataset})
indataset.save_to_disk(dataPath)
# 데이터셋 info 확인
print('데이터셋 info 확인')
print(indataset)
JSON Lines 형식으로 저장된 데이터를 파인튜닝용 포맷으로 변환하고, 변환된 데이터셋을 생성하여 저장하는 과정을 수행한다.
Hugging Face에 데이터 업로드
# huggingface의 Data Directory
indataset.push_to_hub("Isaac-Seungwon/llama2_custom_code")
Hugging Face의 데이터 디렉터리에 데이터셋을 업로드한다.
데이터셋을 업로드하기 전에 Hugging Face에서 데이터셋을 생성한다. 만약 작성한 이름으로 디렉터리가 없을 경우 새로운 데이터셋이 자동으로 생성되므로 생략해도 무방하다.
새로운 데이터셋 생성
https://huggingface.co/docs/diffusers/main/ko/training/create_dataset
학습을 위한 데이터셋 만들기에 대해서는 위 글을 참고한다.
Hugging Face에 데이터셋 생성이 완료되었다.
2. 파인튜닝 모델 생성
구글 드라이브 연결
from google.colab import drive
drive.mount('/content/drive')
파인튜닝 데이터를 생성할 때와 마찬가지로 구글 드라이브에 연결한다.
라이브러리 설치
### accelerate : hugging face 학습루프 가속화 라이브러리
### peft: LoRA, Prefix Tuning, P-Tuing, Prompt Tuning 과 같은 기법들을 쉽게 사용하도록 나온 라이브러리
### bitsandbytes: gpu 에서 모델을 손쉽게 압축할 수 있는 라이브러리
### trl: TRL (Transformer Reinforcement Learning) 은 transfomer언어 모델의 훈련을 위한 풀스택 라이브러리
!pip install accelerate==0.26.1 peft==0.8.2 bitsandbytes==0.42.0 transformers==4.37.2 trl==0.7.10
다섯 가지의 파이썬 라이브러리를 설치한다.
- accelerate: "hugging face" 학습 루프를 가속화하기 위한 라이브러리로, 모델 훈련을 더 빠르고 효율적으로 만들어주는 도구이다.
- peft: LoRA, Prefix Tuning, P-Tuning, Prompt Tuning 등과 같은 기술들을 쉽게 사용할 수 있도록 하는 라이브러리이다. 이러한 기술들은 모델의 특정한 부분을 미세하게 조정하여 성능을 향상하는 데 사용된다.
- bitsandbytes: GPU에서 모델을 손쉽게 압축할 수 있도록 도와주는 라이브러리이다. 모델 압축은 모델의 크기를 줄이고 성능을 최적화하는 데 도움이 된다.
- transformers: Hugging Face에서 제공하는 트랜스포머 모델과 관련된 다양한 작업들을 수행하는 라이브러리이다. 텍스트 생성, 번역, 감정 분석 등 다양한 자연어 처리 작업에 사용될 수 있다.
- trl: Transformer Reinforcement Learning (TRL)은 트랜스포머 언어 모델의 훈련을 위한 풀 스택 라이브러리이다. 강화 학습 기법을 트랜스포머 모델에 적용하여 성능을 향상하는 데 사용된다.
라이브러리 및 패키지 임포트
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig
from trl import SFTTrainer
필요한 라이브러리와 패키지를 가져온다. 그리고 peft와 trl에서는 각각 LoraConfig와 SFTTrainer 클래스를 가져온다.
- os: 운영 체제와 상호 작용하기 위한 라이브러리
- torch: 파이토치 라이브러리, 주로 딥러닝 모델의 구축과 훈련을 위해 사용
- load_dataset: Hugging Face의 datasets 라이브러리에서 데이터셋을 로드하는 함수
- AutoModelForCausalLM, AutoTokenizer: Hugging Face의 transformers 라이브러리에서 자동으로 모델과 토크나이저를 불러오는 함수
- BitsAndBytesConfig: 모델을 압축하기 위한 BitsAndBytes 라이브러리의 설정을 제어하는 클래스
- TrainingArguments: 모델 훈련을 위한 인자들을 설정하는 클래스
- pipeline: Hugging Face의 transformers 라이브러리에서 파이프라인을 생성하는 함수
- logging: 로깅을 위한 모듈
Hugging Face 로그인
import huggingface_hub
huggingface_hub.login()
마찬가지로 Hugging Face에 로그인한다.
모델 설정
# Hugging Face Basic Model 한국어 기본모델
base_model = "beomi/llama-2-ko-7b"
# Custom Dataset ★ 본인이 hugging face 내 저장한 모델경로를 설정해야함 ★
code_dataset = "Isaac-Seungwon/llama2_custom_code"
# Fine-tuned model
new_model = "llama-2-7b-chat-hkcode-kor"
Hugging Face에서 제공하는 한국어 기본 모델을 설정한다. 여기서 "beomi/llama-2-ko-7b"는 Hugging Face에서 제공하는 한국어 기본 모델의 이름이다. 이 모델은 "beomi" 사용자가 훈련시킨 LLAMA (Large Language Model for Korean) 모델 중 하나이며, 7억 개의 파라미터를 가지고 있다.
그리고 Hugging Face에 저장한 사용자 정의 데이터셋의 경로와 Fine-tuning 된 새로운 모델의 이름을 설정한다.
데이터 불러오기 (훈련)
dataset = load_dataset(code_dataset, split="train")
Hugging Face의 datasets 라이브러리를 사용하여 훈련에 사용할 데이터를 불러온다.
load_dataset 함수는 Hugging Face의 데이터셋을 로드하는 함수로, code_dataset과 split 인자를 받는다. code_dataset에서 사용할 데이터셋의 이름 또는 경로를 지정하고, split: 데이터셋에서 사용할 부분을 지정한다. 여기서는 훈련에 사용할 데이터를 불러오기 때문에 "train"을 사용한다.
데이터 확인
print( dataset[28] )
4비트 양자화 QLoRA 파인튜닝
4비트 양자화는 모델의 가중치를 4비트로 표현하여 메모리 사용량을 줄이고 추론 속도를 향상하는 기술을 가리킨다. 이는 모델의 파라미터를 4비트 정밀도로 표현하여 모델의 크기를 줄이는 것이다. 그리고 QLoRA는 양자화를 위한 특정한 기법 중 하나로, 모델의 가중치를 양자화하는 방법을 의미한다.
compute_dtype = getattr(torch, "float16")
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=False,
)
torch 모듈에서 float16 데이터 유형을 가져와서 compute_dtype 변수에 저장한다. 이 부분은 모델을 계산하는 동안 사용할 데이터 유형을 설정하는 데 사용된다. 여기서는 float16을 선택하여 모델의 연산량을 줄이고 성능을 향상한다. 그리고 BitsAndBytes 라이브러리를 사용하여 모델의 양자화 설정을 지정한다. BitsAndBytesConfig 클래스를 사용하여 설정을 구성하는데, 여러 인자들을 설정할 수 있다. 이를 통해 파라미터를 고정시키고 추가데이터만 튜닝함으로써 메모리를 절약하고 추론 속도를 향상해효율성을 높일 수 있다.
Llama 2 Model 불러오기
model = AutoModelForCausalLM.from_pretrained(
base_model,
quantization_config=quant_config,
device_map={"": 0}
)
model.config.use_cache = False
model.config.pretraining_tp = 1
Hugging Face의 transformers 라이브러리를 사용하여 사전 훈련된 모델을 불러온다.
- from_pretrained 함수를 사용하여 사전 훈련된 모델을 불러온다. 여기서는 Causal Language Modeling (CLM)을 위한 모델을 불러오는 데 사용되며, 해당 모델은 앞서 설정한 base_model인 "beomi/llama-2-ko-7b"를 사용한다.
- base_model로 앞서 설정한 한국어 기본 모델을 지정하고, quantization_config에서 양자화 설정을 적용한다. 앞서 설정한 quant_config를 사용하여 모델을 양자화한다. 그리고 device_map을 통해 모델을 어떤 장치(여기서는 GPU)에 로드할지 지정한다. 여기서는 기본 장치(0번 GPU)에 로드한다.
- model.config.use_cache를 통해 모델 구성(config)의 캐시 사용 여부를 설정한다. 여기서는 캐시를 사용하지 않도록 설정하였다. 그리고 model.config.pretraining_tp에서 모델 구성(config)의 사전 훈련 토큰 포지션 값(pretraining token position)을 설정한다. 여기서는 1로 설정되어 있다. 이는 모델이 사전 훈련된 토큰의 위치를 1로 고정한다는 것을 의미한다.
토크나이저 불러오기
tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
Hugging Face의 transformers 라이브러리를 사용하여 토크나이저를 설정한다.
- Hugging Face에서 제공하는 토크나이저를 로드하고, 그 토크나이저의 패딩 방향을 오른쪽으로 설정함으로써 FP16 (16비트 부동소수점)과 관련된 문제를 해결하였다.
- FP16은 16비트 부동소수점 형식을 의미하며, 모델의 가중치 및 계산에 사용되는 데이터 형식 중 하나이다. FP16은 모델의 크기를 줄이고 계산 속도를 높이는 데 사용될 수 있지만, 때로는 숫자의 정밀도가 감소하여 모델의 성능이 저하될 수 있다.
- 패딩은 모델의 입력 시퀀스를 일정한 길이로 맞추기 위해 사용되는 작업이다. 일반적으로 시퀀스의 뒷부분에 패딩을 추가하는데, 이를 "right" 패딩이라고 한다. 그러나 FP16을 사용할 때는 일부 구현에서 패딩 방향에 따라 정확성 문제가 발생할 수 있다.
PEFT 파라미터
peft_params = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM",
)
PEFT 라이브러리의 LoRA (Low Rank Adaptation) 모델의 파라미터를 설정한다.
- lora_alpha는 LoRA 모델의 하이퍼파라미터로, Low Rank Adaptation의 알파 값을 설정한다. 이 값은 모델의 적응 능력에 영향을 준다.
- lora_dropout는 LoRA 모델의 드롭아웃 비율을 설정한다. 드롭아웃은 모델이 학습할 때 무작위로 일부 뉴런을 제외하여 과적합을 방지하는 데 사용된다.
- r은 Low Rank Adaptation의 순위를 나타내는 파라미터이다. 이 값은 모델의 적응 능력을 제어하는 데 사용된다.
- bias는 LoRA 모델에서 사용할 편향(bias)의 유형을 설정한다. 여기서는 "none"으로 설정되어 있으므로 편향이 사용되지 않는다.
- task_type은 모델의 작업 유형을 설정한다. 여기서는 "CAUSAL_LM"으로 설정되어 있으므로 모델은 인과적 언어 모델링 작업에 사용된다.
PEFT
Parameter-Efficient Fine-Tuning(PEFT)는 모델 파라미터 중 일부분만을 업데이트하여 모델을 튜닝하는 기술을 의미한다.
기존의 전체 모델을 대상으로 하는 파인튜닝은 모델의 모든 파라미터를 다시 훈련하여 비용이 많이 들고 시간이 많이 소요될 수 있다. 그러나 PEFT는 전체 모델 대신 모델의 작은 하위 집합인 "파라미터 그룹"만을 업데이트하여 효율적으로 파인튜닝을 수행한다.
Training parameters
training_params = TrainingArguments(
output_dir="./results",
num_train_epochs=5,
per_device_train_batch_size=4,
gradient_accumulation_steps=1,
optim="paged_adamw_32bit",
save_steps=25,
logging_steps=25,
learning_rate=2e-4,
weight_decay=0.001,
fp16=False,
bf16=False,
max_grad_norm=0.3,
max_steps=-1,
warmup_ratio=0.03,
group_by_length=True,
lr_scheduler_type="constant",
report_to="tensorboard"
)
모델 훈련을 위한 설정을 지정한다. 이때 TrainingArguments 클래스를 사용하여 모델 훈련에 필요한 다양한 인자들을 설정할 수 있다.
- output_dir은 훈련 결과가 저장될 디렉터리를 지정한다. 여기서는 "./results" 디렉터리에 저장된다.
- num_train_epochs는 훈련할 epoch 수를 지정한다. 여기서는 5회의 epoch 동안 훈련한다.
- per_device_train_batch_size는 한 번에 각 장치에 할당되는 훈련 배치 크기를 지정한다. 여기서는 각 장치에 4개의 샘플이 할당된다.
- gradient_accumulation_steps는 그래디언트 누적 스텝 수를 지정한다. 여기서는 1로 설정되어 있으므로 그래디언트가 한 번에 업데이트된다.
- optim는 최적화 알고리즘을 지정한다. 여기서는 "paged_adamw_32bit"를 사용한다.
- save_steps는 훈련 중 중간 결과를 저장할 스텝 간격을 지정한다. 여기서는 25번의 스텝마다 결과를 저장한다.
- logging_steps는 훈련 중 중간 결과를 로깅할 스텝 간격을 지정한다. 여기서는 25번의 스텝마다 로깅한다.
- learning_rate는 학습률을 지정한다. 여기서는 2e-4로 설정되어 있다.
- weight_decay는 가중치 감쇠를 지정한다. 여기서는 0.001로 설정되어 있다.
- fp16와 bf16는 FP16 및 BF16을 사용할지 여부를 지정한다. 여기서는 False로 설정되어 있다.
- max_grad_norm는 그래디언트 클리핑을 위한 최대 그래디언트 노름을 지정한다. 여기서는 0.3으로 설정되어 있다.
- max_steps는 최대 훈련 스텝 수를 지정한다. 여기서는 -1로 설정되어 있어 최대 스텝 수를 제한하지 않는다.
- warmup_ratio는 warmup 비율을 지정한다. 여기서는 0.03으로 설정되어 있다.
- group_by_length는 훈련 배치를 길이에 따라 그룹화할지 여부를 지정한다. 여기서는 True로 설정되어 있다.
- lr_scheduler_type는 학습률 스케줄러의 유형을 지정한다. 여기서는 "constant"로 설정되어 있다.
- report_to는 결과를 보고할 위치를 지정한다. 여기서는 텐서보드에 결과를 보고한다.
Model 파인튜닝
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_params,
dataset_text_field="text",
max_seq_length=None,
tokenizer=tokenizer,
args=training_params,
packing=False,
)
TRL (Transformer Reinforcement Learning) 라이브러리에서 제공하는 SFTTrainer 클래스를 사용하여 모델을 훈련시킨다.
- odel은 훈련에 사용할 모델을 지정한다. 앞서 정의한 모델을 사용한다.
- train_dataset은 훈련에 사용할 데이터셋을 지정한다. 앞서 로드한 데이터셋을 사용한다.
- peft_config은 PEFT에 대한 설정을 지정한다. 앞서 정의한 PEFT 설정을 사용한다.
- dataset_text_field은 데이터셋에서 텍스트 필드의 이름을 지정한다. 여기서는 "text" 필드를 사용한다.
- max_seq_length은 최대 시퀀스 길이를 지정한다. 여기서는 None으로 설정되어 있어 시퀀스 길이를 제한하지 않는다.
- tokenizer은 토크나이저를 지정한다. 앞서 설정한 토크나이저를 사용한다.
- args은 훈련에 사용할 인자들을 지정한다. 앞서 설정한 훈련 인자들을 사용한다.
- packing은 패킹을 사용할지 여부를 지정한다. 여기서는 False로 설정되어 있다.
trainer.train()
앞서 설정한 SFTTrainer 객체를 사용하여 모델을 훈련시킨다.
train() 메서드는 SFTTrainer 객체에 정의된 모델을 훈련시키는 메서드이다. 이 메서드를 호출하면 모델이 지정된 데이터셋 (train_dataset)을 사용하여 주어진 훈련 인자들 (training_params)을 기반으로 훈련된다.
훈련 과정에서는 모델의 가중치가 업데이트되고, 손실이 계산되며, 지정된 스텝 간격에 따라 중간 결과가 저장되고 로깅된다. 설정된 epoch 수만큼 훈련이 반복되며, 각 epoch마다 모델의 성능이 향상된다.
이렇게 train() 메서드를 호출하면 모델이 주어진 데이터셋을 사용하여 훈련되고, 훈련 결과가 지정된 디렉터리에 저장된다.
모델 저장하기
output_dir = "/content/gdrive/MyDrive/llama2/models/code_finetuned"
trainer.model.save_pretrained(output_dir)
훈련된 모델을 저장할 디렉터리 경로를 지정하고, trainer.model.save_pretrained() 메서드를 사용하여 훈련된 모델을 해당 디렉터리에 저장하였다.
모델 평가하기
from tensorboard import notebook
log_dir = "results/runs"
notebook.start("--logdir {} --port 4000".format(log_dir))
TensorBoard를 사용하여 훈련 과정에서 생성된 로그 및 결과를 시각화하였다.
TensorBoard 라이브러리에서 notebook 모듈을 가져온다. 이 모듈은 노트북 환경에서 TensorBoard를 실행하는 데 사용된다. 그리고 로그 파일 및 이벤트 파일이 저장된 디렉터리를 지정한다. 이 디렉터리에는 훈련 중 생성된 이벤트 파일이 포함되어 있어야 한다.
마지막으로 TensorBoard를 시작하는 명령어를 실행한다. -logdir 옵션은 로그 및 이벤트 파일이 저장된 디렉터리를 지정하고, --port 옵션은 TensorBoard가 사용할 포트 번호를 지정한다. 여기서는 지정된 디렉터리의 로그를 사용하고, 포트는 4000번을 사용한다.
텍스트 생성 및 출력
logging.set_verbosity(logging.CRITICAL)
prompt = "TCCINS는 어디에 위치하나요?"
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])
/usr/local/lib/python3.10/dist-packages/transformers/generation/utils.py:1295: UserWarning: You have modified the pretrained model configuration to control generation. This is a deprecated strategy to control generation and will be removed soon, in a future version. Please use and modify the model generation configuration (see https://huggingface.co/docs/transformers/generation_strategies#default-text-generation-configuration )
warnings.warn(
<s>[INST] TCCINS는 어디에 위치하나요? [/INST] 서울특별시 중구 을지로29 5층에 위치하며 지하철 2호선 을지로입구역 1-1번 출구 근처에 위치하고 있습니다.
텍스트 생성 모델을 사용하여 주어진 프롬프트에 기반하여 텍스트를 생성하고 출력한다.
- logging.set_verbosity(logging.CRITICAL)는 로깅 레벨을 설정하여 출력되는 로그를 최소화한다. 여기서는 CRITICAL 레벨을 설정하여 가장 심각한 오류 메시지만 출력되도록 한다.
- prompt는 텍스트 생성의 기반이 되는 프롬프트를 설정한다.
- pipe에서는 Hugging Face의 파이프라인을 사용하여 텍스트 생성 모델을 설정한다. 이때 모델과 토크나이저는 앞서 설정한 것을 사용하고, 최대 생성 길이는 200으로 설정하였다.
- result에는 설정한 프롬프트를 사용하여 파이프라인을 실행하여 텍스트를 생성한다. 프롬프트의 앞뒤에 <s>[INST]와 [/INST]를 추가하여 모델에게 해당 문장이 인스트럭션임을 알려준다.
- print 메서드를 이용해 생성된 텍스트를 출력한다. 여기서는 생성된 텍스트의 첫 번째 요소인 'generated_text'를 출력한다.
3. 대화형 챗봇 연결
구글 드라이브 연결
from google.colab import drive
drive.mount('/content/drive')
구글 드라이브에 연결한다.
라이브러리 설치하기
%pip install accelerate==0.26.1 peft==0.8.2 bitsandbytes==0.42.0 transformers==4.37.2 trl==0.7.10
모델을 생성할 때와 마찬가지로 라이브러리를 설치한다.
라이브러리 및 패키지 임포트
from transformers import AutoTokenizer, LlamaForCausalLM
import torch
import argparse
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
HfArgumentParser,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer
import warnings
warnings.filterwarnings('ignore')
텍스트 생성을 위한 환경을 설정하는 데 필요한 라이브러리를 가져왔다.
Hugging Face의 transformers 라이브러리에서 AutoTokenizer와 LlamaForCausalLM 클래스를 가져왔다. AutoTokenizer는 자동으로 토크나이저를 로드하는 데 사용되고, LlamaForCausalLM은 LLAMA 모델을 생성하는 데 사용된다.
Llama 2 Hugging Face Model 불러오기
# 라마2 허깅페이스 모델 불러오기
base_model = "NousResearch/Llama-2-7b-chat-hf"
compute_dtype = getattr(torch, 'float16')
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=False,
)
model = AutoModelForCausalLM.from_pretrained(
base_model,
quantization_config=quant_config,
device_map={"": 0}
)
model.config.use_cache = False
model.config.pretraining_tp = 1
tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# 어댑터 추가
model = PeftModel.from_pretrained(model, "/content/gdrive/MyDrive/llama2/models/code_finetuned")
라마 2 모델과 파인튜닝된 어댑터를 로드하여 사용자가 지정한 양자화 설정을 적용한 후, 모델을 준비한다.
위 코드는 라마 2 허깅페이스 모델 불러오기, 토크나이저 설정, 어댑터 추가 3가지 작업을 수행한다.
라마 2 허깅페이스 모델 불러오기
- base_model는 Hugging Face에서 제공하는 라마 2 모델의 이름을 지정한다.
- compute_dtype는 모델의 계산에 사용할 데이터 유형을 지정한다. 여기서는 float16을 사용한다.
- quant_config의 BitsAndBytesConfig를 사용하여 모델의 양자화 설정을 지정한다. 이는 모델을 4비트로 양자화하여 메모리를 절약하고 추론 속도를 향상한다.
- model을 통해 Hugging Face의 AutoModelForCausalLM 클래스를 사용하여 라마 2 모델을 불러온다. 양자화 설정을 적용하고, 계산에 사용할 데이터 유형을 설정한다.
토크나이저 설정
tokenizer의 AutoTokenizer.from_pretrained(...)를 통해 Hugging Face의 AutoTokenizer 클래스를 사용하여 토크나이저를 불러온다. 이때 양자화된 모델과 일치하도록 설정한다.
어댑터 추가
model의 PeftModel.from_pretrained(...)를 통해 양자화된 모델에 사용자가 파인튜닝한 어댑터를 추가한다. 이를 통해 사용자가 추가한 어댑터와 함께 양자화된 모델을 사용할 수 있다.
텍스트 생성 및 출력
logging.set_verbosity(logging.CRITICAL)
prompt = "Where is the TCCINS located?"
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])
주어진 프롬프트에 기반하여 라마 2 모델을 사용하여 텍스트를 생성하고 출력한다.
Llama 2 챗봇 연결 테스트 with gradio
import locale
locale.getpreferredencoding = lambda: "UTF-8"
!pip install -q gradio==3.45.0
Gradio는 간단한 코드로 웹 애플리케이션을 만들고 실행할 수 있는 라이브러리이다. 사용자가 쉽게 모델을 웹 인터페이스로 배포하고 상호 작용할 수 있도록 도와준다. Gradio를 사용하면 웹 애플리케이션을 만들고 실행하는 과정을 단순화할 수 있다.
locale.getpreferredencoding를 통해 시스템의 기본 인코딩을 UTF-8로 설정한다. 이는 Unicode 문자열을 올바르게 처리하기 위해 사용된다. 그리고 Gradio 라이브러리를 설치한다. gradio==3.45.0은 설치할 Gradio 라이브러리의 버전을 지정하는 부분으로, 여기서는 3.45.0 버전을 설치한다.
import locale
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
# !pip install --upgrade gradio
# !pip install -q gradio==3.45.0
!pip install -q gradio --use-deprecated=legacy-resolver
!pip install typing_extensions --upgrade
import gradio as gr
- locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')에서 로케일을 설정하여 기본 인코딩을 UTF-8로 지정한다. 이는 Unicode 문자열을 올바르게 처리하기 위해 사용된다.
- !pip install -q gradio은 Gradio 라이브러리를 설치하는 명령어이다. -q 옵션은 설치 과정에서 출력되는 로그를 최소화한다. --use-deprecated=legacy-resolver 옵션은 pip가 사용하는 해결자를 이전 버전으로 지정하는 것으로, 종속성 문제를 해결하기 위해 사용될 수 있다.
- !pip install typing_extensions를 통해 패키지를 업그레이드한다. 이는 Gradio에 필요한 종속성 중 하나이다.
- import gradio as gr는 Gradio 라이브러리를 임포트 한다.
파이프라인 설정
llama_pipeline = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
Hugging Face의 pipeline 함수를 사용하여 텍스트 생성 작업을 수행하는 파이프라인을 설정한다.
이렇게 설정된 파이프라인은 주어진 모델과 토크나이저를 사용하여 텍스트 생성 작업을 수행할 준비가 된 상태이다.
Llama 모델에서 사용할 메시지와 대화 기록 포맷
SYSTEM_PROMPT = """<s>[INST] <<SYS>>
You are a helpful bot. Your answers are clear and concise.
<</SYS>>
"""
# Formatting function for message and history
def format_message(message: str, history: list, memory_limit: int = 3) -> str:
"""
Formats the message and history for the Llama model.
Parameters:
message (str): Current message to send.
history (list): Past conversation history.
memory_limit (int): Limit on how many past interactions to consider.
Returns:
str: Formatted message string
"""
# always keep len(history) <= memory_limit
if len(history) > memory_limit:
history = history[-memory_limit:]
if len(history) == 0:
return SYSTEM_PROMPT + f"{message} [/INST]"
formatted_message = SYSTEM_PROMPT + f"{history[0][0]} [/INST] {history[0][1]} </s>"
# Handle conversation history
for user_msg, model_answer in history[1:]:
formatted_message += f"<s>[INST] {user_msg} [/INST] {model_answer} </s>"
# Handle the current message
formatted_message += f"<s>[INST] {message} [/INST]"
return formatted_message
- SYSTEM_PROMPT은 시스템에 대한 프롬프트를 나타내는 문자열이다. 이 프롬프트는 모델이 대화에 참여하는 방식을 지정한다.
- format_message은 메시지와 대화 기록을 포맷하는 함수이다.
- message: 현재 전송할 메시지
- history: 이전 대화 기록
- memory_limit: 고려할 이전 대화 기록의 최대 수, 기본값 3
이 함수는 다음과 같은 작업을 수행한다.
- 대화 기록의 길이가 memory_limit을 초과하는 경우, 최근 대화 기록만 유지한다.
- 시스템 프롬프트와 첫 번째 사용자 메시지와 모델 응답을 결합하여 초기 포맷된 메시지를 생성한다.
- 대화 기록에 있는 모든 이전 메시지와 모델 응답을 추가하여 포맷된 메시지에 추가한다.
- 현재 메시지를 포맷된 메시지에 추가한다.
이렇게 포맷된 메시지는 Llama 모델에 전달되어 대화를 생성하고 응답을 반환하는 데 사용된다.
대화형 응답 생성
# Generate a response from the Llama model
def get_llama_response(message: str, history: list) -> str:
"""
Generates a conversational response from the Llama model.
Parameters:
message (str): User's input message.
history (list): Past conversation history.
Returns:
str: Generated response from the Llama model.
"""
query = format_message(message, history)
response = ""
sequences = llama_pipeline(
query,
do_sample=True,
top_k=10,
num_return_sequences=1,
eos_token_id=tokenizer.eos_token_id,
max_length=1024,
)
generated_text = sequences[0]['generated_text']
response = generated_text[len(query):] # Remove the prompt from the output
print("Chatbot:", response.strip())
return response.strip()
Llama 모델을 사용하여 대화형 응답을 생성하는 함수를 정의한다.
이 함수는 사용자의 입력과 이전 대화 기록을 기반으로 Llama 모델을 사용하여 응답을 생성하고, 생성된 응답을 반환한다.
- get_llama_response(message: str, history: list) -> str은 함수의 시그니처를 정의한다. 이 함수는 사용자의 입력 메시지와 이전 대화 내역을 받아서 Llama 모델을 사용하여 대화 응답을 생성한다.
- format_message(message: str, history: list, memory_limit: int = 3) -> str 함수는 메시지와 대화 기록을 Llama 모델의 입력 형식에 맞게 포맷팅 한다. 현재 메시지와 이전 대화 기록을 조합하여 하나의 형식화된 메시지로 반환한다.
- llama_pipeline(query, do_sample=True, top_k=10, num_return_sequences=1, eos_token_id=tokenizer.eos_token_id, max_length=1024)은 Hugging Face의 파이프라인을 사용하여 Llama 모델에 대한 쿼리를 실행한다. query는 포맷된 메시지이며, do_sample=True는 샘플링 방법을 설정하고, top_k=10은 샘플링 시 상위 k개의 토큰을 고려하도록 설정한다. num_return_sequences=1은 반환할 시퀀스의 수를 지정하고, eos_token_id=tokenizer.eos_token_id는 EOS(End of Sentence) 토큰의 ID를 설정한다. max_length=1024는 생성할 텍스트의 최대 길이를 지정한다.
- generated_text = sequences[0]['generated_text']는 생성된 텍스트를 가져온다.
- response = generated_text[len(query):]는 생성된 텍스트에서 쿼리 부분을 제외한 응답 부분만을 추출한다.
- return response.strip()는 생성된 응답을 반환한다. strip() 함수를 사용하여 문자열 앞뒤의 공백을 제거한다.
대화형 챗봇 실행
gr.ChatInterface(get_llama_response).launch()
Gradio가 생성한 챗봇 인터페이스가 실행되고, 사용자는 텍스트 입력을 통해 챗봇과 대화를 할 수 있다. 사용자의 입력은 get_llama_response 함수에 전달되어 Llama 모델을 사용하여 응답이 생성되고, 생성된 응답은 챗봇 인터페이스에 출력된다. 사용자는 이러한 인터페이스를 통해 대화를 진행할 수 있다.
gr.ChatInterface(get_llama_response).launch()은 Gradio의 ChatInterface 클래스를 사용하여 챗봇 인터페이스를 생성하고, launch() 메서드를 사용하여 인터페이스를 실행한다. 이때 사용되는 함수는 get_llama_response 함수로, 사용자의 입력에 따라 챗봇의 응답을 생성하는 역할을 한다.
참고 학습 페이지
https://wikidocs.net/book/8056
https://www.coursera.org/learn/generative-ai-with-llms
학습에 참고하면 좋은 페이지를 소개한다.
참고 자료
Transformers (신경망 언어모델 라이브러리) 강좌, 최성필, 2023.02.21.
PEFT를 활용한 PLM 파인튜닝 가이드, kjwony, 2023.07.21.
Llama2 Model Customdata Part1 라마2모델 나만의 학습 데이터 생성방법, HK CODE, 2024.02.02.
Llama2 Model Customdata Part2 라마2모델 나만의 학습데이터 파인튜닝 방법, HK CODE, 2024.02.02.
Llama2 Model Customdata Part3 라마2모델 저장 및 활용 챗봇연결, HK CODE, 2024.02.04.
Llama2 Model Customdata Part4 라마2한국어모델 한국어 학습 시키기, HK CODE, 2024.02.19.