ga0n0427/livecommerce_binary_classification

0

stars

2

commits

Jupyter Notebook

primary language

Dec 3, 2025

updated

README

📌 Live Commerce Classification API

Polyglot-ko-3.8B + LoRA 기반 라이브커머스 판별 모델 API 서버

입력으로 제목(title), 채팅(chat), 화자의 발화(speech) 를 보내면
→ 이 콘텐츠가 라이브커머스인지 / 일반 영상인지 자동 분류합니다.

이 모델은 다음 데이터로 파인튜닝되었습니다:

  • 라이브커머스(positive): 약 4,000개
  • 일반 영상(negative): 약 6,000개
  • 총 학습 샘플: 10,000개 (이진 분류 중심)

⭐ 1. 프로젝트 개요

라이브커머스 영상은 제목·대화 흐름·판매 관련 패턴이 분명하여
이를 Polyglot-ko-3.8B 기반으로 분류하는 모델입니다.

본 API 서버는:

  • Flask 기반 REST API
  • Polyglot-ko-3.8B + LoRA 적용 모델
  • 4bit quantization 지원
  • GPU/CPU 자동 감지

구조는 학습용 노트북(finetune.ipynb)과 추론 서버(app.py)를 기반으로 구현됩니다.


⭐ 2. 모델 및 학습

✔ 2.1 Base Model & Fine-tuning 개요

  • Base Model: EleutherAI/polyglot-ko-3.8b
  • Fine-tuning 방식: LoRA(PEFT)를 이용한 경량 파인튜닝
  • Task 타입: Causal Language Modeling을 이용한 “생성 기반 이진 분류(네/아니요)”

이 모델은 “분류 모델”이지만, 내부적으로는

질문(prompt) + “네 / 아니요 / 모름”
을 생성하는 방식으로 학습되어, 생성 결과를 가지고 라이브커머스 여부를 판별합니다.


🧪 2.2 학습 데이터 구성

  1. 원본 JSONL 구조 (merged_normalized.jsonl)

    • title: 영상 제목
    • chat: 채팅 메시지 리스트
    • whisper_transcript: 화자 발화를 Whisper 등으로 받아 적은 자막
    • label: 1(라이브커머스), 0(비라이브커머스), 그 외(모름/애매)
  2. 레이블 → 자연어 응답으로 변환 (merged_data.jsonl)

    • label == 1response = "네 </s>"
    • label == 0response = "아니요 </s>"
    • 기타 값 → response = "모름 </s>"
    • 여기서 </s>EOS 토큰으로, 문장의 끝을 명시하기 위해 추가.
  3. 프롬프트/응답 구조로 변환 (converted_prompt_response.jsonl) 각 샘플은 아래와 같은 형태의 prompt/response 쌍으로 재구성됩니다.

    • prompt 템플릿:

      📌 제목: {title}
      📌 채팅: {chat_1 chat_2 ...}
      📌 자막: {whisper_transcript}
      이 방송은 제품을 판매하는 라이브커머스인가요?
      [답]:
      
    • response:

      • "네 </s>" 또는 "아니요 </s>" 또는 "모름 </s>"
    • 최종 JSONL 구조:

      {"prompt": "...", "response": "네 </s>"}
      
  4. Train / Validation / Test 분할

    • 전체 converted_prompt_response.jsonl을 로드한 뒤:
      • 10% → Test
      • 나머지 90% 중 10% → Validation
      • 나머지 → Train
    • 랜덤 시드: random_state=42
    • DataFrame → HuggingFace Dataset으로 변환 후 Trainer에 전달.

🧩 2.3 프롬프트 설계 & 학습 목적

하나의 학습 샘플은 결국 다음 문장을 완성하도록 모델을 학습시키는 것입니다:

“📌 제목: …\n📌 채팅: …\n📌 자막: …\n이 방송은 제품을 판매하는 라이브커머스인가요?\n[답]: 네 ”

또는

“…\n[답]: 아니요 ”

즉,

  • 입력: 제목 + 채팅 로그 + 자막 + 질문
  • 출력: “네 / 아니요 / 모름” 중 하나

이 구조 덕분에:

  • 추론 시에도 동일한 프롬프트를 넣고
  • 모델이 생성한 첫 토큰/문장을 보고 라이브커머스 여부를 판별할 수 있습니다.

⚙️ 2.4 토크나이징 및 라벨 마스킹 전략

학습은 “Causal LM” 방식으로 진행되지만,
손실(loss)은 오직 ‘답변 구간’에만 걸리도록 마스킹을 합니다.

  1. 토크나이저 설정

    • 모델 ID: EleutherAI/polyglot-ko-3.8b
    • EOS 토큰: </s> 를 추가
    • padding 시에도 eos 토큰을 사용
  2. 입력/라벨 구성

    • full_text = prompt + " " + response
    • prompt_ids = tokenizer(prompt)
    • full_ids = tokenizer(full_text)
    • labels를 만들 때:
      • 프롬프트 길이 구간: -100 (loss 계산에서 무시)
      • 답변 구간(“네 ” 또는 “아니요 ” 등): 실제 토큰 ID
      • 패딩 부분: -100

    이렇게 하면 질문 부분은 단지 조건(conditioning) 으로만 사용되고,
    “답변 토큰을 얼마나 잘 생성하는지”만 학습하게 됩니다.


🧠 2.5 LoRA 설정 (경량 파인튜닝)

모델 전체를 finetune 하는 대신, 아래와 같이 LoRA를 사용하여 일부 Linear 계층만 학습합니다.

  • Base Model 로딩

    • 4bit 양자화(BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16))
    • device_map="auto" 로 GPU 자원에 맞게 자동 배치
    • 토크나이저 vocab 크기에 맞게 resize_token_embeddings 호출
  • LoRA 설정 주요 하이퍼파라미터

    • r = 8
    • lora_alpha = 32
    • lora_dropout = 0.05
    • bias = "none"
    • task_type = "CAUSAL_LM"
    • target_modules = ["query_key_value"]
      → Transformer 블록 내부의 QKV projection에만 LoRA를 적용하여
      추론 비용은 거의 유지하면서도, 라이브커머스 도메인에 적응 가능하도록 설계.
  • 효과

    • 전체 수십억 파라미터를 업데이트할 필요 없이
    • 매우 적은 수의 LoRA 파라미터만 학습 → 학습/저장/배포가 가벼움

📉 2.6 학습 설정 (TrainingArguments)

학습은 HuggingFace Trainer를 사용해 진행하며, 주요 설정은 다음과 같습니다.

  • output_dir = "./results_polyglot"
  • per_device_train_batch_size = 2
  • per_device_eval_batch_size = 2
  • gradient_accumulation_steps = 8
    → 실질적인 effective batch size ≈ 2 × 8 = 16
  • learning_rate = 2e-4
  • num_train_epochs = 최대 100
  • fp16 = True (반정밀도 학습)
  • eval_strategy = "epoch" (매 epoch마다 validation)
  • save_strategy = "epoch" (매 epoch 체크포인트 저장)
  • load_best_model_at_end = True
  • metric_for_best_model = "eval_loss"
  • greater_is_better = False (loss가 낮을수록 좋음)
  • EarlyStoppingCallback(early_stopping_patience=3)
    → validation loss가 개선되지 않으면 3 epoch 후 조기 종료

이 설정으로:

  • 과적합을 방지하고
  • validation loss 기준으로 가장 좋은 모델을 자동으로 선택하여 저장합니다.

💾 2.7 모델 저장 및 배포용 구조

학습 완료 후에는:

  • LoRA가 적용된 모델: final_model_polyglot/ 또는 체크포인트 디렉토리
  • 토크나이저: 동일 경로에 함께 저장

추론 서버(app.py)에서는:

  • Base Polyglot-ko-3.8B 로드
  • PeftModel.from_pretrained(fine_tuned_model_path) 로 LoRA 어댑터 적용
  • /generate 엔드포인트를 통해 HTTP로 분류 결과를 제공

이로써, 학습 노트북 → 저장된 LoRA 모델 → Flask 서버로 이어지는 전체 파이프라인이 완성됩니다.


⭐ 3. 서버 구조 (Flask API)

서버는 다음 파일을 기반으로 동작합니다:

  • app.py: 모델 로드 및 /generate 엔드포인트 정의

주요 기능:

  • 모델 로드 (Polyglot-ko + LoRA)
  • CUDA 사용 시 4bit 양자화로 VRAM 절감
  • /generate에서 프롬프트를 입력받아 생성 결과 반환
  • 생성된 텍스트의 “네 / 아니요 / 모름”을 사용해 라이브커머스 여부 판별 가능

⭐ 4. API 호출 방법

🔥 요청

POST /generate

Content-Type: application/json

Request Body 예시

{
  "prompt": "📌 제목: 여름 원피스 특가 판매합니다\n📌 채팅: 가격 알려주세요!\n📌 자막: 지금 구매하시면 할인 적용됩니다.\n이 방송은 제품을 판매하는 라이브커머스인가요?\n[답]:",
  "max_new_tokens": 10
}

⭐ 5. 실행 방법 (Flask API)

서버는 다음 파일을 기반으로 동작합니다:

  • app.py

주요 기능:

  • 모델 로드 (Polyglot-ko + LoRA)
  • 4bit 양자화를 통한 VRAM 절약
  • /generate 엔드포인트에서 분류 출력
  • 프롬프트 기반 분류 로직

⭐ 6. 파일 예시 구조

project/
├── app.py
├── finetune.ipynb
├── converted_prompt_response.jsonl
├── checkpoint-2030/          # LoRA 체크포인트
├── final_model_polyglot/     # 최종 저장 모델(선택)
└── readme.yaml

Contributors

ga0n0427

2 commits

ga0n0427/livecommerce_binary_classification

0

stars

2

commits

Jupyter Notebook

primary language

Dec 3, 2025

updated

README

📌 Live Commerce Classification API

Polyglot-ko-3.8B + LoRA 기반 라이브커머스 판별 모델 API 서버

입력으로 제목(title), 채팅(chat), 화자의 발화(speech) 를 보내면
→ 이 콘텐츠가 라이브커머스인지 / 일반 영상인지 자동 분류합니다.

이 모델은 다음 데이터로 파인튜닝되었습니다:

  • 라이브커머스(positive): 약 4,000개
  • 일반 영상(negative): 약 6,000개
  • 총 학습 샘플: 10,000개 (이진 분류 중심)

⭐ 1. 프로젝트 개요

라이브커머스 영상은 제목·대화 흐름·판매 관련 패턴이 분명하여
이를 Polyglot-ko-3.8B 기반으로 분류하는 모델입니다.

본 API 서버는:

  • Flask 기반 REST API
  • Polyglot-ko-3.8B + LoRA 적용 모델
  • 4bit quantization 지원
  • GPU/CPU 자동 감지

구조는 학습용 노트북(finetune.ipynb)과 추론 서버(app.py)를 기반으로 구현됩니다.


⭐ 2. 모델 및 학습

✔ 2.1 Base Model & Fine-tuning 개요

  • Base Model: EleutherAI/polyglot-ko-3.8b
  • Fine-tuning 방식: LoRA(PEFT)를 이용한 경량 파인튜닝
  • Task 타입: Causal Language Modeling을 이용한 “생성 기반 이진 분류(네/아니요)”

이 모델은 “분류 모델”이지만, 내부적으로는

질문(prompt) + “네 / 아니요 / 모름”
을 생성하는 방식으로 학습되어, 생성 결과를 가지고 라이브커머스 여부를 판별합니다.


🧪 2.2 학습 데이터 구성

  1. 원본 JSONL 구조 (merged_normalized.jsonl)

    • title: 영상 제목
    • chat: 채팅 메시지 리스트
    • whisper_transcript: 화자 발화를 Whisper 등으로 받아 적은 자막
    • label: 1(라이브커머스), 0(비라이브커머스), 그 외(모름/애매)
  2. 레이블 → 자연어 응답으로 변환 (merged_data.jsonl)

    • label == 1response = "네 </s>"
    • label == 0response = "아니요 </s>"
    • 기타 값 → response = "모름 </s>"
    • 여기서 </s>EOS 토큰으로, 문장의 끝을 명시하기 위해 추가.
  3. 프롬프트/응답 구조로 변환 (converted_prompt_response.jsonl) 각 샘플은 아래와 같은 형태의 prompt/response 쌍으로 재구성됩니다.

    • prompt 템플릿:

      📌 제목: {title}
      📌 채팅: {chat_1 chat_2 ...}
      📌 자막: {whisper_transcript}
      이 방송은 제품을 판매하는 라이브커머스인가요?
      [답]:
      
    • response:

      • "네 </s>" 또는 "아니요 </s>" 또는 "모름 </s>"
    • 최종 JSONL 구조:

      {"prompt": "...", "response": "네 </s>"}
      
  4. Train / Validation / Test 분할

    • 전체 converted_prompt_response.jsonl을 로드한 뒤:
      • 10% → Test
      • 나머지 90% 중 10% → Validation
      • 나머지 → Train
    • 랜덤 시드: random_state=42
    • DataFrame → HuggingFace Dataset으로 변환 후 Trainer에 전달.

🧩 2.3 프롬프트 설계 & 학습 목적

하나의 학습 샘플은 결국 다음 문장을 완성하도록 모델을 학습시키는 것입니다:

“📌 제목: …\n📌 채팅: …\n📌 자막: …\n이 방송은 제품을 판매하는 라이브커머스인가요?\n[답]: 네 ”

또는

“…\n[답]: 아니요 ”

즉,

  • 입력: 제목 + 채팅 로그 + 자막 + 질문
  • 출력: “네 / 아니요 / 모름” 중 하나

이 구조 덕분에:

  • 추론 시에도 동일한 프롬프트를 넣고
  • 모델이 생성한 첫 토큰/문장을 보고 라이브커머스 여부를 판별할 수 있습니다.

⚙️ 2.4 토크나이징 및 라벨 마스킹 전략

학습은 “Causal LM” 방식으로 진행되지만,
손실(loss)은 오직 ‘답변 구간’에만 걸리도록 마스킹을 합니다.

  1. 토크나이저 설정

    • 모델 ID: EleutherAI/polyglot-ko-3.8b
    • EOS 토큰: </s> 를 추가
    • padding 시에도 eos 토큰을 사용
  2. 입력/라벨 구성

    • full_text = prompt + " " + response
    • prompt_ids = tokenizer(prompt)
    • full_ids = tokenizer(full_text)
    • labels를 만들 때:
      • 프롬프트 길이 구간: -100 (loss 계산에서 무시)
      • 답변 구간(“네 ” 또는 “아니요 ” 등): 실제 토큰 ID
      • 패딩 부분: -100

    이렇게 하면 질문 부분은 단지 조건(conditioning) 으로만 사용되고,
    “답변 토큰을 얼마나 잘 생성하는지”만 학습하게 됩니다.


🧠 2.5 LoRA 설정 (경량 파인튜닝)

모델 전체를 finetune 하는 대신, 아래와 같이 LoRA를 사용하여 일부 Linear 계층만 학습합니다.

  • Base Model 로딩

    • 4bit 양자화(BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16))
    • device_map="auto" 로 GPU 자원에 맞게 자동 배치
    • 토크나이저 vocab 크기에 맞게 resize_token_embeddings 호출
  • LoRA 설정 주요 하이퍼파라미터

    • r = 8
    • lora_alpha = 32
    • lora_dropout = 0.05
    • bias = "none"
    • task_type = "CAUSAL_LM"
    • target_modules = ["query_key_value"]
      → Transformer 블록 내부의 QKV projection에만 LoRA를 적용하여
      추론 비용은 거의 유지하면서도, 라이브커머스 도메인에 적응 가능하도록 설계.
  • 효과

    • 전체 수십억 파라미터를 업데이트할 필요 없이
    • 매우 적은 수의 LoRA 파라미터만 학습 → 학습/저장/배포가 가벼움

📉 2.6 학습 설정 (TrainingArguments)

학습은 HuggingFace Trainer를 사용해 진행하며, 주요 설정은 다음과 같습니다.

  • output_dir = "./results_polyglot"
  • per_device_train_batch_size = 2
  • per_device_eval_batch_size = 2
  • gradient_accumulation_steps = 8
    → 실질적인 effective batch size ≈ 2 × 8 = 16
  • learning_rate = 2e-4
  • num_train_epochs = 최대 100
  • fp16 = True (반정밀도 학습)
  • eval_strategy = "epoch" (매 epoch마다 validation)
  • save_strategy = "epoch" (매 epoch 체크포인트 저장)
  • load_best_model_at_end = True
  • metric_for_best_model = "eval_loss"
  • greater_is_better = False (loss가 낮을수록 좋음)
  • EarlyStoppingCallback(early_stopping_patience=3)
    → validation loss가 개선되지 않으면 3 epoch 후 조기 종료

이 설정으로:

  • 과적합을 방지하고
  • validation loss 기준으로 가장 좋은 모델을 자동으로 선택하여 저장합니다.

💾 2.7 모델 저장 및 배포용 구조

학습 완료 후에는:

  • LoRA가 적용된 모델: final_model_polyglot/ 또는 체크포인트 디렉토리
  • 토크나이저: 동일 경로에 함께 저장

추론 서버(app.py)에서는:

  • Base Polyglot-ko-3.8B 로드
  • PeftModel.from_pretrained(fine_tuned_model_path) 로 LoRA 어댑터 적용
  • /generate 엔드포인트를 통해 HTTP로 분류 결과를 제공

이로써, 학습 노트북 → 저장된 LoRA 모델 → Flask 서버로 이어지는 전체 파이프라인이 완성됩니다.


⭐ 3. 서버 구조 (Flask API)

서버는 다음 파일을 기반으로 동작합니다:

  • app.py: 모델 로드 및 /generate 엔드포인트 정의

주요 기능:

  • 모델 로드 (Polyglot-ko + LoRA)
  • CUDA 사용 시 4bit 양자화로 VRAM 절감
  • /generate에서 프롬프트를 입력받아 생성 결과 반환
  • 생성된 텍스트의 “네 / 아니요 / 모름”을 사용해 라이브커머스 여부 판별 가능

⭐ 4. API 호출 방법

🔥 요청

POST /generate

Content-Type: application/json

Request Body 예시

{
  "prompt": "📌 제목: 여름 원피스 특가 판매합니다\n📌 채팅: 가격 알려주세요!\n📌 자막: 지금 구매하시면 할인 적용됩니다.\n이 방송은 제품을 판매하는 라이브커머스인가요?\n[답]:",
  "max_new_tokens": 10
}

⭐ 5. 실행 방법 (Flask API)

서버는 다음 파일을 기반으로 동작합니다:

  • app.py

주요 기능:

  • 모델 로드 (Polyglot-ko + LoRA)
  • 4bit 양자화를 통한 VRAM 절약
  • /generate 엔드포인트에서 분류 출력
  • 프롬프트 기반 분류 로직

⭐ 6. 파일 예시 구조

project/
├── app.py
├── finetune.ipynb
├── converted_prompt_response.jsonl
├── checkpoint-2030/          # LoRA 체크포인트
├── final_model_polyglot/     # 최종 저장 모델(선택)
└── readme.yaml

Contributors

ga0n0427

2 commits

Languages

Jupyter Notebook

80.4%

Python

19.6%