oopere commited on
Commit
0626cea
·
verified ·
1 Parent(s): 3841d65

Upload SmolLM2-1.7B QLoRA fine-tuned on Clinical NER (Chapter 7)

Browse files
README.md ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ tags:
5
+ - qlora
6
+ - clinical-ner
7
+ - smollm2
8
+ - rearchitecting-llms
9
+ - fine-tuning
10
+ - medical
11
+ - educational
12
+ license: apache-2.0
13
+ base_model: HuggingFaceTB/SmolLM2-1.7B-Instruct
14
+ datasets:
15
+ - oopere/clinical-ner-qdora
16
+ metrics:
17
+ - accuracy
18
+ ---
19
+
20
+ # SmolLM2-1.7B-ClinicalNER
21
+
22
+ ## Model Description
23
+
24
+ QLoRA fine-tuned version of **HuggingFaceTB/SmolLM2-1.7B-Instruct** for clinical named entity
25
+ recognition (NER). Created as part of **Chapter 7** of *Rearchitecting LLMs*.
26
+
27
+ * **Book:** [Rearchitecting LLMs](https://hubs.la/Q04k2VyY0)
28
+ * **Technique:** QLoRA (Quantized Low-Rank Adaptation)
29
+ * **Task:** Clinical NER — structured JSON extraction from clinical notes
30
+ * **Chapter:** Chapter 7 — Specialization Tuning
31
+
32
+ [![Rearchitecting LLMs](https://cdn-uploads.huggingface.co/production/uploads/640f7924f2d7c41a1e9eced1/sa4ivCbm8kk6C9NAPmb-x.jpeg)](https://hubs.la/Q040tvsK0)
33
+
34
+ ---
35
+
36
+ ## What This Model Does
37
+
38
+ Given a free-text clinical note, the model extracts structured clinical entities
39
+ into a strict JSON schema using only the two-word prompt `Extract:`.
40
+
41
+ Before fine-tuning: a 15-line system prompt was required.
42
+ After QLoRA training: the model responds correctly to `Extract:` alone.
43
+
44
+ ---
45
+
46
+ ## Schema Compliance Results
47
+
48
+ Results from **CH07_NB02_L4_QLoRA_QDoRA** on the `oopere/clinical-ner-qdora` test set (40 samples, 5 categories).
49
+
50
+ | Model | Prompt | Schema Compliance |
51
+ |:---|:---|:---:|
52
+ | SmolLM2-1.7B baseline | Strict (15-line prompt) | 87.5% |
53
+ | SmolLM2-1.7B baseline | Minimal (`Extract:`) | 0.0% |
54
+ | **SmolLM2-1.7B QLoRA (this model)** | **Minimal (`Extract:`)** | **95.0%** |
55
+
56
+ Fine-tuning permanently absorbed the 15-line prompt into the model weights.
57
+
58
+ ---
59
+
60
+ ## Training Details
61
+
62
+ ### Dataset
63
+
64
+ * **Source:** [oopere/clinical-ner-qdora](https://huggingface.co/datasets/oopere/clinical-ner-qdora)
65
+ * **Train samples:** 200 (40 per category)
66
+ * **Test samples:** 40 (8 per category)
67
+ * **Categories:** clean, abbreviations, implicit, typos, irrelevant
68
+
69
+ ### QLoRA Hyperparameters
70
+
71
+ | Parameter | Value |
72
+ |:---|:---|
73
+ | Base model | `HuggingFaceTB/SmolLM2-1.7B-Instruct` |
74
+ | Quantization | NF4 4-bit + double quantization |
75
+ | LoRA rank (r) | 8 |
76
+ | LoRA alpha | 16 |
77
+ | LoRA dropout | 0.05 |
78
+ | Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
79
+ | Epochs | 3 |
80
+ | Batch size | 8 |
81
+ | Learning rate | 2e-4 |
82
+ | LR scheduler | cosine |
83
+ | Max sequence length | 512 |
84
+ | Compute dtype | bfloat16 |
85
+
86
+ ### Hardware
87
+ * **GPU:** NVIDIA L4 (Google Colab)
88
+
89
+ ---
90
+
91
+ ## How to Use
92
+
93
+ ```python
94
+ from transformers import AutoModelForCausalLM, AutoTokenizer
95
+ import torch
96
+
97
+ model_id = 'oopere/SmolLM2-1.7B-ClinicalNER'
98
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
99
+ model = AutoModelForCausalLM.from_pretrained(model_id)
100
+ model.eval()
101
+
102
+ note = 'Patient 45yo male, fever and dry cough for 3 days. Temp 38.5C, HR 98, BP 120/80.'
103
+
104
+ messages = [{'role': 'system', 'content': 'Extract:'}, {'role': 'user', 'content': note}]
105
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
106
+ inputs = tokenizer([text], return_tensors='pt').to(model.device)
107
+
108
+ with torch.inference_mode():
109
+ output_ids = model.generate(**inputs, max_new_tokens=256, do_sample=False)
110
+
111
+ new_tokens = output_ids[0][len(inputs.input_ids[0]):]
112
+ print(tokenizer.decode(new_tokens, skip_special_tokens=True))
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Limitations & Intended Use
118
+
119
+ **Educational model** from *Rearchitecting LLMs* Chapter 7.
120
+ Demonstrates QLoRA fine-tuning and the workflow: Train → Merge → Upload → Verify.
121
+
122
+ **Not intended for clinical or production use.** Training data is synthetic.
123
+
124
+ ---
125
+
126
+ ## Citation
127
+
128
+ ```bibtex
129
+ @book{martra2026rearchitecting,
130
+ author = {Pere Martra},
131
+ title = {Rearchitecting LLMs: Structural techniques for efficient models},
132
+ publisher = {Manning Publications},
133
+ year = {2026},
134
+ url = {https://hubs.la/Q040tvtp0}
135
+ }
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Acknowledgments
141
+
142
+ Created following *Rearchitecting LLMs* (Manning, 2026).
143
+ Challenge: can you push schema compliance above 95%?
144
+ Try: higher LoRA rank, more epochs, or QDoRA instead.
145
+ Share your results: [discussion forum](https://hubs.la/Q04k2VyY0)
146
+ ____
chat_template.jinja ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system
2
+ You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|>
3
+ ' }}{% endif %}{{'<|im_start|>' + message['role'] + '
4
+ ' + message['content'] + '<|im_end|>' + '
5
+ '}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant
6
+ ' }}{% endif %}
config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 1,
8
+ "dtype": "float32",
9
+ "eos_token_id": 2,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 2048,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 8192,
15
+ "max_position_embeddings": 8192,
16
+ "mlp_bias": false,
17
+ "model_type": "llama",
18
+ "num_attention_heads": 32,
19
+ "num_hidden_layers": 24,
20
+ "num_key_value_heads": 32,
21
+ "pad_token_id": 2,
22
+ "pretraining_tp": 1,
23
+ "quantization_config": {
24
+ "_load_in_4bit": true,
25
+ "_load_in_8bit": false,
26
+ "bnb_4bit_compute_dtype": "bfloat16",
27
+ "bnb_4bit_quant_storage": "uint8",
28
+ "bnb_4bit_quant_type": "nf4",
29
+ "bnb_4bit_use_double_quant": true,
30
+ "llm_int8_enable_fp32_cpu_offload": false,
31
+ "llm_int8_has_fp16_weight": false,
32
+ "llm_int8_skip_modules": null,
33
+ "llm_int8_threshold": 6.0,
34
+ "load_in_4bit": true,
35
+ "load_in_8bit": false,
36
+ "quant_method": "bitsandbytes"
37
+ },
38
+ "rms_norm_eps": 1e-05,
39
+ "rope_parameters": {
40
+ "rope_theta": 130000,
41
+ "rope_type": "default"
42
+ },
43
+ "tie_word_embeddings": true,
44
+ "transformers.js_config": {
45
+ "dtype": "q4",
46
+ "kv_cache_dtype": {
47
+ "fp16": "float16",
48
+ "q4f16": "float16"
49
+ },
50
+ "use_external_data_format": {
51
+ "model.onnx": true,
52
+ "model_fp16.onnx": true
53
+ }
54
+ },
55
+ "transformers_version": "5.0.0",
56
+ "use_cache": false,
57
+ "vocab_size": 49152
58
+ }
generation_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": [
5
+ 2
6
+ ],
7
+ "pad_token_id": 2,
8
+ "transformers_version": "5.0.0"
9
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e31f67669af0dd06d9bfb1232d8b2617bb4def04101758950b6e032a741e172c
3
+ size 1234259317
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": "<|im_start|>",
5
+ "clean_up_tokenization_spaces": false,
6
+ "eos_token": "<|im_end|>",
7
+ "extra_special_tokens": [
8
+ "<|im_start|>",
9
+ "<|im_end|>"
10
+ ],
11
+ "is_local": false,
12
+ "model_max_length": 8192,
13
+ "pad_token": "<|im_end|>",
14
+ "tokenizer_class": "TokenizersBackend",
15
+ "unk_token": "<|endoftext|>",
16
+ "vocab_size": 49152
17
+ }