개요
저번 글에 이어서, 이번에도 생성형 AI 프로젝트에 대한 글이다. 이번에는 BERT, FinancialBERT를 Fine-Tuning 하여 레딧 댓글을 감성 분석할 때 정확도를 끌어올린 뒤, 최적 모델을 저장하는 단계이다.
코드 - 모델 파인 튜닝
from transformers import (
BertTokenizer,
BertForSequenceClassification,
Trainer,
TrainingArguments,
)
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
from torch.utils.data import Dataset
import torch
import pandas as pd
import numpy as np
##################
# 1. 모델 파인튜닝
##################
# 모델 학습시킬 레딧 댓글들 파일 경로 - 글쓴이는 엔비디아 댓글들 사용
DIR_TRAIN = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/데이터1_Finetuning용데이터_엔비디아댓글들.csv" # 학습에 사용되는 데이터 경로
# 1. 데이터 불러오기
df = pd.read_csv(DIR_TRAIN, encoding="latin1") # 엔비디아 댓글들 데이터프레임 만들기
# 2. 토크나이저, 모델, 및 데이터셋
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased") # 토크나이저
model = BertForSequenceClassification.from_pretrained(
"bert-base-uncased", num_labels=3
) # num_labels = 3 : 부정, 중립, 긍정
class RedditDataset(Dataset):
def __init__(self, texts, labels):
self.encodings = tokenizer(
texts, truncation=True, padding=True, max_length=100
) # 문장 최대 길이 100 토큰
self.labels = labels
def __getitem__(self, idx): # 인덱싱 가능하게
return {key: torch.tensor(val[idx]) for key, val in self.encodings.items()} | {
"labels": torch.tensor(self.labels[idx])
}
def __len__(self):
return len(self.labels)
train_texts, test_texts, train_labels, test_labels = train_test_split(
df["body"].tolist(), df["label"].tolist(), test_size=0.2
) # 전체에서 20% 테스트
train_dataset = RedditDataset(train_texts, train_labels) # 훈련 데이터셋
test_dataset = RedditDataset(test_texts, test_labels) # 평가 데이터셋
# 3. Trainer 설정 - 베스트 모델 저장
DIR_BEST_MODEL = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/saved_model" # 학습된 모델 저장할 경로
DIR_LOG = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/logs" # 로그 파일 저장할 경로
training_args = TrainingArguments(
output_dir=DIR_BEST_MODEL, # 베스트 모델 저장 경로
eval_strategy="epoch", # 매 epoch마다 평가
save_strategy="epoch", # epoch 끝날 때마다
save_total_limit=1, # 모델은 최대 1개만 저장
load_best_model_at_end=True, # 훈련 끝날 때마다 베스트 모델 불러오기
metric_for_best_model="accuracy", # 베스트 모델 기준
greater_is_better=True, # 평가 기준이 높을수록 좋음
per_device_train_batch_size=4, # 학습 배치 사이즈
per_device_eval_batch_size=8, # 평가 배치 사이즈
num_train_epochs=4, # 훈련 epoch 수
logging_dir=DIR_LOG, # 로그 저장
logging_steps=10, # 로그 출력 간격 스텝
use_cpu=True, # CPU 사용 여부
)
# 4. 정확도 계산 함수
def compute_metrics(predict):
preds = np.argmax(predict.predictions, axis=1)
acc = accuracy_score(predict.label_ids, preds)
return {"accuracy": acc}
# 5. trainer
trainer = Trainer(
model=model, # 사용할 모델
args=training_args, # 학습 환경
train_dataset=train_dataset, # 훈련 데이터
eval_dataset=test_dataset, # 테스트 데이터
compute_metrics=compute_metrics, # 평가 기준
)
# 6. 학습 실행
trainer.train()
# 최종 모델 저장
DIR_SAVED_MODEL = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/saved_model/final_model" # 모델 저장 경로
trainer.save_model(DIR_SAVED_MODEL) # 모델 저장
tokenizer.save_pretrained(DIR_SAVED_MODEL) # 토크나이저 저장
코드 해설
중요한 부분들을 해설하면 아래와 같다.
1. 데이터 불러오기
- DIR_TRAIN 변수는 학습에 사용할 엔비디아 댓글들이 담긴 csv 파일의 경로이다.
- 엔비디아 댓글들의 정보를 데이터프레임 df 에 저장한다.
- 이때, 나는 50개 또는 62개의 댓글에 대해 직접 부정, 중립, 긍정 라벨링을 했고, 이를 평가 기준으로 삼았다.
2. 모델, 토크나이저 지정
- 위의 코드는 BERT모델인 경우의 코드다.
- 다른 모델들을 보고 싶다면 허깅 페이스에서 찾아보자. FinancialBERT 모델 링크도 첨부할 테니 참고하자.
3. 데이터셋 나누기
- train_test_split 을 사용해서 학습에 사용할 데이터, 평가할 데이터를 나눈다.
- 나의 경우엔 전체 데이터의 20%를 평가에 사용했다.
4. 하이퍼 파라미터 설정
- TrainingArguments 를 이용해 하이퍼 파라미터를 설정한다.
- 평가 주기, 훈련 epoch 수 등을 조정할 수 있다.
- 나의 경우엔 프로젝트 기간이 촉박하여 epoch 수, 데이터셋의 수만 조정하여 최적 모델을 선정했다.
5. 학습, 정확도 계산 함수
- 정확도를 기준으로 베스트 모델을 선정하기 위해 compute_metrics 함수를 만든다.
- trainer : 허깅 페이스 Trainer 설명 참고
6. 최적 모델 저장
- DIR_SAVED_MODEL : 정확도가 가장 높은 모델을 저장할 경로
- 최적 모델과 토크나이저를 저장한다.
코드 - 감성 분석 결과 확인
from transformers import BertTokenizer, BertForSequenceClassification
from torch.utils.data import Dataset
from sklearn.model_selection import train_test_split
import torch
import pandas as pd
# 1. 저장된 모델 불러오기
# 모델 저장 경로
DIR_SAVED_MODEL = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/saved_model/final_model"
model = BertForSequenceClassification.from_pretrained(DIR_SAVED_MODEL) # 모델 불러오기
tokenizer = BertTokenizer.from_pretrained(DIR_SAVED_MODEL) # 토크나이저
model.eval() # 평가용으로 전환
# 다른 종목 텍스트 자료
DIR_TEST_NVDA = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/데이터1_Finetuning용데이터_엔비디아댓글들.csv"
DIR_TEST_TSLA = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/데이터2_Finetuning용데이터_테슬라댓글들_라벨링.csv"
df_nvda = pd.read_csv(DIR_TEST_NVDA, encoding="latin1") # 엔비디아 채점 데이터 불러오기
df_tsla = pd.read_csv(DIR_TEST_TSLA, encoding="latin1") # 테슬라 채점 데이터 불러오기
# 2. 채점 (전체 데이터를 테스트로 사용)
# 엔비디아
texts_nvda = df_nvda["body"].tolist()
true_labels_nvda = df_nvda["label"].tolist()
# 테슬라
texts_tsla = df_tsla["body"].tolist()
true_labels_tsla = df_tsla["label"].tolist()
# 배치 처리 없이 한 번에 추론 (데이터가 적다고 가정)
# 엔비디아
inputs_nvda = tokenizer(
texts_nvda, return_tensors="pt", padding=True, truncation=True, max_length=100
)
# 테슬라
inputs_tsla = tokenizer(
texts_tsla, return_tensors="pt", padding=True, truncation=True, max_length=100
)
# 3. 추론
with torch.no_grad():
outputs_nvda = model(**inputs_nvda)
outputs_tsla = model(**inputs_tsla)
# 예측값 추출
# 엔비디아
preds_nvda = torch.argmax(outputs_nvda.logits, dim=1).tolist()
# 테슬라
preds_tsla = torch.argmax(outputs_tsla.logits, dim=1).tolist()
# 4. 결과 저장
# 엔비디아 데이터프레임
df_result_nvda = pd.DataFrame(
{"comment": texts_nvda, "label": true_labels_nvda, "predicted_label": preds_nvda}
)
# 테슬라 데이터프레임
df_result_tsla = pd.DataFrame(
{"comment": texts_tsla, "label": true_labels_tsla, "predicted_label": preds_tsla}
)
# 결과 출력 및 저장
# 엔비디아
print(df_result_nvda) # 디버깅용
DIR_CHECK_NVDA = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/채점 결과/check_result_nvda.csv"
df_result_nvda.to_csv(DIR_CHECK_NVDA)
# 테슬라
print(df_result_tsla) # 디버깅용
DIR_CHECK_TSLA = "C:/Users/LG/Desktop/바탕화면/학습/컴퓨터 프로그래밍/파이썬/Generative AI/채점 결과/check_result_tsla.csv"
df_result_tsla.to_csv(DIR_CHECK_TSLA)
- 프로젝트에서 베스트 오브 베스트 모델을 선정하기 위해, 각 모델들의 정확도를 비교해야 했다.
- 이를 위해 학습에 사용한 엔비디아 댓글들로 첫 번째 채점했고, 두 번째로는 테슬라 댓글들로 채점했다.
- 나는 BERT, FinancialBERT 2개 모델에 대해 epoch 수와 데이터셋 수를 조정하여 채점했고, 결과는 아래와 같다.
- 최고 정확도가 60%도 넘지 못하는데, 이는 댓글이 이미지거나 은유를 사용하는 경우 모델이 쉽게 판별할 수 없기 때문이다.
(더 무겁고 좋은 모델을 찾아봐야 할 것 같다.)
마치며
다음에는 레딧 댓글을 수집한 뒤 최적 모델을 사용해 감성 분석하는 챗봇을 Streamlit을 통해 구현하는 코드에 대해 살펴보자.
참고 자료
1. 허깅 페이스 : https://huggingface.co/
Hugging Face – The AI community building the future.
The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the foundation of ML tooling with the community.
huggingface.co
2. train_test_split 공식 문서 : https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
train_test_split
Gallery examples: Release Highlights for scikit-learn 1.5 Release Highlights for scikit-learn 1.4 Release Highlights for scikit-learn 0.24 Release Highlights for scikit-learn 0.23 Release Highlight...
scikit-learn.org
3. numpy.argmax 공식 문서 : https://numpy.org/doc/2.2/reference/generated/numpy.argmax.html
numpy.argmax — NumPy v2.2 Manual
If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the array.
numpy.org
4. torch.argmax 공식 문서 : https://docs.pytorch.org/docs/stable/generated/torch.argmax.html
torch.argmax — PyTorch 2.7 documentation
Shortcuts
docs.pytorch.org
5. accuracy_score 공식 문서 : https://scikit-learn.org/stable/modules/generated/sklearn.metrics.accuracy_score.html
accuracy_score
Gallery examples: Plot classification probability Multi-class AdaBoosted Decision Trees Probabilistic predictions with Gaussian process classification (GPC) Demonstration of multi-metric evaluation...
scikit-learn.org
6. 허깅 페이스 Trainer 설명 : https://huggingface.co/docs/transformers/ko/main_classes/trainer
Trainer
If you pass a dictionary with names of datasets as keys and datasets as values, evaluate will run separate evaluations on each dataset. This can be useful to monitor how training affects other datasets or simply to get a more fine-grained evaluation. When
huggingface.co
7. Trainer 사용법 글 : https://bo-10000.tistory.com/154
[HuggingFace] Trainer 사용법
Official Docs: https://huggingface.co/docs/transformers/v4.19.2/en/main_classes/trainer Trainer When using gradient accumulation, one step is counted as one step with backward pass. Therefore, logging, evaluation, save will be conducted every gradient_accu
bo-10000.tistory.com
'컴퓨터 프로그래밍' 카테고리의 다른 글
생성형 AI 프로젝트 3단계 - 챗봇 UI 만들기 (Streamlit) (0) | 2025.05.26 |
---|---|
생성형 AI 프로젝트 - 1단계. PRAW로 레딧 댓글 스크랩하기 (2) | 2025.05.24 |
파이썬 동적 변수 할당 방법 3가지 - globals(), 딕셔너리, setattr() (0) | 2025.05.19 |
트랜스포머(Transformer) 구조, 흐름 정리 (0) | 2025.05.13 |
파이썬 - np.where 개념, 예시 코드, 활용 (1) | 2025.05.01 |