📝 개요
이 글에서는 제품 설명 텍스트만을 입력받아
가격을 예측하는 Fine-tuned GPT-4o-mini 모델을 구축하는 과정을 다룹니다.
데이터 준비부터 모델 파인튜닝,
완성된 모델 테스트까지 전 과정을 코드와 함께 실습하며,
Weights & Biases를 이용한 학습 모니터링과 모델 성능 평가 방법도 소개합니다.
주요 목표:
- 제품 설명을 기반으로 가격을 추론하는 맞춤형 GPT 모델 만들기
- OpenAI Fine-tuning API 실습
- 학습 진행 상황을 Weights & Biases로 실시간 추적
- Fine-tuned 모델을 활용해 테스트 및 성능 평가하기
🎨 Weights & Biases(W&B) 연동 준비
Weights and Biases(W&B)는 학습 과정을 모니터링할 수 있는 무료인 플랫폼입니다.
OpenAI 파인튜닝과도 공식적으로 통합되어 있습니다.
✨ W&B 계정 설정 방법
- Weights & Biases 무료 계정 생성하기
👉https://wandb.ai - API Key 발급받기
- 사이트에 로그인한 뒤
- Avatar(프로필) → Settings → API Key 생성 메뉴로 이동합니다.
- OpenAI 대시보드에서 통합 설정하기
👉 https://platform.openai.com/account/organization- 대시보드의 Integrations 섹션에서
- 방금 생성한 Weights & Biases API Key를 추가합니다.
🎯 Weights & Biases(W&B) 연동 설정 (Set Up Weights & Biases Integration)
파인튜닝 진행 상황을 Weights & Biases 프로젝트에 기록하기 위한 연동 설정을 만듭니다.
# 🎯 W&B 연동 설정을 위한 딕셔너리 생성
wandb_integration = {
"type": "wandb", # 통합 유형(type)을 "wandb"로 설정
"wandb": {
"project": "gpt-pricer" # W&B에서 기록할 프로젝트 이름 지정
}
}
✨ 설명
type: "wandb"
: 통합하려는 대상이 Weights & Biases임을 명시합니다.wandb.project
: W&B 대시보드에 기록할 프로젝트 이름을 지정합니다.(이 예제에서는"gpt-pricer"
라는 이름의 프로젝트로 기록됩니다.)- 이 설정을 나중에 fine-tuning 요청 시 추가 파라미터로 넘기면 됩니다.
🔔 참고
- 프로젝트 이름
"gpt-pricer"
는 자유롭게 바꿀 수 있습니다. (예:"product-price-tuner"
) - 만약 OpenAI 대시보드에 API Key 연동을 안 해두었다면, 이 통합은 작동하지 않습니다.
🆔 업로드된 학습 파일의 ID (Training File ID)
train_file 객체에서 업로드된 학습 파일의 고유 ID를 가져옵니다.
# 🆔 학습 데이터 파일의 고유 ID 가져오기
train_file.id
# - OpenAI에 업로드한 fine_tune_train.jsonl 파일의 고유 식별자(ID)
# - 이 ID는 파인튜닝 작업을 시작할 때 training_file 파라미터로 필요함
✨ 설명
train_file
은openai.files.create()
를 통해 서버에 업로드된 파일 객체입니다.train_file.id
는 해당 파일을 OpenAI 시스템 내부에서 식별하는 고유 ID입니다.- 이 ID를 이용해 나중에 fine-tuning 요청을 할 때 어떤 파일을 학습 데이터로 쓸지 지정할 수 있습니다.
📋 예시
만약 train_file.id
를 출력하면 이런 값이 나올 수 있습니다:
file-abc123xyz456
🔔 참고
- 파일 ID는 업로드할 때마다 새로 생성됩니다.
- 만약 파일을 새로 수정해서 다시 업로드하면 ID도 새로 바뀌므로, 그때마다 새로운 ID를 써야 합니다!
🚀 Fine-tuning Job 시작 (Start Fine-tuning Job)
업로드한 학습 데이터와 검증 데이터를 사용해 OpenAI에서 파인튜닝을 시작합니다.
# 🚀 파인튜닝 작업 생성 (Fine-tuning Job Start)
openai.fine_tuning.jobs.create(
training_file=train_file.id, # 학습 데이터 파일 ID
validation_file=validation_file.id, # 검증 데이터 파일 ID
model="gpt-4o-mini-2024-07-18", # 베이스 모델 (GPT-4o mini 버전, 2024-07-18 기준)
seed=42, # 랜덤 시드를 고정하여 재현 가능한 결과 생성
hyperparameters={"n_epochs": 1}, # 학습 반복 횟수(epoch) 설정 (1회만)
integrations=[wandb_integration], # Weights & Biases 연동 설정
suffix="pricer" # 파인튜닝된 모델 이름에 붙일 접미사 설정
)
📋 결과
이 명령이 실행되면 OpenAI 서버에서 fine-tuning 작업이 시작됩니다.
이후 작업 진행 상황은:
- OpenAI 대시보드
- Weights & Biases 대시보드(연동한 경우)에서 실시간으로 확인할 수 있습니다.
🔔 참고
suffix
를 붙이면, 나중에 생성된 모델 이름이 명확하게 구분됩니다.seed
를 고정하면, 같은 데이터/설정으로 다시 학습했을 때 결과가 거의 일관되게 나옵니다.- epoch 수를 늘리고 싶으면
n_epochs
값을 조정하면 됩니다. (예:{"n_epochs": 3}
)
📋 최근 Fine-tuning Job 조회 (List Recent Fine-tuning Jobs)
가장 최근에 실행된 파인튜닝 작업 정보를 가져옵니다.
# 📋 최근 생성된 파인튜닝 작업 1개 조회
openai.fine_tuning.jobs.list(limit=1)
# 📝 작동 과정:
# - 서버에 등록된 Fine-tuning 작업 중
# - 가장 최근(recent) 1개만 가져옵니다.
✨ 설명
openai.fine_tuning.jobs.list()
는 파인튜닝 작업 목록을 불러오는 함수입니다.limit=1
을 지정하면 가장 최근 작업 하나만 가져옵니다.- 반환되는 결과에는 다음과 같은 정보가 포함됩니다:
- 작업 ID (job ID)
- 사용한 베이스 모델
- 파인튜닝된 모델 ID (완료 시)
- 현재 상태(status: running / succeeded / failed)
- 시작 시간, 종료 시간 등 메타데이터
📋 예시 출력
(실제로 실행하면 이런 형태의 JSON 데이터가 나옵니다)
{
"data": [
{
"id": "ftjob-xyz123abc456",
"object": "fine_tuning.job",
"model": "gpt-4o-mini-2024-07-18",
"fine_tuned_model": "ft:gpt-4o-mini-2024-07-18:pricer:abcde12345",
"status": "succeeded",
"created_at": 1710002000,
"finished_at": 1710004000
}
]
}
🔔 참고
- 상태(
status
)가"succeeded"
이면 파인튜닝이 정상적으로 완료된 것입니다. - 완료된 모델 ID(
fine_tuned_model
)를 복사해 바로 사용할 수 있습니다. - 만약 여러 작업을 관리해야 할 경우,
limit
을 늘리거나openai.fine_tuning.jobs.list()
전체 목록을 가져올 수도 있습니다.
🆔 가장 최근 파인튜닝 작업의 ID 가져오기 (Get Most Recent Fine-tuning Job ID)
가장 최근 실행된 파인튜닝 작업의 ID를 가져와 job_id
변수에 저장합니다.
# 🆔 가장 최근 Fine-tuning 작업의 ID 추출
job_id = openai.fine_tuning.jobs.list(limit=1).data[0].id
# 📝 작동 과정:
# - fine_tuning.jobs.list(limit=1)로 최근 파인튜닝 작업 1개를 가져옴
# - data 리스트에서 첫 번째 작업 선택
# - 선택된 작업의 id 필드를 추출해 job_id 변수에 저장
✨ 설명
openai.fine_tuning.jobs.list(limit=1)
: 최근 생성된 Fine-tuning Job 1개를 조회합니다..data[0]
: 가져온 작업 목록(리스트) 중 첫 번째 작업을 선택합니다..id
: 선택된 작업 객체의 고유 ID를 추출합니다.job_id
: 이 ID를 나중에 작업 상태 확인이나 세부정보 조회할 때 사용합니다.
🔔 참고
- 파인튜닝 작업이 여러 개 있는 경우, limit=1로 가장 최근 작업만 가져온 것입니다.
- 만약 특정 조건(예: 특정 suffix)으로 필터링하고 싶다면 추가적인 코드가 필요합니다.
🆔 저장된 파인튜닝 작업 ID (Stored Fine-tuning Job ID)
가장 최근 실행된 Fine-tuning 작업의 고유 ID를 job_id
변수에 저장한 상태입니다.
# 🆔 최근 생성된 Fine-tuning 작업의 ID
job_id
# - openai.fine_tuning.jobs.list(limit=1).data[0].id 로 가져온 값
# - 이 ID를 이용해 해당 파인튜닝 작업의 상태 조회, 결과 확인 등을 할 수 있음
✨ 설명
job_id
는 가장 최근에 생성된 Fine-tuning 작업의 고유 식별자입니다.- 이 ID를 이용하면 다음과 같은 작업을 할 수 있습니다:
- 파인튜닝 작업 상태 확인 (
running
,succeeded
,failed
등) - 파인튜닝이 완료된 후 생성된 모델 ID 확인
- 파인튜닝 작업 세부정보 조회 (시작 시간, 종료 시간, 에포크 수 등)
- 파인튜닝 작업 상태 확인 (
📋 예시
예를 들어 job_id
를 출력하면 다음과 같은 형태일 수 있습니다:
ftjob-xyz789abc456
이 값을 사용해 세부정보를 조회하거나, fine_tuned_model
이름을 얻어 바로 inference(추론) 요청에 활용할 수 있습니다.
🔔 참고
job_id
는 특정 Fine-tuning 작업을 정확히 추적할 수 있게 해주는 매우 중요한 정보입니다.
특히 fine-tuned 모델 이름을 찾거나, 에러가 발생했을 때 로그를 확인할 때 반드시 필요합니다.
🔍 Fine-tuning 작업 상태 확인 및 모델 ID 추출 (fine_tuned_model_name)
특정 Fine-tuning 작업의 세부 정보 조회
job_id
를 이용해 특정 파인튜닝 작업의 상태와 세부 정보를 조회합니다.
# 🔍 특정 Fine-tuning 작업의 세부 정보 조회
openai.fine_tuning.jobs.retrieve(job_id)
# 📝 작동 과정:
# - 지정한 job_id에 해당하는 Fine-tuning 작업을 가져옵니다.
# - 작업의 현재 상태(status), 결과 모델 ID(fine_tuned_model) 등 다양한 정보를 포함합니다.
✨ 설명
job_id
로 특정 파인튜닝 작업을 직접 조회할 수 있습니다.- 반환되는 결과에는 다음과 같은 정보가 포함됩니다:
- id: 작업 고유 ID
- model: 베이스로 사용된 원본 모델 (ex: gpt-4o-mini-2024-07-18)
- status: 현재 작업 상태 (
running
,succeeded
,failed
등) - fine_tuned_model: 파인튜닝 완료 시 생성된 새 모델 ID
- created_at / finished_at: 작업 시작 및 종료 시각
- hyperparameters: 학습 시 설정한 하이퍼파라미터
- training_file / validation_file: 사용된 파일 ID
- error: 실패했을 경우 에러 내용
📋 예시 출력
(정상적으로 완료된 경우)
{
"id": "ftjob-xyz789abc456",
"object": "fine_tuning.job",
"model": "gpt-4o-mini-2024-07-18",
"fine_tuned_model": "ft:gpt-4o-mini-2024-07-18:pricer:abcde12345",
"status": "succeeded",
"created_at": 1710002000,
"finished_at": 1710004000,
"hyperparameters": {
"n_epochs": 1
},
"training_file": "file-abc123xyz456",
"validation_file": "file-xyz789abc123",
"error": null
}
🔔 참고
- status가
"succeeded"
이면 파인튜닝이 정상 완료된 것입니다. - fine_tuned_model 항목이 생성되면,
이 모델 ID를 가지고 직접 inference(추론 요청)를 할 수 있습니다. - 만약 에러가 발생했다면 error 항목에 상세 원인이 담겨 있습니다.
📜 Fine-tuning 작업 이벤트 로그 조회 (List Fine-tuning Job Events)
지정한 job_id
에 대해 최근 발생한 이벤트 10개를 가져옵니다.
# 📜 특정 Fine-tuning 작업의 최근 이벤트 10개 조회
openai.fine_tuning.jobs.list_events(fine_tuning_job_id=job_id, limit=10).data
# 📝 작동 과정:
# - fine_tuning_job_id=job_id로 특정 작업을 지정합니다.
# - limit=10으로 최근 발생한 이벤트 10개만 가져옵니다.
# - 반환된 결과는 이벤트 객체들의 리스트입니다.
✨ 설명
openai.fine_tuning.jobs.list_events(...)
는
특정 Fine-tuning 작업에서 발생한 진행 이벤트(로그)를 가져오는 함수입니다.- 이벤트에는 다음과 같은 내용이 포함될 수 있습니다:
- 학습 시작
- 학습 에포크(epoch) 진행 상황
- 검증(validation) 진행 상황
- 학습 완료 또는 실패 알림
- 기타 경고나 정보 메시지
📋 예시 출력
(이벤트 1개 예시)
{
"object": "fine_tuning.job.event",
"created_at": 1710002111,
"level": "info",
"message": "Step 50/200: training loss=0.9234"
}
🔔 참고
limit=10
을 설정했기 때문에 최근 10개 이벤트만 가져옵니다.- 전체 이벤트를 보고 싶으면
limit
값을 더 크게 설정하면 됩니다. (예:limit=50
) - 주요 에포크 완료 시점이나 학습 종료 시점 등을 확인할 때 유용합니다.
✅ 이 명령을 사용하면 Fine-tuning 진행 상황을 구체적으로 추적하고, 문제가 발생했을 때도 어디서 실패했는지 쉽게 파악할 수 있습니다! 🚀
🧪 파인튜닝된 모델 테스트 (Test Our Fine-tuned Model)
파인튜닝이 완료된 모델을 사용해, 실제로 원하는 입력(prompt)에 대해 응답을 생성해 봅니다.
✨ 설명
- 이제 Fine-tuning이 완료되었으니,
새로 생성된 fine-tuned 모델 ID를 사용해서 직접 테스트 요청을 보낼 수 있습니다. - 튜닝한 모델은 특정한 스타일(예: 제품 가격 예측)에 맞춰 학습되어 있기 때문에,
기본 모델보다 훨씬 더 정확하고 일관된 응답을 기대할 수 있습니다.
🏷️ 파인튜닝된 모델 이름 가져오기 (Get Fine-tuned Model Name)
Fine-tuning 작업이 완료된 후 생성된 모델의 ID(이름)를 가져와 fine_tuned_model_name
변수에 저장합니다.
# 🏷️ Fine-tuned 모델 ID(이름) 가져오기
fine_tuned_model_name = openai.fine_tuning.jobs.retrieve(job_id).fine_tuned_model
# 📝 작동 과정:
# - 지정한 job_id에 해당하는 파인튜닝 작업을 조회합니다.
# - 작업 결과로 생성된 fine_tuned_model 이름을 추출해 변수에 저장합니다.
✨ 설명
openai.fine_tuning.jobs.retrieve(job_id)
: 해당 job_id에 해당하는 파인튜닝 작업의 전체 정보를 가져옵니다..fine_tuned_model
: 작업이 성공적으로 완료된 경우 생성된 Fine-tuned 모델 ID를 반환합니다.- 이 모델 ID는 이후 chat completion 요청이나 API 호출 시
model
파라미터로 사용해야 합니다.
🔔 참고
- 만약 파인튜닝이 아직 완료되지 않았다면(
status != "succeeded"
),.fine_tuned_model
값은None
이 될 수 있습니다. - 반드시 파인튜닝이 완료된 이후에 이 코드를 실행해야 정상적으로 모델 이름을 얻을 수 있습니다.
🏷️ 저장된 Fine-tuned 모델 이름 (Fine-tuned Model Name)
파인튜닝이 완료된 모델의 ID(이름)가 fine_tuned_model_name
변수에 저장된 상태입니다.
# 🏷️ Fine-tuned 모델 ID(이름)
fine_tuned_model_name
# - openai.fine_tuning.jobs.retrieve(job_id).fine_tuned_model 로 가져온 값
# - 추론(inference) 요청 시 사용할 모델 이름
✨ 설명
fine_tuned_model_name
은 직접 학습시킨 Fine-tuned 모델의 고유 ID입니다.- OpenAI API에서 이 ID를
model
파라미터에 입력하면,
튜닝된 모델로 대화(chat completion) 요청을 보낼 수 있습니다. - 이 모델은 기본(gpt-4o-mini 등) 모델보다 특정 작업(예: 제품 가격 예측)에 더 최적화되어 있습니다.
📋 예시
fine_tuned_model_name
변수에 저장된 값은 다음과 같은 형태입니다:
ft:gpt-4o-mini-2024-07-18:pricer:abcde12345
ft:
접두사가 붙어 있는 것이 특징입니다.- 이후 이 모델 이름을 사용해 바로 테스트할 수 있습니다.
🔔 참고
- fine_tuned_model_name은 자동으로 생성되며,
기존 모델명 + suffix + 고유 식별자로 구성됩니다. - 여러 개의 Fine-tuned 모델을 관리할 때는 이 이름으로 구분합니다.
✏️ 파인튜닝용 프롬프트 구성 함수 (Prompt Formatting for Fine-tuning)
제품 설명을 입력받아, 파인튜닝 및 테스트용 메시지 포맷을 만들어 반환하는 함수입니다.
# ✏️ 주어진 아이템(item)에 대해 프롬프트 메시지 리스트를 생성하는 함수
def messages_for(item):
# 🛠️ 시스템 역할(system message) 설정
system_message = "You estimate prices of items. Reply only with the price, no explanation"
# - 모델에게 '가격만 간결하게 답변하라'는 지시를 전달
# 📩 사용자 입력(user prompt) 준비
user_prompt = item.test_prompt().replace(" to the nearest dollar", "").replace("\n\nPrice is $", "")
# - 원본 프롬프트에서 "to the nearest dollar" 문구 삭제
# - "Price is $" 안내문도 삭제하여 더 깔끔한 입력 문장으로 정제
# 📨 시스템/사용자/어시스턴트 메시지 포맷으로 묶어 반환
return [
{"role": "system", "content": system_message}, # 시스템 역할 지시
{"role": "user", "content": user_prompt}, # 사용자 입력
{"role": "assistant", "content": "Price is $"} # 어시스턴트 답변 양식 (가격 입력 예상 위치)
]
✨ 설명
- system_message: 모델에게 "가격만 답하라"라고 명확히 지시합니다.
- user_prompt: 제품 설명 문장에서 필요 없는 문구를 제거해 모델이 핵심 정보만 이해할 수 있도록 합니다.
- assistant 응답 포맷:
"Price is $"
형태로 기본 응답 포맷을 제공해, 모델이 가격만 자연스럽게 채우도록 유도합니다.
📋 결과 예시
(만약 item.test_prompt()
가
"Wireless mouse with ergonomic design, to the nearest dollar\n\nPrice is $"
였다면, 변환 결과는 다음과 같습니다.)
[
{"role": "system", "content": "You estimate prices of items. Reply only with the price, no explanation"},
{"role": "user", "content": "Wireless mouse with ergonomic design,"},
{"role": "assistant", "content": "Price is $"}
]
🔔 참고
- 실제 모델 테스트 시에는 assistant의
"Price is $"
부분에 이어서 가격을 완성하도록 모델이 학습됩니다. - 여기서는 학습(fine-tuning)과 테스트를 모두 지원할 수 있도록 general 한 프롬프트 구조를 준비하고 있습니다.
🧪 테스트용 프롬프트 생성해 보기 (Try This Out)
테스트 데이터셋의 첫 번째 아이템을 이용해, 모델 입력용 메시지 포맷을 만들어 봅니다.
# 🧪 test 데이터셋의 첫 번째 아이템으로 프롬프트 생성
messages_for(test[0])
# 📝 작동 과정:
# - test[0]: 테스트 데이터셋의 첫 번째 항목을 선택합니다.
# - messages_for(test[0]): 선택한 항목을 기반으로 system/user/assistant 역할 메시지 리스트를 생성합니다.
✨ 설명
test
데이터셋은 모델의 성능을 검증하기 위해 별도로 준비한 데이터입니다.messages_for(test[0])
를 호출하면,- system message (가격만 답하라고 지시)
- user message (제품 설명)
- assistant message (가격 양식)로 구성된 메시지 리스트가 만들어집니다.
📋 예시 결과
(만약 test[0]
이 "Eco-friendly reusable water bottle" 설명을 가진 아이템이라면, 결과는 다음과 같습니다.)
[
{"role": "system", "content": "You estimate prices of items. Reply only with the price, no explanation"},
{"role": "user", "content": "Eco-friendly reusable water bottle"},
{"role": "assistant", "content": "Price is $"}
]
🔔 참고
- 이 출력 결과는 곧바로 fine-tuned 모델에게 입력으로 주어져,
모델이"Price is $19.99"
같은 식으로 가격을 채워 응답하게 됩니다. - 학습용 데이터와 테스트용 데이터 모두 같은 포맷을 유지하는 것이 중요합니다.
'🧠 LLM 엔지니어링' 카테고리의 다른 글
Fine-tuned GPT-4o-mini를 이용한 제품 가격 예측 모델 구축 가이드 03 (2) | 2025.05.06 |
---|---|
Fine-tuned GPT-4o-mini를 이용한 제품 가격 예측 모델 구축 가이드 01 (0) | 2025.05.04 |
제품 설명 기반 가격 예측 실험: Frontier 모델 테스트 (1) | 2025.05.03 |
자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 02 (0) | 2025.05.02 |
자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 01 (1) | 2025.05.01 |