Diff of /fine-tune.ipynb [000000] .. [a108cb]

Switch to unified view

a b/fine-tune.ipynb
1
{
2
 "cells": [
3
  {
4
   "cell_type": "markdown",
5
   "id": "6614ed41-7f65-4495-aa3d-8fba22013597",
6
   "metadata": {},
7
   "source": [
8
    "Different learning rates, number of epochs, and batch sizes were explored, but the results did not change much."
9
   ]
10
  },
11
  {
12
   "cell_type": "code",
13
   "execution_count": 1,
14
   "id": "9bff167f-c177-4f9f-9408-bd499f2d63e8",
15
   "metadata": {},
16
   "outputs": [],
17
   "source": [
18
    "import pandas as pd\n",
19
    "import numpy as np\n",
20
    "import torch\n",
21
    "from sklearn.model_selection import train_test_split\n",
22
    "from torch.utils.data import TensorDataset, DataLoader\n",
23
    "from transformers import AutoTokenizer, AutoModelForSequenceClassification\n",
24
    "from tqdm import tqdm\n",
25
    "import torch.nn as nn"
26
   ]
27
  },
28
  {
29
   "cell_type": "code",
30
   "execution_count": 2,
31
   "id": "c1d30e92-0aea-498c-8d3f-d8b24cf4aeeb",
32
   "metadata": {},
33
   "outputs": [
34
    {
35
     "name": "stdout",
36
     "output_type": "stream",
37
     "text": [
38
      "Number of examples is: 560\n"
39
     ]
40
    },
41
    {
42
     "data": {
43
      "text/html": [
44
       "<div>\n",
45
       "<style scoped>\n",
46
       "    .dataframe tbody tr th:only-of-type {\n",
47
       "        vertical-align: middle;\n",
48
       "    }\n",
49
       "\n",
50
       "    .dataframe tbody tr th {\n",
51
       "        vertical-align: top;\n",
52
       "    }\n",
53
       "\n",
54
       "    .dataframe thead th {\n",
55
       "        text-align: right;\n",
56
       "    }\n",
57
       "</style>\n",
58
       "<table border=\"1\" class=\"dataframe\">\n",
59
       "  <thead>\n",
60
       "    <tr style=\"text-align: right;\">\n",
61
       "      <th></th>\n",
62
       "      <th>CANONICAL_SMILES</th>\n",
63
       "      <th>pIC50</th>\n",
64
       "    </tr>\n",
65
       "  </thead>\n",
66
       "  <tbody>\n",
67
       "    <tr>\n",
68
       "      <th>0</th>\n",
69
       "      <td>Nc1nc(N)c2c(Sc3ccccc3)cccc2n1</td>\n",
70
       "      <td>6.21</td>\n",
71
       "    </tr>\n",
72
       "    <tr>\n",
73
       "      <th>1</th>\n",
74
       "      <td>COc1ccc(OC)c(Cc2sc3nc(N)nc(N)c3c2C)c1</td>\n",
75
       "      <td>6.14</td>\n",
76
       "    </tr>\n",
77
       "    <tr>\n",
78
       "      <th>2</th>\n",
79
       "      <td>CN(Cc1coc2nc(N)nc(N)c12)c3ccc(cc3)C(=O)N[C@@H]...</td>\n",
80
       "      <td>6.66</td>\n",
81
       "    </tr>\n",
82
       "    <tr>\n",
83
       "      <th>3</th>\n",
84
       "      <td>Nc1nc(N)c2nc(CSc3ccc(cc3)C(=O)NC(CCC(=O)O)C(=O...</td>\n",
85
       "      <td>5.57</td>\n",
86
       "    </tr>\n",
87
       "    <tr>\n",
88
       "      <th>4</th>\n",
89
       "      <td>Nc1nc(N)c2nc(CCSc3ccc(cc3)C(=O)NC(CCC(=O)O)C(=...</td>\n",
90
       "      <td>4.60</td>\n",
91
       "    </tr>\n",
92
       "  </tbody>\n",
93
       "</table>\n",
94
       "</div>"
95
      ],
96
      "text/plain": [
97
       "                                    CANONICAL_SMILES  pIC50\n",
98
       "0                      Nc1nc(N)c2c(Sc3ccccc3)cccc2n1   6.21\n",
99
       "1              COc1ccc(OC)c(Cc2sc3nc(N)nc(N)c3c2C)c1   6.14\n",
100
       "2  CN(Cc1coc2nc(N)nc(N)c12)c3ccc(cc3)C(=O)N[C@@H]...   6.66\n",
101
       "3  Nc1nc(N)c2nc(CSc3ccc(cc3)C(=O)NC(CCC(=O)O)C(=O...   5.57\n",
102
       "4  Nc1nc(N)c2nc(CCSc3ccc(cc3)C(=O)NC(CCC(=O)O)C(=...   4.60"
103
      ]
104
     },
105
     "execution_count": 2,
106
     "metadata": {},
107
     "output_type": "execute_result"
108
    }
109
   ],
110
   "source": [
111
    "# Load the dataset\n",
112
    "df = pd.read_csv(\"data/hDHFR_pIC50_data.csv\")[[\"CANONICAL_SMILES\", \"pIC50\"]]\n",
113
    "print(f'Number of examples is: {len(df)}')\n",
114
    "df.head()"
115
   ]
116
  },
117
  {
118
   "cell_type": "code",
119
   "execution_count": 3,
120
   "id": "04851bc1-5707-4bd5-b39d-0d5d618dd116",
121
   "metadata": {},
122
   "outputs": [
123
    {
124
     "name": "stderr",
125
     "output_type": "stream",
126
     "text": [
127
      "Some weights of RobertaForSequenceClassification were not initialized from the model checkpoint at DeepChem/ChemBERTa-77M-MLM and are newly initialized: ['classifier.dense.weight', 'classifier.out_proj.bias', 'classifier.out_proj.weight', 'classifier.dense.bias']\n",
128
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
129
     ]
130
    },
131
    {
132
     "name": "stdout",
133
     "output_type": "stream",
134
     "text": [
135
      "512\n"
136
     ]
137
    }
138
   ],
139
   "source": [
140
    "# Load the pre-trained model and tokenizer\n",
141
    "model_name = \"DeepChem/ChemBERTa-77M-MLM\"\n",
142
    "model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=1)\n",
143
    "tokenizer = AutoTokenizer.from_pretrained(model_name)\n",
144
    "\n",
145
    "# Determine the maximum sequence length\n",
146
    "max_length = tokenizer.model_max_length\n",
147
    "print(max_length)"
148
   ]
149
  },
150
  {
151
   "cell_type": "code",
152
   "execution_count": 4,
153
   "id": "755634da-6e15-46c3-a9d2-fdc7bd2aa75e",
154
   "metadata": {},
155
   "outputs": [
156
    {
157
     "name": "stderr",
158
     "output_type": "stream",
159
     "text": [
160
      "100%|██████████████████████████████████████| 560/560 [00:00<00:00, 15447.41it/s]\n"
161
     ]
162
    }
163
   ],
164
   "source": [
165
    "# Tokenization function\n",
166
    "def tokenize(string):\n",
167
    "    \"\"\"\n",
168
    "    Tokenize and encode a string using the provided tokenizer.\n",
169
    "    \n",
170
    "    Parameters:\n",
171
    "        string (str): Input string to be tokenized.\n",
172
    "    \n",
173
    "    Returns:\n",
174
    "        Tuple of input_ids and attention_mask.\n",
175
    "    \"\"\"\n",
176
    "    encodings = tokenizer.encode_plus(\n",
177
    "        string,\n",
178
    "        add_special_tokens=True,\n",
179
    "        truncation=True,\n",
180
    "        padding=\"max_length\",\n",
181
    "        max_length=max_length,\n",
182
    "        return_attention_mask=True\n",
183
    "    )\n",
184
    "    input_ids = encodings[\"input_ids\"]\n",
185
    "    attention_mask = encodings[\"attention_mask\"]\n",
186
    "    return input_ids, attention_mask\n",
187
    "\n",
188
    "# Tokenize the 'CANONICAL_SMILES' column and create new columns 'input_ids' and 'attention_mask'\n",
189
    "tqdm.pandas()\n",
190
    "df[[\"input_ids\", \"attention_mask\"]] = df[\"CANONICAL_SMILES\"].progress_apply(lambda x: tokenize(x)).apply(pd.Series)"
191
   ]
192
  },
193
  {
194
   "cell_type": "code",
195
   "execution_count": 5,
196
   "id": "63fade54-27fa-4ff1-af69-ea8d96c4ec1d",
197
   "metadata": {},
198
   "outputs": [
199
    {
200
     "name": "stdout",
201
     "output_type": "stream",
202
     "text": [
203
      "There are 448 molecules in Train df.\n",
204
      "There are 56 molecules in Val df.\n",
205
      "There are 56 molecules in Test df.\n"
206
     ]
207
    }
208
   ],
209
   "source": [
210
    "# Split the dataset into train, validation, and test sets\n",
211
    "train_df, temp_df = train_test_split(df, test_size=0.2, random_state=21)\n",
212
    "val_df, test_df = train_test_split(temp_df, test_size=0.5, random_state=21)\n",
213
    "print(f\"There are {len(train_df)} molecules in Train df.\")\n",
214
    "print(f\"There are {len(val_df)} molecules in Val df.\")\n",
215
    "print(f\"There are {len(test_df)} molecules in Test df.\")"
216
   ]
217
  },
218
  {
219
   "cell_type": "code",
220
   "execution_count": 6,
221
   "id": "a7d9638c-b3fc-4063-8ea8-a1303178466f",
222
   "metadata": {},
223
   "outputs": [],
224
   "source": [
225
    "# Function to convert data to PyTorch tensors\n",
226
    "def get_tensor_data(data):\n",
227
    "    \"\"\"\n",
228
    "    Convert data to PyTorch tensors.\n",
229
    "    \n",
230
    "    Parameters:\n",
231
    "        data (DataFrame): Input data containing 'input_ids', 'attention_mask', and 'pIC50' columns.\n",
232
    "    \n",
233
    "    Returns:\n",
234
    "        TensorDataset containing input_ids, attention_mask, and labels tensors.\n",
235
    "    \"\"\"\n",
236
    "    input_ids_tensor = torch.tensor(data[\"input_ids\"].tolist(), dtype=torch.int32)\n",
237
    "    attention_mask_tensor = torch.tensor(data[\"attention_mask\"].tolist(), dtype=torch.int32)\n",
238
    "    labels_tensor = torch.tensor(data[\"pIC50\"].tolist(), dtype=torch.float32)\n",
239
    "    return TensorDataset(input_ids_tensor, attention_mask_tensor, labels_tensor)\n",
240
    "\n",
241
    "# Create datasets and data loaders\n",
242
    "train_dataset = get_tensor_data(train_df)\n",
243
    "val_dataset = get_tensor_data(val_df)\n",
244
    "test_dataset = get_tensor_data(test_df)\n",
245
    "\n",
246
    "batch_size = 32\n",
247
    "train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
248
    "val_loader = DataLoader(val_dataset, batch_size=batch_size)\n",
249
    "test_loader = DataLoader(test_dataset, batch_size=batch_size)"
250
   ]
251
  },
252
  {
253
   "cell_type": "code",
254
   "execution_count": 7,
255
   "id": "6ebfebf6-b6db-4082-ab9a-70b79884014f",
256
   "metadata": {},
257
   "outputs": [
258
    {
259
     "name": "stderr",
260
     "output_type": "stream",
261
     "text": [
262
      " 10%|████▍                                       | 1/10 [00:04<00:37,  4.12s/it]"
263
     ]
264
    },
265
    {
266
     "name": "stdout",
267
     "output_type": "stream",
268
     "text": [
269
      "epoch 1: Train Loss 13.7115, Val Loss 3.4070\n"
270
     ]
271
    },
272
    {
273
     "name": "stderr",
274
     "output_type": "stream",
275
     "text": [
276
      " 20%|████████▊                                   | 2/10 [00:07<00:29,  3.68s/it]"
277
     ]
278
    },
279
    {
280
     "name": "stdout",
281
     "output_type": "stream",
282
     "text": [
283
      "epoch 2: Train Loss 1.8040, Val Loss 1.3049\n"
284
     ]
285
    },
286
    {
287
     "name": "stderr",
288
     "output_type": "stream",
289
     "text": [
290
      " 30%|█████████████▏                              | 3/10 [00:10<00:24,  3.54s/it]"
291
     ]
292
    },
293
    {
294
     "name": "stdout",
295
     "output_type": "stream",
296
     "text": [
297
      "epoch 3: Train Loss 1.4318, Val Loss 1.2696\n"
298
     ]
299
    },
300
    {
301
     "name": "stderr",
302
     "output_type": "stream",
303
     "text": [
304
      " 40%|█████████████████▌                          | 4/10 [00:14<00:20,  3.48s/it]"
305
     ]
306
    },
307
    {
308
     "name": "stdout",
309
     "output_type": "stream",
310
     "text": [
311
      "epoch 4: Train Loss 1.4239, Val Loss 1.2848\n"
312
     ]
313
    },
314
    {
315
     "name": "stderr",
316
     "output_type": "stream",
317
     "text": [
318
      " 50%|██████████████████████                      | 5/10 [00:17<00:17,  3.44s/it]"
319
     ]
320
    },
321
    {
322
     "name": "stdout",
323
     "output_type": "stream",
324
     "text": [
325
      "epoch 5: Train Loss 1.4157, Val Loss 1.3262\n"
326
     ]
327
    },
328
    {
329
     "name": "stderr",
330
     "output_type": "stream",
331
     "text": [
332
      " 60%|██████████████████████████▍                 | 6/10 [00:21<00:13,  3.42s/it]"
333
     ]
334
    },
335
    {
336
     "name": "stdout",
337
     "output_type": "stream",
338
     "text": [
339
      "epoch 6: Train Loss 1.3806, Val Loss 1.2986\n"
340
     ]
341
    },
342
    {
343
     "name": "stderr",
344
     "output_type": "stream",
345
     "text": [
346
      " 70%|██████████████████████████████▊             | 7/10 [00:24<00:10,  3.44s/it]"
347
     ]
348
    },
349
    {
350
     "name": "stdout",
351
     "output_type": "stream",
352
     "text": [
353
      "epoch 7: Train Loss 1.3577, Val Loss 1.2738\n"
354
     ]
355
    },
356
    {
357
     "name": "stderr",
358
     "output_type": "stream",
359
     "text": [
360
      " 80%|███████████████████████████████████▏        | 8/10 [00:27<00:06,  3.46s/it]"
361
     ]
362
    },
363
    {
364
     "name": "stdout",
365
     "output_type": "stream",
366
     "text": [
367
      "epoch 8: Train Loss 1.3578, Val Loss 1.2921\n"
368
     ]
369
    },
370
    {
371
     "name": "stderr",
372
     "output_type": "stream",
373
     "text": [
374
      " 90%|███████████████████████████████████████▌    | 9/10 [00:31<00:03,  3.47s/it]"
375
     ]
376
    },
377
    {
378
     "name": "stdout",
379
     "output_type": "stream",
380
     "text": [
381
      "epoch 9: Train Loss 1.3547, Val Loss 1.3023\n"
382
     ]
383
    },
384
    {
385
     "name": "stderr",
386
     "output_type": "stream",
387
     "text": [
388
      "100%|███████████████████████████████████████████| 10/10 [00:34<00:00,  3.49s/it]"
389
     ]
390
    },
391
    {
392
     "name": "stdout",
393
     "output_type": "stream",
394
     "text": [
395
      "epoch 10: Train Loss 1.3551, Val Loss 1.3414\n"
396
     ]
397
    },
398
    {
399
     "name": "stderr",
400
     "output_type": "stream",
401
     "text": [
402
      "\n"
403
     ]
404
    }
405
   ],
406
   "source": [
407
    "# Loss criterion and optimizer\n",
408
    "criterion = nn.MSELoss()\n",
409
    "optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)\n",
410
    "device = torch.device(\"mps\")\n",
411
    "model.to(device)\n",
412
    "\n",
413
    "epochs = 10\n",
414
    "torch.manual_seed(12345)\n",
415
    "for epoch in tqdm(range(epochs)):\n",
416
    "    # Training loop\n",
417
    "    model.train()\n",
418
    "    total_train_loss = 0\n",
419
    "    for batch in train_loader:\n",
420
    "        optimizer.zero_grad(set_to_none=True)\n",
421
    "        input_ids, attention_mask, labels = batch\n",
422
    "        input_ids, attention_mask, labels = input_ids.to(device), attention_mask.to(device), labels.to(device)\n",
423
    "        output_dict = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)\n",
424
    "        predictions = output_dict.logits.squeeze(dim=1)\n",
425
    "        loss = criterion(predictions, labels)\n",
426
    "        loss.backward()\n",
427
    "        optimizer.step()\n",
428
    "        total_train_loss += loss.item()\n",
429
    "    avg_train_loss = total_train_loss / len(train_loader)\n",
430
    "\n",
431
    "    # Validation loop\n",
432
    "    model.eval()\n",
433
    "    total_val_loss = 0\n",
434
    "    with torch.no_grad():\n",
435
    "        for batch in val_loader:\n",
436
    "            input_ids, attention_mask, labels = batch\n",
437
    "            input_ids, attention_mask, labels = input_ids.to(device), attention_mask.to(device), labels.to(device)\n",
438
    "            output_dict = model(input_ids, attention_mask=attention_mask, labels=labels)\n",
439
    "            predictions = output_dict.logits.squeeze(dim=1)\n",
440
    "            loss = criterion(predictions, labels)\n",
441
    "            total_val_loss += loss.item()\n",
442
    "    avg_val_loss = total_val_loss / len(val_loader)\n",
443
    "    print(f\"epoch {epoch + 1}: Train Loss {avg_train_loss:.4f}, Val Loss {avg_val_loss:.4f}\")\n"
444
   ]
445
  },
446
  {
447
   "cell_type": "code",
448
   "execution_count": 8,
449
   "id": "e15f9a1f-80de-4e97-bb52-03ce819f9ca4",
450
   "metadata": {},
451
   "outputs": [
452
    {
453
     "name": "stdout",
454
     "output_type": "stream",
455
     "text": [
456
      "Test Loss 1.4417\n"
457
     ]
458
    }
459
   ],
460
   "source": [
461
    "# Testing loop\n",
462
    "total_test_loss = 0\n",
463
    "test_labels = []\n",
464
    "test_predictions = []\n",
465
    "with torch.no_grad():\n",
466
    "    for batch in test_loader:\n",
467
    "        input_ids, attention_mask, labels = batch\n",
468
    "        input_ids, attention_mask, labels = input_ids.to(device), attention_mask.to(device), labels.to(device)\n",
469
    "        output_dict = model(input_ids, attention_mask=attention_mask, labels=labels)\n",
470
    "        predictions = output_dict.logits.squeeze(dim=1)\n",
471
    "        loss = criterion(predictions, labels)\n",
472
    "        total_test_loss += loss.item()\n",
473
    "        test_labels.extend(labels.tolist())\n",
474
    "        test_predictions.extend(predictions.tolist())\n",
475
    "avg_test_loss = total_test_loss / len(test_loader)\n",
476
    "print(f\"Test Loss {avg_test_loss:.4f}\")"
477
   ]
478
  },
479
  {
480
   "cell_type": "code",
481
   "execution_count": 9,
482
   "id": "a5325e19-2edd-4732-8732-e6b679fe7561",
483
   "metadata": {},
484
   "outputs": [
485
    {
486
     "data": {
487
      "image/png": "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",
488
      "text/plain": [
489
       "<Figure size 640x480 with 1 Axes>"
490
      ]
491
     },
492
     "metadata": {},
493
     "output_type": "display_data"
494
    }
495
   ],
496
   "source": [
497
    "import matplotlib.pyplot as plt\n",
498
    "plt.scatter(test_predictions, test_labels)\n",
499
    "plt.plot([4, 8], [4, 8], 'k--')\n",
500
    "plt.xlabel('Predicted')\n",
501
    "plt.ylabel('Actual');"
502
   ]
503
  }
504
 ],
505
 "metadata": {
506
  "kernelspec": {
507
   "display_name": "Python 3 (ipykernel)",
508
   "language": "python",
509
   "name": "python3"
510
  },
511
  "language_info": {
512
   "codemirror_mode": {
513
    "name": "ipython",
514
    "version": 3
515
   },
516
   "file_extension": ".py",
517
   "mimetype": "text/x-python",
518
   "name": "python",
519
   "nbconvert_exporter": "python",
520
   "pygments_lexer": "ipython3",
521
   "version": "3.9.18"
522
  }
523
 },
524
 "nbformat": 4,
525
 "nbformat_minor": 5
526
}