E5 Action-Family Classifier for Dacon
Dacon Action 분류 데이터를 이용해 파인튜닝한 계층형 분류 모델입니다.
이 모델은 최종 Action 예측뿐 아니라 E5 embedding과 각 분류 head의 logits·확률을 제공합니다. 사용자는 추출한 특징 위에 LightGBM, XGBoost, RandomForest 등의 분류기를 추가로 학습할 수 있습니다.
모델 구조
1 Shared multilingual-e5-small encoder
2 ├─ Flat Action Head: 14 classes
3 ├─ Family Head: 4 classes
4 └─ Specialist Heads
5 ├─ file_discovery
6 ├─ file_edit
7 ├─ execute_validate
8 └─ interaction
최종 모델 확률은 다음 Soft Routing으로 계산합니다.
1 P_hierarchical(action)
2 = P(family) × P(action | family)
3
4 P_final(action)
5 = α × P_flat(action)
6 + (1-α) × P_hierarchical(action)
지원 클래스
Family Action file_discoveryread_file, grep_search, list_directory, glob_patternfile_editedit_file, write_file, apply_patchexecute_validaterun_bash, run_tests, lint_or_typecheckinteractionask_user, plan_task, web_search, respond_only
저장소 구조
1 repository/
2 ├─ config.json
3 ├─ inference.py
4 ├─ label_mapping.json
5 ├─ model.safetensors
6 ├─ routing_config.json
7 ├─ sentencepiece.bpe.model
8 ├─ special_tokens_map.json
9 ├─ tokenizer.json
10 └─ tokenizer_config.json
1. 라이브러리 설치
pip install torch transformers==4.57.6 safetensors sentencepiece huggingface_hub
LightGBM을 추가로 학습하려면 다음 패키지도 설치합니다.
pip install lightgbm scikit-learn pandas joblib
2. 모델 불러오기
1 import sys
2
3 from huggingface_hub import snapshot_download
4
5 repo_id = "RiverWon/e5-action-family-dacon"
6
7 repo_dir = snapshot_download (
8 repo_id = repo_id
9 )
10
11 # 다운로드된 inference.py를 import할 수 있도록 경로 추가
12 sys . path . insert ( 0 , repo_dir )
13
14 from inference import ActionFamilyFeatureExtractor
15
16 extractor = ActionFamilyFeatureExtractor . from_pretrained (
17 repo_dir
18 )
19
20 print ( "모델 로드 완료" )
21 print ( "device:" , extractor . device )
snapshot_download()는 모델 파일과 inference.py를 함께 내려받습니다.
3. 단일 샘플 예측
1 sample = {
2 "current_prompt" : "수정한 코드가 정상인지 테스트를 실행해줘" ,
3 "history" : [
4 {
5 "role" : "assistant_action" ,
6 "name" : "edit_file" ,
7 "args" : {
8 "path" : "src/app.py"
9 } ,
10 "result_summary" : "파일 수정 완료"
11 }
12 ] ,
13 "session_meta" : {
14 "user_tier" : "pro" ,
15 "language_pref" : "ko" ,
16 "turn_index" : 3 ,
17 "workspace" : {
18 "open_files" : [ "src/app.py" ] ,
19 "language_mix" : {
20 "py" : 1.0
21 } ,
22 "git_dirty" : True ,
23 "last_ci_status" : "none"
24 }
25 }
26 }
27
28 result = extractor . predict ( sample )
29
30 print ( result [ "action" ] )
31 print ( result [ "family" ] )
32 print ( result [ "confidence" ] )
33 print ( result [ "top_k" ] )
출력 예시:
1 {
2 "action" : "run_tests" ,
3 "family" : "execute_validate" ,
4 "confidence" : 0.82 ,
5 "top_k" : [
6 {
7 "action" : "run_tests" ,
8 "family" : "execute_validate" ,
9 "probability" : 0.82
10 } ,
11 {
12 "action" : "run_bash" ,
13 "family" : "execute_validate" ,
14 "probability" : 0.09
15 }
16 ]
17 }
4. 여러 샘플 예측
1 samples = [
2 {
3 "current_prompt" : "프로젝트에서 UserService를 찾아줘" ,
4 "history" : [ ] ,
5 "session_meta" : { "workspace" : { } }
6 } ,
7 {
8 "current_prompt" : "테스트를 실행해줘" ,
9 "history" : [ ] ,
10 "session_meta" : { "workspace" : { } }
11 }
12 ]
13
14 results = extractor . predict_batch (
15 samples ,
16 batch_size = 32 ,
17 top_k = 3
18 )
19
20 for result in results :
21 print ( result [ "action" ] , result [ "confidence" ] )
5. 모델 특징 추출
후속 분류기를 학습할 수 있도록 모델의 중간 특징을 추출할 수 있습니다.
1 features = extractor . extract_features (
2 samples ,
3 batch_size = 32
4 )
5
6 print ( features [ "embedding" ] . shape )
7 print ( features [ "flat_logits" ] . shape )
8 print ( features [ "family_logits" ] . shape )
9 print ( features [ "specialist_logits" ] . shape )
10 print ( features [ "hierarchical_prob" ] . shape )
11 print ( features [ "final_prob" ] . shape )
제공되는 특징:
이름 차원 설명 embedding384 E5 encoder embedding flat_logits14 Flat Action Head logits family_logits4 Action Family logits specialist_logits14 Family별 Specialist logits flat_prob14 Flat Action 확률 family_prob4 Family 확률 hierarchical_prob14 Family × Specialist 확률 final_prob14 최종 Soft Routing 확률
transform()을 사용하면 후속 모델에 바로 넣을 수 있는 하나의 행렬을 반환합니다.
1 X = extractor . transform (
2 samples ,
3 batch_size = 32
4 )
5
6 print ( X . shape ) # (샘플 수, 444)
6. Dacon 데이터 준비
다음과 같은 디렉터리 구조를 사용합니다.
1 project/
2 ├─ data/
3 │ ├─ train.jsonl
4 │ ├─ train_labels.csv
5 │ ├─ test.jsonl
6 │ └─ sample_submission.csv
7 └─ train_and_submit.py
데이터 로더:
1 import json
2 from pathlib import Path
3
4 import pandas as pd
5
6 DATA_DIR = Path ( "./data" )
7
8
9 def load_jsonl ( path ) :
10 with path . open ( encoding = "utf-8" ) as file :
11 return [
12 json . loads ( line )
13 for line in file
14 if line . strip ( )
15 ]
16
17
18 train_samples = load_jsonl (
19 DATA_DIR / "train.jsonl"
20 )
21
22 test_samples = load_jsonl (
23 DATA_DIR / "test.jsonl"
24 )
25
26 labels_df = pd . read_csv (
27 DATA_DIR / "train_labels.csv"
28 )
29
30 label_by_id = dict (
31 zip ( labels_df [ "id" ] , labels_df [ "action" ] )
32 )
33
34 y_text = [
35 label_by_id [ sample [ "id" ] ]
36 for sample in train_samples
37 ]
38
39 print ( "train:" , len ( train_samples ) )
40 print ( "test:" , len ( test_samples ) )
7. 모델만 사용해 Dacon 제출
추가 분류기를 학습하지 않고 모델의 기본 예측을 그대로 제출할 수 있습니다.
1 import pandas as pd
2
3 test_results = extractor . predict_batch (
4 test_samples ,
5 batch_size = 64
6 )
7
8 prediction_by_id = {
9 sample [ "id" ] : result [ "action" ]
10 for sample , result in zip (
11 test_samples ,
12 test_results
13 )
14 }
15
16 submission = pd . read_csv (
17 DATA_DIR / "sample_submission.csv"
18 )
19
20 submission [ "action" ] = submission [ "id" ] . map (
21 prediction_by_id
22 )
23
24 if submission [ "action" ] . isna ( ) . any ( ) :
25 raise ValueError ( "일부 test ID의 예측값이 없습니다." )
26
27 submission . to_csv (
28 "submission_e5_actionfamily.csv" ,
29 index = False
30 )
31
32 print ( submission . head ( ) )
33 print ( "saved: submission_e5_actionfamily.csv" )
생성된 파일:
submission_e5_actionfamily.csv
이 파일을 Dacon 대회 페이지에 제출합니다.
8. LightGBM으로 성능 강화
특징 추출
1 import numpy as np
2
3 X_train = extractor . transform (
4 train_samples ,
5 batch_size = 64
6 )
7
8 X_test = extractor . transform (
9 test_samples ,
10 batch_size = 64
11 )
12
13 print ( "X_train:" , X_train . shape )
14 print ( "X_test:" , X_test . shape )
15
16 np . save ( "X_train_e5_actionfamily.npy" , X_train )
17 np . save ( "X_test_e5_actionfamily.npy" , X_test )
특징 추출에는 GPU 사용을 권장합니다. 저장된 NumPy 파일은 이후 다시 모델을 실행하지 않고 재사용할 수 있습니다.
라벨 인코딩
1 import joblib
2
3 from sklearn . preprocessing import LabelEncoder
4
5 label_encoder = LabelEncoder ( )
6 y = label_encoder . fit_transform ( y_text )
7
8 joblib . dump (
9 label_encoder ,
10 "label_encoder.pkl"
11 )
12
13 print ( label_encoder . classes_ )
간단한 로컬 검증
세션 데이터이므로 ID에서 -step_N을 제거한 값을 group으로 사용합니다.
1 import re
2 import numpy as np
3
4 from sklearn . model_selection import GroupShuffleSplit
5 from sklearn . metrics import f1_score
6
7
8 def get_session_id ( sample_id ) :
9 return re . sub (
10 r"-step_\d+$" ,
11 "" ,
12 sample_id
13 )
14
15
16 groups = np . array ( [
17 get_session_id ( sample [ "id" ] )
18 for sample in train_samples
19 ] )
20
21 splitter = GroupShuffleSplit (
22 n_splits = 1 ,
23 test_size = 0.2 ,
24 random_state = 42
25 )
26
27 train_idx , valid_idx = next (
28 splitter . split (
29 X_train ,
30 y ,
31 groups = groups
32 )
33 )
LightGBM 학습
1 import lightgbm as lgb
2
3 classifier = lgb . LGBMClassifier (
4 objective = "multiclass" ,
5 n_estimators = 1500 ,
6 learning_rate = 0.03 ,
7 num_leaves = 31 ,
8 max_depth = - 1 ,
9 subsample = 0.9 ,
10 colsample_bytree = 0.9 ,
11 class_weight = "balanced" ,
12 random_state = 42 ,
13 n_jobs = - 1
14 )
15
16 classifier . fit (
17 X_train [ train_idx ] ,
18 y [ train_idx ] ,
19 eval_set = [
20 (
21 X_train [ valid_idx ] ,
22 y [ valid_idx ]
23 )
24 ] ,
25 callbacks = [
26 lgb . early_stopping ( 100 ) ,
27 lgb . log_evaluation ( 100 )
28 ]
29 )
30
31 valid_prediction = classifier . predict (
32 X_train [ valid_idx ]
33 )
34
35 macro_f1 = f1_score (
36 y [ valid_idx ] ,
37 valid_prediction ,
38 average = "macro"
39 )
40
41 print ( "validation Macro F1:" , macro_f1 )
전체 데이터 재학습
Validation에서 선택된 boosting round를 사용합니다.
1 best_iteration = (
2 classifier . best_iteration_
3 if classifier . best_iteration_
4 else classifier . n_estimators
5 )
6
7 final_classifier = lgb . LGBMClassifier (
8 objective = "multiclass" ,
9 n_estimators = best_iteration ,
10 learning_rate = 0.03 ,
11 num_leaves = 31 ,
12 max_depth = - 1 ,
13 subsample = 0.9 ,
14 colsample_bytree = 0.9 ,
15 class_weight = "balanced" ,
16 random_state = 42 ,
17 n_jobs = - 1
18 )
19
20 final_classifier . fit (
21 X_train ,
22 y
23 )
24
25 joblib . dump (
26 final_classifier ,
27 "lightgbm_action_classifier.pkl"
28 )
Test 예측 및 제출 파일 생성
1 test_prediction_ids = final_classifier . predict (
2 X_test
3 )
4
5 test_predictions = label_encoder . inverse_transform (
6 test_prediction_ids . astype ( int )
7 )
8
9 prediction_by_id = {
10 sample [ "id" ] : prediction
11 for sample , prediction in zip (
12 test_samples ,
13 test_predictions
14 )
15 }
16
17 submission = pd . read_csv (
18 DATA_DIR / "sample_submission.csv"
19 )
20
21 submission [ "action" ] = submission [ "id" ] . map (
22 prediction_by_id
23 )
24
25 if submission [ "action" ] . isna ( ) . any ( ) :
26 raise ValueError ( "일부 test ID의 예측값이 없습니다." )
27
28 submission . to_csv (
29 "submission_e5_lightgbm.csv" ,
30 index = False
31 )
32
33 print ( submission . head ( ) )
34 print ( "saved: submission_e5_lightgbm.csv" )
생성된 파일:
submission_e5_lightgbm.csv
이 파일을 Dacon에 제출합니다.
9. 원하는 특징만 선택
Embedding만 사용할 수 있습니다.
1 X = extractor . transform (
2 samples ,
3 include = [ "embedding" ]
4 )
모델 logits만 사용할 수 있습니다.
1 X = extractor . transform (
2 samples ,
3 include = [
4 "flat_logits" ,
5 "family_logits" ,
6 "specialist_logits"
7 ]
8 )
확률 특징만 사용할 수 있습니다.
1 X = extractor . transform (
2 samples ,
3 include = [
4 "hierarchical_prob" ,
5 "final_prob"
6 ]
7 )
권장 시작 설정:
1 X = extractor . transform (
2 samples ,
3 include = [
4 "embedding" ,
5 "flat_logits" ,
6 "family_logits" ,
7 "specialist_logits" ,
8 "hierarchical_prob" ,
9 "final_prob"
10 ]
11 )
10. 학습한 분류기 다시 사용
1 import joblib
2 import numpy as np
3
4 classifier = joblib . load (
5 "lightgbm_action_classifier.pkl"
6 )
7
8 label_encoder = joblib . load (
9 "label_encoder.pkl"
10 )
11
12 X_new = extractor . transform (
13 new_samples ,
14 batch_size = 64
15 )
16
17 prediction_ids = classifier . predict (
18 X_new
19 ) . astype ( int )
20
21 predictions = label_encoder . inverse_transform (
22 prediction_ids
23 )
24
25 print ( predictions )
주의사항
이 모델은 일반적인 AutoModelForSequenceClassification 모델이 아닙니다.
제공된 inference.py의 ActionFamilyFeatureExtractor를 이용해 로드해야 합니다.
특징 추출 시 학습 때와 동일한 입력 전처리를 사용해야 합니다.
입력 형식이 학습 데이터와 크게 다르면 성능이 낮아질 수 있습니다.
단일 Decision Tree는 쉽게 과적합할 수 있으므로 LightGBM이나 XGBoost를 권장합니다.
클래스 불균형이 있으므로 Accuracy뿐 아니라 Macro F1을 확인하세요.
세션형 데이터의 로컬 검증은 행 단위가 아니라 session 단위 분할을 권장합니다.
공개 모델이 Dacon 전체 학습 데이터로 파인튜닝됐다면, 같은 학습 데이터에서 계산한 로컬 검증 점수는 낙관적일 수 있습니다.
Dacon 데이터 및 대회 규정에 따라 모델과 외부 데이터 사용 가능 여부를 직접 확인하세요.
모델 정보
항목 값 Base model intfloat/multilingual-e5-smallEmbedding size 384 Maximum length 320 Action classes 14 Action families 4 기본 특징 차원 444 Model format Safetensors Routing Flat + hierarchical soft routing
인용 및 라이선스
기반 모델 intfloat/multilingual-e5-small의 모델 카드와 라이선스를 확인해주세요.
본 모델을 Dacon 대회에 사용하는 경우 해당 대회의 데이터·외부 모델·제출 규정을 우선적으로 준수해야 합니다.