본문 바로가기

스타트업 투자/데이터 + 테크

패스트캠퍼스 환급챌린지 21일차 : 데이터셋 준비, 파인튜닝

by Sungwook Choi 2025. 4. 21.

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

*_1. 학습 인증샷 4장 이상 포함
*_① 오늘자 날짜, 공부 시작 시각 포함 사진 1장

② 오늘자 날짜, 공부 종료 시각 포함 사진 1장

③ 1개 클립 수강 인증 사진 (강의장 목록 캡쳐, 강의 내용이 담긴 수강화면이 보이지 않도록) 1장

④ 학습 인증샷 1장 이상 (ex. 필기 촬영, 작업물, 등)

2. 학습 후기 700자 이상 (공백 제외)

  • PDF를 문서데이터(페이지별로) 로 청크
  • 각 페이지에 질문 2개씩 생성 (오픈api사용)
    • 텍스트 본문 (queryies) 과 질문 (positive docs)의 쌍
  • 센텐스 트랜스포머로 이 (질문, 본문)쌍을 넣어서 파인튜닝
  • MultipleNegativesRankingLoss는 유사도를 높이고 싶은 문장의 쌍들의 데이터를 준비했을 경우 학습에 사용할 수 있는 함수
    • 유사 문장 쌍들
    • (질의어, 응답) 쌍들
    • (번역하고자 하는 언어, 번역된 언어) 쌍들

예시코드

  1. PDF 파일 로드
    for url in urls:
    filename = url.split("/")[-1]
    response = requests.get(url)
    with open(filename, "wb") as f:
        f.write(response.content)
    print(f"{filename} 다운로드 완료")
    

2. PDF를 문서로 변환 (PyPDF2 사용)

import PyPDF2

def extract_text_from_pdf(pdf_path):
"""PDF 파일에서 텍스트를 추출하는 함수"""
text_chunks = []
with open(pdf_path, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
for page_num in range(len(pdf_reader.pages)):
page = pdf_reader.pages[page_num]
text = page.extract_text()
# 페이지 단위로 청크 생성
if text.strip():
text = text.strip()
# 문서 길이가 10자 초과인 경우만 추가
if len(text) > 10:
text_chunks.append(text)
return text_chunks

미국 ICT 동향 (학습 데이터)

train_corpus = extract_text_from_pdf('ict_usa_2024.pdf')
print(f'학습 데이터 문서 개수: {len(train_corpus)}')

일본 ICT 동향 (검증 데이터)

val_corpus = extract_text_from_pdf('ict_japan_2024.pdf')
print(f'검증 데이터 문서 개수: {len(val_corpus)}')



3. 각 문서에 대해서 질문 2개씩 생성
~~~code
# OpenAI 클라이언트 초기화
client = OpenAI()

# 3. 각 문서에 대한 질문 생성 (OpenAI API 사용)
def generate_queries(corpus, num_questions_per_chunk=2):
    all_queries = []
    all_positive_docs = []

    # 기본 프롬프트 템플릿 설정
    prompt_template = """\
    다음은 참고할 내용입니다.

    ---------------------
    {context_str}
    ---------------------

    위 내용을 바탕으로 낼 수 있는 질문을 {num_questions_per_chunk}개 만들어주세요.
    질문만 작성하고 실제 정답이나 보기 등은 작성하지 않습니다.

    해당 질문은 본문을 볼 수 없다고 가정합니다.
    따라서 '위 본문을 바탕으로~' 라는 식의 질문은 할 수 없습니다.

    질문은 아래와 같은 형식으로 번호를 나열하여 생성하십시오.

    1. (질문)
    2. (질문)
    """

    # corpus의 각 문서에 대해 반복 실행
    for text in tqdm(corpus):
        # 현재 문서에 대한 프롬프트 생성
        messages = [
            {"role": "system", "content": "You are a helpful assistant that generates questions based on provided content."},
            {"role": "user", "content": prompt_template.format(
                context_str=text,
                num_questions_per_chunk=num_questions_per_chunk
            )}
        ]

        # GPT 모델을 사용해 질문 생성
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            temperature=0.7,
        )

        # 응답을 줄바꿈을 기준으로 분리하여 개별 질문으로 만듦
        result = response.choices[0].message.content.strip().split("\n")

        # 질문 형식 정리
        questions = []
        for line in result:
            if line.strip():
                parts = line.strip().split('. ', 1)
                if len(parts) > 1:
                    questions.append(parts[1])
                else:
                    questions.append(parts[0])

        # 빈 질문 제거
        questions = [q for q in questions if len(q) > 0]

        # 각 질문에 대해 문서 매칭 및 저장
        for question in questions:
            all_queries.append(question)
            all_positive_docs.append(text)

    return all_queries, all_positive_docs

# 학습 데이터 질문 생성
train_queries, train_positive_docs = generate_queries(train_corpus)
print(f'생성된 학습용 질문 개수: {len(train_queries)}')

# 검증 데이터 질문 생성
val_queries, val_positive_docs = generate_queries(val_corpus)
print(f'생성된 검증용 질문 개수: {len(val_queries)}')

# 4. 학습 데이터 준비
train_examples = []
for query, doc in zip(train_queries, train_positive_docs):
    example = InputExample(texts=[query, doc])
    train_examples.append(example)
  1. 센텐스 트랜스포머 학습형식으로 변환
    # 5. 데이터 로더 생성
    # 현재 Colab GPU의 한계로 매우 작은 배치 크기인 5를 선택했습니다.
    # 일반적으로는 배치 크기가 클수록 성능이 좋습니다.
    BATCH_SIZE = 4  # 배치 크기 조정
    loader = DataLoader(train_examples, batch_size=BATCH_SIZE, shuffle=True)
    

6. 모델 및 손실 함수 설정

model_id = "BAAI/bge-m3"
model = SentenceTransformer(model_id)

손실 함수 정의: 모델이 검색어와 포지티브 문서는 가깝게, 네거티브 문서는 멀게 학습하도록 유도

loss = losses.MultipleNegativesRankingLoss(model)

~

url : https://abit.ly/lisbva

댓글