HarshalGunjalOp commited on
Commit
eccd289
·
1 Parent(s): 689c80d

Add notebooks and kaggle data for GitHub, configure HuggingFace ignore

Browse files
.gitignore CHANGED
@@ -9,12 +9,4 @@ __pycache__/
9
  wandb/
10
  .venv/
11
  .env
12
- kaggle/
13
- main.ipynb
14
- training_notebook.ipynb
15
- submission_notebook.ipynb
16
- submission_scratch_notebook.ipynb
17
- training_scratch_notebook.ipynb
18
- main_code_explanation.md
19
- gradio_app.py
20
  .env.example
 
9
  wandb/
10
  .venv/
11
  .env
 
 
 
 
 
 
 
 
12
  .env.example
.huggingface-ignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Exclude notebooks from HuggingFace Spaces
2
+ *.ipynb
3
+ main_code_explanation.md
4
+
5
+ # Exclude kaggle data
6
+ kaggle/
gradio_app.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio Deployment App for Emotion Classification Model
3
+ This app loads the trained model from HuggingFace Hub and creates an interactive interface.
4
+ """
5
+
6
+ import gradio as gr
7
+ import torch
8
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
9
+ import numpy as np
10
+ from huggingface_hub import hf_hub_download
11
+
12
+ # Configuration
13
+ HF_REPO_ID = "hrshlgunjal/emotion-classifier-deberta-v3" # UPDATE THIS!
14
+ LABELS = ["anger", "fear", "joy", "sadness", "surprise"]
15
+ MAX_LEN = 128
16
+
17
+ # Load model and tokenizer
18
+ print("Loading model from HuggingFace Hub...")
19
+ model = AutoModelForSequenceClassification.from_pretrained(
20
+ HF_REPO_ID,
21
+ num_labels=len(LABELS),
22
+ problem_type="multi_label_classification"
23
+ )
24
+ tokenizer = AutoTokenizer.from_pretrained(HF_REPO_ID)
25
+ model.eval()
26
+ print("✅ Model loaded successfully!")
27
+
28
+ # Load optimized thresholds
29
+ print("Loading optimized thresholds...")
30
+ try:
31
+ threshold_path = hf_hub_download(
32
+ repo_id=HF_REPO_ID,
33
+ filename="best_thresholds.npy"
34
+ )
35
+ thresholds = np.load(threshold_path)
36
+ print("✅ Optimized thresholds loaded!")
37
+ except Exception as e:
38
+ print(f"⚠️ Could not load thresholds: {e}")
39
+ print("Using default thresholds of 0.5")
40
+ thresholds = np.array([0.5] * len(LABELS))
41
+
42
+ # Prediction function
43
+ def predict_emotions(text):
44
+ """
45
+ Predict emotions from input text.
46
+
47
+ Args:
48
+ text (str): Input text to analyze
49
+
50
+ Returns:
51
+ dict: Probability scores for each emotion
52
+ """
53
+ if not text.strip():
54
+ return {label: 0.0 for label in LABELS}
55
+
56
+ # Tokenize
57
+ inputs = tokenizer(
58
+ text,
59
+ return_tensors="pt",
60
+ truncation=True,
61
+ max_length=MAX_LEN,
62
+ padding=True
63
+ )
64
+
65
+ # Predict
66
+ with torch.no_grad():
67
+ outputs = model(**inputs)
68
+
69
+ # Get probabilities
70
+ probs = torch.sigmoid(outputs.logits).cpu().numpy()[0]
71
+
72
+ # Apply thresholds for binary predictions
73
+ predictions = (probs >= thresholds).astype(int)
74
+
75
+ # Create result dictionary
76
+ result = {}
77
+ for i, label in enumerate(LABELS):
78
+ result[label] = float(probs[i])
79
+
80
+ return result
81
+
82
+ def predict_with_explanation(text):
83
+ """
84
+ Predict emotions and provide detailed explanation.
85
+
86
+ Args:
87
+ text (str): Input text to analyze
88
+
89
+ Returns:
90
+ tuple: (emotion_scores, explanation_text)
91
+ """
92
+ if not text.strip():
93
+ return {label: 0.0 for label in LABELS}, "Please enter some text to analyze."
94
+
95
+ # Get predictions
96
+ result = predict_emotions(text)
97
+
98
+ # Create explanation
99
+ detected_emotions = []
100
+ for label, score in result.items():
101
+ if score >= thresholds[LABELS.index(label)]:
102
+ detected_emotions.append(f"**{label.capitalize()}** ({score:.2%})")
103
+
104
+ if detected_emotions:
105
+ explanation = f"**Detected Emotions:** {', '.join(detected_emotions)}\n\n"
106
+ else:
107
+ explanation = "**No strong emotions detected.**\n\n"
108
+
109
+ explanation += "**All Emotion Scores:**\n"
110
+ for label, score in sorted(result.items(), key=lambda x: x[1], reverse=True):
111
+ bar = "█" * int(score * 20)
112
+ explanation += f"- {label.capitalize()}: {bar} {score:.2%}\n"
113
+
114
+ return result, explanation
115
+
116
+ # Example texts
117
+ examples = [
118
+ ["I am so excited about this amazing opportunity!"],
119
+ ["I can't believe you did this to me. I'm so angry!"],
120
+ ["I'm terrified of what might happen next."],
121
+ ["This is the saddest day of my life."],
122
+ ["Wow! I didn't expect that at all!"],
123
+ ["I'm feeling really happy and grateful today."],
124
+ ["I'm so frustrated with this situation."],
125
+ ["This news is shocking and scary."],
126
+ ["I'm overjoyed and surprised by this wonderful gift!"],
127
+ ["I'm deeply saddened and disappointed."],
128
+ ]
129
+
130
+ # Create Gradio interface
131
+ with gr.Blocks(title="🎭 Emotion Classification") as demo:
132
+ gr.Markdown(
133
+ """
134
+ # 🎭 Emotion Classification Model
135
+
136
+ This model analyzes text and identifies 5 emotions: **anger**, **fear**, **joy**, **sadness**, and **surprise**.
137
+
138
+ ### Features:
139
+ - ✅ Multi-label classification (can detect multiple emotions)
140
+ - ✅ Based on DeBERTa-v3 transformer model
141
+ - ✅ Trained with 5-fold cross-validation
142
+ - ✅ Optimized thresholds for best performance
143
+
144
+ ---
145
+ """
146
+ )
147
+
148
+ with gr.Row():
149
+ with gr.Column(scale=2):
150
+ text_input = gr.Textbox(
151
+ label="Enter Text",
152
+ placeholder="Type or paste your text here...",
153
+ lines=5
154
+ )
155
+
156
+ with gr.Row():
157
+ submit_btn = gr.Button("Analyze Emotions 🔍", variant="primary")
158
+ clear_btn = gr.Button("Clear 🗑️")
159
+
160
+ with gr.Column(scale=1):
161
+ emotion_output = gr.Label(
162
+ label="Emotion Scores",
163
+ num_top_classes=5
164
+ )
165
+
166
+ explanation_output = gr.Markdown(label="Detailed Analysis")
167
+
168
+ # Example section
169
+ gr.Markdown("### 📝 Try These Examples:")
170
+ gr.Examples(
171
+ examples=examples,
172
+ inputs=text_input,
173
+ outputs=[emotion_output, explanation_output],
174
+ fn=predict_with_explanation,
175
+ cache_examples=False
176
+ )
177
+
178
+ # Info section
179
+ gr.Markdown(
180
+ """
181
+ ---
182
+
183
+ ### ℹ️ About This Model
184
+
185
+ **Model:** microsoft/deberta-v3-base (fine-tuned)
186
+
187
+ **Training:**
188
+ - 5-fold stratified cross-validation
189
+ - Mixed precision training (FP16)
190
+ - Threshold optimization for each emotion
191
+
192
+ **Performance:**
193
+ - Macro F1 Score: [Your CV Score]
194
+ - Kaggle Score: 8.3+
195
+
196
+ **Labels:**
197
+ - 😠 **Anger:** Expressions of anger, frustration, or annoyance
198
+ - 😨 **Fear:** Expressions of fear, anxiety, or worry
199
+ - 😊 **Joy:** Expressions of happiness, pleasure, or satisfaction
200
+ - 😢 **Sadness:** Expressions of sadness, sorrow, or disappointment
201
+ - 😲 **Surprise:** Expressions of surprise, shock, or amazement
202
+
203
+ ---
204
+
205
+ **Repository:** [HuggingFace Hub](https://huggingface.co/{})
206
+
207
+ **Created for:** Deep Learning & Gen AI Project 2025
208
+ """.format(HF_REPO_ID)
209
+ )
210
+
211
+ # Button actions
212
+ submit_btn.click(
213
+ fn=predict_with_explanation,
214
+ inputs=text_input,
215
+ outputs=[emotion_output, explanation_output]
216
+ )
217
+
218
+ clear_btn.click(
219
+ fn=lambda: ("", {label: 0.0 for label in LABELS}, ""),
220
+ inputs=None,
221
+ outputs=[text_input, emotion_output, explanation_output]
222
+ )
223
+
224
+ # Launch the app
225
+ if __name__ == "__main__":
226
+ demo.launch(
227
+ share=False, # Set to True to create a public link
228
+ server_name="0.0.0.0",
229
+ server_port=7860
230
+ )
kaggle/input/2025-sep-dl-gen-ai-project/sample_submission.csv ADDED
@@ -0,0 +1,1708 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ id,anger,fear,joy,sadness,surprise
2
+ 0,1,0,0,0,1
3
+ 1,0,1,1,1,0
4
+ 2,1,1,0,0,1
5
+ 3,0,0,0,0,1
6
+ 4,1,1,1,0,0
7
+ 5,1,0,0,0,1
8
+ 6,0,0,0,1,0
9
+ 7,0,0,0,1,1
10
+ 8,0,0,1,1,1
11
+ 9,0,1,0,1,1
12
+ 10,1,1,1,0,0
13
+ 11,1,1,1,1,0
14
+ 12,0,1,0,1,0
15
+ 13,0,0,0,1,1
16
+ 14,0,1,1,0,1
17
+ 15,0,1,0,0,0
18
+ 16,0,1,0,1,0
19
+ 17,1,0,0,0,0
20
+ 18,0,1,0,0,1
21
+ 19,0,1,1,0,0
22
+ 20,1,0,0,1,0
23
+ 21,1,1,1,0,1
24
+ 22,0,0,1,0,1
25
+ 23,1,0,1,0,1
26
+ 24,1,1,0,1,0
27
+ 25,0,1,1,1,1
28
+ 26,0,0,0,0,1
29
+ 27,0,1,0,0,1
30
+ 28,0,1,1,1,1
31
+ 29,1,0,1,0,1
32
+ 30,0,1,1,1,0
33
+ 31,1,1,1,1,1
34
+ 32,0,0,1,0,0
35
+ 33,0,1,0,1,1
36
+ 34,0,0,0,0,1
37
+ 35,1,1,1,0,0
38
+ 36,1,1,0,0,0
39
+ 37,0,0,0,1,1
40
+ 38,1,0,0,0,0
41
+ 39,0,1,0,0,0
42
+ 40,0,0,1,1,0
43
+ 41,1,1,0,0,1
44
+ 42,1,1,0,0,1
45
+ 43,1,0,0,1,0
46
+ 44,1,0,1,0,0
47
+ 45,0,0,0,1,0
48
+ 46,1,0,1,0,1
49
+ 47,1,0,0,1,0
50
+ 48,1,0,1,1,1
51
+ 49,1,1,1,0,0
52
+ 50,0,0,0,1,1
53
+ 51,1,1,1,1,0
54
+ 52,1,1,0,0,1
55
+ 53,0,0,1,1,0
56
+ 54,0,0,0,0,0
57
+ 55,0,0,0,1,0
58
+ 56,0,0,0,1,0
59
+ 57,0,1,0,0,0
60
+ 58,1,0,0,0,0
61
+ 59,0,0,0,1,1
62
+ 60,0,0,1,0,0
63
+ 61,1,0,0,0,1
64
+ 62,1,1,1,0,1
65
+ 63,0,0,0,0,0
66
+ 64,0,0,0,1,0
67
+ 65,0,1,1,0,0
68
+ 66,1,1,0,1,0
69
+ 67,1,0,0,0,0
70
+ 68,1,0,0,1,1
71
+ 69,1,1,0,1,1
72
+ 70,0,0,1,1,1
73
+ 71,0,1,1,0,0
74
+ 72,1,1,0,1,1
75
+ 73,1,1,1,1,1
76
+ 74,1,1,1,0,1
77
+ 75,1,1,0,0,1
78
+ 76,0,1,0,1,1
79
+ 77,1,1,0,1,0
80
+ 78,0,1,1,1,1
81
+ 79,0,1,0,0,1
82
+ 80,0,0,1,0,1
83
+ 81,1,0,1,1,1
84
+ 82,1,0,1,0,1
85
+ 83,0,1,0,0,1
86
+ 84,0,1,0,1,0
87
+ 85,0,0,0,1,0
88
+ 86,1,1,1,1,1
89
+ 87,1,0,1,1,0
90
+ 88,0,1,0,1,0
91
+ 89,1,1,1,1,1
92
+ 90,1,1,0,1,1
93
+ 91,0,1,0,0,0
94
+ 92,1,0,0,0,1
95
+ 93,1,0,0,1,1
96
+ 94,1,1,0,1,0
97
+ 95,0,1,1,0,1
98
+ 96,0,1,0,0,1
99
+ 97,1,0,0,0,0
100
+ 98,1,1,1,1,1
101
+ 99,0,0,0,0,0
102
+ 100,0,1,1,1,0
103
+ 101,0,1,1,1,1
104
+ 102,1,1,1,1,0
105
+ 103,1,0,0,1,1
106
+ 104,0,0,0,1,0
107
+ 105,0,0,0,1,0
108
+ 106,0,1,1,0,0
109
+ 107,0,1,1,0,1
110
+ 108,1,1,0,1,1
111
+ 109,1,0,0,0,0
112
+ 110,0,1,1,1,1
113
+ 111,1,1,1,1,0
114
+ 112,0,0,1,1,0
115
+ 113,1,0,0,0,1
116
+ 114,1,0,0,0,0
117
+ 115,0,1,1,0,1
118
+ 116,0,0,0,0,0
119
+ 117,0,0,0,0,1
120
+ 118,1,1,0,0,0
121
+ 119,1,1,0,1,1
122
+ 120,0,1,1,1,1
123
+ 121,0,0,0,1,1
124
+ 122,0,1,0,0,0
125
+ 123,1,1,0,1,0
126
+ 124,1,1,0,0,0
127
+ 125,1,0,0,0,0
128
+ 126,0,1,0,1,0
129
+ 127,1,0,1,0,0
130
+ 128,1,0,0,0,1
131
+ 129,0,0,0,1,0
132
+ 130,1,1,0,0,1
133
+ 131,0,1,0,0,1
134
+ 132,0,1,0,1,1
135
+ 133,1,0,1,0,1
136
+ 134,1,1,0,0,0
137
+ 135,1,1,0,0,0
138
+ 136,1,1,1,1,0
139
+ 137,1,1,0,1,0
140
+ 138,0,1,0,1,0
141
+ 139,0,1,1,1,1
142
+ 140,0,0,1,0,0
143
+ 141,0,0,1,1,0
144
+ 142,0,1,1,0,1
145
+ 143,1,0,0,0,0
146
+ 144,0,0,1,1,1
147
+ 145,0,0,0,0,1
148
+ 146,0,1,0,0,0
149
+ 147,1,1,0,0,1
150
+ 148,1,0,0,0,0
151
+ 149,1,1,1,1,0
152
+ 150,1,1,0,1,1
153
+ 151,0,1,1,0,0
154
+ 152,1,1,1,1,0
155
+ 153,1,1,1,1,0
156
+ 154,1,1,0,1,0
157
+ 155,1,1,1,0,1
158
+ 156,0,1,0,1,1
159
+ 157,1,0,0,1,1
160
+ 158,1,1,1,0,0
161
+ 159,1,0,1,1,0
162
+ 160,1,1,0,1,0
163
+ 161,0,1,0,0,1
164
+ 162,1,1,1,0,1
165
+ 163,1,0,0,0,1
166
+ 164,0,1,1,1,1
167
+ 165,0,0,1,1,0
168
+ 166,0,0,0,0,1
169
+ 167,1,0,0,0,1
170
+ 168,0,0,0,1,0
171
+ 169,0,0,1,1,1
172
+ 170,0,1,0,1,1
173
+ 171,0,1,1,1,1
174
+ 172,0,0,1,1,0
175
+ 173,0,1,1,0,0
176
+ 174,1,0,1,1,1
177
+ 175,0,1,1,1,1
178
+ 176,0,1,0,0,0
179
+ 177,1,0,1,1,1
180
+ 178,0,0,1,1,0
181
+ 179,0,0,1,1,0
182
+ 180,0,1,0,1,0
183
+ 181,1,0,0,0,0
184
+ 182,1,0,1,1,1
185
+ 183,1,1,0,0,0
186
+ 184,0,0,0,1,0
187
+ 185,0,0,0,0,1
188
+ 186,1,0,1,0,1
189
+ 187,0,0,0,1,0
190
+ 188,0,1,0,0,0
191
+ 189,1,0,0,0,0
192
+ 190,0,0,0,1,1
193
+ 191,0,1,0,1,0
194
+ 192,0,1,0,0,0
195
+ 193,0,0,0,0,0
196
+ 194,1,0,0,0,1
197
+ 195,1,1,1,1,1
198
+ 196,0,0,0,1,1
199
+ 197,0,1,0,0,0
200
+ 198,0,1,0,1,1
201
+ 199,1,1,1,1,1
202
+ 200,1,1,0,0,1
203
+ 201,0,0,1,1,0
204
+ 202,0,0,1,1,1
205
+ 203,0,0,1,0,1
206
+ 204,1,1,0,0,1
207
+ 205,0,1,1,0,0
208
+ 206,0,1,0,1,0
209
+ 207,0,0,1,0,0
210
+ 208,0,1,0,0,1
211
+ 209,1,1,1,1,1
212
+ 210,1,0,1,1,0
213
+ 211,1,0,1,1,0
214
+ 212,1,1,1,1,1
215
+ 213,1,0,1,1,1
216
+ 214,0,1,0,1,1
217
+ 215,0,1,1,1,1
218
+ 216,1,0,0,0,0
219
+ 217,1,0,0,0,0
220
+ 218,0,1,0,1,0
221
+ 219,0,0,0,0,1
222
+ 220,0,0,1,1,0
223
+ 221,0,0,1,1,0
224
+ 222,1,1,0,0,0
225
+ 223,0,0,1,1,1
226
+ 224,1,0,0,0,1
227
+ 225,1,1,0,0,1
228
+ 226,0,0,1,0,1
229
+ 227,0,0,1,0,0
230
+ 228,1,1,1,0,1
231
+ 229,1,1,1,1,1
232
+ 230,1,1,0,1,1
233
+ 231,0,0,1,0,0
234
+ 232,0,0,1,1,1
235
+ 233,0,1,0,1,0
236
+ 234,0,0,0,1,0
237
+ 235,1,0,0,0,0
238
+ 236,0,1,0,0,1
239
+ 237,1,1,1,1,0
240
+ 238,0,0,1,0,1
241
+ 239,1,0,1,1,0
242
+ 240,1,1,0,0,0
243
+ 241,0,1,1,1,1
244
+ 242,1,0,0,0,1
245
+ 243,1,1,0,1,1
246
+ 244,0,1,1,1,1
247
+ 245,0,0,1,0,1
248
+ 246,1,1,1,1,1
249
+ 247,1,1,0,0,1
250
+ 248,1,0,0,0,1
251
+ 249,0,1,0,1,1
252
+ 250,1,1,0,1,1
253
+ 251,0,0,0,1,0
254
+ 252,0,1,0,0,0
255
+ 253,1,0,1,1,1
256
+ 254,1,1,1,1,1
257
+ 255,0,1,1,0,1
258
+ 256,1,0,0,0,0
259
+ 257,1,0,0,0,0
260
+ 258,1,1,1,1,0
261
+ 259,0,0,0,0,1
262
+ 260,1,1,0,1,1
263
+ 261,0,1,0,0,1
264
+ 262,1,0,0,1,1
265
+ 263,0,0,0,1,0
266
+ 264,0,1,0,1,0
267
+ 265,0,1,0,0,0
268
+ 266,1,0,1,0,0
269
+ 267,0,0,0,1,0
270
+ 268,1,1,0,0,0
271
+ 269,1,0,1,0,0
272
+ 270,0,0,0,0,0
273
+ 271,1,0,0,1,1
274
+ 272,1,0,0,0,1
275
+ 273,1,1,0,0,1
276
+ 274,1,0,1,0,1
277
+ 275,0,0,1,1,0
278
+ 276,1,1,0,1,0
279
+ 277,1,1,0,1,0
280
+ 278,0,1,1,1,1
281
+ 279,1,0,0,1,0
282
+ 280,1,1,1,1,0
283
+ 281,0,0,1,0,0
284
+ 282,0,0,1,1,1
285
+ 283,1,0,1,1,1
286
+ 284,1,1,0,1,1
287
+ 285,0,1,1,1,1
288
+ 286,0,0,0,0,1
289
+ 287,0,1,1,0,0
290
+ 288,1,1,0,1,1
291
+ 289,0,0,0,0,0
292
+ 290,0,1,0,0,0
293
+ 291,1,1,0,0,0
294
+ 292,0,0,1,0,0
295
+ 293,0,1,1,1,1
296
+ 294,1,1,0,1,1
297
+ 295,0,0,1,0,0
298
+ 296,1,0,0,1,0
299
+ 297,0,1,1,1,1
300
+ 298,1,0,0,1,1
301
+ 299,1,1,0,0,1
302
+ 300,0,1,1,0,1
303
+ 301,1,1,1,1,1
304
+ 302,0,0,1,1,1
305
+ 303,1,1,1,0,0
306
+ 304,1,0,0,0,1
307
+ 305,0,1,0,1,0
308
+ 306,0,1,1,1,1
309
+ 307,0,0,0,1,0
310
+ 308,0,1,0,1,0
311
+ 309,0,1,1,1,0
312
+ 310,0,1,0,0,1
313
+ 311,0,1,0,1,0
314
+ 312,1,0,0,1,0
315
+ 313,1,0,0,0,1
316
+ 314,0,0,0,1,0
317
+ 315,0,1,0,0,1
318
+ 316,0,0,0,0,0
319
+ 317,0,1,0,0,1
320
+ 318,1,1,1,1,0
321
+ 319,1,0,0,1,1
322
+ 320,1,0,0,1,0
323
+ 321,1,0,1,0,1
324
+ 322,1,1,0,1,0
325
+ 323,0,0,0,0,1
326
+ 324,1,1,1,0,0
327
+ 325,0,0,1,0,1
328
+ 326,0,1,1,0,0
329
+ 327,0,0,1,0,0
330
+ 328,0,0,0,1,0
331
+ 329,0,0,1,1,1
332
+ 330,1,1,1,0,1
333
+ 331,0,0,1,1,0
334
+ 332,0,1,0,1,0
335
+ 333,0,0,1,0,1
336
+ 334,1,1,1,0,0
337
+ 335,0,0,0,1,1
338
+ 336,1,0,0,0,1
339
+ 337,0,0,0,1,0
340
+ 338,0,1,1,0,0
341
+ 339,1,0,1,0,1
342
+ 340,1,1,1,0,0
343
+ 341,0,1,0,0,0
344
+ 342,1,0,1,0,0
345
+ 343,1,1,1,1,0
346
+ 344,0,1,0,1,1
347
+ 345,0,1,1,0,0
348
+ 346,1,1,0,1,1
349
+ 347,1,0,0,0,0
350
+ 348,1,0,0,1,1
351
+ 349,0,1,1,0,1
352
+ 350,0,1,0,1,1
353
+ 351,1,0,1,1,1
354
+ 352,0,1,0,0,1
355
+ 353,0,0,1,0,0
356
+ 354,1,0,1,0,1
357
+ 355,0,0,1,0,1
358
+ 356,1,0,1,1,0
359
+ 357,1,1,0,1,0
360
+ 358,0,0,0,1,1
361
+ 359,1,0,1,1,0
362
+ 360,0,0,1,1,1
363
+ 361,0,0,1,1,1
364
+ 362,0,1,0,1,0
365
+ 363,0,0,1,0,0
366
+ 364,0,1,1,0,1
367
+ 365,1,1,1,1,0
368
+ 366,0,0,1,1,1
369
+ 367,0,1,1,0,0
370
+ 368,0,1,1,0,1
371
+ 369,1,1,0,0,1
372
+ 370,0,0,0,0,1
373
+ 371,1,0,1,0,1
374
+ 372,1,1,1,1,0
375
+ 373,1,1,1,1,0
376
+ 374,0,0,0,0,0
377
+ 375,0,0,0,1,0
378
+ 376,1,0,0,0,1
379
+ 377,0,0,0,1,1
380
+ 378,0,1,1,0,1
381
+ 379,0,1,1,0,0
382
+ 380,1,1,1,1,0
383
+ 381,1,1,0,1,0
384
+ 382,1,0,0,1,0
385
+ 383,1,0,1,0,0
386
+ 384,1,1,1,0,1
387
+ 385,0,0,0,1,1
388
+ 386,1,1,0,0,1
389
+ 387,0,1,0,1,1
390
+ 388,0,1,1,1,0
391
+ 389,0,1,0,0,0
392
+ 390,1,0,1,1,0
393
+ 391,1,0,1,1,0
394
+ 392,0,1,0,1,1
395
+ 393,0,1,0,1,1
396
+ 394,0,0,1,1,1
397
+ 395,1,0,0,0,1
398
+ 396,0,1,0,0,0
399
+ 397,1,0,1,0,1
400
+ 398,1,0,0,1,0
401
+ 399,1,1,0,0,0
402
+ 400,0,0,1,0,1
403
+ 401,1,1,1,1,0
404
+ 402,1,0,1,1,0
405
+ 403,1,1,0,1,0
406
+ 404,1,1,0,0,1
407
+ 405,1,1,1,1,0
408
+ 406,1,0,0,0,0
409
+ 407,1,0,0,0,0
410
+ 408,1,0,1,1,0
411
+ 409,0,1,1,0,0
412
+ 410,1,1,0,0,0
413
+ 411,1,0,1,1,0
414
+ 412,0,1,1,0,0
415
+ 413,1,0,1,1,1
416
+ 414,1,1,0,0,0
417
+ 415,1,1,0,0,0
418
+ 416,0,1,1,0,1
419
+ 417,0,0,1,0,1
420
+ 418,0,0,1,1,0
421
+ 419,0,1,0,0,1
422
+ 420,1,1,1,1,1
423
+ 421,1,1,0,1,0
424
+ 422,0,0,1,1,1
425
+ 423,0,1,1,0,0
426
+ 424,1,0,0,0,0
427
+ 425,0,1,0,0,0
428
+ 426,1,0,0,1,1
429
+ 427,1,0,0,0,1
430
+ 428,1,0,1,1,0
431
+ 429,1,1,0,0,1
432
+ 430,0,1,1,0,0
433
+ 431,0,1,0,0,1
434
+ 432,1,0,1,0,0
435
+ 433,1,1,0,1,0
436
+ 434,0,1,0,0,0
437
+ 435,1,1,1,1,1
438
+ 436,1,0,0,0,0
439
+ 437,0,1,0,1,1
440
+ 438,0,1,0,0,0
441
+ 439,0,0,0,1,1
442
+ 440,0,1,1,0,1
443
+ 441,0,0,1,0,0
444
+ 442,0,1,0,1,1
445
+ 443,1,1,0,0,0
446
+ 444,1,1,0,0,1
447
+ 445,0,0,0,0,1
448
+ 446,0,0,1,0,1
449
+ 447,0,0,1,1,1
450
+ 448,1,0,0,0,0
451
+ 449,0,1,0,1,1
452
+ 450,0,0,1,1,1
453
+ 451,0,1,1,0,0
454
+ 452,0,1,0,1,0
455
+ 453,1,1,1,0,1
456
+ 454,1,1,1,0,0
457
+ 455,1,1,1,0,0
458
+ 456,1,1,1,0,0
459
+ 457,1,0,0,0,0
460
+ 458,0,0,0,1,0
461
+ 459,1,1,0,0,0
462
+ 460,0,0,0,1,0
463
+ 461,1,1,1,1,0
464
+ 462,0,0,1,1,1
465
+ 463,0,0,1,0,0
466
+ 464,0,1,1,1,1
467
+ 465,0,1,0,1,1
468
+ 466,0,0,0,1,1
469
+ 467,1,1,1,1,1
470
+ 468,1,1,1,1,1
471
+ 469,0,0,1,1,0
472
+ 470,1,1,0,1,1
473
+ 471,0,1,1,1,0
474
+ 472,0,1,0,0,1
475
+ 473,1,1,0,0,1
476
+ 474,1,0,1,0,1
477
+ 475,1,0,1,0,0
478
+ 476,1,1,1,0,1
479
+ 477,1,0,1,1,1
480
+ 478,1,0,0,1,0
481
+ 479,0,1,0,0,0
482
+ 480,1,0,0,1,0
483
+ 481,1,0,1,0,1
484
+ 482,1,0,0,0,0
485
+ 483,0,1,1,0,1
486
+ 484,1,1,1,1,0
487
+ 485,0,0,0,0,0
488
+ 486,1,1,1,0,0
489
+ 487,0,1,1,1,0
490
+ 488,1,1,1,0,0
491
+ 489,1,1,1,1,0
492
+ 490,0,0,0,0,1
493
+ 491,0,0,1,0,0
494
+ 492,0,1,0,1,0
495
+ 493,1,0,1,0,0
496
+ 494,1,0,0,1,0
497
+ 495,0,0,1,1,1
498
+ 496,1,0,0,0,0
499
+ 497,0,1,1,1,1
500
+ 498,1,1,1,1,0
501
+ 499,1,0,1,1,1
502
+ 500,1,1,1,0,1
503
+ 501,0,0,0,1,0
504
+ 502,0,0,0,0,0
505
+ 503,1,1,0,0,0
506
+ 504,1,1,1,1,0
507
+ 505,1,1,1,0,0
508
+ 506,0,1,0,1,0
509
+ 507,0,1,0,1,0
510
+ 508,1,0,0,1,1
511
+ 509,1,0,0,1,0
512
+ 510,0,1,0,1,1
513
+ 511,0,0,0,1,1
514
+ 512,0,1,1,1,0
515
+ 513,1,1,0,1,0
516
+ 514,1,1,1,0,0
517
+ 515,1,0,0,0,0
518
+ 516,0,1,1,0,0
519
+ 517,0,0,0,1,0
520
+ 518,1,1,0,1,1
521
+ 519,0,1,0,0,0
522
+ 520,0,0,0,0,1
523
+ 521,1,0,1,0,1
524
+ 522,1,1,0,1,1
525
+ 523,1,0,0,0,0
526
+ 524,0,0,1,1,0
527
+ 525,1,0,1,0,1
528
+ 526,1,1,0,0,0
529
+ 527,1,0,1,0,0
530
+ 528,1,0,1,1,1
531
+ 529,0,1,0,0,0
532
+ 530,0,0,0,0,1
533
+ 531,0,1,1,0,0
534
+ 532,0,1,1,0,1
535
+ 533,1,0,1,1,0
536
+ 534,1,1,1,1,0
537
+ 535,1,0,0,1,1
538
+ 536,1,1,1,0,1
539
+ 537,1,1,0,0,1
540
+ 538,0,1,0,1,1
541
+ 539,0,1,0,1,1
542
+ 540,0,1,0,1,1
543
+ 541,1,1,1,1,0
544
+ 542,1,1,0,1,1
545
+ 543,0,0,1,0,0
546
+ 544,0,1,0,1,0
547
+ 545,1,1,1,0,1
548
+ 546,0,1,1,0,0
549
+ 547,0,1,0,0,1
550
+ 548,1,1,0,1,0
551
+ 549,1,0,1,1,0
552
+ 550,0,1,0,0,0
553
+ 551,1,0,1,0,0
554
+ 552,0,0,0,1,1
555
+ 553,0,0,1,1,1
556
+ 554,0,0,1,1,0
557
+ 555,0,0,0,0,0
558
+ 556,0,0,1,0,1
559
+ 557,0,1,0,0,0
560
+ 558,1,1,1,0,1
561
+ 559,1,1,0,1,1
562
+ 560,1,0,0,1,1
563
+ 561,0,0,1,0,0
564
+ 562,0,1,1,0,1
565
+ 563,0,1,1,1,1
566
+ 564,1,1,1,0,0
567
+ 565,0,1,1,1,0
568
+ 566,1,1,1,1,0
569
+ 567,1,0,0,0,0
570
+ 568,1,1,0,0,1
571
+ 569,1,1,0,1,1
572
+ 570,1,1,1,1,1
573
+ 571,1,1,0,0,1
574
+ 572,0,1,0,1,1
575
+ 573,1,1,0,1,1
576
+ 574,0,1,0,0,0
577
+ 575,0,1,0,1,1
578
+ 576,0,1,0,0,1
579
+ 577,0,0,1,0,1
580
+ 578,0,0,0,0,0
581
+ 579,1,0,1,0,1
582
+ 580,1,0,0,1,0
583
+ 581,1,1,0,0,1
584
+ 582,0,1,0,0,0
585
+ 583,0,1,1,1,1
586
+ 584,0,0,1,1,1
587
+ 585,1,0,0,0,1
588
+ 586,1,1,1,0,0
589
+ 587,0,0,0,1,1
590
+ 588,0,0,1,0,0
591
+ 589,1,0,1,1,1
592
+ 590,0,0,1,1,1
593
+ 591,0,1,0,0,0
594
+ 592,0,1,1,1,0
595
+ 593,0,0,0,0,1
596
+ 594,0,0,1,1,1
597
+ 595,1,1,0,0,0
598
+ 596,1,0,0,1,1
599
+ 597,1,1,0,1,0
600
+ 598,0,1,1,0,0
601
+ 599,1,1,0,1,1
602
+ 600,1,1,0,0,0
603
+ 601,1,1,0,0,0
604
+ 602,1,1,1,1,1
605
+ 603,1,0,0,0,0
606
+ 604,0,0,1,0,1
607
+ 605,1,1,1,1,0
608
+ 606,1,1,1,0,1
609
+ 607,1,1,1,0,0
610
+ 608,1,0,0,0,1
611
+ 609,0,1,1,0,0
612
+ 610,0,0,0,0,0
613
+ 611,1,0,1,0,1
614
+ 612,1,1,0,1,0
615
+ 613,1,1,1,0,0
616
+ 614,1,0,0,1,1
617
+ 615,0,0,0,1,1
618
+ 616,1,0,1,0,1
619
+ 617,1,1,0,0,0
620
+ 618,0,0,1,0,0
621
+ 619,0,1,1,0,0
622
+ 620,0,1,0,0,0
623
+ 621,1,1,0,0,0
624
+ 622,1,1,1,1,0
625
+ 623,0,1,0,0,1
626
+ 624,1,1,1,0,1
627
+ 625,0,1,0,1,1
628
+ 626,0,0,1,0,1
629
+ 627,1,1,0,1,1
630
+ 628,1,1,1,1,1
631
+ 629,1,1,0,1,1
632
+ 630,1,0,0,1,1
633
+ 631,1,1,1,1,1
634
+ 632,1,1,1,0,0
635
+ 633,1,1,0,0,0
636
+ 634,0,0,0,0,0
637
+ 635,0,1,1,0,0
638
+ 636,1,0,0,0,0
639
+ 637,1,0,1,1,0
640
+ 638,1,0,1,1,0
641
+ 639,1,1,1,0,0
642
+ 640,0,1,0,1,0
643
+ 641,0,0,1,0,1
644
+ 642,0,0,0,1,0
645
+ 643,1,1,0,0,1
646
+ 644,1,1,0,0,0
647
+ 645,0,1,0,0,0
648
+ 646,1,1,1,1,1
649
+ 647,1,1,0,0,1
650
+ 648,1,0,1,0,0
651
+ 649,0,0,1,1,0
652
+ 650,0,0,1,0,0
653
+ 651,1,0,0,1,1
654
+ 652,1,1,0,0,1
655
+ 653,0,0,0,1,1
656
+ 654,1,1,1,1,1
657
+ 655,0,0,0,0,0
658
+ 656,1,1,0,1,1
659
+ 657,0,0,0,0,0
660
+ 658,1,1,0,0,0
661
+ 659,1,0,1,0,1
662
+ 660,1,1,1,1,1
663
+ 661,0,0,0,1,1
664
+ 662,0,1,1,0,1
665
+ 663,0,1,1,0,1
666
+ 664,1,0,0,1,0
667
+ 665,0,0,0,0,0
668
+ 666,1,1,1,0,0
669
+ 667,0,1,1,1,0
670
+ 668,0,0,1,0,1
671
+ 669,0,0,1,0,1
672
+ 670,1,0,0,0,1
673
+ 671,0,1,1,1,0
674
+ 672,1,1,1,0,0
675
+ 673,1,1,1,1,0
676
+ 674,0,0,0,1,1
677
+ 675,1,0,0,1,0
678
+ 676,0,0,0,1,1
679
+ 677,1,1,0,1,0
680
+ 678,1,0,0,1,0
681
+ 679,0,1,1,1,0
682
+ 680,0,0,1,0,0
683
+ 681,0,0,0,0,1
684
+ 682,0,0,1,0,1
685
+ 683,0,1,0,1,0
686
+ 684,1,1,0,0,1
687
+ 685,1,1,1,1,1
688
+ 686,0,0,1,1,0
689
+ 687,0,0,0,0,1
690
+ 688,0,1,1,0,0
691
+ 689,1,0,0,0,0
692
+ 690,1,0,1,0,1
693
+ 691,0,0,0,1,0
694
+ 692,1,0,0,1,1
695
+ 693,1,1,0,1,0
696
+ 694,0,1,0,0,0
697
+ 695,0,1,1,0,0
698
+ 696,0,0,1,1,0
699
+ 697,1,1,1,1,0
700
+ 698,0,1,1,1,0
701
+ 699,0,0,0,1,0
702
+ 700,1,1,1,0,0
703
+ 701,1,1,1,0,0
704
+ 702,0,1,0,1,1
705
+ 703,0,1,1,1,1
706
+ 704,0,0,0,1,1
707
+ 705,0,0,1,1,1
708
+ 706,1,0,0,0,1
709
+ 707,1,1,1,0,1
710
+ 708,0,1,0,0,1
711
+ 709,1,1,0,0,1
712
+ 710,1,1,0,0,1
713
+ 711,1,0,0,1,0
714
+ 712,0,0,0,1,0
715
+ 713,1,0,0,1,1
716
+ 714,1,0,1,0,1
717
+ 715,1,0,0,1,1
718
+ 716,1,1,1,1,0
719
+ 717,0,0,0,0,1
720
+ 718,1,1,0,1,1
721
+ 719,1,1,1,1,1
722
+ 720,0,1,1,0,1
723
+ 721,1,0,1,1,1
724
+ 722,0,0,1,1,0
725
+ 723,0,0,0,0,0
726
+ 724,1,0,0,0,0
727
+ 725,0,0,1,0,0
728
+ 726,1,1,1,0,1
729
+ 727,1,1,0,0,1
730
+ 728,0,1,1,1,1
731
+ 729,1,0,1,1,0
732
+ 730,0,0,1,1,1
733
+ 731,0,0,1,1,0
734
+ 732,1,1,0,0,0
735
+ 733,1,1,0,0,1
736
+ 734,0,0,0,0,0
737
+ 735,0,1,0,1,0
738
+ 736,1,1,0,1,1
739
+ 737,0,0,1,0,0
740
+ 738,0,1,0,1,1
741
+ 739,1,1,0,1,0
742
+ 740,0,1,0,0,1
743
+ 741,1,0,1,1,1
744
+ 742,1,0,0,0,0
745
+ 743,0,1,0,0,1
746
+ 744,0,0,0,1,1
747
+ 745,1,0,0,0,0
748
+ 746,0,1,1,1,1
749
+ 747,1,0,0,1,1
750
+ 748,1,0,0,1,1
751
+ 749,0,0,0,0,1
752
+ 750,0,1,0,0,1
753
+ 751,0,0,1,1,1
754
+ 752,0,1,0,1,1
755
+ 753,1,1,1,1,0
756
+ 754,1,1,0,0,0
757
+ 755,0,0,0,1,0
758
+ 756,0,0,1,0,1
759
+ 757,1,1,1,0,0
760
+ 758,0,0,0,0,1
761
+ 759,0,0,1,0,0
762
+ 760,0,0,0,1,1
763
+ 761,1,0,1,1,1
764
+ 762,1,0,1,1,0
765
+ 763,1,1,1,1,1
766
+ 764,1,0,1,1,1
767
+ 765,0,1,0,1,0
768
+ 766,1,0,0,1,1
769
+ 767,0,0,1,0,0
770
+ 768,0,1,0,1,1
771
+ 769,0,0,0,1,1
772
+ 770,0,0,1,1,0
773
+ 771,1,1,1,0,1
774
+ 772,1,0,0,1,0
775
+ 773,1,1,0,1,1
776
+ 774,1,1,1,0,0
777
+ 775,0,0,0,0,0
778
+ 776,1,1,1,1,0
779
+ 777,0,1,0,1,0
780
+ 778,0,1,0,1,1
781
+ 779,0,0,1,1,0
782
+ 780,1,1,0,0,0
783
+ 781,0,1,0,1,0
784
+ 782,1,1,0,1,1
785
+ 783,1,0,1,1,0
786
+ 784,0,1,1,1,1
787
+ 785,0,1,1,0,1
788
+ 786,1,0,1,1,1
789
+ 787,0,1,1,1,0
790
+ 788,1,0,1,0,0
791
+ 789,0,0,0,1,0
792
+ 790,0,0,0,0,1
793
+ 791,0,1,1,0,1
794
+ 792,0,1,1,0,0
795
+ 793,1,1,0,0,0
796
+ 794,0,0,1,0,0
797
+ 795,1,0,1,0,0
798
+ 796,0,1,1,1,1
799
+ 797,1,1,1,0,0
800
+ 798,0,0,0,0,0
801
+ 799,0,1,0,0,0
802
+ 800,0,1,1,0,1
803
+ 801,1,0,0,1,0
804
+ 802,0,1,1,1,1
805
+ 803,0,0,1,1,0
806
+ 804,0,0,0,1,1
807
+ 805,1,1,0,1,1
808
+ 806,1,1,0,0,1
809
+ 807,0,0,1,1,1
810
+ 808,0,1,0,1,0
811
+ 809,0,1,0,0,0
812
+ 810,0,0,0,1,1
813
+ 811,0,0,1,1,0
814
+ 812,1,0,0,0,0
815
+ 813,0,0,1,1,1
816
+ 814,1,1,0,0,1
817
+ 815,1,0,1,0,1
818
+ 816,0,0,0,0,1
819
+ 817,0,0,0,0,1
820
+ 818,0,0,1,0,1
821
+ 819,1,0,0,0,1
822
+ 820,1,1,0,1,0
823
+ 821,1,1,1,0,0
824
+ 822,1,0,1,0,1
825
+ 823,0,0,0,0,0
826
+ 824,1,0,0,0,0
827
+ 825,1,1,1,0,1
828
+ 826,1,1,0,0,1
829
+ 827,1,1,0,1,0
830
+ 828,0,1,0,1,0
831
+ 829,1,0,1,1,0
832
+ 830,0,0,0,1,1
833
+ 831,1,0,0,1,1
834
+ 832,0,0,1,0,0
835
+ 833,0,0,1,1,0
836
+ 834,1,1,0,1,1
837
+ 835,1,1,1,0,0
838
+ 836,0,1,0,1,0
839
+ 837,1,1,1,0,0
840
+ 838,0,1,1,0,1
841
+ 839,1,0,0,0,1
842
+ 840,1,0,1,0,1
843
+ 841,0,0,0,1,1
844
+ 842,0,0,1,0,0
845
+ 843,1,0,1,0,1
846
+ 844,1,0,0,1,0
847
+ 845,1,0,0,1,1
848
+ 846,1,1,0,0,0
849
+ 847,0,0,0,0,1
850
+ 848,1,0,0,1,0
851
+ 849,1,0,1,1,1
852
+ 850,0,0,0,1,1
853
+ 851,0,1,1,0,1
854
+ 852,0,0,0,0,0
855
+ 853,1,0,1,0,0
856
+ 854,0,1,1,0,1
857
+ 855,0,1,0,0,0
858
+ 856,0,0,0,1,0
859
+ 857,0,1,1,0,1
860
+ 858,1,0,0,0,0
861
+ 859,0,1,0,1,1
862
+ 860,1,1,0,0,1
863
+ 861,1,1,0,0,1
864
+ 862,0,0,0,1,1
865
+ 863,0,1,1,1,1
866
+ 864,1,1,1,1,0
867
+ 865,0,0,0,0,1
868
+ 866,1,1,0,0,0
869
+ 867,0,0,0,1,1
870
+ 868,1,0,1,0,0
871
+ 869,0,0,0,1,0
872
+ 870,0,1,1,0,1
873
+ 871,0,1,1,1,1
874
+ 872,1,1,1,1,0
875
+ 873,0,0,1,0,1
876
+ 874,0,0,1,0,0
877
+ 875,1,0,0,0,1
878
+ 876,0,0,0,0,1
879
+ 877,1,0,0,0,0
880
+ 878,0,0,0,1,1
881
+ 879,0,1,0,0,1
882
+ 880,1,1,1,1,0
883
+ 881,0,0,0,0,0
884
+ 882,0,0,0,1,1
885
+ 883,0,1,0,0,1
886
+ 884,0,1,0,1,1
887
+ 885,0,0,1,0,0
888
+ 886,0,0,0,1,0
889
+ 887,0,1,1,0,1
890
+ 888,1,0,0,1,0
891
+ 889,1,0,1,0,1
892
+ 890,1,0,1,1,1
893
+ 891,0,0,1,1,1
894
+ 892,1,1,0,1,0
895
+ 893,0,1,1,0,0
896
+ 894,0,0,0,0,1
897
+ 895,1,1,1,1,0
898
+ 896,1,0,1,1,1
899
+ 897,0,1,1,0,0
900
+ 898,1,1,0,0,1
901
+ 899,0,0,0,1,0
902
+ 900,0,1,0,0,0
903
+ 901,0,1,0,0,1
904
+ 902,1,1,0,1,0
905
+ 903,1,0,1,1,0
906
+ 904,0,1,0,0,0
907
+ 905,0,0,0,1,1
908
+ 906,0,0,1,0,1
909
+ 907,0,1,1,0,1
910
+ 908,1,1,0,0,1
911
+ 909,1,0,0,1,0
912
+ 910,0,1,1,1,0
913
+ 911,0,1,1,1,0
914
+ 912,0,1,0,1,1
915
+ 913,1,1,0,0,1
916
+ 914,0,0,0,1,0
917
+ 915,0,0,0,0,1
918
+ 916,0,0,1,1,0
919
+ 917,1,1,0,1,0
920
+ 918,1,0,0,1,0
921
+ 919,1,0,1,0,0
922
+ 920,1,0,0,1,0
923
+ 921,1,0,1,1,0
924
+ 922,1,0,1,1,1
925
+ 923,0,1,1,0,1
926
+ 924,1,0,1,1,0
927
+ 925,0,0,1,1,0
928
+ 926,1,0,0,0,1
929
+ 927,0,1,1,0,0
930
+ 928,0,1,1,0,1
931
+ 929,1,1,1,0,0
932
+ 930,0,0,1,1,0
933
+ 931,0,0,0,0,1
934
+ 932,0,0,1,0,1
935
+ 933,1,1,0,0,0
936
+ 934,1,0,0,0,0
937
+ 935,1,0,0,1,1
938
+ 936,0,1,1,1,0
939
+ 937,0,0,0,0,0
940
+ 938,1,0,0,1,0
941
+ 939,0,1,0,1,0
942
+ 940,1,1,0,1,1
943
+ 941,0,0,0,0,0
944
+ 942,1,0,1,0,0
945
+ 943,1,1,0,0,0
946
+ 944,1,0,1,0,0
947
+ 945,1,1,1,0,1
948
+ 946,1,0,1,0,1
949
+ 947,1,0,0,1,1
950
+ 948,1,1,1,1,0
951
+ 949,1,1,0,1,1
952
+ 950,0,0,0,0,1
953
+ 951,1,1,0,1,1
954
+ 952,0,0,0,1,1
955
+ 953,0,1,0,0,0
956
+ 954,0,1,0,1,0
957
+ 955,0,0,0,0,1
958
+ 956,1,1,1,0,1
959
+ 957,0,0,0,1,0
960
+ 958,1,1,1,0,0
961
+ 959,0,0,1,1,0
962
+ 960,1,0,1,1,0
963
+ 961,1,1,0,1,1
964
+ 962,0,1,1,0,1
965
+ 963,0,1,0,0,1
966
+ 964,0,0,0,1,1
967
+ 965,1,1,0,0,0
968
+ 966,1,1,0,1,0
969
+ 967,0,0,0,1,0
970
+ 968,1,1,1,1,0
971
+ 969,1,0,1,1,1
972
+ 970,0,1,0,0,1
973
+ 971,0,1,1,1,0
974
+ 972,0,1,0,1,0
975
+ 973,1,1,1,0,0
976
+ 974,1,0,0,0,0
977
+ 975,0,1,0,1,1
978
+ 976,1,1,1,0,1
979
+ 977,0,1,0,0,0
980
+ 978,0,0,1,1,1
981
+ 979,1,1,1,0,1
982
+ 980,1,0,0,1,1
983
+ 981,0,0,0,0,1
984
+ 982,0,0,1,0,1
985
+ 983,1,0,0,1,1
986
+ 984,0,0,0,0,1
987
+ 985,0,0,0,0,0
988
+ 986,1,0,1,0,1
989
+ 987,0,0,1,1,0
990
+ 988,0,0,0,1,1
991
+ 989,0,0,1,1,1
992
+ 990,0,1,1,1,0
993
+ 991,0,0,1,1,0
994
+ 992,1,1,1,0,0
995
+ 993,1,1,0,0,0
996
+ 994,1,1,0,1,0
997
+ 995,0,1,1,1,1
998
+ 996,1,0,1,1,0
999
+ 997,0,0,1,0,1
1000
+ 998,1,1,1,1,1
1001
+ 999,1,0,1,1,1
1002
+ 1000,1,0,0,0,1
1003
+ 1001,1,0,0,0,0
1004
+ 1002,1,1,1,1,1
1005
+ 1003,1,0,1,0,1
1006
+ 1004,0,1,0,1,0
1007
+ 1005,1,0,0,0,1
1008
+ 1006,0,0,1,0,0
1009
+ 1007,1,0,1,0,1
1010
+ 1008,1,1,1,1,0
1011
+ 1009,1,1,0,0,0
1012
+ 1010,1,0,0,1,0
1013
+ 1011,1,1,1,1,0
1014
+ 1012,1,0,0,0,0
1015
+ 1013,1,1,1,1,1
1016
+ 1014,1,1,1,0,0
1017
+ 1015,1,0,1,0,1
1018
+ 1016,1,0,0,0,1
1019
+ 1017,1,1,0,1,1
1020
+ 1018,0,0,0,0,1
1021
+ 1019,0,0,1,1,0
1022
+ 1020,1,1,1,1,0
1023
+ 1021,1,0,1,0,1
1024
+ 1022,1,0,0,1,1
1025
+ 1023,0,1,0,1,0
1026
+ 1024,1,0,1,1,1
1027
+ 1025,0,1,1,0,1
1028
+ 1026,0,1,1,1,0
1029
+ 1027,0,0,0,0,1
1030
+ 1028,1,0,1,1,0
1031
+ 1029,1,1,0,0,0
1032
+ 1030,1,0,1,1,0
1033
+ 1031,0,0,1,0,0
1034
+ 1032,1,0,0,0,0
1035
+ 1033,0,0,0,0,1
1036
+ 1034,0,1,0,1,0
1037
+ 1035,1,0,0,0,1
1038
+ 1036,0,1,1,1,1
1039
+ 1037,0,0,0,0,0
1040
+ 1038,0,1,0,1,1
1041
+ 1039,0,1,1,1,0
1042
+ 1040,0,0,0,0,1
1043
+ 1041,1,1,1,1,0
1044
+ 1042,1,1,1,0,1
1045
+ 1043,1,0,1,0,0
1046
+ 1044,0,1,0,1,1
1047
+ 1045,0,1,0,1,0
1048
+ 1046,1,1,1,0,0
1049
+ 1047,0,0,0,0,0
1050
+ 1048,0,0,0,1,0
1051
+ 1049,1,0,0,1,0
1052
+ 1050,1,0,0,0,0
1053
+ 1051,0,1,1,0,0
1054
+ 1052,0,0,1,1,1
1055
+ 1053,0,1,0,1,1
1056
+ 1054,0,0,1,1,0
1057
+ 1055,1,1,0,1,0
1058
+ 1056,1,0,0,0,1
1059
+ 1057,1,1,1,0,1
1060
+ 1058,1,0,0,1,0
1061
+ 1059,0,1,1,1,0
1062
+ 1060,1,0,1,1,1
1063
+ 1061,0,1,0,0,0
1064
+ 1062,1,1,0,0,0
1065
+ 1063,0,0,0,1,1
1066
+ 1064,0,0,0,1,1
1067
+ 1065,1,1,1,0,1
1068
+ 1066,1,1,0,1,0
1069
+ 1067,0,1,0,0,1
1070
+ 1068,0,1,0,0,1
1071
+ 1069,0,1,1,0,1
1072
+ 1070,1,1,1,1,1
1073
+ 1071,1,0,1,0,0
1074
+ 1072,1,0,0,1,1
1075
+ 1073,1,0,1,1,0
1076
+ 1074,1,0,0,1,0
1077
+ 1075,1,1,1,0,1
1078
+ 1076,1,1,0,1,0
1079
+ 1077,0,0,0,1,1
1080
+ 1078,0,0,1,0,1
1081
+ 1079,1,1,0,1,1
1082
+ 1080,0,0,1,0,0
1083
+ 1081,1,1,1,0,0
1084
+ 1082,0,0,1,0,1
1085
+ 1083,1,0,0,0,1
1086
+ 1084,1,1,0,0,1
1087
+ 1085,1,0,0,1,1
1088
+ 1086,0,1,1,0,1
1089
+ 1087,0,0,0,0,1
1090
+ 1088,0,1,1,1,0
1091
+ 1089,1,0,1,1,1
1092
+ 1090,0,0,0,0,0
1093
+ 1091,0,1,1,0,0
1094
+ 1092,1,1,1,1,0
1095
+ 1093,0,0,0,1,0
1096
+ 1094,1,1,1,1,1
1097
+ 1095,1,0,0,0,1
1098
+ 1096,1,1,0,0,0
1099
+ 1097,1,0,1,1,1
1100
+ 1098,1,0,0,0,1
1101
+ 1099,0,0,0,0,0
1102
+ 1100,1,0,1,1,0
1103
+ 1101,0,0,0,0,0
1104
+ 1102,0,0,1,1,1
1105
+ 1103,0,1,0,0,0
1106
+ 1104,0,1,0,0,0
1107
+ 1105,0,0,1,0,1
1108
+ 1106,1,0,0,1,0
1109
+ 1107,1,1,1,0,1
1110
+ 1108,1,0,0,1,0
1111
+ 1109,1,0,0,1,0
1112
+ 1110,1,0,0,1,0
1113
+ 1111,1,0,1,0,1
1114
+ 1112,1,0,0,0,0
1115
+ 1113,1,1,0,1,0
1116
+ 1114,1,0,1,1,0
1117
+ 1115,0,1,1,1,0
1118
+ 1116,0,1,1,0,0
1119
+ 1117,0,1,1,0,0
1120
+ 1118,1,0,1,1,1
1121
+ 1119,1,0,1,0,0
1122
+ 1120,1,0,0,1,1
1123
+ 1121,1,0,1,0,1
1124
+ 1122,1,0,1,0,1
1125
+ 1123,0,0,1,0,1
1126
+ 1124,1,0,0,1,0
1127
+ 1125,1,1,0,1,0
1128
+ 1126,0,1,1,0,0
1129
+ 1127,0,0,1,0,1
1130
+ 1128,0,1,1,0,1
1131
+ 1129,0,1,0,0,1
1132
+ 1130,1,1,0,0,1
1133
+ 1131,1,0,0,1,0
1134
+ 1132,0,0,0,1,0
1135
+ 1133,0,1,0,1,0
1136
+ 1134,0,0,1,0,1
1137
+ 1135,1,0,1,0,0
1138
+ 1136,1,0,1,0,0
1139
+ 1137,0,1,1,0,1
1140
+ 1138,0,1,1,1,1
1141
+ 1139,1,0,0,1,1
1142
+ 1140,0,0,1,0,1
1143
+ 1141,1,0,0,0,0
1144
+ 1142,1,1,0,0,1
1145
+ 1143,0,1,1,1,0
1146
+ 1144,0,1,0,0,0
1147
+ 1145,0,0,1,1,1
1148
+ 1146,0,1,1,1,0
1149
+ 1147,1,0,0,0,0
1150
+ 1148,0,0,1,0,0
1151
+ 1149,0,1,0,0,1
1152
+ 1150,1,1,1,1,0
1153
+ 1151,1,1,0,0,1
1154
+ 1152,1,0,0,1,0
1155
+ 1153,1,0,1,0,1
1156
+ 1154,0,1,1,0,1
1157
+ 1155,0,0,1,1,0
1158
+ 1156,1,0,1,0,1
1159
+ 1157,0,0,1,1,1
1160
+ 1158,0,0,0,0,1
1161
+ 1159,1,1,1,0,1
1162
+ 1160,0,1,0,0,0
1163
+ 1161,1,1,0,1,0
1164
+ 1162,1,0,1,1,1
1165
+ 1163,1,1,1,0,0
1166
+ 1164,0,0,1,0,1
1167
+ 1165,0,0,1,0,0
1168
+ 1166,1,1,1,0,1
1169
+ 1167,0,1,0,0,0
1170
+ 1168,0,0,1,0,0
1171
+ 1169,0,0,1,0,1
1172
+ 1170,1,1,1,1,0
1173
+ 1171,1,1,0,1,1
1174
+ 1172,0,0,1,1,0
1175
+ 1173,0,0,1,0,1
1176
+ 1174,0,1,1,0,0
1177
+ 1175,0,1,1,1,1
1178
+ 1176,0,0,1,0,1
1179
+ 1177,0,0,1,0,0
1180
+ 1178,1,1,1,1,0
1181
+ 1179,0,1,0,0,1
1182
+ 1180,1,1,0,1,1
1183
+ 1181,0,0,1,0,0
1184
+ 1182,1,0,1,1,0
1185
+ 1183,0,0,1,1,0
1186
+ 1184,1,1,0,0,0
1187
+ 1185,0,1,1,0,1
1188
+ 1186,1,0,1,1,1
1189
+ 1187,1,1,0,0,1
1190
+ 1188,0,0,0,0,0
1191
+ 1189,0,1,0,0,1
1192
+ 1190,1,0,0,0,0
1193
+ 1191,0,0,1,1,1
1194
+ 1192,0,1,1,1,1
1195
+ 1193,1,1,0,1,1
1196
+ 1194,0,0,0,1,0
1197
+ 1195,1,1,1,0,1
1198
+ 1196,1,1,0,1,1
1199
+ 1197,1,1,0,1,0
1200
+ 1198,1,1,1,0,0
1201
+ 1199,0,0,0,1,0
1202
+ 1200,0,0,1,1,0
1203
+ 1201,0,1,1,1,0
1204
+ 1202,1,1,1,0,0
1205
+ 1203,0,1,0,1,0
1206
+ 1204,0,1,1,0,1
1207
+ 1205,0,1,1,0,1
1208
+ 1206,1,1,1,0,0
1209
+ 1207,1,1,1,0,1
1210
+ 1208,0,1,1,1,1
1211
+ 1209,1,0,0,1,1
1212
+ 1210,0,1,1,1,0
1213
+ 1211,1,0,0,1,1
1214
+ 1212,0,1,0,0,0
1215
+ 1213,1,0,1,0,0
1216
+ 1214,1,1,0,1,1
1217
+ 1215,1,0,1,1,1
1218
+ 1216,0,0,0,0,1
1219
+ 1217,0,1,1,0,1
1220
+ 1218,0,0,0,0,1
1221
+ 1219,0,1,1,0,1
1222
+ 1220,1,0,0,1,0
1223
+ 1221,1,1,0,0,0
1224
+ 1222,1,1,0,1,0
1225
+ 1223,1,1,0,1,0
1226
+ 1224,0,0,1,1,1
1227
+ 1225,0,0,0,0,1
1228
+ 1226,1,0,0,1,0
1229
+ 1227,0,0,0,1,0
1230
+ 1228,1,0,0,1,1
1231
+ 1229,1,1,1,0,1
1232
+ 1230,0,1,1,0,1
1233
+ 1231,0,1,1,1,1
1234
+ 1232,0,1,0,0,0
1235
+ 1233,1,0,1,0,0
1236
+ 1234,1,1,1,1,0
1237
+ 1235,1,0,1,1,0
1238
+ 1236,0,0,1,0,1
1239
+ 1237,0,1,1,0,0
1240
+ 1238,0,0,1,1,1
1241
+ 1239,0,1,0,1,0
1242
+ 1240,0,0,0,0,0
1243
+ 1241,1,1,1,0,0
1244
+ 1242,1,1,0,0,0
1245
+ 1243,1,1,0,1,0
1246
+ 1244,1,0,0,0,1
1247
+ 1245,0,0,0,1,1
1248
+ 1246,1,1,0,0,0
1249
+ 1247,0,0,1,0,0
1250
+ 1248,1,1,1,0,0
1251
+ 1249,0,0,1,1,0
1252
+ 1250,0,0,0,0,0
1253
+ 1251,0,1,0,1,0
1254
+ 1252,0,0,0,1,1
1255
+ 1253,1,0,1,0,0
1256
+ 1254,0,1,1,0,1
1257
+ 1255,1,1,1,1,0
1258
+ 1256,1,1,1,0,0
1259
+ 1257,0,0,0,1,1
1260
+ 1258,1,1,0,0,0
1261
+ 1259,1,0,0,1,0
1262
+ 1260,1,1,1,0,1
1263
+ 1261,1,0,0,0,0
1264
+ 1262,1,1,1,1,1
1265
+ 1263,0,1,0,0,1
1266
+ 1264,0,0,0,0,1
1267
+ 1265,1,0,1,1,1
1268
+ 1266,1,0,1,0,0
1269
+ 1267,0,1,1,0,1
1270
+ 1268,0,1,1,1,1
1271
+ 1269,1,0,1,0,0
1272
+ 1270,1,0,1,1,0
1273
+ 1271,1,0,0,1,1
1274
+ 1272,0,1,0,0,1
1275
+ 1273,1,1,0,1,1
1276
+ 1274,0,1,1,0,1
1277
+ 1275,0,1,1,0,0
1278
+ 1276,0,0,1,0,0
1279
+ 1277,1,1,0,0,0
1280
+ 1278,1,0,0,0,1
1281
+ 1279,0,0,1,0,1
1282
+ 1280,0,0,1,1,1
1283
+ 1281,0,1,0,0,1
1284
+ 1282,0,1,1,1,0
1285
+ 1283,1,0,0,0,0
1286
+ 1284,1,1,0,1,1
1287
+ 1285,0,1,1,1,0
1288
+ 1286,1,1,1,1,1
1289
+ 1287,1,0,1,1,0
1290
+ 1288,0,0,1,0,1
1291
+ 1289,1,1,0,0,0
1292
+ 1290,0,0,0,0,0
1293
+ 1291,0,1,0,1,0
1294
+ 1292,1,0,1,1,1
1295
+ 1293,1,0,0,1,0
1296
+ 1294,1,0,0,0,0
1297
+ 1295,0,0,0,1,0
1298
+ 1296,1,1,1,1,1
1299
+ 1297,1,1,0,1,1
1300
+ 1298,1,1,0,1,1
1301
+ 1299,0,0,1,1,1
1302
+ 1300,1,0,0,0,1
1303
+ 1301,0,0,0,1,0
1304
+ 1302,1,1,1,1,1
1305
+ 1303,1,1,0,1,1
1306
+ 1304,1,0,1,0,1
1307
+ 1305,0,1,1,0,1
1308
+ 1306,0,0,1,1,1
1309
+ 1307,1,1,1,1,0
1310
+ 1308,0,0,1,1,1
1311
+ 1309,0,1,0,1,1
1312
+ 1310,1,1,1,1,0
1313
+ 1311,1,1,1,1,1
1314
+ 1312,0,0,0,0,1
1315
+ 1313,1,0,0,1,1
1316
+ 1314,1,0,1,0,1
1317
+ 1315,1,1,0,1,0
1318
+ 1316,1,0,0,0,1
1319
+ 1317,1,1,1,0,0
1320
+ 1318,1,1,1,1,0
1321
+ 1319,0,0,0,0,0
1322
+ 1320,1,0,0,1,1
1323
+ 1321,1,1,0,0,0
1324
+ 1322,0,1,1,1,1
1325
+ 1323,0,1,1,0,0
1326
+ 1324,0,1,1,1,0
1327
+ 1325,1,0,0,0,1
1328
+ 1326,1,0,1,0,1
1329
+ 1327,0,0,0,0,0
1330
+ 1328,0,1,1,0,0
1331
+ 1329,1,1,0,0,1
1332
+ 1330,0,0,0,1,1
1333
+ 1331,0,1,0,0,0
1334
+ 1332,0,0,0,0,0
1335
+ 1333,1,0,1,0,0
1336
+ 1334,0,0,0,0,1
1337
+ 1335,1,1,0,0,0
1338
+ 1336,1,0,0,0,1
1339
+ 1337,1,0,0,1,0
1340
+ 1338,0,1,1,0,0
1341
+ 1339,0,1,0,0,0
1342
+ 1340,0,1,1,1,0
1343
+ 1341,1,0,0,1,0
1344
+ 1342,0,0,0,0,0
1345
+ 1343,1,1,1,1,0
1346
+ 1344,1,1,1,1,0
1347
+ 1345,0,0,1,0,0
1348
+ 1346,1,1,0,1,1
1349
+ 1347,0,0,0,0,1
1350
+ 1348,1,0,0,0,0
1351
+ 1349,0,0,1,1,1
1352
+ 1350,0,1,0,0,0
1353
+ 1351,0,0,1,1,0
1354
+ 1352,1,0,0,1,0
1355
+ 1353,1,0,0,0,0
1356
+ 1354,1,1,1,1,0
1357
+ 1355,0,0,0,0,0
1358
+ 1356,0,0,1,0,0
1359
+ 1357,1,1,0,1,1
1360
+ 1358,0,0,0,1,0
1361
+ 1359,1,0,1,1,1
1362
+ 1360,1,1,0,0,0
1363
+ 1361,1,1,0,1,1
1364
+ 1362,0,1,0,0,1
1365
+ 1363,1,0,0,1,0
1366
+ 1364,0,1,1,0,1
1367
+ 1365,1,1,0,0,1
1368
+ 1366,0,0,1,1,0
1369
+ 1367,0,0,0,0,0
1370
+ 1368,1,0,1,1,0
1371
+ 1369,1,1,1,0,1
1372
+ 1370,0,0,0,1,1
1373
+ 1371,0,0,1,0,1
1374
+ 1372,0,1,1,1,1
1375
+ 1373,0,0,0,0,1
1376
+ 1374,0,1,1,1,1
1377
+ 1375,0,0,0,0,0
1378
+ 1376,1,1,0,1,1
1379
+ 1377,1,0,0,0,1
1380
+ 1378,0,0,0,1,0
1381
+ 1379,1,0,0,0,1
1382
+ 1380,0,1,1,1,0
1383
+ 1381,0,1,0,1,1
1384
+ 1382,1,1,0,1,1
1385
+ 1383,1,1,1,1,1
1386
+ 1384,0,1,0,1,0
1387
+ 1385,0,1,1,1,0
1388
+ 1386,1,0,0,1,0
1389
+ 1387,0,1,0,1,1
1390
+ 1388,1,1,0,0,0
1391
+ 1389,0,0,0,0,1
1392
+ 1390,0,1,0,0,1
1393
+ 1391,0,0,0,0,0
1394
+ 1392,0,1,1,0,1
1395
+ 1393,0,1,0,0,0
1396
+ 1394,1,1,1,1,0
1397
+ 1395,1,0,0,1,1
1398
+ 1396,0,1,0,0,0
1399
+ 1397,0,0,1,1,1
1400
+ 1398,1,0,1,1,1
1401
+ 1399,0,1,0,1,1
1402
+ 1400,0,0,0,1,1
1403
+ 1401,0,1,1,1,0
1404
+ 1402,0,1,0,1,0
1405
+ 1403,1,0,1,0,0
1406
+ 1404,0,0,1,0,0
1407
+ 1405,0,0,1,1,0
1408
+ 1406,1,0,1,1,0
1409
+ 1407,0,0,0,1,0
1410
+ 1408,1,0,0,1,0
1411
+ 1409,1,0,1,1,1
1412
+ 1410,0,0,1,0,0
1413
+ 1411,1,0,0,1,0
1414
+ 1412,0,0,1,0,1
1415
+ 1413,0,0,0,1,1
1416
+ 1414,0,1,1,1,1
1417
+ 1415,0,1,0,1,1
1418
+ 1416,1,0,1,1,1
1419
+ 1417,1,0,0,0,1
1420
+ 1418,0,1,0,1,1
1421
+ 1419,1,1,1,1,0
1422
+ 1420,1,0,0,0,1
1423
+ 1421,1,1,1,0,1
1424
+ 1422,1,1,1,0,1
1425
+ 1423,1,1,0,0,0
1426
+ 1424,0,1,1,1,0
1427
+ 1425,1,1,1,0,1
1428
+ 1426,0,0,0,1,0
1429
+ 1427,1,0,1,0,1
1430
+ 1428,0,1,1,0,1
1431
+ 1429,0,1,0,1,1
1432
+ 1430,0,0,1,1,1
1433
+ 1431,1,0,1,1,0
1434
+ 1432,0,1,0,1,0
1435
+ 1433,1,0,1,1,0
1436
+ 1434,0,1,1,1,0
1437
+ 1435,0,0,1,0,1
1438
+ 1436,0,1,0,1,1
1439
+ 1437,1,1,1,1,1
1440
+ 1438,1,1,1,0,0
1441
+ 1439,0,0,1,1,1
1442
+ 1440,0,1,0,1,1
1443
+ 1441,0,0,1,1,1
1444
+ 1442,0,1,1,0,0
1445
+ 1443,0,0,0,1,1
1446
+ 1444,0,0,0,0,0
1447
+ 1445,0,1,1,0,0
1448
+ 1446,0,0,1,1,0
1449
+ 1447,0,0,1,0,1
1450
+ 1448,0,1,1,0,0
1451
+ 1449,0,0,1,0,1
1452
+ 1450,1,0,0,0,1
1453
+ 1451,0,1,1,0,1
1454
+ 1452,1,1,1,1,0
1455
+ 1453,1,0,0,1,0
1456
+ 1454,0,1,0,1,1
1457
+ 1455,0,0,0,1,0
1458
+ 1456,0,1,0,0,0
1459
+ 1457,0,0,0,1,1
1460
+ 1458,0,1,0,0,1
1461
+ 1459,0,1,1,0,1
1462
+ 1460,1,0,0,1,1
1463
+ 1461,1,0,1,0,1
1464
+ 1462,1,0,0,0,1
1465
+ 1463,1,1,1,0,1
1466
+ 1464,1,0,0,1,1
1467
+ 1465,1,0,0,0,1
1468
+ 1466,1,0,0,0,0
1469
+ 1467,1,0,0,0,0
1470
+ 1468,1,0,1,1,0
1471
+ 1469,0,1,0,0,1
1472
+ 1470,0,0,0,0,0
1473
+ 1471,1,0,1,0,1
1474
+ 1472,0,0,1,1,1
1475
+ 1473,1,1,1,0,0
1476
+ 1474,1,0,1,1,0
1477
+ 1475,0,0,1,0,0
1478
+ 1476,1,0,1,0,1
1479
+ 1477,0,0,1,1,0
1480
+ 1478,0,1,1,0,1
1481
+ 1479,1,1,0,0,0
1482
+ 1480,1,0,1,0,1
1483
+ 1481,0,0,1,1,0
1484
+ 1482,0,1,1,0,0
1485
+ 1483,1,0,0,0,1
1486
+ 1484,1,1,0,0,0
1487
+ 1485,1,0,1,0,1
1488
+ 1486,0,1,0,0,1
1489
+ 1487,1,1,1,0,0
1490
+ 1488,1,1,1,1,1
1491
+ 1489,1,0,0,0,0
1492
+ 1490,1,1,0,1,0
1493
+ 1491,0,0,1,1,0
1494
+ 1492,0,0,1,0,1
1495
+ 1493,0,0,1,0,1
1496
+ 1494,0,0,0,1,0
1497
+ 1495,1,1,0,0,0
1498
+ 1496,0,1,0,0,1
1499
+ 1497,0,1,0,1,0
1500
+ 1498,1,1,1,0,1
1501
+ 1499,1,1,0,0,1
1502
+ 1500,1,0,1,0,0
1503
+ 1501,1,1,1,1,0
1504
+ 1502,0,1,0,0,0
1505
+ 1503,1,0,1,0,0
1506
+ 1504,1,0,1,1,1
1507
+ 1505,0,1,0,0,1
1508
+ 1506,1,0,0,1,1
1509
+ 1507,1,0,1,1,0
1510
+ 1508,1,1,0,0,0
1511
+ 1509,0,0,1,0,0
1512
+ 1510,0,0,1,1,0
1513
+ 1511,0,1,1,0,0
1514
+ 1512,0,0,1,1,0
1515
+ 1513,1,1,0,0,1
1516
+ 1514,1,0,0,0,1
1517
+ 1515,1,0,1,0,0
1518
+ 1516,1,0,1,0,0
1519
+ 1517,0,0,1,0,0
1520
+ 1518,1,0,1,1,0
1521
+ 1519,0,1,1,0,0
1522
+ 1520,0,1,0,1,0
1523
+ 1521,1,1,0,1,0
1524
+ 1522,1,1,1,1,0
1525
+ 1523,0,0,1,1,1
1526
+ 1524,0,0,0,1,0
1527
+ 1525,1,0,0,1,0
1528
+ 1526,1,1,1,1,1
1529
+ 1527,1,0,0,0,1
1530
+ 1528,0,1,0,1,0
1531
+ 1529,0,0,1,1,1
1532
+ 1530,0,1,0,0,0
1533
+ 1531,0,1,1,1,1
1534
+ 1532,0,0,1,0,1
1535
+ 1533,1,0,1,0,0
1536
+ 1534,1,0,1,0,1
1537
+ 1535,1,1,0,0,0
1538
+ 1536,0,1,0,1,1
1539
+ 1537,0,1,1,1,0
1540
+ 1538,0,0,0,1,0
1541
+ 1539,0,0,0,0,1
1542
+ 1540,1,1,0,0,0
1543
+ 1541,0,0,1,0,0
1544
+ 1542,0,0,1,0,0
1545
+ 1543,1,0,1,0,1
1546
+ 1544,0,1,0,0,1
1547
+ 1545,1,0,0,1,1
1548
+ 1546,1,0,1,1,1
1549
+ 1547,1,1,0,0,1
1550
+ 1548,0,0,1,1,0
1551
+ 1549,0,0,0,1,0
1552
+ 1550,0,0,0,1,0
1553
+ 1551,0,1,0,0,0
1554
+ 1552,1,0,0,1,1
1555
+ 1553,1,1,1,1,1
1556
+ 1554,0,1,0,0,1
1557
+ 1555,0,0,1,1,0
1558
+ 1556,1,0,0,1,0
1559
+ 1557,0,1,0,0,0
1560
+ 1558,1,1,0,0,1
1561
+ 1559,0,0,0,1,0
1562
+ 1560,1,1,1,0,1
1563
+ 1561,1,1,0,1,0
1564
+ 1562,0,0,0,1,1
1565
+ 1563,0,0,0,1,1
1566
+ 1564,1,0,0,1,1
1567
+ 1565,1,1,1,1,1
1568
+ 1566,1,1,0,1,0
1569
+ 1567,0,1,0,0,0
1570
+ 1568,1,1,0,1,1
1571
+ 1569,1,1,0,1,1
1572
+ 1570,0,0,0,0,1
1573
+ 1571,0,1,0,0,0
1574
+ 1572,0,0,1,0,0
1575
+ 1573,0,1,1,0,1
1576
+ 1574,1,0,0,0,1
1577
+ 1575,0,1,0,1,1
1578
+ 1576,0,0,1,1,0
1579
+ 1577,1,1,1,0,1
1580
+ 1578,1,0,0,1,1
1581
+ 1579,1,1,0,0,0
1582
+ 1580,1,1,0,0,0
1583
+ 1581,1,0,1,0,0
1584
+ 1582,0,1,0,0,1
1585
+ 1583,1,0,1,0,0
1586
+ 1584,1,0,0,0,0
1587
+ 1585,0,0,1,1,1
1588
+ 1586,1,1,1,0,0
1589
+ 1587,1,1,1,0,1
1590
+ 1588,1,1,1,0,1
1591
+ 1589,0,0,1,1,0
1592
+ 1590,1,0,1,0,0
1593
+ 1591,0,1,1,0,1
1594
+ 1592,0,1,0,0,0
1595
+ 1593,1,0,0,0,1
1596
+ 1594,0,1,1,0,0
1597
+ 1595,1,0,0,1,1
1598
+ 1596,1,1,1,1,1
1599
+ 1597,0,0,0,0,1
1600
+ 1598,1,0,0,1,0
1601
+ 1599,0,1,0,0,1
1602
+ 1600,0,0,1,0,1
1603
+ 1601,0,0,0,0,1
1604
+ 1602,1,0,0,1,1
1605
+ 1603,1,0,0,1,0
1606
+ 1604,0,0,0,1,1
1607
+ 1605,1,0,0,0,0
1608
+ 1606,1,0,0,0,1
1609
+ 1607,1,0,1,1,0
1610
+ 1608,0,1,1,0,1
1611
+ 1609,0,1,0,0,0
1612
+ 1610,0,1,0,0,0
1613
+ 1611,1,0,0,1,1
1614
+ 1612,1,0,1,0,0
1615
+ 1613,1,0,0,1,0
1616
+ 1614,0,0,0,1,0
1617
+ 1615,0,1,0,0,0
1618
+ 1616,0,0,1,1,0
1619
+ 1617,0,0,0,0,1
1620
+ 1618,0,1,1,1,0
1621
+ 1619,0,0,0,1,1
1622
+ 1620,0,1,1,0,1
1623
+ 1621,1,0,0,1,1
1624
+ 1622,1,0,1,0,0
1625
+ 1623,0,0,0,0,1
1626
+ 1624,1,1,0,0,0
1627
+ 1625,1,0,0,1,0
1628
+ 1626,0,1,1,0,0
1629
+ 1627,1,0,1,0,1
1630
+ 1628,0,1,0,1,1
1631
+ 1629,1,0,1,1,1
1632
+ 1630,0,0,0,0,1
1633
+ 1631,1,0,1,1,0
1634
+ 1632,0,0,0,1,0
1635
+ 1633,0,0,1,1,1
1636
+ 1634,0,1,0,1,0
1637
+ 1635,0,0,0,0,1
1638
+ 1636,0,0,0,0,0
1639
+ 1637,1,0,1,1,0
1640
+ 1638,0,0,1,0,0
1641
+ 1639,0,1,1,0,1
1642
+ 1640,1,1,0,1,1
1643
+ 1641,0,0,1,1,0
1644
+ 1642,1,0,0,1,0
1645
+ 1643,1,1,1,1,0
1646
+ 1644,0,0,0,1,1
1647
+ 1645,0,1,0,1,1
1648
+ 1646,0,1,0,1,1
1649
+ 1647,1,0,1,1,1
1650
+ 1648,1,0,1,0,1
1651
+ 1649,1,0,0,1,0
1652
+ 1650,1,1,0,1,1
1653
+ 1651,0,0,1,1,0
1654
+ 1652,1,1,0,0,0
1655
+ 1653,1,1,1,1,0
1656
+ 1654,0,0,0,1,1
1657
+ 1655,1,1,0,0,1
1658
+ 1656,0,0,1,1,0
1659
+ 1657,0,1,1,1,1
1660
+ 1658,1,0,1,0,0
1661
+ 1659,0,0,1,1,0
1662
+ 1660,1,1,0,1,0
1663
+ 1661,0,1,1,1,1
1664
+ 1662,0,1,1,1,0
1665
+ 1663,0,1,1,0,0
1666
+ 1664,1,0,1,1,1
1667
+ 1665,1,1,1,1,1
1668
+ 1666,0,0,1,0,0
1669
+ 1667,0,1,0,0,1
1670
+ 1668,1,1,1,0,0
1671
+ 1669,1,1,1,1,1
1672
+ 1670,1,0,1,1,1
1673
+ 1671,1,1,0,0,0
1674
+ 1672,0,0,1,0,1
1675
+ 1673,0,0,0,1,1
1676
+ 1674,1,1,0,0,1
1677
+ 1675,0,0,1,1,1
1678
+ 1676,1,1,1,1,0
1679
+ 1677,1,1,1,0,1
1680
+ 1678,1,0,0,1,0
1681
+ 1679,0,1,0,1,1
1682
+ 1680,1,0,0,0,0
1683
+ 1681,0,0,1,1,1
1684
+ 1682,1,0,1,1,1
1685
+ 1683,1,1,1,0,0
1686
+ 1684,0,1,1,0,1
1687
+ 1685,1,0,0,0,0
1688
+ 1686,1,0,0,1,0
1689
+ 1687,0,1,0,0,1
1690
+ 1688,0,0,1,1,0
1691
+ 1689,0,1,0,1,1
1692
+ 1690,1,0,1,1,0
1693
+ 1691,0,0,0,1,1
1694
+ 1692,1,1,0,1,0
1695
+ 1693,0,0,0,0,0
1696
+ 1694,0,0,0,0,1
1697
+ 1695,1,0,0,0,1
1698
+ 1696,0,1,1,0,1
1699
+ 1697,0,0,1,1,1
1700
+ 1698,1,1,1,1,0
1701
+ 1699,1,0,1,1,0
1702
+ 1700,1,1,1,1,0
1703
+ 1701,1,0,0,1,0
1704
+ 1702,1,1,0,0,1
1705
+ 1703,1,0,0,1,0
1706
+ 1704,0,0,1,0,1
1707
+ 1705,0,0,0,1,0
1708
+ 1706,0,0,1,0,0
kaggle/input/2025-sep-dl-gen-ai-project/test.csv ADDED
The diff for this file is too large to render. See raw diff
 
kaggle/input/2025-sep-dl-gen-ai-project/train.csv ADDED
The diff for this file is too large to render. See raw diff
 
main.ipynb ADDED
@@ -0,0 +1,621 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Deep Learning Project - Emotion Classification\n",
8
+ "\n",
9
+ "This notebook implements a **multi-label emotion classification system** using state-of-the-art transformer models. The goal is to predict multiple emotions (anger, fear, joy, sadness, surprise) that may be present in a given text.\n",
10
+ "\n",
11
+ "**Key Features:**\n",
12
+ "- **Model**: Microsoft DeBERTa-v3-base (184M parameters)\n",
13
+ "- **Strategy**: 5-Fold Stratified Cross-Validation for robust performance estimation\n",
14
+ "- **Optimization**: Mixed Precision Training, Gradient Clipping, Learning Rate Warmup\n",
15
+ "- **Evaluation**: Macro F1 Score with Per-Label Threshold Tuning\n",
16
+ "- **Ensemble**: Average predictions across all folds for final submission\n",
17
+ "\n",
18
+ "**Problem Type**: Multi-label classification (each text can have 0 or more emotions)\n",
19
+ "\n",
20
+ "---\n",
21
+ "\n",
22
+ "## 1. Imports & Setup\n",
23
+ "\n",
24
+ "We import all necessary libraries for:\n",
25
+ "- **Data handling**: `numpy`, `pandas` for data manipulation\n",
26
+ "- **Deep learning**: `torch` (PyTorch) and `transformers` (Hugging Face) for model training\n",
27
+ "- **Evaluation**: `sklearn` for F1 metrics and stratified k-fold cross-validation\n",
28
+ "- **Optimization**: Mixed precision training with `autocast` and `GradScaler` to speed up training and reduce memory usage\n",
29
+ "- **Memory management**: `gc` for garbage collection to free up GPU memory between folds"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": null,
35
+ "metadata": {},
36
+ "outputs": [],
37
+ "source": [
38
+ "import numpy as np\n",
39
+ "import pandas as pd\n",
40
+ "import torch\n",
41
+ "import torch.nn as nn\n",
42
+ "from sklearn.model_selection import StratifiedKFold\n",
43
+ "from sklearn.metrics import f1_score\n",
44
+ "from transformers import (\n",
45
+ " AutoTokenizer,\n",
46
+ " AutoModelForSequenceClassification,\n",
47
+ " get_linear_schedule_with_warmup,\n",
48
+ " AutoConfig\n",
49
+ ")\n",
50
+ "from torch.optim import AdamW\n",
51
+ "from torch.cuda.amp import autocast, GradScaler\n",
52
+ "import gc\n",
53
+ "import warnings\n",
54
+ "import os\n",
55
+ "\n",
56
+ "warnings.filterwarnings(\"ignore\")"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "markdown",
61
+ "metadata": {},
62
+ "source": [
63
+ "## 2. Configuration\n",
64
+ "\n",
65
+ "Centralized configuration class containing all hyperparameters and paths. This makes it easy to:\n",
66
+ "- Experiment with different settings\n",
67
+ "- Ensure reproducibility\n",
68
+ "- Keep the code organized\n",
69
+ "\n",
70
+ "**Key Hyperparameters:**\n",
71
+ "- `MODEL_NAME`: DeBERTa-v3-base chosen for its strong performance on text classification tasks\n",
72
+ "- `MAX_LEN=128`: Balance between capturing context and computational efficiency\n",
73
+ "- `BATCH_SIZE=16`: Fits in GPU memory while maintaining good gradient estimates\n",
74
+ "- `LR=1.5e-5`: Small learning rate typical for fine-tuning pre-trained transformers\n",
75
+ "- `EPOCHS=4`: Sufficient for fine-tuning without overfitting\n",
76
+ "- `N_FOLDS=5`: Standard choice for cross-validation, balances between training data and validation reliability"
77
+ ]
78
+ },
79
+ {
80
+ "cell_type": "code",
81
+ "execution_count": null,
82
+ "metadata": {},
83
+ "outputs": [],
84
+ "source": [
85
+ "# ========= CONFIG =========\n",
86
+ "class Config:\n",
87
+ " SEED = 42\n",
88
+ " LABELS = [\"anger\", \"fear\", \"joy\", \"sadness\", \"surprise\"]\n",
89
+ " MODEL_NAME = \"microsoft/deberta-v3-base\"\n",
90
+ " MAX_LEN = 128\n",
91
+ " BATCH_SIZE = 16\n",
92
+ " EPOCHS = 4\n",
93
+ " LR = 1.5e-5\n",
94
+ " WEIGHT_DECAY = 0.01\n",
95
+ " WARMUP_RATIO = 0.1\n",
96
+ " N_FOLDS = 5\n",
97
+ " TRAIN_CSV = \"/kaggle/input/2025-sep-dl-gen-ai-project/train.csv\"\n",
98
+ " TEST_CSV = \"/kaggle/input/2025-sep-dl-gen-ai-project/test.csv\"\n",
99
+ " SUBMISSION_PATH = \"submission.csv\"\n",
100
+ "\n",
101
+ "CONFIG = Config()"
102
+ ]
103
+ },
104
+ {
105
+ "cell_type": "markdown",
106
+ "metadata": {},
107
+ "source": [
108
+ "## 3. Seed & Device Setup\n",
109
+ "\n",
110
+ "**Reproducibility**: Setting seeds ensures that our results can be replicated exactly.\n",
111
+ "We set seeds for:\n",
112
+ "- NumPy random number generation\n",
113
+ "- PyTorch CPU operations\n",
114
+ "- PyTorch GPU operations (all CUDA devices)\n",
115
+ "- Python's built-in hash function\n",
116
+ "\n",
117
+ "**Device Selection**: Automatically detects and uses GPU if available (CUDA), otherwise falls back to CPU.\n",
118
+ "GPU training is significantly faster (~10-50x) than CPU for deep learning models."
119
+ ]
120
+ },
121
+ {
122
+ "cell_type": "code",
123
+ "execution_count": null,
124
+ "metadata": {},
125
+ "outputs": [],
126
+ "source": [
127
+ "def set_seed(seed=CONFIG.SEED):\n",
128
+ " np.random.seed(seed)\n",
129
+ " torch.manual_seed(seed)\n",
130
+ " torch.cuda.manual_seed_all(seed)\n",
131
+ " os.environ['PYTHONHASHSEED'] = str(seed)\n",
132
+ "\n",
133
+ "set_seed()\n",
134
+ "\n",
135
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
136
+ "print(f\"Using device: {device}\")"
137
+ ]
138
+ },
139
+ {
140
+ "cell_type": "markdown",
141
+ "metadata": {},
142
+ "source": [
143
+ "## 4. Utility Functions\n",
144
+ "\n",
145
+ "Helper functions used throughout the pipeline:\n",
146
+ "\n",
147
+ "### `ensure_text_column(df)`\n",
148
+ "- Standardizes the text column name across different datasets\n",
149
+ "- Searches for common alternatives like 'comment_text', 'sentence', etc.\n",
150
+ "- Raises error if no text column is found\n",
151
+ "\n",
152
+ "### `tune_thresholds(y_true, y_prob)`\n",
153
+ "- **Critical for multi-label classification performance**\n",
154
+ "- Default threshold of 0.5 is often suboptimal\n",
155
+ "- Finds the best threshold per label that maximizes F1 score\n",
156
+ "- Tests 17 different thresholds between 0.1 and 0.9\n",
157
+ "- Can improve F1 score by 2-5% over default threshold\n",
158
+ "\n",
159
+ "### `get_optimizer_params(model, lr, weight_decay)`\n",
160
+ "- Implements **differential weight decay**\n",
161
+ "- Applies weight decay to most parameters (helps prevent overfitting)\n",
162
+ "- No weight decay for bias and LayerNorm parameters (standard practice in transformer fine-tuning)\n",
163
+ "- This technique is recommended in the BERT and DeBERTa papers"
164
+ ]
165
+ },
166
+ {
167
+ "cell_type": "code",
168
+ "execution_count": null,
169
+ "metadata": {},
170
+ "outputs": [],
171
+ "source": [
172
+ "def ensure_text_column(df: pd.DataFrame) -> pd.DataFrame:\n",
173
+ " if \"text\" in df.columns:\n",
174
+ " return df\n",
175
+ " for c in [\"comment_text\", \"sentence\", \"content\", \"review\"]:\n",
176
+ " if c in df.columns:\n",
177
+ " return df.rename(columns={c: \"text\"})\n",
178
+ " raise ValueError(\"No text column found. Add/rename your text column to 'text'.\")\n",
179
+ "\n",
180
+ "def tune_thresholds(y_true: np.ndarray, y_prob: np.ndarray) -> np.ndarray:\n",
181
+ " th = np.zeros(y_true.shape[1], dtype=np.float32)\n",
182
+ " for j in range(y_true.shape[1]):\n",
183
+ " best_t, best_f1 = 0.5, -1\n",
184
+ " for t in np.linspace(0.1, 0.9, 17):\n",
185
+ " f1 = f1_score(y_true[:, j], (y_prob[:, j] >= t).astype(int), zero_division=0)\n",
186
+ " if f1 > best_f1:\n",
187
+ " best_f1, best_t = f1, t\n",
188
+ " th[j] = best_t\n",
189
+ " return th\n",
190
+ "\n",
191
+ "def get_optimizer_params(model, lr, weight_decay):\n",
192
+ " param_optimizer = list(model.named_parameters())\n",
193
+ " no_decay = [\"bias\", \"LayerNorm.bias\", \"LayerNorm.weight\"]\n",
194
+ " optimizer_parameters = [\n",
195
+ " {\n",
196
+ " \"params\": [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],\n",
197
+ " \"weight_decay\": weight_decay,\n",
198
+ " },\n",
199
+ " {\n",
200
+ " \"params\": [p for n, p in param_optimizer if any(nd in n for nd in no_decay)],\n",
201
+ " \"weight_decay\": 0.0,\n",
202
+ " },\n",
203
+ " ]\n",
204
+ " return optimizer_parameters"
205
+ ]
206
+ },
207
+ {
208
+ "cell_type": "markdown",
209
+ "metadata": {},
210
+ "source": [
211
+ "## 5. Dataset Class\n",
212
+ "\n",
213
+ "Custom PyTorch Dataset for emotion classification.\n",
214
+ "\n",
215
+ "**Key Features:**\n",
216
+ "- Tokenizes text on-the-fly using the DeBERTa tokenizer\n",
217
+ "- Handles both training data (with labels) and test data (without labels)\n",
218
+ "- Uses `padding='max_length'` to ensure all sequences have the same length (required for batching)\n",
219
+ "- Applies `truncation=True` to handle texts longer than MAX_LEN\n",
220
+ "\n",
221
+ "**Returns:**\n",
222
+ "- `input_ids`: Token IDs representing the text\n",
223
+ "- `attention_mask`: Indicates which tokens are real vs padding\n",
224
+ "- `labels`: Multi-label binary targets (only for training data)\n",
225
+ "\n",
226
+ "**PyTorch DataLoader** will use this dataset to create batches efficiently with multi-processing."
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "class EmotionDS(torch.utils.data.Dataset):\n",
236
+ " def __init__(self, df, tokenizer, max_len, is_test=False):\n",
237
+ " self.texts = df[\"text\"].tolist()\n",
238
+ " self.is_test = is_test\n",
239
+ " if not is_test:\n",
240
+ " self.labels = df[CONFIG.LABELS].values.astype(np.float32)\n",
241
+ " self.tok = tokenizer\n",
242
+ " self.max_len = max_len\n",
243
+ "\n",
244
+ " def __len__(self):\n",
245
+ " return len(self.texts)\n",
246
+ "\n",
247
+ " def __getitem__(self, i):\n",
248
+ " enc = self.tok(\n",
249
+ " self.texts[i],\n",
250
+ " truncation=True,\n",
251
+ " padding=\"max_length\",\n",
252
+ " max_length=self.max_len,\n",
253
+ " return_tensors=\"pt\",\n",
254
+ " )\n",
255
+ " item = {k: v.squeeze(0) for k, v in enc.items()}\n",
256
+ " if not self.is_test:\n",
257
+ " item[\"labels\"] = torch.tensor(self.labels[i])\n",
258
+ " return item"
259
+ ]
260
+ },
261
+ {
262
+ "cell_type": "markdown",
263
+ "metadata": {},
264
+ "source": [
265
+ "## 6. Training & Validation Helper Functions\n",
266
+ "\n",
267
+ "Core training and validation loops.\n",
268
+ "\n",
269
+ "### `train_one_epoch()`\n",
270
+ "Trains the model for one complete pass through the training data.\n",
271
+ "\n",
272
+ "**Key Techniques:**\n",
273
+ "- **Mixed Precision Training** (`autocast`): Uses float16 where safe, reducing memory and increasing speed by ~2x\n",
274
+ "- **Gradient Scaling** (`GradScaler`): Prevents gradient underflow in mixed precision\n",
275
+ "- **Gradient Clipping** (max_norm=1.0): Prevents exploding gradients, stabilizes training\n",
276
+ "- **Memory Efficient**: Uses `zero_grad(set_to_none=True)` and `non_blocking=True` for async GPU transfers\n",
277
+ "\n",
278
+ "### `validate()`\n",
279
+ "Evaluates the model on validation data without updating weights.\n",
280
+ "\n",
281
+ "**Features:**\n",
282
+ "- Runs in `model.eval()` mode (disables dropout, fixes batch normalization)\n",
283
+ "- Uses `torch.no_grad()` to save memory (no gradient computation)\n",
284
+ "- Applies sigmoid to convert logits to probabilities [0, 1]\n",
285
+ "- Returns predictions and targets for metric calculation"
286
+ ]
287
+ },
288
+ {
289
+ "cell_type": "code",
290
+ "execution_count": null,
291
+ "metadata": {},
292
+ "outputs": [],
293
+ "source": [
294
+ "def train_one_epoch(model, loader, optimizer, scheduler, scaler, criterion):\n",
295
+ " model.train()\n",
296
+ " losses = []\n",
297
+ " for batch in loader:\n",
298
+ " batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}\n",
299
+ " optimizer.zero_grad(set_to_none=True)\n",
300
+ " with autocast(enabled=True):\n",
301
+ " out = model(input_ids=batch[\"input_ids\"], attention_mask=batch[\"attention_mask\"])\n",
302
+ " loss = criterion(out.logits, batch[\"labels\"])\n",
303
+ " \n",
304
+ " scaler.scale(loss).backward()\n",
305
+ " scaler.unscale_(optimizer)\n",
306
+ " torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n",
307
+ " scaler.step(optimizer)\n",
308
+ " scaler.update()\n",
309
+ " scheduler.step()\n",
310
+ " losses.append(loss.item())\n",
311
+ " return np.mean(losses)\n",
312
+ "\n",
313
+ "def validate(model, loader, criterion):\n",
314
+ " model.eval()\n",
315
+ " losses = []\n",
316
+ " preds = []\n",
317
+ " targs = []\n",
318
+ " with torch.no_grad():\n",
319
+ " for batch in loader:\n",
320
+ " batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}\n",
321
+ " with autocast(enabled=True):\n",
322
+ " out = model(input_ids=batch[\"input_ids\"], attention_mask=batch[\"attention_mask\"])\n",
323
+ " loss = criterion(out.logits, batch[\"labels\"])\n",
324
+ " losses.append(loss.item())\n",
325
+ " preds.append(torch.sigmoid(out.logits).float().cpu().numpy())\n",
326
+ " targs.append(batch[\"labels\"].cpu().numpy())\n",
327
+ " \n",
328
+ " return np.mean(losses), np.vstack(preds), np.vstack(targs)"
329
+ ]
330
+ },
331
+ {
332
+ "cell_type": "markdown",
333
+ "metadata": {},
334
+ "source": [
335
+ "## 7. Main K-Fold Training Loop\n",
336
+ "\n",
337
+ "The heart of our training pipeline - implements **5-Fold Stratified Cross-Validation**.\n",
338
+ "\n",
339
+ "### Why K-Fold Cross-Validation?\n",
340
+ "- More reliable performance estimates than a single train/val split\n",
341
+ "- Every sample is used for validation exactly once\n",
342
+ "- Out-of-fold predictions can be used for threshold optimization\n",
343
+ "- Reduces variance in model performance\n",
344
+ "\n",
345
+ "### Why Stratified?\n",
346
+ "- Maintains label distribution in each fold\n",
347
+ "- Important for imbalanced datasets\n",
348
+ "- For multi-label, we concatenate all labels into a string for stratification\n",
349
+ "\n",
350
+ "### Training Process per Fold:\n",
351
+ "1. **Split data**: 80% training, 20% validation\n",
352
+ "2. **Initialize model**: Fresh DeBERTa-v3-base with random classification head\n",
353
+ "3. **Setup optimizer**: AdamW with differential weight decay\n",
354
+ "4. **Setup scheduler**: Linear warmup (10% of steps) then linear decay to 0\n",
355
+ "5. **Train for 4 epochs**: Track training and validation metrics\n",
356
+ "6. **Save best model**: Based on validation F1 score\n",
357
+ "7. **Store OOF predictions**: For threshold tuning\n",
358
+ "8. **Clean up memory**: Delete model and optimizer, run garbage collection\n",
359
+ "\n",
360
+ "### Output:\n",
361
+ "- 5 trained models (one per fold) saved as `model_fold_{0-4}.pth`\n",
362
+ "- Out-of-fold predictions for the entire training set\n",
363
+ "- Cross-validated performance metrics"
364
+ ]
365
+ },
366
+ {
367
+ "cell_type": "code",
368
+ "execution_count": null,
369
+ "metadata": {},
370
+ "outputs": [],
371
+ "source": [
372
+ "def run_training():\n",
373
+ " if not os.path.exists(CONFIG.TRAIN_CSV):\n",
374
+ " print(\"Train CSV not found. Please check the path.\")\n",
375
+ " return None, None\n",
376
+ "\n",
377
+ " df = pd.read_csv(CONFIG.TRAIN_CSV)\n",
378
+ " df = ensure_text_column(df)\n",
379
+ " \n",
380
+ " # Create Stratified Folds\n",
381
+ " skf = StratifiedKFold(n_splits=CONFIG.N_FOLDS, shuffle=True, random_state=CONFIG.SEED)\n",
382
+ " y_str = df[CONFIG.LABELS].astype(str).agg(\"\".join, axis=1)\n",
383
+ " \n",
384
+ " oof_preds = np.zeros((len(df), len(CONFIG.LABELS)))\n",
385
+ " \n",
386
+ " tokenizer = AutoTokenizer.from_pretrained(CONFIG.MODEL_NAME)\n",
387
+ " \n",
388
+ " for fold, (train_idx, val_idx) in enumerate(skf.split(df, y_str)):\n",
389
+ " print(f\"\\n{'='*20} FOLD {fold+1}/{CONFIG.N_FOLDS} {'='*20}\")\n",
390
+ " \n",
391
+ " df_tr = df.iloc[train_idx].reset_index(drop=True)\n",
392
+ " df_va = df.iloc[val_idx].reset_index(drop=True)\n",
393
+ " \n",
394
+ " ds_tr = EmotionDS(df_tr, tokenizer, CONFIG.MAX_LEN)\n",
395
+ " ds_va = EmotionDS(df_va, tokenizer, CONFIG.MAX_LEN)\n",
396
+ " \n",
397
+ " dl_tr = torch.utils.data.DataLoader(ds_tr, batch_size=CONFIG.BATCH_SIZE, shuffle=True, num_workers=2, pin_memory=True)\n",
398
+ " dl_va = torch.utils.data.DataLoader(ds_va, batch_size=CONFIG.BATCH_SIZE, shuffle=False, num_workers=2, pin_memory=True)\n",
399
+ " \n",
400
+ " model = AutoModelForSequenceClassification.from_pretrained(\n",
401
+ " CONFIG.MODEL_NAME, \n",
402
+ " num_labels=len(CONFIG.LABELS),\n",
403
+ " problem_type=\"multi_label_classification\"\n",
404
+ " )\n",
405
+ " model.to(device)\n",
406
+ " \n",
407
+ " optimizer_params = get_optimizer_params(model, CONFIG.LR, CONFIG.WEIGHT_DECAY)\n",
408
+ " optimizer = AdamW(optimizer_params, lr=CONFIG.LR)\n",
409
+ " \n",
410
+ " total_steps = len(dl_tr) * CONFIG.EPOCHS\n",
411
+ " scheduler = get_linear_schedule_with_warmup(\n",
412
+ " optimizer, \n",
413
+ " num_warmup_steps=int(total_steps * CONFIG.WARMUP_RATIO), \n",
414
+ " num_training_steps=total_steps\n",
415
+ " )\n",
416
+ " \n",
417
+ " criterion = nn.BCEWithLogitsLoss()\n",
418
+ " scaler = GradScaler(enabled=True)\n",
419
+ " \n",
420
+ " best_f1 = 0\n",
421
+ " best_state = None\n",
422
+ " \n",
423
+ " for ep in range(CONFIG.EPOCHS):\n",
424
+ " train_loss = train_one_epoch(model, dl_tr, optimizer, scheduler, scaler, criterion)\n",
425
+ " val_loss, val_preds, val_targs = validate(model, dl_va, criterion)\n",
426
+ " \n",
427
+ " val_f1 = f1_score(val_targs, (val_preds >= 0.5).astype(int), average=\"macro\", zero_division=0)\n",
428
+ " \n",
429
+ " print(f\"Ep {ep+1}: TrLoss={train_loss:.4f} | VaLoss={val_loss:.4f} | VaF1={val_f1:.4f}\")\n",
430
+ " \n",
431
+ " if val_f1 > best_f1:\n",
432
+ " best_f1 = val_f1\n",
433
+ " best_state = model.state_dict()\n",
434
+ " \n",
435
+ " torch.save(best_state, f\"model_fold_{fold}.pth\")\n",
436
+ " \n",
437
+ " model.load_state_dict(best_state)\n",
438
+ " _, val_preds, _ = validate(model, dl_va, criterion)\n",
439
+ " oof_preds[val_idx] = val_preds\n",
440
+ " \n",
441
+ " del model, optimizer, scaler, scheduler\n",
442
+ " torch.cuda.empty_cache()\n",
443
+ " gc.collect()\n",
444
+ " \n",
445
+ " return oof_preds, df[CONFIG.LABELS].values\n",
446
+ "\n",
447
+ "if os.path.exists(CONFIG.TRAIN_CSV):\n",
448
+ " oof_preds, y_true = run_training()\n",
449
+ "else:\n",
450
+ " print(\"Skipping training as data is not found (likely in a dry-run environment).\")"
451
+ ]
452
+ },
453
+ {
454
+ "cell_type": "markdown",
455
+ "metadata": {},
456
+ "source": [
457
+ "## 8. Threshold Optimization\n",
458
+ "\n",
459
+ "**Why optimize thresholds?**\n",
460
+ "\n",
461
+ "In multi-label classification, we convert probabilities to binary predictions using a threshold:\n",
462
+ "- `prediction = 1 if probability >= threshold else 0`\n",
463
+ "- The default threshold of 0.5 is often suboptimal\n",
464
+ "- Different emotion labels may have different optimal thresholds\n",
465
+ "\n",
466
+ "**Example:**\n",
467
+ "- 'Joy' might be common → optimal threshold could be 0.4\n",
468
+ "- 'Surprise' might be rare → optimal threshold could be 0.6\n",
469
+ "\n",
470
+ "### Process:\n",
471
+ "1. Use out-of-fold predictions (already trained models, no data leakage)\n",
472
+ "2. For each label independently, test thresholds from 0.1 to 0.9\n",
473
+ "3. Select threshold that maximizes F1 score for that label\n",
474
+ "4. Apply optimized thresholds to get final binary predictions\n",
475
+ "\n",
476
+ "**Expected Improvement**: 2-5% increase in Macro F1 score\n",
477
+ "\n",
478
+ "This is a standard technique in Kaggle competitions and production systems."
479
+ ]
480
+ },
481
+ {
482
+ "cell_type": "code",
483
+ "execution_count": null,
484
+ "metadata": {},
485
+ "outputs": [],
486
+ "source": [
487
+ "if os.path.exists(CONFIG.TRAIN_CSV):\n",
488
+ " best_thresholds = tune_thresholds(y_true, oof_preds)\n",
489
+ " oof_tuned = (oof_preds >= best_thresholds).astype(int)\n",
490
+ " final_f1 = f1_score(y_true, oof_tuned, average=\"macro\", zero_division=0)\n",
491
+ " print(f\"\\nFinal CV Macro F1: {final_f1:.4f}\")\n",
492
+ " print(f\"Best Thresholds: {best_thresholds}\")\n",
493
+ "else:\n",
494
+ " best_thresholds = np.array([0.5] * len(CONFIG.LABELS))"
495
+ ]
496
+ },
497
+ {
498
+ "cell_type": "markdown",
499
+ "metadata": {},
500
+ "source": [
501
+ "## 9. Inference & Submission\n",
502
+ "\n",
503
+ "Final prediction pipeline for test data.\n",
504
+ "\n",
505
+ "### Ensemble Strategy:\n",
506
+ "We use **model averaging** across all 5 folds:\n",
507
+ "1. Load each trained fold model\n",
508
+ "2. Make predictions on test set\n",
509
+ "3. Average the probabilities across all folds\n",
510
+ "4. Apply optimized thresholds to get binary predictions\n",
511
+ "\n",
512
+ "### Why ensemble?\n",
513
+ "- Reduces variance and overfitting\n",
514
+ "- More robust predictions\n",
515
+ "- Often improves score by 1-3%\n",
516
+ "- Each fold sees different training data, captures different patterns\n",
517
+ "\n",
518
+ "### Process:\n",
519
+ "1. Load test data and tokenize\n",
520
+ "2. For each fold:\n",
521
+ " - Load saved model weights\n",
522
+ " - Generate predictions (probabilities)\n",
523
+ " - Clean up memory\n",
524
+ "3. Average all fold predictions\n",
525
+ "4. Apply optimized thresholds\n",
526
+ "5. Create submission file with format: `id, anger, fear, joy, sadness, surprise`\n",
527
+ "\n",
528
+ "### Output:\n",
529
+ "- `submission.csv` ready for Kaggle upload\n",
530
+ "- Binary predictions (0 or 1) for each emotion per text"
531
+ ]
532
+ },
533
+ {
534
+ "cell_type": "code",
535
+ "execution_count": null,
536
+ "metadata": {},
537
+ "outputs": [],
538
+ "source": [
539
+ "def predict_test(thresholds):\n",
540
+ " if not os.path.exists(CONFIG.TEST_CSV):\n",
541
+ " print(\"Test CSV not found.\")\n",
542
+ " return\n",
543
+ "\n",
544
+ " df_test = pd.read_csv(CONFIG.TEST_CSV)\n",
545
+ " df_test = ensure_text_column(df_test)\n",
546
+ " \n",
547
+ " tokenizer = AutoTokenizer.from_pretrained(CONFIG.MODEL_NAME)\n",
548
+ " ds_test = EmotionDS(df_test, tokenizer, CONFIG.MAX_LEN, is_test=True)\n",
549
+ " dl_test = torch.utils.data.DataLoader(ds_test, batch_size=CONFIG.BATCH_SIZE, shuffle=False, num_workers=2)\n",
550
+ " \n",
551
+ " fold_preds = []\n",
552
+ " \n",
553
+ " for fold in range(CONFIG.N_FOLDS):\n",
554
+ " model_path = f\"model_fold_{fold}.pth\"\n",
555
+ " if not os.path.exists(model_path):\n",
556
+ " print(f\"Model for fold {fold} not found, skipping.\")\n",
557
+ " continue\n",
558
+ " \n",
559
+ " print(f\"Predicting Fold {fold+1}...\")\n",
560
+ " model = AutoModelForSequenceClassification.from_pretrained(\n",
561
+ " CONFIG.MODEL_NAME, \n",
562
+ " num_labels=len(CONFIG.LABELS),\n",
563
+ " problem_type=\"multi_label_classification\"\n",
564
+ " )\n",
565
+ " model.load_state_dict(torch.load(model_path))\n",
566
+ " model.to(device)\n",
567
+ " model.eval()\n",
568
+ " \n",
569
+ " preds = []\n",
570
+ " with torch.no_grad():\n",
571
+ " for batch in dl_test:\n",
572
+ " batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}\n",
573
+ " with autocast(enabled=True):\n",
574
+ " out = model(input_ids=batch[\"input_ids\"], attention_mask=batch[\"attention_mask\"])\n",
575
+ " preds.append(torch.sigmoid(out.logits).float().cpu().numpy())\n",
576
+ " \n",
577
+ " fold_preds.append(np.vstack(preds))\n",
578
+ " del model\n",
579
+ " torch.cuda.empty_cache()\n",
580
+ " gc.collect()\n",
581
+ " \n",
582
+ " if not fold_preds:\n",
583
+ " print(\"No predictions made.\")\n",
584
+ " return\n",
585
+ "\n",
586
+ " avg_preds = np.mean(fold_preds, axis=0)\n",
587
+ " final_preds = (avg_preds >= thresholds).astype(int)\n",
588
+ " \n",
589
+ " sub = pd.DataFrame(columns=[\"id\"] + CONFIG.LABELS)\n",
590
+ " sub[\"id\"] = df_test[\"id\"] if \"id\" in df_test.columns else np.arange(len(df_test))\n",
591
+ " sub[CONFIG.LABELS] = final_preds\n",
592
+ " sub.to_csv(CONFIG.SUBMISSION_PATH, index=False)\n",
593
+ " print(f\"Submission saved to {CONFIG.SUBMISSION_PATH}\")\n",
594
+ " print(sub.head())\n",
595
+ "\n",
596
+ "predict_test(best_thresholds)"
597
+ ]
598
+ }
599
+ ],
600
+ "metadata": {
601
+ "kernelspec": {
602
+ "display_name": ".venv",
603
+ "language": "python",
604
+ "name": "python3"
605
+ },
606
+ "language_info": {
607
+ "codemirror_mode": {
608
+ "name": "ipython",
609
+ "version": 3
610
+ },
611
+ "file_extension": ".py",
612
+ "mimetype": "text/x-python",
613
+ "name": "python",
614
+ "nbconvert_exporter": "python",
615
+ "pygments_lexer": "ipython3",
616
+ "version": "3.13.7"
617
+ }
618
+ },
619
+ "nbformat": 4,
620
+ "nbformat_minor": 5
621
+ }
main_code_explanation.md ADDED
@@ -0,0 +1,812 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deep Learning Emotion Classification - Code Explanation
2
+
3
+ This document provides a detailed line-by-line explanation of the `main.ipynb` notebook, which implements a multi-label emotion classification system using the DeBERTa transformer model with K-Fold cross-validation.
4
+
5
+ ---
6
+
7
+ ## Section 1: Imports & Setup
8
+
9
+ ### Lines 18-36: Import Statements
10
+
11
+ ```python
12
+ import numpy as np
13
+ import pandas as pd
14
+ ```
15
+ - **numpy**: Used for numerical operations, array manipulation, and random seed setting
16
+ - **pandas**: Used for data loading and manipulation (CSV files, DataFrames)
17
+
18
+ ```python
19
+ import torch
20
+ import torch.nn as nn
21
+ ```
22
+ - **torch**: PyTorch deep learning framework for tensor operations and model training
23
+ - **torch.nn**: Neural network modules including loss functions
24
+
25
+ ```python
26
+ from sklearn.model_selection import StratifiedKFold
27
+ from sklearn.metrics import f1_score
28
+ ```
29
+ - **StratifiedKFold**: Creates k-fold splits while maintaining class distribution in each fold
30
+ - **f1_score**: Calculates F1 metric for evaluation (harmonic mean of precision and recall)
31
+
32
+ ```python
33
+ from transformers import (
34
+ AutoTokenizer,
35
+ AutoModelForSequenceClassification,
36
+ get_linear_schedule_with_warmup,
37
+ AutoConfig
38
+ )
39
+ ```
40
+ - **AutoTokenizer**: Automatically loads the appropriate tokenizer for the specified model
41
+ - **AutoModelForSequenceClassification**: Pre-trained transformer model for classification tasks
42
+ - **get_linear_schedule_with_warmup**: Learning rate scheduler with warmup and linear decay
43
+ - **AutoConfig**: Model configuration loader
44
+
45
+ ```python
46
+ from torch.optim import AdamW
47
+ ```
48
+ - **AdamW**: Adam optimizer with decoupled weight decay (better than standard Adam for transformers)
49
+
50
+ ```python
51
+ from torch.cuda.amp import autocast, GradScaler
52
+ ```
53
+ - **autocast**: Enables automatic mixed precision (AMP) to speed up training
54
+ - **GradScaler**: Scales gradients for mixed precision training to prevent underflow
55
+
56
+ ```python
57
+ import gc
58
+ import warnings
59
+ import os
60
+ ```
61
+ - **gc**: Garbage collection to free up memory
62
+ - **warnings**: To suppress warning messages
63
+ - **os**: For file system operations and environment variables
64
+
65
+ ```python
66
+ warnings.filterwarnings("ignore")
67
+ ```
68
+ - Suppresses all warning messages for cleaner output
69
+
70
+ ---
71
+
72
+ ## Section 2: Configuration
73
+
74
+ ### Lines 52-68: Configuration Class
75
+
76
+ ```python
77
+ class Config:
78
+ SEED = 42
79
+ ```
80
+ - Sets random seed for reproducibility across all random operations
81
+
82
+ ```python
83
+ LABELS = ["anger", "fear", "joy", "sadness", "surprise"]
84
+ ```
85
+ - Defines the 5 emotion labels for multi-label classification
86
+
87
+ ```python
88
+ MODEL_NAME = "microsoft/deberta-v3-base"
89
+ ```
90
+ - Specifies the pre-trained model (DeBERTa v3 base - 184M parameters, SOTA performance)
91
+
92
+ ```python
93
+ MAX_LEN = 128
94
+ ```
95
+ - Maximum sequence length for tokenization (tokens longer than this are truncated)
96
+
97
+ ```python
98
+ BATCH_SIZE = 16
99
+ ```
100
+ - Number of samples processed together in one forward/backward pass
101
+
102
+ ```python
103
+ EPOCHS = 4
104
+ ```
105
+ - Number of complete passes through the training dataset
106
+
107
+ ```python
108
+ LR = 1.5e-5
109
+ ```
110
+ - Learning rate (1.5 × 10⁻⁵) - small value typical for fine-tuning transformers
111
+
112
+ ```python
113
+ WEIGHT_DECAY = 0.01
114
+ ```
115
+ - L2 regularization strength to prevent overfitting
116
+
117
+ ```python
118
+ WARMUP_RATIO = 0.1
119
+ ```
120
+ - Fraction of training steps used for learning rate warmup (10% of total steps)
121
+
122
+ ```python
123
+ N_FOLDS = 5
124
+ ```
125
+ - Number of folds for K-Fold cross-validation
126
+
127
+ ```python
128
+ TRAIN_CSV = "/kaggle/input/2025-sep-dl-gen-ai-project/train.csv"
129
+ TEST_CSV = "/kaggle/input/2025-sep-dl-gen-ai-project/test.csv"
130
+ ```
131
+ - Paths to training and test datasets (Kaggle environment paths)
132
+
133
+ ```python
134
+ SUBMISSION_PATH = "submission.csv"
135
+ ```
136
+ - Output file for predictions
137
+
138
+ ```python
139
+ CONFIG = Config()
140
+ ```
141
+ - Creates a global instance of the configuration class
142
+
143
+ ---
144
+
145
+ ## Section 3: Seed & Device Setup
146
+
147
+ ### Lines 84-93: Reproducibility and Device Selection
148
+
149
+ ```python
150
+ def set_seed(seed=CONFIG.SEED):
151
+ np.random.seed(seed)
152
+ ```
153
+ - Sets numpy's random seed for reproducible random number generation
154
+
155
+ ```python
156
+ torch.manual_seed(seed)
157
+ ```
158
+ - Sets PyTorch's random seed for CPU operations
159
+
160
+ ```python
161
+ torch.cuda.manual_seed_all(seed)
162
+ ```
163
+ - Sets PyTorch's random seed for all GPU devices
164
+
165
+ ```python
166
+ os.environ['PYTHONHASHSEED'] = str(seed)
167
+ ```
168
+ - Sets hash seed for Python's built-in hash() function for reproducibility
169
+
170
+ ```python
171
+ set_seed()
172
+ ```
173
+ - Calls the seed setting function
174
+
175
+ ```python
176
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
177
+ print(f"Using device: {device}")
178
+ ```
179
+ - Checks if GPU is available; uses GPU if available, otherwise falls back to CPU
180
+ - Prints the device being used for training
181
+
182
+ ---
183
+
184
+ ## Section 4: Utility Functions
185
+
186
+ ### Lines 109-115: `ensure_text_column` Function
187
+
188
+ ```python
189
+ def ensure_text_column(df: pd.DataFrame) -> pd.DataFrame:
190
+ if "text" in df.columns:
191
+ return df
192
+ ```
193
+ - Checks if DataFrame already has a "text" column; if yes, returns unchanged
194
+
195
+ ```python
196
+ for c in ["comment_text", "sentence", "content", "review"]:
197
+ if c in df.columns:
198
+ return df.rename(columns={c: "text"})
199
+ ```
200
+ - Searches for common alternative text column names
201
+ - Renames the first matching column to "text" for standardization
202
+
203
+ ```python
204
+ raise ValueError("No text column found. Add/rename your text column to 'text'.")
205
+ ```
206
+ - Raises an error if no text column is found
207
+
208
+ ### Lines 117-126: `tune_thresholds` Function
209
+
210
+ ```python
211
+ def tune_thresholds(y_true: np.ndarray, y_prob: np.ndarray) -> np.ndarray:
212
+ th = np.zeros(y_true.shape[1], dtype=np.float32)
213
+ ```
214
+ - Creates array to store optimal threshold for each label (initialized to 0)
215
+ - Multi-label classification requires separate thresholds per label
216
+
217
+ ```python
218
+ for j in range(y_true.shape[1]):
219
+ best_t, best_f1 = 0.5, -1
220
+ ```
221
+ - Iterates through each label
222
+ - Initializes best threshold to 0.5 (default) and best F1 to -1
223
+
224
+ ```python
225
+ for t in np.linspace(0.1, 0.9, 17):
226
+ ```
227
+ - Tests 17 threshold values evenly spaced between 0.1 and 0.9
228
+
229
+ ```python
230
+ f1 = f1_score(y_true[:, j], (y_prob[:, j] >= t).astype(int), zero_division=0)
231
+ ```
232
+ - Calculates F1 score for current label and threshold
233
+ - Converts probabilities to binary predictions using threshold
234
+
235
+ ```python
236
+ if f1 > best_f1:
237
+ best_f1, best_t = f1, t
238
+ ```
239
+ - Updates best threshold if current F1 is better
240
+
241
+ ```python
242
+ th[j] = best_t
243
+ return th
244
+ ```
245
+ - Stores optimal threshold for each label and returns the array
246
+
247
+ ### Lines 128-141: `get_optimizer_params` Function
248
+
249
+ ```python
250
+ def get_optimizer_params(model, lr, weight_decay):
251
+ param_optimizer = list(model.named_parameters())
252
+ ```
253
+ - Gets all model parameters with their names
254
+
255
+ ```python
256
+ no_decay = ["bias", "LayerNorm.bias", "LayerNorm.weight"]
257
+ ```
258
+ - Lists parameters that should NOT have weight decay applied
259
+ - Bias and LayerNorm parameters typically trained without weight decay
260
+
261
+ ```python
262
+ optimizer_parameters = [
263
+ {
264
+ "params": [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],
265
+ "weight_decay": weight_decay,
266
+ },
267
+ ```
268
+ - First parameter group: all parameters EXCEPT bias and LayerNorm
269
+ - These parameters will have weight decay applied
270
+
271
+ ```python
272
+ {
273
+ "params": [p for n, p in param_optimizer if any(nd in n for nd in no_decay)],
274
+ "weight_decay": 0.0,
275
+ },
276
+ ]
277
+ ```
278
+ - Second parameter group: only bias and LayerNorm parameters
279
+ - These parameters have weight decay set to 0.0
280
+
281
+ ```python
282
+ return optimizer_parameters
283
+ ```
284
+ - Returns grouped parameters for differential weight decay
285
+
286
+ ---
287
+
288
+ ## Section 5: Dataset Class
289
+
290
+ ### Lines 157-180: `EmotionDS` Class
291
+
292
+ ```python
293
+ class EmotionDS(torch.utils.data.Dataset):
294
+ def __init__(self, df, tokenizer, max_len, is_test=False):
295
+ ```
296
+ - Custom PyTorch Dataset class for emotion classification
297
+ - `is_test` flag indicates whether this is test data (no labels)
298
+
299
+ ```python
300
+ self.texts = df["text"].tolist()
301
+ ```
302
+ - Extracts text data as a Python list
303
+
304
+ ```python
305
+ self.is_test = is_test
306
+ if not is_test:
307
+ self.labels = df[CONFIG.LABELS].values.astype(np.float32)
308
+ ```
309
+ - Stores test flag
310
+ - If training data, extracts multi-label targets as float32 array
311
+
312
+ ```python
313
+ self.tok = tokenizer
314
+ self.max_len = max_len
315
+ ```
316
+ - Stores tokenizer and max length for later use
317
+
318
+ ```python
319
+ def __len__(self):
320
+ return len(self.texts)
321
+ ```
322
+ - Returns dataset size (required by PyTorch)
323
+
324
+ ```python
325
+ def __getitem__(self, i):
326
+ enc = self.tok(
327
+ self.texts[i],
328
+ truncation=True,
329
+ padding="max_length",
330
+ max_length=self.max_len,
331
+ return_tensors="pt",
332
+ )
333
+ ```
334
+ - Tokenizes the text at index `i`
335
+ - **truncation**: Cuts text longer than max_len
336
+ - **padding**: Pads shorter sequences to max_len
337
+ - **return_tensors="pt"**: Returns PyTorch tensors
338
+
339
+ ```python
340
+ item = {k: v.squeeze(0) for k, v in enc.items()}
341
+ ```
342
+ - Removes the batch dimension (1, seq_len) → (seq_len)
343
+ - Returns dict with keys: input_ids, attention_mask, token_type_ids (if applicable)
344
+
345
+ ```python
346
+ if not self.is_test:
347
+ item["labels"] = torch.tensor(self.labels[i])
348
+ return item
349
+ ```
350
+ - Adds labels to the item dict if training data
351
+ - Returns the complete item
352
+
353
+ ---
354
+
355
+ ## Section 6: Training & Validation Helper Functions
356
+
357
+ ### Lines 196-213: `train_one_epoch` Function
358
+
359
+ ```python
360
+ def train_one_epoch(model, loader, optimizer, scheduler, scaler, criterion):
361
+ model.train()
362
+ ```
363
+ - Sets model to training mode (enables dropout, batch normalization updates)
364
+
365
+ ```python
366
+ losses = []
367
+ for batch in loader:
368
+ ```
369
+ - Initializes list to track losses
370
+ - Iterates through batches
371
+
372
+ ```python
373
+ batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}
374
+ ```
375
+ - Moves batch data to GPU (or CPU)
376
+ - `non_blocking=True`: Async transfer for faster processing
377
+
378
+ ```python
379
+ optimizer.zero_grad(set_to_none=True)
380
+ ```
381
+ - Clears gradients from previous step
382
+ - `set_to_none=True`: More memory efficient than setting to zero
383
+
384
+ ```python
385
+ with autocast(enabled=True):
386
+ out = model(input_ids=batch["input_ids"], attention_mask=batch["attention_mask"])
387
+ loss = criterion(out.logits, batch["labels"])
388
+ ```
389
+ - **autocast**: Uses mixed precision (float16) for faster computation
390
+ - Forward pass through model
391
+ - Calculates loss between predictions (logits) and true labels
392
+
393
+ ```python
394
+ scaler.scale(loss).backward()
395
+ ```
396
+ - Scales loss to prevent gradient underflow in mixed precision
397
+ - Computes gradients via backpropagation
398
+
399
+ ```python
400
+ scaler.unscale_(optimizer)
401
+ torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
402
+ ```
403
+ - Unscales gradients before clipping
404
+ - Clips gradients to maximum norm of 1.0 to prevent exploding gradients
405
+
406
+ ```python
407
+ scaler.step(optimizer)
408
+ scaler.update()
409
+ ```
410
+ - Updates model parameters (with scaled gradients)
411
+ - Updates the scaler's internal state
412
+
413
+ ```python
414
+ scheduler.step()
415
+ ```
416
+ - Updates learning rate according to schedule
417
+
418
+ ```python
419
+ losses.append(loss.item())
420
+ return np.mean(losses)
421
+ ```
422
+ - Stores loss value
423
+ - Returns average loss for the epoch
424
+
425
+ ### Lines 215-230: `validate` Function
426
+
427
+ ```python
428
+ def validate(model, loader, criterion):
429
+ model.eval()
430
+ ```
431
+ - Sets model to evaluation mode (disables dropout, fixes batch norm)
432
+
433
+ ```python
434
+ losses = []
435
+ preds = []
436
+ targs = []
437
+ ```
438
+ - Initializes lists for losses, predictions, and targets
439
+
440
+ ```python
441
+ with torch.no_grad():
442
+ ```
443
+ - Disables gradient computation (saves memory and speeds up inference)
444
+
445
+ ```python
446
+ for batch in loader:
447
+ batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}
448
+ with autocast(enabled=True):
449
+ out = model(input_ids=batch["input_ids"], attention_mask=batch["attention_mask"])
450
+ loss = criterion(out.logits, batch["labels"])
451
+ ```
452
+ - Moves batch to device
453
+ - Forward pass with mixed precision
454
+ - Calculates validation loss
455
+
456
+ ```python
457
+ losses.append(loss.item())
458
+ preds.append(torch.sigmoid(out.logits).float().cpu().numpy())
459
+ targs.append(batch["labels"].cpu().numpy())
460
+ ```
461
+ - Stores loss
462
+ - Applies sigmoid to convert logits to probabilities [0, 1]
463
+ - Moves predictions and targets to CPU as numpy arrays
464
+
465
+ ```python
466
+ return np.mean(losses), np.vstack(preds), np.vstack(targs)
467
+ ```
468
+ - Returns average loss, stacked predictions, and stacked targets
469
+
470
+ ---
471
+
472
+ ## Section 7: Main K-Fold Training Loop
473
+
474
+ ### Lines 246-324: `run_training` Function
475
+
476
+ ```python
477
+ def run_training():
478
+ if not os.path.exists(CONFIG.TRAIN_CSV):
479
+ print("Train CSV not found. Please check the path.")
480
+ return None, None
481
+ ```
482
+ - Checks if training data exists
483
+ - Returns None if not found (graceful failure)
484
+
485
+ ```python
486
+ df = pd.read_csv(CONFIG.TRAIN_CSV)
487
+ df = ensure_text_column(df)
488
+ ```
489
+ - Loads training data
490
+ - Ensures text column exists
491
+
492
+ ```python
493
+ skf = StratifiedKFold(n_splits=CONFIG.N_FOLDS, shuffle=True, random_state=CONFIG.SEED)
494
+ y_str = df[CONFIG.LABELS].astype(str).agg("".join, axis=1)
495
+ ```
496
+ - Creates 5-fold stratified splitter
497
+ - Converts multi-label to string representation for stratification
498
+ - Example: [1,0,1,0,0] → "10100"
499
+
500
+ ```python
501
+ oof_preds = np.zeros((len(df), len(CONFIG.LABELS)))
502
+ ```
503
+ - Initializes out-of-fold predictions array (for all training samples)
504
+
505
+ ```python
506
+ tokenizer = AutoTokenizer.from_pretrained(CONFIG.MODEL_NAME)
507
+ ```
508
+ - Loads DeBERTa tokenizer
509
+
510
+ ```python
511
+ for fold, (train_idx, val_idx) in enumerate(skf.split(df, y_str)):
512
+ print(f"\n{'='*20} FOLD {fold+1}/{CONFIG.N_FOLDS} {'='*20}")
513
+ ```
514
+ - Iterates through each fold
515
+ - `train_idx`: indices for training, `val_idx`: indices for validation
516
+
517
+ ```python
518
+ df_tr = df.iloc[train_idx].reset_index(drop=True)
519
+ df_va = df.iloc[val_idx].reset_index(drop=True)
520
+ ```
521
+ - Splits data into training and validation sets for current fold
522
+ - Resets index for clean indexing
523
+
524
+ ```python
525
+ ds_tr = EmotionDS(df_tr, tokenizer, CONFIG.MAX_LEN)
526
+ ds_va = EmotionDS(df_va, tokenizer, CONFIG.MAX_LEN)
527
+ ```
528
+ - Creates PyTorch datasets for training and validation
529
+
530
+ ```python
531
+ dl_tr = torch.utils.data.DataLoader(ds_tr, batch_size=CONFIG.BATCH_SIZE, shuffle=True, num_workers=2, pin_memory=True)
532
+ dl_va = torch.utils.data.DataLoader(ds_va, batch_size=CONFIG.BATCH_SIZE, shuffle=False, num_workers=2, pin_memory=True)
533
+ ```
534
+ - Creates data loaders
535
+ - **shuffle=True** for training (randomizes batch order)
536
+ - **shuffle=False** for validation (keeps consistent order)
537
+ - **num_workers=2**: Uses 2 subprocesses for data loading
538
+ - **pin_memory=True**: Speeds up CPU→GPU transfer
539
+
540
+ ```python
541
+ model = AutoModelForSequenceClassification.from_pretrained(
542
+ CONFIG.MODEL_NAME,
543
+ num_labels=len(CONFIG.LABELS),
544
+ problem_type="multi_label_classification"
545
+ )
546
+ model.to(device)
547
+ ```
548
+ - Loads pre-trained DeBERTa model
549
+ - Configures for 5-label multi-label classification
550
+ - Moves model to GPU/CPU
551
+
552
+ ```python
553
+ optimizer_params = get_optimizer_params(model, CONFIG.LR, CONFIG.WEIGHT_DECAY)
554
+ optimizer = AdamW(optimizer_params, lr=CONFIG.LR)
555
+ ```
556
+ - Gets parameter groups with differential weight decay
557
+ - Creates AdamW optimizer
558
+
559
+ ```python
560
+ total_steps = len(dl_tr) * CONFIG.EPOCHS
561
+ scheduler = get_linear_schedule_with_warmup(
562
+ optimizer,
563
+ num_warmup_steps=int(total_steps * CONFIG.WARMUP_RATIO),
564
+ num_training_steps=total_steps
565
+ )
566
+ ```
567
+ - Calculates total training steps
568
+ - Creates learning rate scheduler:
569
+ - Warmup: LR increases linearly for 10% of steps
570
+ - Decay: LR decreases linearly to 0 for remaining 90%
571
+
572
+ ```python
573
+ criterion = nn.BCEWithLogitsLoss()
574
+ scaler = GradScaler(enabled=True)
575
+ ```
576
+ - **BCEWithLogitsLoss**: Binary cross-entropy loss for multi-label classification
577
+ - Creates gradient scaler for mixed precision
578
+
579
+ ```python
580
+ best_f1 = 0
581
+ best_state = None
582
+ ```
583
+ - Initializes tracking for best model
584
+
585
+ ```python
586
+ for ep in range(CONFIG.EPOCHS):
587
+ train_loss = train_one_epoch(model, dl_tr, optimizer, scheduler, scaler, criterion)
588
+ val_loss, val_preds, val_targs = validate(model, dl_va, criterion)
589
+ ```
590
+ - Trains for one epoch
591
+ - Validates on validation set
592
+
593
+ ```python
594
+ val_f1 = f1_score(val_targs, (val_preds >= 0.5).astype(int), average="macro", zero_division=0)
595
+ ```
596
+ - Calculates macro F1 score (average F1 across all labels)
597
+ - Uses 0.5 threshold for predictions
598
+
599
+ ```python
600
+ print(f"Ep {ep+1}: TrLoss={train_loss:.4f} | VaLoss={val_loss:.4f} | VaF1={val_f1:.4f}")
601
+ ```
602
+ - Prints epoch metrics
603
+
604
+ ```python
605
+ if val_f1 > best_f1:
606
+ best_f1 = val_f1
607
+ best_state = model.state_dict()
608
+ ```
609
+ - Saves model state if validation F1 improves
610
+
611
+ ```python
612
+ torch.save(best_state, f"model_fold_{fold}.pth")
613
+ ```
614
+ - Saves best model weights to disk
615
+
616
+ ```python
617
+ model.load_state_dict(best_state)
618
+ _, val_preds, _ = validate(model, dl_va, criterion)
619
+ oof_preds[val_idx] = val_preds
620
+ ```
621
+ - Loads best weights
622
+ - Gets predictions on validation set
623
+ - Stores out-of-fold predictions
624
+
625
+ ```python
626
+ del model, optimizer, scaler, scheduler
627
+ torch.cuda.empty_cache()
628
+ gc.collect()
629
+ ```
630
+ - Deletes objects to free memory
631
+ - Clears GPU cache
632
+ - Runs garbage collector
633
+
634
+ ```python
635
+ return oof_preds, df[CONFIG.LABELS].values
636
+ ```
637
+ - Returns out-of-fold predictions and true labels
638
+
639
+ ```python
640
+ if os.path.exists(CONFIG.TRAIN_CSV):
641
+ oof_preds, y_true = run_training()
642
+ else:
643
+ print("Skipping training as data is not found (likely in a dry-run environment).")
644
+ ```
645
+ - Executes training if data exists
646
+ - Otherwise skips gracefully
647
+
648
+ ---
649
+
650
+ ## Section 8: Threshold Optimization
651
+
652
+ ### Lines 340-347: Threshold Tuning
653
+
654
+ ```python
655
+ if os.path.exists(CONFIG.TRAIN_CSV):
656
+ best_thresholds = tune_thresholds(y_true, oof_preds)
657
+ ```
658
+ - Finds optimal threshold for each emotion label using validation predictions
659
+
660
+ ```python
661
+ oof_tuned = (oof_preds >= best_thresholds).astype(int)
662
+ ```
663
+ - Converts probabilities to binary predictions using optimized thresholds
664
+
665
+ ```python
666
+ final_f1 = f1_score(y_true, oof_tuned, average="macro", zero_division=0)
667
+ print(f"\nFinal CV Macro F1: {final_f1:.4f}")
668
+ print(f"Best Thresholds: {best_thresholds}")
669
+ ```
670
+ - Calculates cross-validated F1 score with optimized thresholds
671
+ - Prints final performance and optimal thresholds
672
+
673
+ ```python
674
+ else:
675
+ best_thresholds = np.array([0.5] * len(CONFIG.LABELS))
676
+ ```
677
+ - Falls back to 0.5 thresholds if training data not available
678
+
679
+ ---
680
+
681
+ ## Section 9: Inference & Submission
682
+
683
+ ### Lines 363-420: `predict_test` Function
684
+
685
+ ```python
686
+ def predict_test(thresholds):
687
+ if not os.path.exists(CONFIG.TEST_CSV):
688
+ print("Test CSV not found.")
689
+ return
690
+ ```
691
+ - Checks if test data exists
692
+
693
+ ```python
694
+ df_test = pd.read_csv(CONFIG.TEST_CSV)
695
+ df_test = ensure_text_column(df_test)
696
+ ```
697
+ - Loads test data and ensures text column
698
+
699
+ ```python
700
+ tokenizer = AutoTokenizer.from_pretrained(CONFIG.MODEL_NAME)
701
+ ds_test = EmotionDS(df_test, tokenizer, CONFIG.MAX_LEN, is_test=True)
702
+ dl_test = torch.utils.data.DataLoader(ds_test, batch_size=CONFIG.BATCH_SIZE, shuffle=False, num_workers=2)
703
+ ```
704
+ - Creates tokenizer, dataset, and data loader for test data
705
+ - `is_test=True`: No labels expected
706
+
707
+ ```python
708
+ fold_preds = []
709
+ ```
710
+ - Initializes list to store predictions from each fold
711
+
712
+ ```python
713
+ for fold in range(CONFIG.N_FOLDS):
714
+ model_path = f"model_fold_{fold}.pth"
715
+ if not os.path.exists(model_path):
716
+ print(f"Model for fold {fold} not found, skipping.")
717
+ continue
718
+ ```
719
+ - Iterates through all folds
720
+ - Checks if model exists
721
+
722
+ ```python
723
+ print(f"Predicting Fold {fold+1}...")
724
+ model = AutoModelForSequenceClassification.from_pretrained(
725
+ CONFIG.MODEL_NAME,
726
+ num_labels=len(CONFIG.LABELS),
727
+ problem_type="multi_label_classification"
728
+ )
729
+ model.load_state_dict(torch.load(model_path))
730
+ model.to(device)
731
+ model.eval()
732
+ ```
733
+ - Loads model architecture
734
+ - Loads trained weights
735
+ - Sets to evaluation mode
736
+
737
+ ```python
738
+ preds = []
739
+ with torch.no_grad():
740
+ for batch in dl_test:
741
+ batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}
742
+ with autocast(enabled=True):
743
+ out = model(input_ids=batch["input_ids"], attention_mask=batch["attention_mask"])
744
+ preds.append(torch.sigmoid(out.logits).float().cpu().numpy())
745
+ ```
746
+ - Makes predictions without computing gradients
747
+ - Uses mixed precision for speed
748
+ - Applies sigmoid to get probabilities
749
+
750
+ ```python
751
+ fold_preds.append(np.vstack(preds))
752
+ del model
753
+ torch.cuda.empty_cache()
754
+ gc.collect()
755
+ ```
756
+ - Stores fold predictions
757
+ - Frees memory
758
+
759
+ ```python
760
+ if not fold_preds:
761
+ print("No predictions made.")
762
+ return
763
+ ```
764
+ - Checks if any predictions were made
765
+
766
+ ```python
767
+ avg_preds = np.mean(fold_preds, axis=0)
768
+ ```
769
+ - Averages predictions across all folds (ensemble)
770
+
771
+ ```python
772
+ final_preds = (avg_preds >= thresholds).astype(int)
773
+ ```
774
+ - Applies optimized thresholds to get binary predictions
775
+
776
+ ```python
777
+ sub = pd.DataFrame(columns=["id"] + CONFIG.LABELS)
778
+ sub["id"] = df_test["id"] if "id" in df_test.columns else np.arange(len(df_test))
779
+ sub[CONFIG.LABELS] = final_preds
780
+ sub.to_csv(CONFIG.SUBMISSION_PATH, index=False)
781
+ print(f"Submission saved to {CONFIG.SUBMISSION_PATH}")
782
+ print(sub.head())
783
+ ```
784
+ - Creates submission DataFrame
785
+ - Adds ID column (from data or generated)
786
+ - Adds prediction columns
787
+ - Saves to CSV
788
+ - Displays first few rows
789
+
790
+ ```python
791
+ predict_test(best_thresholds)
792
+ ```
793
+ - Executes prediction function with optimized thresholds
794
+
795
+ ---
796
+
797
+ ## Summary
798
+
799
+ This notebook implements a **robust emotion classification pipeline** with:
800
+
801
+ 1. **K-Fold Cross-Validation**: 5-fold stratified CV for reliable performance estimates
802
+ 2. **State-of-the-Art Model**: DeBERTa-v3-base transformer
803
+ 3. **Optimization Techniques**:
804
+ - Mixed precision training (faster, less memory)
805
+ - Gradient clipping (stability)
806
+ - Learning rate warmup and decay
807
+ - Differential weight decay
808
+ 4. **Threshold Optimization**: Per-label thresholds for better F1 scores
809
+ 5. **Ensemble Prediction**: Averages predictions from all folds
810
+ 6. **Memory Management**: Explicit cleanup between folds
811
+
812
+ The model predicts 5 emotions (anger, fear, joy, sadness, surprise) in a **multi-label** setting, where text can have multiple emotions simultaneously.
submission_notebook.ipynb ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "b2b05c00",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "!pip install -q transformers torch huggingface_hub pandas numpy kaggle\n",
11
+ "\n",
12
+ "import os\n",
13
+ "from pathlib import Path\n",
14
+ "\n",
15
+ "kaggle_json_path = Path.home() / '.kaggle' / 'kaggle.json'\n",
16
+ "\n",
17
+ "if not kaggle_json_path.exists():\n",
18
+ " print(\"Kaggle credentials not found.\")\n",
19
+ " print(\"\\nIf you have kaggle.json in the current directory:\")\n",
20
+ " if Path('kaggle.json').exists():\n",
21
+ " kaggle_json_path.parent.mkdir(exist_ok=True, parents=True)\n",
22
+ " import shutil\n",
23
+ " shutil.copy('kaggle.json', kaggle_json_path)\n",
24
+ " kaggle_json_path.chmod(0o600)\n",
25
+ " print(\"Kaggle credentials configured\")\n",
26
+ " else:\n",
27
+ " print(\"\\nPlease upload kaggle.json to this directory, then re-run this cell.\")\n",
28
+ " print(\"Download from: https://www.kaggle.com/settings\")\n",
29
+ "else:\n",
30
+ " print(\"Kaggle credentials found\")\n",
31
+ "\n",
32
+ "import numpy as np\n",
33
+ "import pandas as pd\n",
34
+ "import torch\n",
35
+ "from transformers import AutoTokenizer, AutoModelForSequenceClassification\n",
36
+ "from torch.cuda.amp import autocast\n",
37
+ "from huggingface_hub import hf_hub_download\n",
38
+ "import warnings\n",
39
+ "\n",
40
+ "warnings.filterwarnings(\"ignore\")\n",
41
+ "\n",
42
+ "class Config:\n",
43
+ " HF_REPO_ID = \"YOUR_USERNAME/emotion-classifier-deberta-v3\"\n",
44
+ " COMPETITION_NAME = \"2025-sep-dl-gen-ai-project\"\n",
45
+ " LABELS = [\"anger\", \"fear\", \"joy\", \"sadness\", \"surprise\"]\n",
46
+ " MAX_LEN = 128\n",
47
+ " BATCH_SIZE = 32\n",
48
+ " TEST_CSV = \"/kaggle/input/2025-sep-dl-gen-ai-project/test.csv\"\n",
49
+ " SUBMISSION_PATH = \"submission.csv\"\n",
50
+ "\n",
51
+ "CONFIG = Config()\n",
52
+ "\n",
53
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
54
+ "print(f\"Using device: {device}\")\n",
55
+ "if torch.cuda.is_available():\n",
56
+ " print(f\"GPU: {torch.cuda.get_device_name(0)}\")\n",
57
+ "\n",
58
+ "print(f\"Loading model from HuggingFace: {CONFIG.HF_REPO_ID}\")\n",
59
+ "\n",
60
+ "try:\n",
61
+ " print(\" Loading model...\")\n",
62
+ " model = AutoModelForSequenceClassification.from_pretrained(\n",
63
+ " CONFIG.HF_REPO_ID,\n",
64
+ " num_labels=len(CONFIG.LABELS),\n",
65
+ " problem_type=\"multi_label_classification\"\n",
66
+ " )\n",
67
+ " model.to(device)\n",
68
+ " model.eval()\n",
69
+ " print(\" Model loaded\")\n",
70
+ " \n",
71
+ " print(\" Loading tokenizer...\")\n",
72
+ " tokenizer = AutoTokenizer.from_pretrained(CONFIG.HF_REPO_ID)\n",
73
+ " print(\" Tokenizer loaded\")\n",
74
+ " \n",
75
+ " print(\" Loading optimized thresholds...\")\n",
76
+ " try:\n",
77
+ " threshold_path = hf_hub_download(\n",
78
+ " repo_id=CONFIG.HF_REPO_ID,\n",
79
+ " filename=\"best_thresholds.npy\"\n",
80
+ " )\n",
81
+ " best_thresholds = np.load(threshold_path)\n",
82
+ " print(\" Optimized thresholds loaded\")\n",
83
+ " print(f\"\\n Thresholds per label:\")\n",
84
+ " for i, label in enumerate(CONFIG.LABELS):\n",
85
+ " print(f\" {label}: {best_thresholds[i]:.3f}\")\n",
86
+ " except Exception as e:\n",
87
+ " print(f\" Could not load thresholds: {e}\")\n",
88
+ " print(\" Using default thresholds of 0.5\")\n",
89
+ " best_thresholds = np.array([0.5] * len(CONFIG.LABELS))\n",
90
+ " \n",
91
+ " print(\"\\nModel setup complete\")\n",
92
+ " \n",
93
+ "except Exception as e:\n",
94
+ " print(f\"\\nError loading model: {e}\")\n",
95
+ " print(\"\\nPlease ensure:\")\n",
96
+ " print(\"1. You've updated CONFIG.HF_REPO_ID with your actual repository ID\")\n",
97
+ " print(\"2. The model was successfully uploaded in the training notebook\")\n",
98
+ " print(\"3. The repository is public or you're logged in to HuggingFace\")\n",
99
+ " raise\n",
100
+ "\n",
101
+ "def ensure_text_column(df: pd.DataFrame) -> pd.DataFrame:\n",
102
+ " if \"text\" in df.columns:\n",
103
+ " return df\n",
104
+ " for c in [\"comment_text\", \"sentence\", \"content\", \"review\"]:\n",
105
+ " if c in df.columns:\n",
106
+ " return df.rename(columns={c: \"text\"})\n",
107
+ " raise ValueError(\"No text column found. Add/rename your text column to 'text'.\")\n",
108
+ "\n",
109
+ "class EmotionDS(torch.utils.data.Dataset):\n",
110
+ " def __init__(self, texts, tokenizer, max_len):\n",
111
+ " self.texts = texts\n",
112
+ " self.tok = tokenizer\n",
113
+ " self.max_len = max_len\n",
114
+ "\n",
115
+ " def __len__(self):\n",
116
+ " return len(self.texts)\n",
117
+ "\n",
118
+ " def __getitem__(self, i):\n",
119
+ " enc = self.tok(\n",
120
+ " self.texts[i],\n",
121
+ " truncation=True,\n",
122
+ " padding=\"max_length\",\n",
123
+ " max_length=self.max_len,\n",
124
+ " return_tensors=\"pt\",\n",
125
+ " )\n",
126
+ " return {k: v.squeeze(0) for k, v in enc.items()}\n",
127
+ "\n",
128
+ "print(f\"Loading test data from: {CONFIG.TEST_CSV}\")\n",
129
+ "\n",
130
+ "if not os.path.exists(CONFIG.TEST_CSV):\n",
131
+ " print(\"Test CSV not found. Please check the path.\")\n",
132
+ " print(\"\\nIf you're running locally, make sure you have the test data.\")\n",
133
+ " print(\"On Kaggle, ensure you've added the competition data as input.\")\n",
134
+ " raise FileNotFoundError(CONFIG.TEST_CSV)\n",
135
+ "\n",
136
+ "df_test = pd.read_csv(CONFIG.TEST_CSV)\n",
137
+ "df_test = ensure_text_column(df_test)\n",
138
+ "\n",
139
+ "print(f\"Test data loaded: {len(df_test)} samples\")\n",
140
+ "print(f\"\\nColumns: {df_test.columns.tolist()}\")\n",
141
+ "print(f\"\\nFirst few rows:\")\n",
142
+ "print(df_test.head())\n",
143
+ "\n",
144
+ "print(\"\\nGenerating predictions...\\n\")\n",
145
+ "\n",
146
+ "test_texts = df_test[\"text\"].tolist()\n",
147
+ "test_dataset = EmotionDS(test_texts, tokenizer, CONFIG.MAX_LEN)\n",
148
+ "test_loader = torch.utils.data.DataLoader(\n",
149
+ " test_dataset, \n",
150
+ " batch_size=CONFIG.BATCH_SIZE, \n",
151
+ " shuffle=False, \n",
152
+ " num_workers=2,\n",
153
+ " pin_memory=True\n",
154
+ ")\n",
155
+ "\n",
156
+ "all_preds = []\n",
157
+ "\n",
158
+ "with torch.no_grad():\n",
159
+ " for batch_idx, batch in enumerate(test_loader):\n",
160
+ " batch = {k: v.to(device, non_blocking=True) for k, v in batch.items()}\n",
161
+ " \n",
162
+ " with autocast(enabled=True):\n",
163
+ " outputs = model(\n",
164
+ " input_ids=batch[\"input_ids\"], \n",
165
+ " attention_mask=batch[\"attention_mask\"]\n",
166
+ " )\n",
167
+ " \n",
168
+ " probs = torch.sigmoid(outputs.logits).float().cpu().numpy()\n",
169
+ " all_preds.append(probs)\n",
170
+ " \n",
171
+ " if (batch_idx + 1) % 10 == 0:\n",
172
+ " progress = (batch_idx + 1) * CONFIG.BATCH_SIZE\n",
173
+ " print(f\" Processed {min(progress, len(df_test))}/{len(df_test)} samples...\")\n",
174
+ "\n",
175
+ "all_probs = np.vstack(all_preds)\n",
176
+ "\n",
177
+ "print(f\"\\nPredictions generated for {len(all_probs)} samples\")\n",
178
+ "print(f\"Shape: {all_probs.shape}\")\n",
179
+ "\n",
180
+ "print(\"\\nApplying optimized thresholds...\\n\")\n",
181
+ "\n",
182
+ "final_predictions = (all_probs >= best_thresholds).astype(int)\n",
183
+ "\n",
184
+ "print(f\"Thresholds applied\")\n",
185
+ "print(f\"\\nPrediction distribution:\")\n",
186
+ "for i, label in enumerate(CONFIG.LABELS):\n",
187
+ " count = final_predictions[:, i].sum()\n",
188
+ " percentage = (count / len(final_predictions)) * 100\n",
189
+ " print(f\" {label:<12} {count:>6} samples ({percentage:>5.1f}%)\")\n",
190
+ "\n",
191
+ "avg_labels_per_sample = final_predictions.sum(axis=1).mean()\n",
192
+ "print(f\"\\n Average labels per sample: {avg_labels_per_sample:.2f}\")\n",
193
+ "\n",
194
+ "print(\"\\nCreating submission file...\\n\")\n",
195
+ "\n",
196
+ "submission = pd.DataFrame()\n",
197
+ "\n",
198
+ "if \"id\" in df_test.columns:\n",
199
+ " submission[\"id\"] = df_test[\"id\"]\n",
200
+ "else:\n",
201
+ " submission[\"id\"] = np.arange(len(df_test))\n",
202
+ "\n",
203
+ "for i, label in enumerate(CONFIG.LABELS):\n",
204
+ " submission[label] = final_predictions[:, i]\n",
205
+ "\n",
206
+ "submission.to_csv(CONFIG.SUBMISSION_PATH, index=False)\n",
207
+ "\n",
208
+ "print(f\"Submission file saved to: {CONFIG.SUBMISSION_PATH}\")\n",
209
+ "print(f\"\\nSubmission preview:\")\n",
210
+ "print(submission.head(10))\n",
211
+ "print(f\"\\nTotal rows: {len(submission)}\")\n",
212
+ "print(f\"Columns: {submission.columns.tolist()}\")\n",
213
+ "\n",
214
+ "print(\"Verifying submission format...\\n\")\n",
215
+ "\n",
216
+ "required_columns = [\"id\"] + CONFIG.LABELS\n",
217
+ "submission_columns = submission.columns.tolist()\n",
218
+ "\n",
219
+ "if submission_columns == required_columns:\n",
220
+ " print(\"Submission format is correct\")\n",
221
+ " print(f\" Columns: {submission_columns}\")\n",
222
+ " \n",
223
+ " if submission[CONFIG.LABELS].isin([0, 1]).all().all():\n",
224
+ " print(\"All predictions are binary (0 or 1)\")\n",
225
+ " else:\n",
226
+ " print(\"Warning: Some predictions are not binary\")\n",
227
+ " \n",
228
+ " if not submission.isnull().any().any():\n",
229
+ " print(\"No missing values\")\n",
230
+ " else:\n",
231
+ " print(\"Missing values detected\")\n",
232
+ " print(submission.isnull().sum())\n",
233
+ "else:\n",
234
+ " print(\"Submission format is incorrect\")\n",
235
+ " print(f\" Expected: {required_columns}\")\n",
236
+ " print(f\" Got: {submission_columns}\")\n",
237
+ "\n",
238
+ "print(\"\\nSubmitting to Kaggle...\\n\")\n",
239
+ "\n",
240
+ "submission_message = f\"DeBERTa-v3 with optimized thresholds - HF: {CONFIG.HF_REPO_ID}\"\n",
241
+ "\n",
242
+ "try:\n",
243
+ " import kaggle\n",
244
+ " \n",
245
+ " kaggle.api.competition_submit(\n",
246
+ " file_name=CONFIG.SUBMISSION_PATH,\n",
247
+ " message=submission_message,\n",
248
+ " competition=CONFIG.COMPETITION_NAME\n",
249
+ " )\n",
250
+ " \n",
251
+ " print(\"Submission successful\")\n",
252
+ " print(f\"\\nSubmission message: {submission_message}\")\n",
253
+ " print(f\"\\nView your submission at:\")\n",
254
+ " print(f\" https://www.kaggle.com/c/{CONFIG.COMPETITION_NAME}/submissions\")\n",
255
+ " \n",
256
+ "except Exception as e:\n",
257
+ " print(f\"Submission failed: {e}\")\n",
258
+ " print(\"\\nPossible reasons:\")\n",
259
+ " print(\"1. Kaggle API credentials not configured\")\n",
260
+ " print(\"2. Competition name is incorrect\")\n",
261
+ " print(\"3. You've reached the daily submission limit\")\n",
262
+ " print(\"4. The competition has ended\")\n",
263
+ " print(\"\\nYou can manually upload the submission.csv file to Kaggle.\")\n",
264
+ "\n",
265
+ "print(\"\\n\" + \"=\"*60)\n",
266
+ "print(\"PREDICTION STATISTICS\")\n",
267
+ "print(\"=\"*60)\n",
268
+ "\n",
269
+ "labels_per_sample = final_predictions.sum(axis=1)\n",
270
+ "print(\"\\nLabels per sample distribution:\")\n",
271
+ "for i in range(6):\n",
272
+ " count = (labels_per_sample == i).sum()\n",
273
+ " percentage = (count / len(labels_per_sample)) * 100\n",
274
+ " print(f\" {i} labels: {count:>6} samples ({percentage:>5.1f}%)\")\n",
275
+ "\n",
276
+ "print(\"\\nMost common label combinations:\")\n",
277
+ "label_combinations = []\n",
278
+ "for pred in final_predictions:\n",
279
+ " active_labels = [CONFIG.LABELS[i] for i, val in enumerate(pred) if val == 1]\n",
280
+ " if active_labels:\n",
281
+ " label_combinations.append(\", \".join(sorted(active_labels)))\n",
282
+ " else:\n",
283
+ " label_combinations.append(\"(none)\")\n",
284
+ "\n",
285
+ "from collections import Counter\n",
286
+ "combo_counts = Counter(label_combinations)\n",
287
+ "for combo, count in combo_counts.most_common(10):\n",
288
+ " percentage = (count / len(label_combinations)) * 100\n",
289
+ " print(f\" {combo:<30} {count:>6} ({percentage:>5.1f}%)\")\n",
290
+ "\n",
291
+ "print(\"\\nAverage probability per label:\")\n",
292
+ "for i, label in enumerate(CONFIG.LABELS):\n",
293
+ " avg_prob = all_probs[:, i].mean()\n",
294
+ " std_prob = all_probs[:, i].std()\n",
295
+ " print(f\" {label:<12} {avg_prob:.4f} +/- {std_prob:.4f}\")\n",
296
+ "\n",
297
+ "print(\"\\n\" + \"=\"*60)\n",
298
+ "print(\"SUBMISSION COMPLETE\")\n",
299
+ "print(\"=\"*60)\n",
300
+ "print(f\"\\nSubmission file: {CONFIG.SUBMISSION_PATH}\")\n",
301
+ "print(f\"Model used: {CONFIG.HF_REPO_ID}\")\n",
302
+ "print(f\"Optimized thresholds: {best_thresholds}\")\n",
303
+ "print(\"\\nCheck Kaggle leaderboard for your score\")"
304
+ ]
305
+ }
306
+ ],
307
+ "metadata": {
308
+ "language_info": {
309
+ "name": "python"
310
+ }
311
+ },
312
+ "nbformat": 4,
313
+ "nbformat_minor": 5
314
+ }
training_notebook.ipynb ADDED
The diff for this file is too large to render. See raw diff