burtenshaw commited on
Commit
c0d911e
·
1 Parent(s): 6d5550e

update application with latest logic from parent

Browse files
Files changed (7) hide show
  1. app.py +107 -84
  2. data/supervised-finetuning.json +338 -0
  3. example.json +0 -82
  4. push_questions.py +33 -0
  5. pyproject.toml +1 -1
  6. requirements.txt +3 -3
  7. uv.lock +9 -9
app.py CHANGED
@@ -6,8 +6,9 @@ import gradio as gr
6
  from datasets import load_dataset, Dataset
7
  from huggingface_hub import whoami
8
 
9
-
10
- EXAM_DATASET_ID = os.getenv("EXAM_DATASET_ID") or "agents-course/unit_1_quiz"
 
11
  EXAM_MAX_QUESTIONS = os.getenv("EXAM_MAX_QUESTIONS") or 10
12
  EXAM_PASSING_SCORE = os.getenv("EXAM_PASSING_SCORE") or 0.7
13
 
@@ -24,14 +25,37 @@ if EXAM_MAX_QUESTIONS:
24
 
25
  def on_user_logged_in(token: gr.OAuthToken | None):
26
  """
27
- If the user has a valid token, hide the login button and show the Start button.
28
- Otherwise, keep the login button visible, hide Start.
29
  """
30
  if token is not None:
31
- return gr.update(visible=False), gr.update(visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
32
  else:
33
- # Not logged in, keep the login visible, hide Start
34
- return gr.update(visible=True), gr.update(visible=False)
 
 
 
 
 
 
 
 
 
 
 
35
 
36
 
37
  def push_results_to_hub(user_answers, token: gr.OAuthToken | None):
@@ -74,36 +98,24 @@ def push_results_to_hub(user_answers, token: gr.OAuthToken | None):
74
 
75
  def handle_quiz(question_idx, user_answers, selected_answer, is_start):
76
  """
77
- A single function that handles both 'Start' and 'Next' logic:
78
- - If is_start=True, skip storing an answer and show the first question.
79
- - Otherwise, store the last answer and move on.
80
- - If we've reached the end, display results.
81
  """
82
- # Hide the start button once the first question is shown
83
- start_btn_update = gr.update(visible=False) if is_start else None
84
-
85
- # If this is the first time (start=True), begin at question_idx=0
86
- if is_start:
87
- question_idx = 0
88
- else:
89
- # If not the very first question, store the user's last selection
90
- if question_idx < len(quiz_data):
91
- current_q = quiz_data[question_idx]
92
- correct_reference = current_q["correct_answer"]
93
- correct_reference = f"answer_{correct_reference}".lower()
94
- is_correct = selected_answer == current_q[correct_reference]
95
- user_answers.append(
96
- {
97
- "question": current_q["question"],
98
- "selected_answer": selected_answer,
99
- "correct_answer": current_q[correct_reference],
100
- "is_correct": is_correct,
101
- "correct_reference": correct_reference,
102
- }
103
- )
104
  question_idx += 1
105
 
106
- # If we've reached the end, show final results
107
  if question_idx >= len(quiz_data):
108
  correct_count = sum(1 for answer in user_answers if answer["is_correct"])
109
  grade = correct_count / len(user_answers)
@@ -112,37 +124,35 @@ def handle_quiz(question_idx, user_answers, selected_answer, is_start):
112
  f"Your score: {grade:.1%}\n"
113
  f"Passing score: {float(EXAM_PASSING_SCORE):.1%}\n\n"
114
  )
115
- return (
116
- "", # question_text becomes blank
117
- gr.update(choices=[], visible=False),
118
  f"{'✅ Passed!' if grade >= float(EXAM_PASSING_SCORE) else '❌ Did not pass'}",
119
  question_idx,
120
  user_answers,
121
- start_btn_update,
122
- gr.update(value=results_text, visible=True), # show final_markdown
123
- )
124
- else:
125
- # Otherwise, show the next question
126
- q = quiz_data[question_idx]
127
- updated_question = f"## Question {question_idx + 1} \n### {q['question']}"
128
- return (
129
- updated_question,
130
- gr.update(
131
- choices=[
132
- q["answer_a"],
133
- q["answer_b"],
134
- q["answer_c"],
135
- q["answer_d"],
136
- ],
137
- value=None,
138
- visible=True,
139
- ),
140
- "Select an answer and click 'Next' to continue.",
141
- question_idx,
142
- user_answers,
143
- start_btn_update,
144
- gr.update(visible=False), # Hide final_markdown for now
145
- )
146
 
147
 
148
  def success_message(response):
@@ -152,47 +162,58 @@ def success_message(response):
152
 
153
  with gr.Blocks() as demo:
154
  demo.title = f"Dataset Quiz for {EXAM_DATASET_ID}"
 
155
  # State variables
156
  question_idx = gr.State(value=0)
157
  user_answers = gr.State(value=[])
 
158
 
159
  with gr.Row(variant="compact"):
160
  gr.Markdown(f"## Welcome to the {EXAM_DATASET_ID} Quiz")
 
161
  with gr.Row(variant="compact"):
162
  gr.Markdown(
163
  "Log in first, then click 'Start' to begin. Answer each question, click 'Next', and finally click 'Submit' to publish your results to the Hugging Face Hub."
164
  )
165
- # We display question text with Markdown
166
- with gr.Row(
167
- variant="panel",
168
- ):
169
  question_text = gr.Markdown("")
170
  radio_choices = gr.Radio(
171
- choices=[], visible=False, label="Your Answer", scale=1.5
172
  )
173
 
174
  with gr.Row(variant="compact"):
175
  status_text = gr.Markdown("")
 
176
 
177
  with gr.Row(variant="compact"):
178
- # Final results after all questions are done
179
- final_markdown = gr.Markdown("", visible=False)
180
-
181
- next_btn = gr.Button("Next ⏭️")
182
- submit_btn = gr.Button("Submit ✅")
183
-
184
- with gr.Row(variant="compact"):
185
- login_btn = gr.LoginButton()
186
- # We'll hide the Start button until user logs in
187
- start_btn = gr.Button("Start", visible=False)
188
-
189
- # Use click() instead of login()
190
- login_btn.click(fn=on_user_logged_in, inputs=None, outputs=[login_btn, start_btn])
 
 
 
 
 
 
 
 
 
 
191
 
192
- # Click "Start" => show first question, hide Start button
193
  start_btn.click(
194
  fn=handle_quiz,
195
- inputs=[question_idx, user_answers, radio_choices, gr.State(True)],
196
  outputs=[
197
  question_text,
198
  radio_choices,
@@ -200,11 +221,12 @@ with gr.Blocks() as demo:
200
  question_idx,
201
  user_answers,
202
  start_btn,
 
 
203
  final_markdown,
204
  ],
205
  )
206
 
207
- # Click "Next" => store selection, move on
208
  next_btn.click(
209
  fn=handle_quiz,
210
  inputs=[question_idx, user_answers, radio_choices, gr.State(False)],
@@ -215,13 +237,14 @@ with gr.Blocks() as demo:
215
  question_idx,
216
  user_answers,
217
  start_btn,
 
 
218
  final_markdown,
219
  ],
220
  )
221
 
222
  submit_btn.click(fn=push_results_to_hub, inputs=[user_answers])
223
 
224
-
225
  if __name__ == "__main__":
226
  # Note: If testing locally, you'll need to run `huggingface-cli login` or set HF_TOKEN
227
  # environment variable for the login to work locally.
 
6
  from datasets import load_dataset, Dataset
7
  from huggingface_hub import whoami
8
 
9
+ EXAM_DATASET_ID = (
10
+ os.getenv("EXAM_DATASET_ID") or "nlp-course/supervised-finetuning_quiz"
11
+ )
12
  EXAM_MAX_QUESTIONS = os.getenv("EXAM_MAX_QUESTIONS") or 10
13
  EXAM_PASSING_SCORE = os.getenv("EXAM_PASSING_SCORE") or 0.7
14
 
 
25
 
26
  def on_user_logged_in(token: gr.OAuthToken | None):
27
  """
28
+ If the user has a valid token, show Start button.
29
+ Otherwise, keep the login button visible.
30
  """
31
  if token is not None:
32
+ return [
33
+ gr.update(visible=False), # login button visibility
34
+ gr.update(visible=True), # start button visibility
35
+ gr.update(visible=False), # next button visibility
36
+ gr.update(visible=False), # submit button visibility
37
+ "", # question text
38
+ [], # radio choices (empty list = no choices)
39
+ "Click 'Start' to begin the quiz", # status message
40
+ 0, # question_idx
41
+ [], # user_answers
42
+ "", # final_markdown content
43
+ token, # user token
44
+ ]
45
  else:
46
+ return [
47
+ gr.update(visible=True), # login button visibility
48
+ gr.update(visible=False), # start button visibility
49
+ gr.update(visible=False), # next button visibility
50
+ gr.update(visible=False), # submit button visibility
51
+ "", # question text
52
+ [], # radio choices
53
+ "", # status message
54
+ 0, # question_idx
55
+ [], # user_answers
56
+ "", # final_markdown content
57
+ None, # no token
58
+ ]
59
 
60
 
61
  def push_results_to_hub(user_answers, token: gr.OAuthToken | None):
 
98
 
99
  def handle_quiz(question_idx, user_answers, selected_answer, is_start):
100
  """
101
+ Handle quiz state transitions and store answers
 
 
 
102
  """
103
+ if not is_start and question_idx < len(quiz_data):
104
+ current_q = quiz_data[question_idx]
105
+ correct_reference = current_q["correct_answer"]
106
+ correct_reference = f"answer_{correct_reference}".lower()
107
+ is_correct = selected_answer == current_q[correct_reference]
108
+ user_answers.append(
109
+ {
110
+ "question": current_q["question"],
111
+ "selected_answer": selected_answer,
112
+ "correct_answer": current_q[correct_reference],
113
+ "is_correct": is_correct,
114
+ "correct_reference": correct_reference,
115
+ }
116
+ )
 
 
 
 
 
 
 
 
117
  question_idx += 1
118
 
 
119
  if question_idx >= len(quiz_data):
120
  correct_count = sum(1 for answer in user_answers if answer["is_correct"])
121
  grade = correct_count / len(user_answers)
 
124
  f"Your score: {grade:.1%}\n"
125
  f"Passing score: {float(EXAM_PASSING_SCORE):.1%}\n\n"
126
  )
127
+ return [
128
+ "", # question_text
129
+ gr.update(choices=[], visible=False), # hide radio choices
130
  f"{'✅ Passed!' if grade >= float(EXAM_PASSING_SCORE) else '❌ Did not pass'}",
131
  question_idx,
132
  user_answers,
133
+ gr.update(visible=False), # start button visibility
134
+ gr.update(visible=False), # next button visibility
135
+ gr.update(visible=True), # submit button visibility
136
+ results_text, # final results text
137
+ ]
138
+
139
+ # Show next question
140
+ q = quiz_data[question_idx]
141
+ return [
142
+ f"## Question {question_idx + 1} \n### {q['question']}", # question text
143
+ gr.update( # properly update radio choices
144
+ choices=[q["answer_a"], q["answer_b"], q["answer_c"], q["answer_d"]],
145
+ value=None,
146
+ visible=True,
147
+ ),
148
+ "Select an answer and click 'Next' to continue.",
149
+ question_idx,
150
+ user_answers,
151
+ gr.update(visible=False), # start button visibility
152
+ gr.update(visible=True), # next button visibility
153
+ gr.update(visible=False), # submit button visibility
154
+ "", # clear final markdown
155
+ ]
 
 
156
 
157
 
158
  def success_message(response):
 
162
 
163
  with gr.Blocks() as demo:
164
  demo.title = f"Dataset Quiz for {EXAM_DATASET_ID}"
165
+
166
  # State variables
167
  question_idx = gr.State(value=0)
168
  user_answers = gr.State(value=[])
169
+ user_token = gr.State(value=None)
170
 
171
  with gr.Row(variant="compact"):
172
  gr.Markdown(f"## Welcome to the {EXAM_DATASET_ID} Quiz")
173
+
174
  with gr.Row(variant="compact"):
175
  gr.Markdown(
176
  "Log in first, then click 'Start' to begin. Answer each question, click 'Next', and finally click 'Submit' to publish your results to the Hugging Face Hub."
177
  )
178
+
179
+ with gr.Row(variant="panel"):
 
 
180
  question_text = gr.Markdown("")
181
  radio_choices = gr.Radio(
182
+ choices=[], label="Your Answer", scale=1.5, visible=False
183
  )
184
 
185
  with gr.Row(variant="compact"):
186
  status_text = gr.Markdown("")
187
+ final_markdown = gr.Markdown("")
188
 
189
  with gr.Row(variant="compact"):
190
+ login_btn = gr.LoginButton(visible=True)
191
+ start_btn = gr.Button("Start ⏭️", visible=True)
192
+ next_btn = gr.Button("Next ⏭️", visible=False)
193
+ submit_btn = gr.Button("Submit ", visible=False)
194
+
195
+ # Wire up the event handlers
196
+ login_btn.click(
197
+ fn=on_user_logged_in,
198
+ inputs=None,
199
+ outputs=[
200
+ login_btn,
201
+ start_btn,
202
+ next_btn,
203
+ submit_btn,
204
+ question_text,
205
+ radio_choices,
206
+ status_text,
207
+ question_idx,
208
+ user_answers,
209
+ final_markdown,
210
+ user_token,
211
+ ],
212
+ )
213
 
 
214
  start_btn.click(
215
  fn=handle_quiz,
216
+ inputs=[question_idx, user_answers, gr.State(""), gr.State(True)],
217
  outputs=[
218
  question_text,
219
  radio_choices,
 
221
  question_idx,
222
  user_answers,
223
  start_btn,
224
+ next_btn,
225
+ submit_btn,
226
  final_markdown,
227
  ],
228
  )
229
 
 
230
  next_btn.click(
231
  fn=handle_quiz,
232
  inputs=[question_idx, user_answers, radio_choices, gr.State(False)],
 
237
  question_idx,
238
  user_answers,
239
  start_btn,
240
+ next_btn,
241
+ submit_btn,
242
  final_markdown,
243
  ],
244
  )
245
 
246
  submit_btn.click(fn=push_results_to_hub, inputs=[user_answers])
247
 
 
248
  if __name__ == "__main__":
249
  # Note: If testing locally, you'll need to run `huggingface-cli login` or set HF_TOKEN
250
  # environment variable for the login to work locally.
data/supervised-finetuning.json ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "question": "What is Supervised Fine-Tuning (SFT) in the context of LLMs?",
4
+ "answer_a": "A technique to make models run faster",
5
+ "answer_b": "A method to train models on specific tasks using labeled data",
6
+ "answer_c": "A way to reduce model size",
7
+ "answer_d": "A process to create new model architectures",
8
+ "correct_answer": "B"
9
+ },
10
+ {
11
+ "question": "What is LoRA (Low-Rank Adaptation)?",
12
+ "answer_a": "A new type of transformer architecture",
13
+ "answer_b": "A method to compress models after training",
14
+ "answer_c": "An efficient fine-tuning technique that updates a small number of trainable parameters",
15
+ "answer_d": "A data preprocessing technique",
16
+ "correct_answer": "C"
17
+ },
18
+ {
19
+ "question": "What is the main advantage of using LoRA for fine-tuning?",
20
+ "answer_a": "It makes models more accurate than full fine-tuning",
21
+ "answer_b": "It reduces memory requirements and training costs while maintaining performance",
22
+ "answer_c": "It allows training without any original model weights",
23
+ "answer_d": "It automatically improves model inference speed",
24
+ "correct_answer": "B"
25
+ },
26
+ {
27
+ "question": "In chat templates, what is the purpose of the 'system' message?",
28
+ "answer_a": "To log system errors",
29
+ "answer_b": "To define the behavior and role of the assistant",
30
+ "answer_c": "To store user preferences",
31
+ "answer_d": "To handle technical configurations",
32
+ "correct_answer": "B"
33
+ },
34
+ {
35
+ "question": "Which of these is a common format marker in chat templates?",
36
+ "answer_a": "<|im_start|>",
37
+ "answer_b": "{BEGIN}",
38
+ "answer_c": "START_CHAT",
39
+ "answer_d": "<<START>>",
40
+ "correct_answer": "A"
41
+ },
42
+ {
43
+ "question": "What is the primary purpose of SFT datasets?",
44
+ "answer_a": "To create new model architectures",
45
+ "answer_b": "To train models to follow specific instructions and generate desired outputs",
46
+ "answer_c": "To test model performance only",
47
+ "answer_d": "To compress model size",
48
+ "correct_answer": "B"
49
+ },
50
+ {
51
+ "question": "Which statement about LoRA is TRUE?",
52
+ "answer_a": "It requires modifying the original model architecture",
53
+ "answer_b": "It can only be used with small models",
54
+ "answer_c": "It adds low-rank matrices to existing weights during training",
55
+ "answer_d": "It permanently changes the base model weights",
56
+ "correct_answer": "C"
57
+ },
58
+ {
59
+ "question": "What is a key benefit of using standardized chat templates?",
60
+ "answer_a": "They make models run faster",
61
+ "answer_b": "They ensure consistent formatting across different model implementations",
62
+ "answer_c": "They reduce model size",
63
+ "answer_d": "They eliminate the need for tokenization",
64
+ "correct_answer": "B"
65
+ },
66
+ {
67
+ "question": "In the context of SFT, what is a 'prompt-completion' pair?",
68
+ "answer_a": "Two separate models working together",
69
+ "answer_b": "A training example consisting of an input and its desired output",
70
+ "answer_c": "A type of model architecture",
71
+ "answer_d": "A method to compress training data",
72
+ "correct_answer": "B"
73
+ },
74
+ {
75
+ "question": "Which of these is NOT a typical component of a chat template?",
76
+ "answer_a": "System message",
77
+ "answer_b": "User message",
78
+ "answer_c": "Assistant message",
79
+ "answer_d": "Database message",
80
+ "correct_answer": "D"
81
+ },
82
+ {
83
+ "question": "What is the purpose of the SFTTrainer in the TRL library?",
84
+ "answer_a": "To train models from scratch",
85
+ "answer_b": "To simplify the process of fine-tuning language models on instruction datasets",
86
+ "answer_c": "To evaluate model performance",
87
+ "answer_d": "To compress model weights",
88
+ "correct_answer": "B"
89
+ },
90
+ {
91
+ "question": "What is a key characteristic of LoRA's training approach?",
92
+ "answer_a": "It trains all model parameters",
93
+ "answer_b": "It only works with small models",
94
+ "answer_c": "It freezes the original model weights and injects trainable rank decomposition matrices",
95
+ "answer_d": "It requires multiple GPUs",
96
+ "correct_answer": "C"
97
+ },
98
+ {
99
+ "question": "Which parameter in LoRA determines the size of the rank decomposition matrices?",
100
+ "answer_a": "lora_alpha",
101
+ "answer_b": "r",
102
+ "answer_c": "dropout",
103
+ "answer_d": "bias",
104
+ "correct_answer": "B"
105
+ },
106
+ {
107
+ "question": "What is the role of 'target_modules' in LoRA configuration?",
108
+ "answer_a": "To specify which layers to remove",
109
+ "answer_b": "To define which layers will be adapted with LoRA",
110
+ "answer_c": "To set the learning rate for each layer",
111
+ "answer_d": "To determine model output",
112
+ "correct_answer": "B"
113
+ },
114
+ {
115
+ "question": "What is the purpose of chat template's 'add_generation_prompt' parameter?",
116
+ "answer_a": "To end the conversation",
117
+ "answer_b": "To add a prompt for the model to continue generating",
118
+ "answer_c": "To change the system message",
119
+ "answer_d": "To modify user input",
120
+ "correct_answer": "B"
121
+ },
122
+ {
123
+ "question": "In SFT training, what is gradient checkpointing used for?",
124
+ "answer_a": "To save training progress",
125
+ "answer_b": "To reduce memory usage during training",
126
+ "answer_c": "To increase model accuracy",
127
+ "answer_d": "To speed up training",
128
+ "correct_answer": "B"
129
+ },
130
+ {
131
+ "question": "What is the purpose of the 'lora_alpha' parameter in LoRA?",
132
+ "answer_a": "To set the learning rate",
133
+ "answer_b": "To scale the LoRA weights during inference",
134
+ "answer_c": "To determine batch size",
135
+ "answer_d": "To control model size",
136
+ "correct_answer": "B"
137
+ },
138
+ {
139
+ "question": "Which of these is a benefit of using the SFTTrainer?",
140
+ "answer_a": "It automatically handles padding and truncation of inputs",
141
+ "answer_b": "It creates new model architectures",
142
+ "answer_c": "It performs unsupervised learning",
143
+ "answer_d": "It generates training data",
144
+ "correct_answer": "A"
145
+ },
146
+ {
147
+ "question": "What is the purpose of 'formatting_func' in SFTTrainer?",
148
+ "answer_a": "To format the output text",
149
+ "answer_b": "To preprocess and structure the training data",
150
+ "answer_c": "To modify model architecture",
151
+ "answer_d": "To handle error messages",
152
+ "correct_answer": "B"
153
+ },
154
+ {
155
+ "question": "Which of these is TRUE about LoRA training?",
156
+ "answer_a": "It requires more memory than full fine-tuning",
157
+ "answer_b": "It can only be used with specific model architectures",
158
+ "answer_c": "It allows efficient adaptation while keeping original weights frozen",
159
+ "answer_d": "It always produces better results than full fine-tuning",
160
+ "correct_answer": "C"
161
+ },
162
+ {
163
+ "question": "What is the purpose of 'max_seq_length' in SFTTrainer?",
164
+ "answer_a": "To limit the model's vocabulary size",
165
+ "answer_b": "To set the maximum length of input sequences",
166
+ "answer_c": "To determine the batch size",
167
+ "answer_d": "To control the learning rate",
168
+ "correct_answer": "B"
169
+ },
170
+ {
171
+ "question": "In chat templates, what is the purpose of conversation history?",
172
+ "answer_a": "To store user preferences",
173
+ "answer_b": "To maintain context across multiple turns of dialogue",
174
+ "answer_c": "To track error messages",
175
+ "answer_d": "To count tokens",
176
+ "correct_answer": "B"
177
+ },
178
+ {
179
+ "question": "What is a key advantage of using BitsAndBytes for SFT?",
180
+ "answer_a": "It makes training faster",
181
+ "answer_b": "It reduces memory usage through quantization",
182
+ "answer_c": "It improves model accuracy",
183
+ "answer_d": "It simplifies the code",
184
+ "correct_answer": "B"
185
+ },
186
+ {
187
+ "question": "Which of these is NOT a typical parameter in LoRA configuration?",
188
+ "answer_a": "r",
189
+ "answer_b": "lora_alpha",
190
+ "answer_c": "model_size",
191
+ "answer_d": "target_modules",
192
+ "correct_answer": "C"
193
+ },
194
+ {
195
+ "question": "What is the purpose of 'warmup_ratio' in training arguments?",
196
+ "answer_a": "To set the final learning rate",
197
+ "answer_b": "To determine the portion of training used for learning rate warmup",
198
+ "answer_c": "To control model temperature",
199
+ "answer_d": "To set the batch size",
200
+ "correct_answer": "B"
201
+ },
202
+ {
203
+ "question": "Which statement about SFT datasets is TRUE?",
204
+ "answer_a": "They must always be in JSON format",
205
+ "answer_b": "They typically contain input-output pairs for training",
206
+ "answer_c": "They can only contain single-turn conversations",
207
+ "answer_d": "They must include system prompts",
208
+ "correct_answer": "B"
209
+ },
210
+ {
211
+ "question": "What is the role of 'gradient_accumulation_steps' in training?",
212
+ "answer_a": "To speed up training",
213
+ "answer_b": "To simulate larger batch sizes with limited memory",
214
+ "answer_c": "To reduce model size",
215
+ "answer_d": "To improve accuracy",
216
+ "correct_answer": "B"
217
+ },
218
+ {
219
+ "question": "Which of these is a common use case for LoRA?",
220
+ "answer_a": "Creating new model architectures",
221
+ "answer_b": "Adapting large models to specific tasks efficiently",
222
+ "answer_c": "Reducing model inference time",
223
+ "answer_d": "Generating training data",
224
+ "correct_answer": "B"
225
+ },
226
+ {
227
+ "question": "What is the purpose of 'save_total_limit' in training arguments?",
228
+ "answer_a": "To limit the model's vocabulary",
229
+ "answer_b": "To control how many checkpoints are saved during training",
230
+ "answer_c": "To set the maximum sequence length",
231
+ "answer_d": "To limit training time",
232
+ "correct_answer": "B"
233
+ },
234
+ {
235
+ "question": "Which optimization technique is commonly used with LoRA?",
236
+ "answer_a": "SGD",
237
+ "answer_b": "AdamW",
238
+ "answer_c": "RMSprop",
239
+ "answer_d": "Momentum",
240
+ "correct_answer": "B"
241
+ },
242
+ {
243
+ "question": "What is the most significant difference between full fine-tuning and LoRA?",
244
+ "answer_a": "LoRA updates a subset of model weights while full fine-tuning updates all weights",
245
+ "answer_b": "LoRA adds new parameters while keeping original weights frozen",
246
+ "answer_c": "LoRA modifies attention layers while full fine-tuning modifies feed-forward layers",
247
+ "answer_d": "LoRA trains faster but requires more memory than full fine-tuning",
248
+ "correct_answer": "B"
249
+ },
250
+ {
251
+ "question": "When implementing chat templates, which approach is most likely to maintain model performance?",
252
+ "answer_a": "Using the exact template format from the model's training data",
253
+ "answer_b": "Using a simplified template with just role and content",
254
+ "answer_c": "Using a standardized template across all models",
255
+ "answer_d": "Using a template with additional control tokens",
256
+ "correct_answer": "A"
257
+ },
258
+ {
259
+ "question": "What is the key technical innovation of LoRA's rank decomposition approach?",
260
+ "answer_a": "It reduces model parameters through matrix factorization",
261
+ "answer_b": "It decomposes weight updates into low-rank matrices while preserving model capacity",
262
+ "answer_c": "It compresses the model weights using SVD decomposition",
263
+ "answer_d": "It optimizes attention mechanisms through rank reduction",
264
+ "correct_answer": "B"
265
+ },
266
+ {
267
+ "question": "How does the 'r' parameter in LoRA affect the training process?",
268
+ "answer_a": "Higher r increases model capacity but requires more memory",
269
+ "answer_b": "Lower r reduces training time but may impact performance",
270
+ "answer_c": "Higher r improves convergence but increases computation",
271
+ "answer_d": "Lower r decreases memory usage but may limit expressiveness",
272
+ "correct_answer": "D"
273
+ },
274
+ {
275
+ "question": "What is the primary consideration when choosing target_modules for LoRA?",
276
+ "answer_a": "Selecting layers that most influence task-specific behavior",
277
+ "answer_b": "Targeting modules with the most parameters",
278
+ "answer_c": "Choosing layers closest to the model output",
279
+ "answer_d": "Selecting modules with the least impact on inference speed",
280
+ "correct_answer": "A"
281
+ },
282
+ {
283
+ "question": "How does gradient checkpointing affect the training process in SFT?",
284
+ "answer_a": "Trades computation time for reduced memory usage",
285
+ "answer_b": "Reduces memory by storing fewer activation gradients",
286
+ "answer_c": "Improves training stability through gradient accumulation",
287
+ "answer_d": "Optimizes memory by recomputing forward passes",
288
+ "correct_answer": "A"
289
+ },
290
+ {
291
+ "question": "What role does lora_alpha play in the training dynamics?",
292
+ "answer_a": "Controls the learning rate scaling of LoRA updates",
293
+ "answer_b": "Scales the contribution of LoRA weights during inference",
294
+ "answer_c": "Determines the initialization range of LoRA matrices",
295
+ "answer_d": "Adjusts the gradient flow through LoRA layers",
296
+ "correct_answer": "B"
297
+ },
298
+ {
299
+ "question": "Which aspect of SFT datasets most influences training effectiveness?",
300
+ "answer_a": "The diversity of instruction-output pairs",
301
+ "answer_b": "The total number of training examples",
302
+ "answer_c": "The complexity of individual instructions",
303
+ "answer_d": "The length of output sequences",
304
+ "correct_answer": "A"
305
+ },
306
+ {
307
+ "question": "How does warmup_ratio impact the training dynamics?",
308
+ "answer_a": "Prevents early overfitting by gradually increasing learning rate",
309
+ "answer_b": "Stabilizes initial training by ramping up learning rate",
310
+ "answer_c": "Reduces gradient variance in early training steps",
311
+ "answer_d": "Improves model convergence through learning rate scheduling",
312
+ "correct_answer": "B"
313
+ },
314
+ {
315
+ "question": "What is the primary challenge addressed by gradient_accumulation_steps?",
316
+ "answer_a": "Memory constraints limiting batch size",
317
+ "answer_b": "Training instability with large learning rates",
318
+ "answer_c": "Slow convergence with small batches",
319
+ "answer_d": "Gradient vanishing in deep networks",
320
+ "correct_answer": "A"
321
+ },
322
+ {
323
+ "question": "How does BitsAndBytes quantization affect SFT training?",
324
+ "answer_a": "Reduces precision while maintaining training stability",
325
+ "answer_b": "Compresses weights with minimal performance impact",
326
+ "answer_c": "Optimizes memory usage through dynamic quantization",
327
+ "answer_d": "Balances precision and memory requirements",
328
+ "correct_answer": "D"
329
+ },
330
+ {
331
+ "question": "What distinguishes an effective chat template implementation?",
332
+ "answer_a": "Minimal special token usage with clear role separation",
333
+ "answer_b": "Consistent formatting with explicit turn boundaries",
334
+ "answer_c": "Efficient token usage while maintaining context",
335
+ "answer_d": "Flexible role definition with standardized markers",
336
+ "correct_answer": "C"
337
+ }
338
+ ]
example.json DELETED
@@ -1,82 +0,0 @@
1
- [
2
- {
3
- "question": "Which of the following best describes a Large Language Model (LLM)?",
4
- "answer_a": "A model specializing in language recognition",
5
- "answer_b": "A massive neural network that understands and generates human language",
6
- "answer_c": "A model exclusively used for language data tasks like summarization or classification",
7
- "answer_d": "A rule-based chatbot used for conversations",
8
- "correct_answer": "B"
9
- },
10
- {
11
- "question": "LLMs are typically:",
12
- "answer_a": "Pre-trained on small, curated datasets",
13
- "answer_b": "Trained on large text corpora to capture linguistic patterns",
14
- "answer_c": "Trained purely on translation tasks",
15
- "answer_d": "Designed to function solely with GPU resources",
16
- "correct_answer": "B"
17
- },
18
- {
19
- "question": "Which of the following is a common architecture for LLMs?",
20
- "answer_a": "Convolutional Neural Networks (CNNs)",
21
- "answer_b": "Transformer",
22
- "answer_c": "Recurrent Neural Networks (RNNs) with LSTM",
23
- "answer_d": "Support Vector Machines",
24
- "correct_answer": "B"
25
- },
26
- {
27
- "question": "What does it mean when we say LLMs are \"autoregressive\"?",
28
- "answer_a": "They regress to the mean to reduce variance",
29
- "answer_b": "They generate text by predicting the next token based on previous tokens",
30
- "answer_c": "They can only handle labeled data",
31
- "answer_d": "They can output text only after the entire input is known at once",
32
- "correct_answer": "B"
33
- },
34
- {
35
- "question": "Which of these is NOT a common use of LLMs?",
36
- "answer_a": "Summarizing content",
37
- "answer_b": "Generating code",
38
- "answer_c": "Playing strategy games like chess or Go",
39
- "answer_d": "Conversational AI",
40
- "correct_answer": "C"
41
- },
42
- {
43
- "question": "Which of the following best describes a \"special token\"?",
44
- "answer_a": "A token that makes the model forget all context",
45
- "answer_b": "A model signature required for API calls",
46
- "answer_c": "A token that helps segment or structure the conversation in the model",
47
- "answer_d": "A token that always represents the end of text",
48
- "correct_answer": "C"
49
- },
50
- {
51
- "question": "What is the primary goal of a \"chat template\"?",
52
- "answer_a": "To force the model into a single-turn conversation",
53
- "answer_b": "To structure interactions and define roles in a conversation",
54
- "answer_c": "To replace the need for system messages",
55
- "answer_d": "To store prompts into the model's weights permanently",
56
- "correct_answer": "B"
57
- },
58
- {
59
- "question": "How do tokenizers handle text for modern NLP models?",
60
- "answer_a": "By splitting text into individual words only",
61
- "answer_b": "By breaking words into subword units and assigning numerical IDs",
62
- "answer_c": "By storing text directly without transformation",
63
- "answer_d": "By removing all punctuation automatically",
64
- "correct_answer": "B"
65
- },
66
- {
67
- "question": "Which role in a conversation sets the overall behavior for a model?",
68
- "answer_a": "user",
69
- "answer_b": "system",
70
- "answer_c": "assistant",
71
- "answer_d": "developer",
72
- "correct_answer": "B"
73
- },
74
- {
75
- "question": "Which statement is TRUE about tool usage in chat templates?",
76
- "answer_a": "Tools cannot be used within the conversation context.",
77
- "answer_b": "Tools are used only for logging messages.",
78
- "answer_c": "Tools allow the assistant to offload tasks like web search or calculations.",
79
- "answer_d": "Tools are unsupported in all modern LLMs.",
80
- "correct_answer": "C"
81
- }
82
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
push_questions.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+ from datasets import Dataset
4
+ from huggingface_hub import HfApi
5
+
6
+
7
+ ORG_NAME = "nlp-course"
8
+
9
+
10
+ def main():
11
+ """Push quiz questions to the Hugging Face Hub"""
12
+
13
+ for file in Path("data").glob("*.json"):
14
+ print(f"Processing {file}")
15
+
16
+ with open(file, "r") as f:
17
+ quiz_data = json.load(f)
18
+
19
+ repo_id = f"{ORG_NAME}/{file.stem}_quiz"
20
+
21
+ dataset = Dataset.from_list(quiz_data)
22
+
23
+ print(f"Pushing {repo_id} to the Hugging Face Hub")
24
+
25
+ dataset.push_to_hub(
26
+ repo_id,
27
+ private=True,
28
+ commit_message=f"Update quiz questions for {file.stem}",
29
+ )
30
+
31
+
32
+ if __name__ == "__main__":
33
+ main()
pyproject.toml CHANGED
@@ -6,7 +6,7 @@ readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "datasets>=3.2.0",
9
- "gradio[oauth]>=5.13.1",
10
  "huggingface-hub>=0.27.1",
11
  "ipykernel>=6.29.5",
12
  ]
 
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "datasets>=3.2.0",
9
+ "gradio[oauth]==5.15.0",
10
  "huggingface-hub>=0.27.1",
11
  "ipykernel>=6.29.5",
12
  ]
requirements.txt CHANGED
@@ -28,12 +28,12 @@ ffmpy==0.5.0
28
  filelock==3.17.0
29
  frozenlist==1.5.0
30
  fsspec==2024.9.0
31
- gradio==5.13.1
32
- gradio-client==1.6.0
33
  h11==0.14.0
34
  httpcore==1.0.7
35
  httpx==0.28.1
36
- huggingface-hub==0.27.1
37
  idna==3.10
38
  ipykernel==6.29.5
39
  ipython==8.31.0
 
28
  filelock==3.17.0
29
  frozenlist==1.5.0
30
  fsspec==2024.9.0
31
+ gradio==5.15.0
32
+ gradio-client==1.7.0
33
  h11==0.14.0
34
  httpcore==1.0.7
35
  httpx==0.28.1
36
+ huggingface-hub==0.28.1
37
  idna==3.10
38
  ipykernel==6.29.5
39
  ipython==8.31.0
uv.lock CHANGED
@@ -541,7 +541,7 @@ http = [
541
 
542
  [[package]]
543
  name = "gradio"
544
- version = "5.13.1"
545
  source = { registry = "https://pypi.org/simple" }
546
  dependencies = [
547
  { name = "aiofiles" },
@@ -574,7 +574,7 @@ dependencies = [
574
  { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
575
  ]
576
  wheels = [
577
- { url = "https://files.pythonhosted.org/packages/a0/4e/ac75bede5dc13ae8dfc79432f7578c30f2821265789918941457e4ccb940/gradio-5.13.1-py3-none-any.whl", hash = "sha256:ea5a5f2b1e0cd883211c1a8cc47d52343126e2c313762d26572bfcfb248da299", size = 57634647 },
578
  ]
579
 
580
  [package.optional-dependencies]
@@ -585,7 +585,7 @@ oauth = [
585
 
586
  [[package]]
587
  name = "gradio-client"
588
- version = "1.6.0"
589
  source = { registry = "https://pypi.org/simple" }
590
  dependencies = [
591
  { name = "fsspec" },
@@ -595,9 +595,9 @@ dependencies = [
595
  { name = "typing-extensions" },
596
  { name = "websockets" },
597
  ]
598
- sdist = { url = "https://files.pythonhosted.org/packages/1c/d4/96a11493f6aea9d96ba5302b2e73725d07cee49c9d555190f4631372e028/gradio_client-1.6.0.tar.gz", hash = "sha256:1c6fae52181d483c010cfbc4e4df8520da33ab4365ab412acabc798d7022ad98", size = 319910 }
599
  wheels = [
600
- { url = "https://files.pythonhosted.org/packages/9b/41/dc3358708c4e461bec82e9bbf5e7b1821b1fa45c5f078f3baeb3e8686f57/gradio_client-1.6.0-py3-none-any.whl", hash = "sha256:172175510a0cc92928f5d376e95e93f94d1558e4a360969fcc0dfc4c9e313872", size = 321777 },
601
  ]
602
 
603
  [[package]]
@@ -639,7 +639,7 @@ wheels = [
639
 
640
  [[package]]
641
  name = "huggingface-hub"
642
- version = "0.27.1"
643
  source = { registry = "https://pypi.org/simple" }
644
  dependencies = [
645
  { name = "filelock" },
@@ -650,9 +650,9 @@ dependencies = [
650
  { name = "tqdm" },
651
  { name = "typing-extensions" },
652
  ]
653
- sdist = { url = "https://files.pythonhosted.org/packages/e1/d2/d6976de7542792fc077b498d64af64882b6d8bb40679284ec0bff77d5929/huggingface_hub-0.27.1.tar.gz", hash = "sha256:c004463ca870283909d715d20f066ebd6968c2207dae9393fdffb3c1d4d8f98b", size = 379407 }
654
  wheels = [
655
- { url = "https://files.pythonhosted.org/packages/6c/3f/50f6b25fafdcfb1c089187a328c95081abf882309afd86f4053951507cd1/huggingface_hub-0.27.1-py3-none-any.whl", hash = "sha256:1c5155ca7d60b60c2e2fc38cbb3ffb7f7c3adf48f824015b219af9061771daec", size = 450658 },
656
  ]
657
 
658
  [[package]]
@@ -1518,7 +1518,7 @@ dependencies = [
1518
  [package.metadata]
1519
  requires-dist = [
1520
  { name = "datasets", specifier = ">=3.2.0" },
1521
- { name = "gradio", extras = ["oauth"], specifier = ">=5.13.1" },
1522
  { name = "huggingface-hub", specifier = ">=0.27.1" },
1523
  { name = "ipykernel", specifier = ">=6.29.5" },
1524
  ]
 
541
 
542
  [[package]]
543
  name = "gradio"
544
+ version = "5.15.0"
545
  source = { registry = "https://pypi.org/simple" }
546
  dependencies = [
547
  { name = "aiofiles" },
 
574
  { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
575
  ]
576
  wheels = [
577
+ { url = "https://files.pythonhosted.org/packages/a4/28/6a52bac8b13aca4f76baef03d5f840cc1f7486e879bc1ee19df51b7590d2/gradio-5.15.0-py3-none-any.whl", hash = "sha256:b0d72bf1e70c4a08283066c510d03bbdb9e378c1f806dd948e333c75bb22b3f1", size = 57766589 },
578
  ]
579
 
580
  [package.optional-dependencies]
 
585
 
586
  [[package]]
587
  name = "gradio-client"
588
+ version = "1.7.0"
589
  source = { registry = "https://pypi.org/simple" }
590
  dependencies = [
591
  { name = "fsspec" },
 
595
  { name = "typing-extensions" },
596
  { name = "websockets" },
597
  ]
598
+ sdist = { url = "https://files.pythonhosted.org/packages/c5/78/e5a4a2b0f4d1ba01ec4169e181a3134fc65b6360d40817070892c3557000/gradio_client-1.7.0.tar.gz", hash = "sha256:87f6ade197951f38bac0431b2a436a8ebb2f33b2ceba2ef8e1e5bef8d8b238e4", size = 320039 }
599
  wheels = [
600
+ { url = "https://files.pythonhosted.org/packages/f3/c1/def2bd93b8beab342c443bf5ac47f85e48b78eca010bbff51d6978472a3f/gradio_client-1.7.0-py3-none-any.whl", hash = "sha256:b403570c67f121ebbbc19ac1f0afa2ab1bab085ce60d96eb190832fe871aa946", size = 321900 },
601
  ]
602
 
603
  [[package]]
 
639
 
640
  [[package]]
641
  name = "huggingface-hub"
642
+ version = "0.28.1"
643
  source = { registry = "https://pypi.org/simple" }
644
  dependencies = [
645
  { name = "filelock" },
 
650
  { name = "tqdm" },
651
  { name = "typing-extensions" },
652
  ]
653
+ sdist = { url = "https://files.pythonhosted.org/packages/e7/ce/a734204aaae6c35a22f9956ebcd8d8708ae5b842e15d6f42bd6f49e634a4/huggingface_hub-0.28.1.tar.gz", hash = "sha256:893471090c98e3b6efbdfdacafe4052b20b84d59866fb6f54c33d9af18c303ae", size = 387074 }
654
  wheels = [
655
+ { url = "https://files.pythonhosted.org/packages/ea/da/6c2bea5327b640920267d3bf2c9fc114cfbd0a5de234d81cda80cc9e33c8/huggingface_hub-0.28.1-py3-none-any.whl", hash = "sha256:aa6b9a3ffdae939b72c464dbb0d7f99f56e649b55c3d52406f49e0a5a620c0a7", size = 464068 },
656
  ]
657
 
658
  [[package]]
 
1518
  [package.metadata]
1519
  requires-dist = [
1520
  { name = "datasets", specifier = ">=3.2.0" },
1521
+ { name = "gradio", extras = ["oauth"], specifier = "==5.15.0" },
1522
  { name = "huggingface-hub", specifier = ">=0.27.1" },
1523
  { name = "ipykernel", specifier = ">=6.29.5" },
1524
  ]