Dacon 도배 하자 질의 응답 처리 경진대회 (2) 임베딩 모델 및 베이스라인 코드

2024. 2. 19. 18:53DL Life

1. Embedding Vector 추출 모델 ?

AI 동계 강좌를 듣고 온 사이 몇개의 코드 공유 글이 더 올라와서 해당 코드들을 참고해보려고 한다

import numpy as np  from sentence_transformers import SentenceTransformer   # SentenceTransformer Version 2.2.2 # Embedding Vector 추출에 활용할 모델(distiluse-base-multilingual-cased-v1) 불러오기   model = SentenceTransformer('distiluse-base-multilingual-cased-v1') 

Distiluse-base-mulitlingual-cased-v1 모델도 잘 몰라서 찾아보니 (Reference #1)
각 단어의 임베딩 벡터를 만드는 모델이였다. 평가할 때, Cosine similarity 를 활용하기 때문에 사용하는 모델

역시 가장 먼저 파악하는게 필요하다고 생각한 건
→ Baseline 모델 + 점수 평가 코드 : 주어진 코드를 다시 살펴보자!

Import Part

import pandas as pd import numpy as np import torch from transformers import GPT2LMHeadModel, PreTrainedTokenizerFast, AdamW from tqdm import tqdm  # CUDA 사용 가능 여부 확인 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Using device: {device}") 

Data Preprocessing

# 데이터 로드 data = pd.read_csv('train.csv')  # 토크나이저 로드 tokenizer = PreTrainedTokenizerFast.from_pretrained('skt/kogpt2-base-v2', eos_token='</s>')  # 데이터 포맷팅 및 토크나이징 formatted_data = [] for _, row in tqdm(data.iterrows()):     for q_col in ['질문_1', '질문_2']:         for a_col in ['답변_1', '답변_2', '답변_3', '답변_4', '답변_5']:             # 질문과 답변 쌍을 </s> token으로 연결             input_text = row[q_col] + tokenizer.eos_token + row[a_col]             input_ids = tokenizer.encode(input_text, return_tensors='pt')             formatted_data.append(input_ids) print('Done.') 

→ .encode 로 데이터 수치화
Formatted Data → 해당 질문과 답변을 조합해서 행마다 10개의 Q-A 쌍을 만듦
토크나이저를 통해 QA 쌍을 수치화 하고 Formatted data 에 저장

→ Kogpt 보다 좋은 모델은 뭐가 있을까?
Ko-SOLAR 사용해보기 (https://huggingface.co/yanolja/KoSOLAR-10.7B-v0.3)

Fine-tuning → KoGPT2

  1. 가장 쉬운 것부터 해보기 : 모델 더 큰 거 로 바꿔보기
# 모델 로드 model = GPT2LMHeadModel.from_pretrained('skt/kogpt2-base-v2') model.to(device) # 모델을 GPU단으로 이동  # 모델 학습 하이퍼파라미터(Hyperparameter) 세팅 # 실제 필요에 따라 조정하세요. CFG = {     'LR' : 2e-5, # Learning Rate     'EPOCHS' : 10, # 학습 Epoch }  # 모델 학습 설정 optimizer = AdamW(model.parameters(), lr=CFG['LR']) model.train()  # 모델 학습 for epoch in range(CFG['EPOCHS']):     total_loss = 0     progress_bar = tqdm(enumerate(formatted_data), total=len(formatted_data))     for batch_idx, batch in progress_bar:         # 데이터를 GPU단으로 이동         batch = batch.to(device)         outputs = model(batch, labels=batch)         loss = outputs.loss         loss.backward()         optimizer.step()         optimizer.zero_grad()          total_loss += loss.item()          # 진행률 표시줄에 평균 손실 업데이트         progress_bar.set_description(f"Epoch {epoch+1} - Avg Loss: {total_loss / (batch_idx+1):.4f}")      # 에폭의 평균 손실을 출력     print(f"Epoch {epoch+1}/{CFG['EPOCHS']}, Average Loss: {total_loss / len(formatted_data)}")  # 모델 저장 model.save_pretrained("./hansoldeco-kogpt2") tokenizer.save_pretrained("./hansoldeco-kogpt2") 

kmj00825(4245M) → 4GB 정도 사용하는데 이거 Batch size 를 어떻게 늘리지…?


1 Epoch당 4분정도 걸렸다

Model Inference

# 저장된 Fine-tuned 모델과 토크나이저 불러오기 model_dir = "./hansoldeco-kogpt2" model = GPT2LMHeadModel.from_pretrained(model_dir) model.to(device) tokenizer = PreTrainedTokenizerFast.from_pretrained(model_dir)  # Inference를 위한 test.csv 파일 로드 test = pd.read_csv('./test.csv')  # test.csv의 '질문'에 대한 '답변'을 저장할 리스트 preds = []  # '질문' 컬럼의 각 질문에 대해 답변 생성 for test_question in tqdm(test['질문']):     # 입력 텍스트를 토큰화하고 모델 입력 형태로 변환     input_ids = tokenizer.encode(test_question + tokenizer.eos_token, return_tensors='pt')      # 답변 생성     output_sequences = model.generate(         input_ids=input_ids.to(device),         max_length=300,         temperature=0.9,         top_k=1,         top_p=0.9,         repetition_penalty=1.2,         do_sample=True,         num_return_sequences=1     )      # 생성된 텍스트(답변) 저장     for generated_sequence in output_sequences:         full_text = tokenizer.decode(generated_sequence, skip_special_tokens=False)         # 질문과 답변의 사이를 나타내는 eos_token (</s>)를 찾아, 이후부터 출력         answer_start = full_text.find(tokenizer.eos_token) + len(tokenizer.eos_token)         answer_only = full_text[answer_start:].strip()         answer_only = answer_only.replace('\n', ' ')         preds.append(answer_only) 


Inference 130 개 하는데에는 5분 30초

Model Submission

# Test 데이터셋의 모든 질의에 대한 답변으로부터 512 차원의 Embedding Vector 추출 # 평가를 위한 Embedding Vector 추출에 활용하는 모델은 'distiluse-base-multilingual-cased-v1' 이므로 반드시 확인해주세요. from sentence_transformers import SentenceTransformer # SentenceTransformer Version 2.2.2  # Embedding Vector 추출에 활용할 모델(distiluse-base-multilingual-cased-v1) 불러오기 model = SentenceTransformer('distiluse-base-multilingual-cased-v1')  # 생성한 모든 응답(답변)으로부터 Embedding Vector 추출 pred_embeddings = model.encode(preds) pred_embeddings.shape  submit = pd.read_csv('./sample_submission.csv') # 제출 양식 파일(sample_submission.csv)을 활용하여 Embedding Vector로 변환한 결과를 삽입 submit.iloc[:,1:] = pred_embeddings submit.head() # 리더보드 제출을 위한 csv파일 생성 submit.to_csv('./baseline_submit.csv', index=False) 


제출해본 결과 이정도 성능

일단 Ko-SOLAR 모델을 그냥 올려봤더니 메모리가 터졌다. 80기가를 통으로 쓰지 못해서 혹시나 올려봤는데 역시나였다

OutOfMemoryError: CUDA out of memory. Tried to allocate 64.00 MiB (GPU 0; 79.35 GiB total capacity; 45.82 GiB already allocated; 30.19 MiB free; 45.90 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF 

64GB 이상은 할당 해줘야하는 것 같다
GPU 2개로 나눠서 올려서 시도해봐야할 것 같고, 서버 바꿔서 해봐야겠다.
일단 모델만 바꿔서 성능 측정해보고 아이디어 하나씩 추가해보는 쪽으로 해야겠다

Prompt tuning 쪽 이야기도 있던데 해당 내용도 살펴보고 진행해야할 듯하다


Reference

#1 https://0goodmorning.tistory.com/61
#2 https://dacon.io/competitions/official/236216/codeshare
#3 https://huggingface.co/yanolja/KoSOLAR-10.7B-v0.3

Link


“이 글은 Obsidian 에서 작성되어 업로드 되었습니다”