Fine-tune Qwen3-4B with QLoRA

Import the libraries

In [ ]:

Check the GPU

In [ ]:

Create the project folders

In [ ]:

Download the base model

In [ ]:

Configure 4-bit quantization

TODO 1

Complete the 4-bit configuration used to load the base model within the available GPU memory.

Check: NF4 weights, bfloat16 computation, and double quantization enabled.

Show hint

Use "nf4", torch.bfloat16, and True for the three unfinished values.

In [ ]:

Load the tokenizer and model

In [ ]:

Download MedQuAD

In [ ]:

Inspect the dataset

TODO 2

Inspect the available columns and calculate the median answer length for the training split.

Check: The available dataset columns, a non-empty list of answer lengths, and one median value.

Show hint

Read column_names from the training split. Sort the word counts and select the middle value.

In [ ]:

Prepare a clean training split

TODO 3

Complete the filtering condition used to build the training and evaluation splits.

Check: 96 training rows and 8 evaluation rows, with every answer between 20 and 160 words.

Show hint

Use the cleaned question and answer_words values when setting keep_example.

In [ ]:

Build the generation prompt

TODO 4

Create the messages for a medical question and render the prompt used for generation.

Check: System and user messages rendered with a generation prompt and returned as PyTorch tensors.

Show hint

Call apply_chat_template with add_generation_prompt, return_tensors, and return_dict enabled. Disable thinking.

In [ ]:

Implement the evaluation metric

TODO 5

Implement token F1 so the base and fine-tuned models can be compared with the same metric.

Check: Lowercase word tokens and an overlap count that handles repeated words correctly.

Show hint

Use re.findall for word tokens. Counter intersection gives the repeated-token overlap.

In [ ]:

Measure the base model

In [ ]:

Format examples as conversations

TODO 6

Build the system, user, and assistant messages, then render them with the tokenizer chat template.

Check: Each row contains one non-empty text field with the complete conversation.

Show hint

Use SYSTEM_PROMPT, example["question"], and example["answer"]. Keep tokenize and enable_thinking disabled.

In [ ]:

Complete the QLoRA adapter

TODO 7

Set adapter dropout and choose which linear layers receive LoRA adapters.

Check: A dropout no greater than 0.1 and adapters applied to all linear layers.

Show hint

A small dropout such as 0.05 is suitable here. PEFT accepts "all-linear" for the target modules.

In [ ]:

Fine-tune the model

TODO 8

Connect the model, training settings, formatted dataset, QLoRA adapter, and tokenizer to SFTTrainer, then train once.

Check: One configured trainer and one completed call to trainer.train().

Show hint

Pass base_model, training_config, train, lora, and tokenizer to the matching SFTTrainer arguments.

In [ ]:

Inspect where the model still fails

TODO 9

Measure the score change, then sort the per-example results and keep the two weakest answers.

Check: A numeric score_change and exactly two result records ordered from lowest token F1.

Show hint

Subtract the baseline token_f1 from the fine-tuned token_f1. Sort fine_tuned_result["results"] by token_f1 and take the first two rows.

In [ ]: