네이버 영화 리뷰 감정 분석 데이터세트로 분류 모델을 학습
#데이터 불러오기
import numpy as np
import pandas as pd
from Korpora import Korpora
# Korpora 라이브러리를 사용하여 네이버 영화 리뷰 데이터셋을 불러오기
corpus = Korpora.load("nsmc")
# 테스트 데이터셋에서 샘플을 랜덤하게 선택하고 20000개의 샘플을 추출한 후 데이터프레임으로 변환
df = pd.DataFrame(corpus.test).sample(20000, random_state=42)
# 전체 데이터셋을 훈련, 검증, 테스트 세트로 나눔
train, valid, test = np.split(
df.sample(frac=1, random_state=42), [int(0.6 * len(df)), int(0.8 * len(df))]
)
# 훈련, 검증, 테스트 세트의 크기 출력
print(train.head(5).to_markdown())
print(f"Training Data Size : {len(train)}")
print(f"Validation Data Size : {len(valid)}")
print(f"Testing Data Size : {len(test)}")
# 전처리된 데이터를 Electra 모델에 적합한 형식으로 변환하는 함수 정의
def make_dataset(data, tokenizer, device):
# 입력 텍스트를 토큰화하고 텐서로 변환
tokenized = tokenizer(
text=data.text.tolist(),
padding="longest",
truncation=True,
return_tensors="pt"
)
# 토큰화된 입력 데이터와 라벨을 텐서 데이터셋으로 변환하여 반환
input_ids = tokenized["input_ids"].to(device)
attention_mask = tokenized["attention_mask"].to(device)
labels = torch.tensor(data.label.values, dtype=torch.long).to(device)
return TensorDataset(input_ids, attention_mask, labels)
# 데이터로더 생성 함수 정의
def get_datalodader(dataset, sampler, batch_size):
data_sampler = sampler(dataset)
dataloader = DataLoader(dataset, sampler=data_sampler, batch_size=batch_size)
return dataloader
# 하이퍼파라미터 설정
epochs = 5
batch_size = 32
device = "cuda" if torch.cuda.is_available() else "cpu"
# Electra 토크나이저 로드
tokenizer = ElectraTokenizer.from_pretrained(
pretrained_model_name_or_path="monologg/koelectra-base-v3-discriminator",
do_lower_case=False,
)
# 훈련 데이터셋 전처리 및 데이터로더 생성
train_dataset = make_dataset(train, tokenizer, device)
train_dataloader = get_datalodader(train_dataset, RandomSampler, batch_size)
# 검증 데이터셋 전처리 및 데이터로더 생성
valid_dataset = make_dataset(valid, tokenizer, device)
valid_dataloader = get_datalodader(valid_dataset, SequentialSampler, batch_size)
# 테스트 데이터셋 전처리 및 데이터로더 생성
test_dataset = make_dataset(test, tokenizer, device)
test_dataloader = get_datalodader(test_dataset, SequentialSampler, batch_size)
# 훈련 데이터셋의 첫 번째 샘플 출력 (입력 텐서, 어텐션 마스크, 라벨)
print(train_dataset[0])
#KoELECTRA 모델 선언
from torch import optim
from transformers import ElectraForSequenceClassification
# KoELECTRA 모델 선언
model = ElectraForSequenceClassification.from_pretrained(
pretrained_model_name_or_path="monologg/koelectra-base-v3-discriminator", # 사전 학습된 KoELECTRA 모델 로드
num_labels=2 # 분류할 클래스 수 설정 (긍정, 부정)
).to(device) # 모델을 GPU 또는 CPU로 이동
# 옵티마이저 설정 (AdamW 사용)
optimizer = optim.AdamW(
model.parameters(), # 모델의 파라미터를 최적화 대상으로 지정
lr=1e-5, # 학습률 설정
eps=1e-8 # AdamW 옵티마이저의 epsilon 값 설정
)
#모델 구조 출력
for main_name, main_module in model.named_children():
print(main_name)
for sub_name, sub_module in main_module.named_children():
print("└", sub_name)
for ssub_name, ssub_module in sub_module.named_children():
print("│ └", ssub_name)
for sssub_name, sssub_module in ssub_module.named_children():
print("│ │ └", sssub_name)
#학습
import numpy as np
from torch import nn
# 정확도 계산 함수 정의
def calc_accuracy(preds, labels):
pred_flat = np.argmax(preds, axis=1).flatten()
labels_flat = labels.flatten()
return np.sum(pred_flat == labels_flat) / len(labels_flat)
# 모델 훈련 함수 정의
def train(model, optimizer, dataloader):
model.train()
train_loss = 0.0
for input_ids, attention_mask, labels in dataloader:
outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
train_loss += loss.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss = train_loss / len(dataloader)
return train_loss
# 모델 평가 함수 정의
def evaluation(model, dataloader):
with torch.no_grad():
model.eval()
criterion = nn.CrossEntropyLoss()
val_loss, val_accuracy = 0.0, 0.0
for input_ids, attention_mask, labels in dataloader:
outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
logits = outputs.logits
loss = criterion(logits, labels)
logits = logits.detach().cpu().numpy()
label_ids = labels.to("cpu").numpy()
accuracy = calc_accuracy(logits, label_ids)
val_loss += loss
val_accuracy += accuracy
val_loss = val_loss/len(dataloader)
val_accuracy = val_accuracy/len(dataloader)
return val_loss, val_accuracy
# 최적의 검증 손실 기록 및 모델 저장
best_loss = 10000
for epoch in range(epochs):
train_loss = train(model, optimizer, train_dataloader)
val_loss, val_accuracy = evaluation(model, valid_dataloader)
print(f"Epoch {epoch + 1}: Train Loss: {train_loss:.4f} Val Loss: {val_loss:.4f} Val Accuracy {val_accuracy:.4f}")
if val_loss < best_loss:
best_loss = val_loss
torch.save(model.state_dict(), "../models/ElectraForSequenceClassification.pt")
print("Saved the model weights")
# 저장된 모델 가중치 로드 및 테스트 데이터셋 평가
model = ElectraForSequenceClassification.from_pretrained(
pretrained_model_name_or_path="monologg/koelectra-base-v3-discriminator",
num_labels=2
).to(device)
model.load_state_dict(torch.load("../models/ElectraForSequenceClassification.pt"))
test_loss, test_accuracy = evaluation(model, test_dataloader)
print(f"Test Loss : {test_loss:.4f}")
print(f"Test Accuracy : {test_accuracy:.4f}")