oddadmix commited on
Commit
e727c1c
·
verified ·
1 Parent(s): cabb601

Upload Arabic_Summarization_LFM2_SFT_with_TRL.ipynb

Browse files
Arabic_Summarization_LFM2_SFT_with_TRL.ipynb ADDED
@@ -0,0 +1,721 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {
6
+ "id": "a3PTFH-H9Ozk"
7
+ },
8
+ "source": [
9
+ "# 💧 LFM2 - SFT with TRL\n",
10
+ "\n",
11
+ "This tutorial demonstrates how to fine-tune our LFM2 models, e.g. [`LiquidAI/LFM2-1.2B`](https://huggingface.co/LiquidAI/LFM2-1.2B), using the TRL library.\n",
12
+ "\n",
13
+ "Follow along if it's your first time using trl, or take single code snippets for your own workflow\n",
14
+ "\n",
15
+ "## 🎯 What you'll find:\n",
16
+ "- **SFT** (Supervised Fine-Tuning) - Basic instruction following\n",
17
+ "- **LoRA + SFT** - Using LoRA (from PEFT) to SFT while on constrained hardware\n",
18
+ "\n",
19
+ "## 📋 Prerequisites:\n",
20
+ "- **GPU Runtime**: Select GPU in `Runtime` → `Change runtime type`\n",
21
+ "- **Hugging Face Account**: For accessing models and datasets\n",
22
+ "\n"
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "markdown",
27
+ "metadata": {
28
+ "id": "x0RPLu2h9ome"
29
+ },
30
+ "source": [
31
+ "# 📦 Installation & Setup\n",
32
+ "\n",
33
+ "First, let's install all the required packages:\n"
34
+ ]
35
+ },
36
+ {
37
+ "cell_type": "code",
38
+ "execution_count": null,
39
+ "metadata": {
40
+ "id": "3FIcp_wo9nsR",
41
+ "tags": []
42
+ },
43
+ "outputs": [],
44
+ "source": [
45
+ "!pip install transformers==4.54.1 trl>=0.18.2 peft>=0.15.2"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "code",
50
+ "execution_count": null,
51
+ "metadata": {
52
+ "tags": []
53
+ },
54
+ "outputs": [],
55
+ "source": [
56
+ "!pip install sentencepiece --upgrade"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "code",
61
+ "execution_count": null,
62
+ "metadata": {
63
+ "tags": []
64
+ },
65
+ "outputs": [],
66
+ "source": [
67
+ "!pip install patchelf"
68
+ ]
69
+ },
70
+ {
71
+ "cell_type": "code",
72
+ "execution_count": null,
73
+ "metadata": {
74
+ "tags": []
75
+ },
76
+ "outputs": [],
77
+ "source": [
78
+ "!patchelf --add-rpath '$ORIGIN/../../nvidia/cusparse/lib' /usr/local/lib/python3.11/dist-packages/torch/lib/libtorch_cuda.so"
79
+ ]
80
+ },
81
+ {
82
+ "cell_type": "markdown",
83
+ "metadata": {
84
+ "id": "41UEf1uxCd6m"
85
+ },
86
+ "source": [
87
+ "Let's now verify the packages are installed correctly"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": null,
93
+ "metadata": {
94
+ "colab": {
95
+ "base_uri": "https://localhost:8080/"
96
+ },
97
+ "id": "bSJgYtHT_Os4",
98
+ "outputId": "23f86c62-471c-4579-fc23-1df88e87698b",
99
+ "tags": []
100
+ },
101
+ "outputs": [],
102
+ "source": [
103
+ "import torch\n",
104
+ "import transformers\n",
105
+ "import trl\n",
106
+ "import os\n",
107
+ "os.environ[\"WANDB_DISABLED\"] = \"true\"\n",
108
+ "\n",
109
+ "print(f\"📦 PyTorch version: {torch.__version__}\")\n",
110
+ "print(f\"🤗 Transformers version: {transformers.__version__}\")\n",
111
+ "print(f\"📊 TRL version: {trl.__version__}\")"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "markdown",
116
+ "metadata": {
117
+ "id": "v_uXLzxQ_rnK"
118
+ },
119
+ "source": [
120
+ "# Loading the model from Transformers 🤗\n",
121
+ "\n"
122
+ ]
123
+ },
124
+ {
125
+ "cell_type": "code",
126
+ "execution_count": 1,
127
+ "metadata": {
128
+ "id": "iA3erKM4-HhS",
129
+ "tags": []
130
+ },
131
+ "outputs": [
132
+ {
133
+ "name": "stdout",
134
+ "output_type": "stream",
135
+ "text": [
136
+ "📚 Loading tokenizer...\n",
137
+ "🧠 Loading model...\n"
138
+ ]
139
+ },
140
+ {
141
+ "name": "stderr",
142
+ "output_type": "stream",
143
+ "text": [
144
+ "/usr/local/lib/python3.11/dist-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: '/usr/local/lib/python3.11/dist-packages/torchvision/image.so: undefined symbol: _ZN3c1017RegisterOperatorsD1Ev'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?\n",
145
+ " warn(\n",
146
+ "2025-08-19 00:26:28.995179: I tensorflow/core/util/port.cc:113] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n",
147
+ "2025-08-19 00:26:29.033924: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
148
+ "2025-08-19 00:26:29.033969: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
149
+ "2025-08-19 00:26:29.035101: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
150
+ "2025-08-19 00:26:29.042173: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
151
+ "To enable the following instructions: AVX2 AVX512F AVX512_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n",
152
+ "2025-08-19 00:26:29.962824: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n"
153
+ ]
154
+ },
155
+ {
156
+ "name": "stdout",
157
+ "output_type": "stream",
158
+ "text": [
159
+ "✅ Local model loaded successfully!\n",
160
+ "🔢 Parameters: 354,483,968\n",
161
+ "📖 Vocab size: 64400\n",
162
+ "💾 Model size: ~0.7 GB (bfloat16)\n"
163
+ ]
164
+ }
165
+ ],
166
+ "source": [
167
+ "from transformers import AutoTokenizer, AutoModelForCausalLM\n",
168
+ "from IPython.display import display, HTML, Markdown\n",
169
+ "import torch\n",
170
+ "\n",
171
+ "model_id = \"LiquidAI/LFM2-350M\" # <- or LFM2-700M or LFM2-350M\n",
172
+ "\n",
173
+ "print(\"📚 Loading tokenizer...\")\n",
174
+ "tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
175
+ "\n",
176
+ "print(\"🧠 Loading model...\")\n",
177
+ "model = AutoModelForCausalLM.from_pretrained(\n",
178
+ " model_id,\n",
179
+ " device_map=\"auto\",\n",
180
+ " torch_dtype=\"bfloat16\",\n",
181
+ "# attn_implementation=\"flash_attention_2\" <- uncomment on compatible GPU\n",
182
+ ")\n",
183
+ "\n",
184
+ "print(\"✅ Local model loaded successfully!\")\n",
185
+ "print(f\"🔢 Parameters: {model.num_parameters():,}\")\n",
186
+ "print(f\"📖 Vocab size: {len(tokenizer)}\")\n",
187
+ "print(f\"💾 Model size: ~{model.num_parameters() * 2 / 1e9:.1f} GB (bfloat16)\")"
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "markdown",
192
+ "metadata": {
193
+ "id": "6ABA6Yrm_lql"
194
+ },
195
+ "source": [
196
+ "# 🎯 Part 1: Supervised Fine-Tuning (SFT)\n",
197
+ "\n",
198
+ "SFT teaches the model to follow instructions by training on input-output pairs (instruction vs response). This is the foundation for creating instruction-following models."
199
+ ]
200
+ },
201
+ {
202
+ "cell_type": "markdown",
203
+ "metadata": {
204
+ "id": "KufdgeypHtst"
205
+ },
206
+ "source": [
207
+ "## Load an SFT Dataset\n",
208
+ "\n",
209
+ "We will use [HuggingFaceTB/smoltalk](https://huggingface.co/datasets/HuggingFaceTB/smoltalk), limiting ourselves to the first 5k samples for brevity. Feel free to change the limit by changing the slicing index in the parameter `split`."
210
+ ]
211
+ },
212
+ {
213
+ "cell_type": "code",
214
+ "execution_count": 2,
215
+ "metadata": {
216
+ "id": "XCe8O06-_Cps",
217
+ "tags": []
218
+ },
219
+ "outputs": [
220
+ {
221
+ "name": "stdout",
222
+ "output_type": "stream",
223
+ "text": [
224
+ "📥 Loading SFT dataset...\n"
225
+ ]
226
+ },
227
+ {
228
+ "data": {
229
+ "application/vnd.jupyter.widget-view+json": {
230
+ "model_id": "f2f49b719f5f4528bebae99c4c81ae18",
231
+ "version_major": 2,
232
+ "version_minor": 0
233
+ },
234
+ "text/plain": [
235
+ "README.md: 0%| | 0.00/716 [00:00<?, ?B/s]"
236
+ ]
237
+ },
238
+ "metadata": {},
239
+ "output_type": "display_data"
240
+ },
241
+ {
242
+ "data": {
243
+ "application/vnd.jupyter.widget-view+json": {
244
+ "model_id": "60f5230f2b4341a29b74697578722896",
245
+ "version_major": 2,
246
+ "version_minor": 0
247
+ },
248
+ "text/plain": [
249
+ "data/train-00000-of-00001.parquet: 0%| | 0.00/92.1M [00:00<?, ?B/s]"
250
+ ]
251
+ },
252
+ "metadata": {},
253
+ "output_type": "display_data"
254
+ },
255
+ {
256
+ "data": {
257
+ "application/vnd.jupyter.widget-view+json": {
258
+ "model_id": "1b97ee6327f446718d444df1e8854ffe",
259
+ "version_major": 2,
260
+ "version_minor": 0
261
+ },
262
+ "text/plain": [
263
+ "data/test-00000-of-00001.parquet: 0%| | 0.00/928k [00:00<?, ?B/s]"
264
+ ]
265
+ },
266
+ "metadata": {},
267
+ "output_type": "display_data"
268
+ },
269
+ {
270
+ "data": {
271
+ "application/vnd.jupyter.widget-view+json": {
272
+ "model_id": "54b95e6f022b416aa8011112366811d2",
273
+ "version_major": 2,
274
+ "version_minor": 0
275
+ },
276
+ "text/plain": [
277
+ "Generating train split: 0%| | 0/17862 [00:00<?, ? examples/s]"
278
+ ]
279
+ },
280
+ "metadata": {},
281
+ "output_type": "display_data"
282
+ },
283
+ {
284
+ "data": {
285
+ "application/vnd.jupyter.widget-view+json": {
286
+ "model_id": "813d3db99d7a4d06b7f65ea8512f8095",
287
+ "version_major": 2,
288
+ "version_minor": 0
289
+ },
290
+ "text/plain": [
291
+ "Generating test split: 0%| | 0/181 [00:00<?, ? examples/s]"
292
+ ]
293
+ },
294
+ "metadata": {},
295
+ "output_type": "display_data"
296
+ },
297
+ {
298
+ "data": {
299
+ "application/vnd.jupyter.widget-view+json": {
300
+ "model_id": "ccd9f894c8184189bcfcb53b6e9fcf68",
301
+ "version_major": 2,
302
+ "version_minor": 0
303
+ },
304
+ "text/plain": [
305
+ "Filter: 0%| | 0/17862 [00:00<?, ? examples/s]"
306
+ ]
307
+ },
308
+ "metadata": {},
309
+ "output_type": "display_data"
310
+ },
311
+ {
312
+ "data": {
313
+ "application/vnd.jupyter.widget-view+json": {
314
+ "model_id": "b3d2ff96d0ba4d7eba593847ec10957d",
315
+ "version_major": 2,
316
+ "version_minor": 0
317
+ },
318
+ "text/plain": [
319
+ "Filter: 0%| | 0/181 [00:00<?, ? examples/s]"
320
+ ]
321
+ },
322
+ "metadata": {},
323
+ "output_type": "display_data"
324
+ },
325
+ {
326
+ "data": {
327
+ "application/vnd.jupyter.widget-view+json": {
328
+ "model_id": "be362032b9b041b0b891894ff43e1f45",
329
+ "version_major": 2,
330
+ "version_minor": 0
331
+ },
332
+ "text/plain": [
333
+ "Map: 0%| | 0/17862 [00:00<?, ? examples/s]"
334
+ ]
335
+ },
336
+ "metadata": {},
337
+ "output_type": "display_data"
338
+ },
339
+ {
340
+ "data": {
341
+ "application/vnd.jupyter.widget-view+json": {
342
+ "model_id": "80e634f73d4f472f898fb072ac479ee6",
343
+ "version_major": 2,
344
+ "version_minor": 0
345
+ },
346
+ "text/plain": [
347
+ "Map: 0%| | 0/181 [00:00<?, ? examples/s]"
348
+ ]
349
+ },
350
+ "metadata": {},
351
+ "output_type": "display_data"
352
+ },
353
+ {
354
+ "name": "stdout",
355
+ "output_type": "stream",
356
+ "text": [
357
+ "✅ SFT Dataset loaded:\n",
358
+ " 📚 Train samples: 17862\n",
359
+ " 🧪 Eval samples: 181\n",
360
+ "\n",
361
+ "📝 Single Sample: [{'content': 'Summarize the following text: \\n\\n بقلم: وليام تورفيل. نشر في: 08:04 صباحًا بتوقيت شرق الولايات المتحدة، 21 ديسمبر 2013 | تم تحديثه: 09:07 صباحًا بتوقيت شرق الولايات المتحدة، 21 ديسمبر 2013. إذا كنت تدخل في الروح المناسبة لعيد الميلاد بمجرد سماع أغنية عيد الميلاد أو رؤية صفوف من الزخارف للبيع، فمن الأفضل أن تبتعد عن هذه الشوارع. قد تبدو شوارع مثل تينسيل لين في نونيتون، وارويكشاير، غريبة في الصيف - لكنها تأخذ مكانها في ديسمبر. وجد بحث موظفي رويال ميل أن المملكة المتحدة لديها 3369 اسمًا لشوارع مرتبطة بعيد الميلاد، بناءً على تحليل كل اسم شارع في البلاد. تينسيل لين في نونيتون، وارويكشاير، مزينة هذا العام من قبل السكان ميشيل أورتون وابنها ذي الثلاث سنوات، ماثيو. تعرض الأخوات نيام ديفي (على اليسار)، البالغة من العمر ثماني سنوات، وسيارا ديفي، البالغة من العمر خمس سنوات، أمام اسم شارعهم - الذي قد يبدو غريبًا بعض الشيء في الصيف - في نورثامبتون. هولي ستريت هي أكثر الأسماء شيوعًا لشوارع عيد الميلاد في المملكة المتحدة. هناك 990 اسمًا لهذا النوع من الشوارع في جميع أنحاء المملكة المتحدة. 1. شارع هولي. 2. شارع بيل. 3. شارع ماري. 4. شارع إنجل. 5. طريق ستار. 6. شارع بو. 7. ساحة فيستيفال. 8. شارع نويل. 9. شارع غولد. 10. شارع غارلاند. كشف البحث أيضًا أن إقليم ميدلاندز لديه ما مجموعه 560 اسمًا لشوارع عيد الميلاد، أكثر من أي منطقة أخرى في المملكة المتحدة. تحتوي المنطقة على ما مجموعه 560 اسمًا لشوارع عيد الميلاد وتتمتع بأسماء شوارع مناسبة لعيد الميلاد مثل ريندير رود، ونويل رود، وبيل كلوز، وهولي ستريت. التقييمات جاءت من تحليل قاعدة بيانات رويال ميل التي تحتوي على 29 مليون عنوان في المملكة المتحدة. تكشف قاعدة البيانات أيضًا عن حبنا لرنود سانتا، حيث أن سبعة من تسعة رنود ممثلة في اسم شارع. وتشمل هذه: داشر، ودانسر، وفيكسن، وكوميت، وكيوبيد، ودونر، ورودولف. سكان تينسيل لين في نونيتون، نورثامبتون، بذلوا جهدًا كبيرًا هذا العام من خلال تزيين لافتتهم مثل شجرة الميلاد. قدم ماثيو البالغ من العمر ثلاث سنوات وأمه ميشيل أورتون بالفعل لتزيين لافتة شارعهم. في غضون ذلك، سيكون فريستي هولو في نورثامبتون عنصر جذب كبير للصور الفوتوغرافية خلال هذا الشهر. ويبدو أن الأخوات نيام ديفي، البالغة من العمر ثماني سنوات، وسيارا، البالغة من العمر خمس سنوات، قد فازتا على أصدقائهما. شارع نويل، في إيلينج، لندن الغربية، يتطلب القليل من الخيال لكنه لا يزال يمكن اعتباره شارعًا يبدو مناسبًا جدًا لعيد الميلاد، إذا نطقت بشكل صحيح. ريندير كلوز أكثر وضوحًا، وسيكون من المؤكد أن سكان شرق لندن في حالة مزاجية لعيد الميلاد بحلول ديسمبر. أربع سنوات من السن بوبي جروت تلتقط صورة مع جدتها جين لونج بالقرب من ميستل تو غرين في أكسفورد. ومع ذلك، على أساس الأدلة الفوتوغرافية، لا يبدو أن المرح أكبر في لندن، حيث أن اللافتات المناسبة لعيد الميلاد أكثر شيوعًا ويتم التعامل معها بقليل من الحماس. بعض اللافتات المصورة مثل نويل رود، التي تتطلب نطقًا خاصًا، وستار رود. لكن في حالات أخرى - ريندير كلوز وهولي واي - لا يمكن الهروب من المعنى المسيحي للأسماء. قد يجذب ستريت توركيل الناس في نورث إنجلاند إلى عيد الميلاد، لكن عليهم أن يسافروا إلى تاور هاملتس لإيجاد كرانبري لين. فريستي يارد في مدينة ويستمنستر، لندن، توفر اسمًا مناسبًا لعيد الميلاد مع خلفية أكثر توراتية. يجب على أولئك الذين لا يستمتعون بعيد الميلاد أن يبتعدوا عن هذه الشوارع. وبالمثل، إذا كنت لا تشعر بالرغبة في قبلة عيد الميلاد، فتعلم من أخطاء بوبي جروت البالغة من العمر أربع سنوات، التي اشتعلت وهي تلتقط صورة مع جدتها، جين لونج، أمام ميستل غرين في أكسفورد. بالنسبة لسكان أدفنت واي، ديسمبر لا يمكن أن يأتي بسرعة كافية. على الرغم من كل شيء، لا يوجد في نويسلين في نورثلينكولن، إلينج، شارع مناسب لعيد الميلاد .', 'role': 'user'}, {'content': 'وجد بحث أجراه موظفو \"رويال ميل\" العام الماضي أن المملكة المتحدة لديها 3369 اسمًا لشوارع مُوَضوعها الميلاد. ويعد \"هولي ستريت\" أكثر أسماء الشوارع احتفالية شيوعًا في المملكة المتحدة. هناك 990 اسمًا لشوارع من هذا النوع في جميع أنحاء المملكة المتحدة.', 'role': 'assistant'}]\n"
362
+ ]
363
+ }
364
+ ],
365
+ "source": [
366
+ "from datasets import load_dataset\n",
367
+ "\n",
368
+ "print(\"📥 Loading SFT dataset...\")\n",
369
+ "train_dataset_sft = load_dataset(\"oddadmix/arabic-news-summarization\", split=\"train\")\n",
370
+ "eval_dataset_sft = load_dataset(\"oddadmix/arabic-news-summarization\", split=\"test\")\n",
371
+ "\n",
372
+ "\n",
373
+ "def filterEmpty(example):\n",
374
+ " if example[\"summary_text_translated\"] is None or example[\"origin_text_translated\"] is None: \n",
375
+ " return False\n",
376
+ " return True\n",
377
+ "\n",
378
+ "train_dataset_sft = train_dataset_sft.filter(filterEmpty)\n",
379
+ "eval_dataset_sft = eval_dataset_sft.filter(filterEmpty)\n",
380
+ "\n",
381
+ "\n",
382
+ "def convert_to_conversation(example):\n",
383
+ " example[\"messages\"] = [\n",
384
+ " {\n",
385
+ " \"content\": \"Summarize the following text: \\n\\n \" + example[\"origin_text_translated\"] ,\n",
386
+ " \"role\": \"user\"\n",
387
+ " },\n",
388
+ " {\n",
389
+ " \"content\": example[\"summary_text_translated\"],\n",
390
+ " \"role\": \"assistant\"\n",
391
+ " }\n",
392
+ " ]\n",
393
+ " return example\n",
394
+ "\n",
395
+ "train_dataset_sft = train_dataset_sft.map(convert_to_conversation, remove_columns=[\"origin_text_translated\", \"origin_text\", \"summary_text_translated\",\"summary_text\"])\n",
396
+ "eval_dataset_sft = eval_dataset_sft.map(convert_to_conversation, remove_columns=[\"origin_text_translated\", \"origin_text\", \"summary_text_translated\",\"summary_text\"])\n",
397
+ "\n",
398
+ "print(\"✅ SFT Dataset loaded:\")\n",
399
+ "print(f\" 📚 Train samples: {len(train_dataset_sft)}\")\n",
400
+ "print(f\" 🧪 Eval samples: {len(eval_dataset_sft)}\")\n",
401
+ "print(f\"\\n📝 Single Sample: {train_dataset_sft[0]['messages']}\")"
402
+ ]
403
+ },
404
+ {
405
+ "cell_type": "markdown",
406
+ "metadata": {
407
+ "id": "n5pI5JWpIlFQ"
408
+ },
409
+ "source": [
410
+ "## Launch Training\n",
411
+ "\n",
412
+ "We are now ready to launch an SFT run with `SFTTrainer`, feel free to modify `SFTConfig` to play around with different configurations.\n",
413
+ "\n"
414
+ ]
415
+ },
416
+ {
417
+ "cell_type": "code",
418
+ "execution_count": null,
419
+ "metadata": {
420
+ "id": "ixD8Po-eAbPp",
421
+ "tags": []
422
+ },
423
+ "outputs": [
424
+ {
425
+ "name": "stdout",
426
+ "output_type": "stream",
427
+ "text": [
428
+ "🏗️ Creating SFT trainer...\n"
429
+ ]
430
+ },
431
+ {
432
+ "data": {
433
+ "application/vnd.jupyter.widget-view+json": {
434
+ "model_id": "9dfa2b44e9cc4428bb62a6a39e817602",
435
+ "version_major": 2,
436
+ "version_minor": 0
437
+ },
438
+ "text/plain": [
439
+ "Tokenizing train dataset: 0%| | 0/17862 [00:00<?, ? examples/s]"
440
+ ]
441
+ },
442
+ "metadata": {},
443
+ "output_type": "display_data"
444
+ }
445
+ ],
446
+ "source": [
447
+ "from trl import SFTConfig, SFTTrainer\n",
448
+ "\n",
449
+ "sft_config = SFTConfig(\n",
450
+ " output_dir=\"./lfm2-sft-summary\",\n",
451
+ " num_train_epochs=10,\n",
452
+ " per_device_train_batch_size=16,\n",
453
+ " learning_rate=5e-5,\n",
454
+ " lr_scheduler_type=\"linear\",\n",
455
+ " warmup_steps=100,\n",
456
+ " warmup_ratio=0.2,\n",
457
+ " logging_steps=10,\n",
458
+ " save_strategy=\"epoch\",\n",
459
+ " eval_strategy=\"epoch\",\n",
460
+ " load_best_model_at_end=True,\n",
461
+ " report_to=None,\n",
462
+ " bf16=False # <- not all colab GPUs support bf16\n",
463
+ ")\n",
464
+ "\n",
465
+ "print(\"🏗️ Creating SFT trainer...\")\n",
466
+ "sft_trainer = SFTTrainer(\n",
467
+ " model=model,\n",
468
+ " args=sft_config,\n",
469
+ " train_dataset=train_dataset_sft,\n",
470
+ " eval_dataset=eval_dataset_sft,\n",
471
+ " processing_class=tokenizer,\n",
472
+ ")\n",
473
+ "\n",
474
+ "print(\"\\n🚀 Starting SFT training...\")\n",
475
+ "sft_trainer.train(resume_from_checkpoint=True)\n",
476
+ "\n",
477
+ "print(\"🎉 SFT training completed!\")\n",
478
+ "\n",
479
+ "sft_trainer.push_to_hub(\"oddadmix/arabic-summarization\")\n",
480
+ "#sft_trainer.save_model()\n",
481
+ "print(f\"💾 SFT model saved to: {sft_config.output_dir}\")"
482
+ ]
483
+ },
484
+ {
485
+ "cell_type": "code",
486
+ "execution_count": null,
487
+ "metadata": {
488
+ "tags": []
489
+ },
490
+ "outputs": [],
491
+ "source": [
492
+ "sft_trainer.push_to_hub(\"oddadmix/lfm2-arabic-summarizer\")"
493
+ ]
494
+ },
495
+ {
496
+ "cell_type": "code",
497
+ "execution_count": null,
498
+ "metadata": {
499
+ "tags": []
500
+ },
501
+ "outputs": [],
502
+ "source": [
503
+ "text = \"\"\"\n",
504
+ "شاهد زوجان صدمان فريقًا من خفر السواحل ينقذ بشكل درامي كلبهما الأليف المحاصِر في جرف يبلغ طوله 200 قدم. شاهد جون جريفيتس، البالغ من العمر 47 عامًا، وزوجته ميشيل، البالغة من العمر 36 عامًا، بينما يتم سحب كلب جرمن شيبرد الخاص بهما كلوي إلى مكان آمن. استغرقت العملية المعقدة أكثر من ساعة على الواجهة البحرية في كرومر، شمال نورفولك، صباح أمس. شعر جون جريفيتس، البالغ من العمر 47 عامًا، وزوجته ميشيل، البالغة من العمر 36 عامًا، بالارتياح للم شملهما مع كلبهما الأليف، كلوي (في الصورة على اليسار). أنقذ جيري وودلي، من فريق إنقاذ خفر السواحل الملكي، الكلب الذي انزلق من جرف في كرومر. استغرقت العملية المعقدة أكثر من ساعة على الواجهة البحرية في كرومر، في شمال نورفولك. وهتف حشد من المصطافين والسكان المحليين الذين تجمعوا لمشاهدة الحدث المثير عند إنقاذ كلوي. بكت السيدة جريفيتس من الارتياح عند لم شملها مع كلبها الأليف. وقالت: \"أشعر فقط بالارتياح لأنها لم تتأذى - قام خفر السواحل بعمل رائع\". كان الزوجان يمشان على طول قمة الجرف مع كلوي البالغة من العمر ست سنوات وتيلي البالغة من العمر 14 شهرًا، وهي كلب جرمن شيبرد مهجن مع سبيزي هسكي، عندما انزلق الكلب الأكبر سنًا وسقط. وقال جريفيثس: \"لم نر كلوي تسقط من الجرف، لكننا عرفنا أن شيئًا ما قد حدث عندما اختفت. تقرأ عن الكلاب التي تسقط من الجرف وتفكر، كيف يمكن أن يحدث ذلك، ولكن يمكن ذلك. لم أستطع أن أصدق أنها اقتربت كثيرًا من الجرف\". انزلق جريفيثز بشجاعة جزءًا من الطريق من خلال الشجيرات الكثيفة والأراضي الفضية في محاولة يائسة للوصول إلى كلوي. لكنه أدرك سريعًا أنه كان خطيرًا جدًا واتصل برقم الطوارئ 999 لإثارة الإنذار. انتظر جريفيثز بتوترٍ وفريق الإنقاذ يعمل على استعادة كلبه الجرمان شيبرد، كلوي. أقام فريق الإنقاذ حبالًا خاصة وآلة سحب لإنزال جيري ودلي من كرومر. وقال وودلي إنه وجد كلوي تقوم بنباح من الرعب ومحاصرة على بعد حوالي 60 قدمًا أسفل الجرف الحاد الذي يبلغ طوله 200 قدم. وقال إنه كان إنقاذًا صعبًا حيث كانت شجيرات الزعرور الكثيفة تغطي الكلب تمامًا. وقال: \"كان من الصعب وضع الكلب في حقيبة الإنقاذ. بمجرد أن حققنا ذلك، كان كل شيء على ما يرام\"، قال جريفيثز، الذي قدم تبرعًا سخيًا لخفر السواحل كعلامة على تقديره لإنقاذ حياة كلوي، قائلاً: \"لقد كانوا رائعين - خاصة عندما تفكر في أنهم جميعًا متطوعون. لا يمكننا شكرهم بما فيه الكفاية\".\n",
505
+ "\"\"\"\n",
506
+ "from transformers import pipeline\n",
507
+ "\n",
508
+ "prompt = \"Summarize the following text: \\n\\n \" + text\n",
509
+ "\n",
510
+ "\n",
511
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
512
+ "\n",
513
+ "# Load model and tokenizer\n",
514
+ "model_id = \"oddadmix/lfm2-sft-summary\"\n",
515
+ "model = AutoModelForCausalLM.from_pretrained(\n",
516
+ " model_id,\n",
517
+ " device_map=\"auto\",\n",
518
+ " torch_dtype=\"bfloat16\",\n",
519
+ "# attn_implementation=\"flash_attention_2\" <- uncomment on compatible GPU\n",
520
+ ")\n",
521
+ "tokenizer = AutoTokenizer.from_pretrained(model_id)\n",
522
+ "\n",
523
+ "\n",
524
+ "input_ids = tokenizer.apply_chat_template(\n",
525
+ " [{\"role\": \"user\", \"content\": prompt}],\n",
526
+ " add_generation_prompt=True,\n",
527
+ " return_tensors=\"pt\",\n",
528
+ " tokenize=True,\n",
529
+ ").to(model.device)\n",
530
+ "\n",
531
+ "output = model.generate(\n",
532
+ " input_ids,\n",
533
+ " do_sample=True,\n",
534
+ " temperature=0.3,\n",
535
+ " min_p=0.15,\n",
536
+ " repetition_penalty=1.05,\n",
537
+ " max_new_tokens=512,\n",
538
+ ")\n",
539
+ "\n",
540
+ "print(tokenizer.decode(output[0], skip_special_tokens=False))\n",
541
+ "\n",
542
+ "# <|startoftext|><|im_start|>user\n",
543
+ "# What is C. elegans?<|im_end|>\n",
544
+ "# <|im_start|>assistant\n",
545
+ "# C. elegans, also known as Caenorhabditis elegans, is a small, free-living\n",
546
+ "# nematode worm (roundworm) that belongs to the phylum Nematoda.\n"
547
+ ]
548
+ },
549
+ {
550
+ "cell_type": "code",
551
+ "execution_count": null,
552
+ "metadata": {},
553
+ "outputs": [],
554
+ "source": []
555
+ },
556
+ {
557
+ "cell_type": "markdown",
558
+ "metadata": {
559
+ "id": "08Y3TxKrBRXo"
560
+ },
561
+ "source": [
562
+ "# 🎛️ Part 2: LoRA + SFT (Parameter-Efficient Fine-tuning)\n",
563
+ "\n",
564
+ "LoRA (Low-Rank Adaptation) allows efficient fine-tuning by only training a small number of additional parameters. Perfect for limited compute resources!\n"
565
+ ]
566
+ },
567
+ {
568
+ "cell_type": "markdown",
569
+ "metadata": {
570
+ "id": "-MfWfc-Pvl9q"
571
+ },
572
+ "source": [
573
+ "## Wrap the model with PEFT\n",
574
+ "\n",
575
+ "We specify target modules that will be finetuned while the rest of the models weights remains frozen. Feel free to modify the `r` (rank) value:\n",
576
+ "- higher -> better approximation of full-finetuning\n",
577
+ "- lower -> needs even less compute resources"
578
+ ]
579
+ },
580
+ {
581
+ "cell_type": "code",
582
+ "execution_count": null,
583
+ "metadata": {
584
+ "id": "puYp_gTpBSsf"
585
+ },
586
+ "outputs": [],
587
+ "source": [
588
+ "from peft import LoraConfig, get_peft_model, TaskType\n",
589
+ "\n",
590
+ "GLU_MODULES = [\"w1\", \"w2\", \"w3\"]\n",
591
+ "MHA_MODULES = [\"q_proj\", \"k_proj\", \"v_proj\", \"out_proj\"]\n",
592
+ "CONV_MODULES = [\"in_proj\", \"out_proj\"]\n",
593
+ "\n",
594
+ "lora_config = LoraConfig(\n",
595
+ " task_type=TaskType.CAUSAL_LM,\n",
596
+ " inference_mode=False,\n",
597
+ " r=8, # <- lower values = fewer parameters\n",
598
+ " lora_alpha=16,\n",
599
+ " lora_dropout=0.1,\n",
600
+ " target_modules=GLU_MODULES + MHA_MODULES + CONV_MODULES,\n",
601
+ " bias=\"none\",\n",
602
+ " modules_to_save=None,\n",
603
+ ")\n",
604
+ "\n",
605
+ "lora_model = get_peft_model(model, lora_config)\n",
606
+ "lora_model.print_trainable_parameters()\n",
607
+ "\n",
608
+ "print(\"✅ LoRA configuration applied!\")\n",
609
+ "print(f\"🎛️ LoRA rank: {lora_config.r}\")\n",
610
+ "print(f\"📊 LoRA alpha: {lora_config.lora_alpha}\")\n",
611
+ "print(f\"🎯 Target modules: {lora_config.target_modules}\")"
612
+ ]
613
+ },
614
+ {
615
+ "cell_type": "markdown",
616
+ "metadata": {
617
+ "id": "L1Hem_DOwHgY"
618
+ },
619
+ "source": [
620
+ "## Launch Training\n",
621
+ "\n",
622
+ "Now ready to launch the SFT training, but this time with the LoRA-wrapped model"
623
+ ]
624
+ },
625
+ {
626
+ "cell_type": "code",
627
+ "execution_count": null,
628
+ "metadata": {
629
+ "id": "u-VYQysHBY8-"
630
+ },
631
+ "outputs": [],
632
+ "source": [
633
+ "from trl import SFTConfig, SFTTrainer\n",
634
+ "\n",
635
+ "lora_sft_config = SFTConfig(\n",
636
+ " output_dir=\"./lfm2-sft-lora\",\n",
637
+ " num_train_epochs=1,\n",
638
+ " per_device_train_batch_size=1,\n",
639
+ " learning_rate=5e-5,\n",
640
+ " lr_scheduler_type=\"linear\",\n",
641
+ " warmup_steps=100,\n",
642
+ " warmup_ratio=0.2,\n",
643
+ " logging_steps=10,\n",
644
+ " save_strategy=\"epoch\",\n",
645
+ " eval_strategy=\"epoch\",\n",
646
+ " load_best_model_at_end=True,\n",
647
+ " report_to=None,\n",
648
+ ")\n",
649
+ "\n",
650
+ "print(\"🏗️ Creating LoRA SFT trainer...\")\n",
651
+ "lora_sft_trainer = SFTTrainer(\n",
652
+ " model=lora_model,\n",
653
+ " args=lora_sft_config,\n",
654
+ " train_dataset=train_dataset_sft,\n",
655
+ " eval_dataset=eval_dataset_sft,\n",
656
+ " processing_class=tokenizer,\n",
657
+ ")\n",
658
+ "\n",
659
+ "print(\"\\n🚀 Starting LoRA + SFT training...\")\n",
660
+ "lora_sft_trainer.train()\n",
661
+ "\n",
662
+ "print(\"🎉 LoRA + SFT training completed!\")\n",
663
+ "\n",
664
+ "lora_sft_trainer.save_model()\n",
665
+ "print(f\"💾 LoRA model saved to: {lora_sft_config.output_dir}\")"
666
+ ]
667
+ },
668
+ {
669
+ "cell_type": "markdown",
670
+ "metadata": {
671
+ "id": "xI1-N-_Ev0cC"
672
+ },
673
+ "source": [
674
+ "## Save merged model\n",
675
+ "\n",
676
+ "Merge the extra weights learned with LoRA back into the model to obtain a \"normal\" model checkpoint."
677
+ ]
678
+ },
679
+ {
680
+ "cell_type": "code",
681
+ "execution_count": null,
682
+ "metadata": {
683
+ "id": "_rizEFUsvwce"
684
+ },
685
+ "outputs": [],
686
+ "source": [
687
+ "print(\"\\n🔄 Merging LoRA weights...\")\n",
688
+ "merged_model = lora_model.merge_and_unload()\n",
689
+ "merged_model.save_pretrained(\"./lfm2-lora-merged\")\n",
690
+ "tokenizer.save_pretrained(\"./lfm2-lora-merged\")\n",
691
+ "print(\"💾 Merged model saved to: ./lfm2-lora-merged\")"
692
+ ]
693
+ }
694
+ ],
695
+ "metadata": {
696
+ "accelerator": "GPU",
697
+ "colab": {
698
+ "gpuType": "T4",
699
+ "provenance": []
700
+ },
701
+ "kernelspec": {
702
+ "display_name": "Python 3 (ipykernel)",
703
+ "language": "python",
704
+ "name": "python3"
705
+ },
706
+ "language_info": {
707
+ "codemirror_mode": {
708
+ "name": "ipython",
709
+ "version": 3
710
+ },
711
+ "file_extension": ".py",
712
+ "mimetype": "text/x-python",
713
+ "name": "python",
714
+ "nbconvert_exporter": "python",
715
+ "pygments_lexer": "ipython3",
716
+ "version": "3.11.7"
717
+ }
718
+ },
719
+ "nbformat": 4,
720
+ "nbformat_minor": 4
721
+ }