본문 바로가기
프로젝트

[프로젝트] 데이콘 주관 도배하자 질의응답 처리 언어모델 개발 공모전 리뷰

by 단깅수 2024. 2. 26.
728x90

이번에 학회 프로젝트로 데이콘에서 주관하는 도배하자 질의응답 처리 언어모델 개발 공모전에 참여하였다.

프로젝트 발표는 끝났지만 아직 대회 종료일이 남아, 대회 종료일까지는 열심히 달릴 생각을 하고 있다.

 

1. 공모전 소개

관련 : 알고리즘 / 언어 / LLM / MLOps / QA / Cosine Simiarity

주제 : 도배 하자 질의 응답 AI 모델 개발

주 : 한솔데코 AI

상금 : 1000만 원

기간 : 2024.01.29 ~ 2024.03.11

배경 : 한솔데코는 인공지능(AI) 기술을 공동 주택 내 실내 마감재 분야에 접목시켜 혁신을 추진하고 있습니다. AI의 활용은 시트, 마루, 벽면, 도배와 같은 건축의 핵심 자재들의 품질 관리와 하자 판단 과정을 더욱 정교하고 효율적으로 만들어, 이러한 자재들의 관리 및 운용의 질을 향상시키는 데 중점을 두고 있습니다. 이러한 기술적 통합은 고객 만족도를 높이는 동시에, 제품과 서비스의 전반적인 품질 향상에 기여하게 됩니다.


2. 데이터 소개

  • train.csv
    • id : 질문 - 답변 (QA) 샘플 고유 번호
    • 질문_1, 질문_2 : 샘플 별 동일한 내용으로 구성된 질문 2개
    • category : 질문 - 답변 (QA) 샘플의 도메인 세부 분야
    • 답변_1, 답변_2, 답변_3, 답변_4, 답변_5 : 샘플 별 질문에 대한 동일한 답변 Reference 5개
  • test.csv
    • id : 평가 질문 샘플 고유 번호
    • 질문 : 평가 샘플의 질의 내용
  • sample_submission.csv
    • id : 평가 질문 샘플 고유 번호
    • vec_0, vec_1 ... vec_511 : 생성된 답변을 512 차원의 Embedding Vector로 표현된 결과

3. 코드 리뷰

3-1. Import

  • 개발에 필요한 판다스 패키지 및 파이토치 패키지, 아담 패키지 등을 임포트
  • 캐글 노트북 상에서 무료 gpu 사용 (Cuda)
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}")

3-2. Data Preprocessing

  • 데이터 로드
  • baseline에서 제공하는 토크나이저 로드
  • 데이터를 질문과 답변 한 쌍으로 토큰화 진행 후 임베딩
# 데이터 로드
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.')

3-3. Model Fine-tuning

  • skt에서 제공하는 kogpt2-base-v2라는 모델 사용
  • 학습 에포크 20번으로 과적합 날 수 있지만 최대한 성능 올리는데 주력
  • 모델 학습 및 저장
# 모델 로드
model = GPT2LMHeadModel.from_pretrained('skt/kogpt2-base-v2')
model.to(device) # 모델을 GPU단으로 이동

# 모델 학습 하이퍼파라미터(Hyperparameter) 세팅
# 실제 필요에 따라 조정하세요.
CFG = {
    'LR' : 2e-5, # Learning Rate
    'EPOCHS' : 20, # 학습 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")

3-4. Model Inference

  • 저장된 모델과 토크나이저를 불러와 test 파일에 적용
  • 답변 생성 및 저장
# 저장된 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)

3-5. 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)

 

오늘은 현재 진행하고 있는 도배하자 질의응답 처리 언어모델 개발 공모전에 대한 리뷰를 적었습니다.

아직 공모전이 종료되지 않아 baseline 을 참고해 적었는데요.

공모전 기간이 끝나면 제대로 다시 한 번 리뷰할 계획입니다.

728x90