{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":14897,"databundleVersionId":1020216,"sourceType":"competition"}],"dockerImageVersionId":30887,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **1.  Import**","metadata":{}},{"cell_type":"code","source":"!pip install pretrainedmodels\n!pip install iterative-stratification","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T15:01:24.716238Z","iopub.execute_input":"2025-02-15T15:01:24.716499Z","iopub.status.idle":"2025-02-15T15:01:31.524145Z","shell.execute_reply.started":"2025-02-15T15:01:24.716479Z","shell.execute_reply":"2025-02-15T15:01:31.523259Z"},"scrolled":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nimport joblib\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport pretrainedmodels\nfrom iterstrat.ml_stratifiers import MultilabelStratifiedKFold\n\n\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torch\n\nfrom tqdm import tqdm\nfrom tqdm import tqdm_notebook\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T15:01:31.525808Z","iopub.execute_input":"2025-02-15T15:01:31.526198Z","iopub.status.idle":"2025-02-15T15:01:35.271366Z","shell.execute_reply.started":"2025-02-15T15:01:31.526177Z","shell.execute_reply":"2025-02-15T15:01:35.270502Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **2. Revise data**","metadata":{}},{"cell_type":"code","source":"!mkdir /kaggle/working/images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T15:01:35.272799Z","iopub.execute_input":"2025-02-15T15:01:35.273263Z","iopub.status.idle":"2025-02-15T15:01:35.416584Z","shell.execute_reply.started":"2025-02-15T15:01:35.273245Z","shell.execute_reply":"2025-02-15T15:01:35.415525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_dir = '../input/bengaliai-cv19/'\nfiles_train = [f'train_image_data_{fid}.parquet' for fid in range(4)]\n\ndf_train = pd.read_csv(os.path.join(data_dir, 'train.csv'))\ndf_train.head()\ndf_train['id'] = df_train['image_id'].apply(lambda x: int(x.split('_')[1]))\n\nX = df_train[['id', 'grapheme_root', 'vowel_diacritic', 'consonant_diacritic']].values[:, 0]\ny = df_train[['id', 'grapheme_root', 'vowel_diacritic', 'consonant_diacritic']].values[:, 1:]\n\nmskf = MultilabelStratifiedKFold(n_splits=6, random_state=42, shuffle=True)\n\ndf_train['fold'] = -1\n\nfor i, (trn_idx, vid_idx) in enumerate(mskf.split(X, y)):\n    df_train.loc[vid_idx, 'fold'] = i\n\ndf_train.to_csv(os.path.join('/kaggle/working/', 'df_folds.csv'), index=False)\n\nfor fname in files_train:\n    F = os.path.join(data_dir, fname)\n    df_train = pd.read_parquet(F)\n    img_ids = df_train['image_id'].values\n    img_array = df_train.iloc[:, 1:].values\n    for idx in tqdm(range(len(df_train))):\n        img_id = img_ids[idx]\n        img = img_array[idx]\n        joblib.dump(img, os.path.join('/kaggle/working/images/', f'{img_id}.pkl'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T15:01:35.41817Z","iopub.execute_input":"2025-02-15T15:01:35.418478Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **3. Define Dataset, DataLoader**","metadata":{}},{"cell_type":"code","source":"class BengaliDataset(Dataset):\n    def __init__(self, csv, img_height, img_width, transform):\n        self.csv = csv.reset_index()\n        self.img_ids = csv['image_id'].values\n        self.img_height = img_height\n        self.img_width = img_width\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.csv)\n\n    def __getitem__(self, index):\n        img_id = self.img_ids[index]\n        img = joblib.load(f'/kaggle/working/images/{img_id}.pkl').astype(np.uint8)\n        img = img.reshape(HEIGHT, WIDTH)\n        img = 255 - img\n        img = img[:, :, np.newaxis]\n        img = np.repeat(img, 3, 2)\n        if self.transform is not None:\n            img = self.transform(image=img)['image']\n\n        label1 = self.csv.iloc[index].grapheme_root\n        label2 = self.csv.iloc[index].vowel_diacritic\n        label3 = self.csv.iloc[index].consonant_diacritic\n\n        return img, np.array([label1, label2, label3])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_augmentation = A.Compose(\n    [\n        A.Rotate(20),\n        A.Normalize(mean=0.5, std=1),\n        ToTensorV2()\n    ]\n)\n\nvalid_augmentation = A.Compose(\n    [\n        A.Normalize(mean=0.5, std=1),\n        ToTensorV2()\n    ]\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trn_dataset = BengaliDataset(csv=df_train.loc[trn_idx][:10], img_height=137, img_width=236, transform=train_augmentation)\nvld_dataset = BengaliDataset(csv=df_train.loc[vld_idx][:10], img_height=137, img_width=236, transform=valid_augmentation)\n\ntrn_loader = DataLoader(trn_dataset, shuffle=True, num_workers=4, batch_size=256)\nvld_loader = DataLoader(vld_dataset, shuffle=True, num_workers=4, batch_size=256)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **4. Import pretrained model**","metadata":{}},{"cell_type":"code","source":"model_name = 'resnet34'\nmodel = pretrainedmodels.__dict__[model_name](pretrained='imagenet')\nin_features = model.last_linear.in_features\nmodel.last_linear = nn.Linear(in_features, 186)\n\nmodel.cuda()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\nloss_fn = nn.CrossEntropyLoss()\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', verbose=True, patience=7, factor=0.5)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **5. Train model**","metadata":{}},{"cell_type":"code","source":"best_score = -1\nfor epoch in range(1, 20):\n    train_loss = []\n    model.train()\n    \n    for inputs, targets in trn_loader:\n        inputs = inputs.cuda()\n        targets = targets.cuda()\n        logits = model(inputs)\n        \n        grapheme = logits[:, :168]\n        vowel = logits[:, 168:179]\n        cons = logits[:, 179:]\n        \n        loss = loss_fn(grapheme, targets[:, 0]) + loss_fn(vowel, targets[:, 1]) + loss_fn(cons, targets[:, 2])\n        \n        loss.backward()\n        \n        optimizer.step()\n        optimizer.zero_grad()\n        train_loss.append(loss.item())\n    \n    val_loss = []\n    val_true = []\n    val_pred = []\n    \n    model.eval()\n    \n    with torch.no_grad():\n        for inputs, targets in vld_loader:\n            inputs = inputs.cuda()\n            targets = targets.cuda()\n            \n            logits = model(inputs)\n            \n            grapheme = logits[:, :168]\n            vowel = logits[:, 168:179]\n            cons = logits[:, 179:]\n            \n            loss = loss_fn(grapheme, targets[:, 0]) + loss_fn(vowel, targets[:, 1]) + loss_fn(cons, targets[:, 2])\n            val_loss.append(loss.item())\n    \n            grapheme = grapheme.cpu().argmax(dim=1).data.numpy()\n            vowel = vowel.cpu().argmax(dim=1).data.numpy()\n            cons = cons.cpu().argmax(dim=1).data.numpy()\n            \n            val_true.append(targets.cpu().numpy())\n            val_pred.append(np.stack([grapheme, vowel, cons], axis=1))\n    \n    val_true = np.concatenate(val_true).shape\n    val_pred = np.concatenate(val_pred).shape\n    \n    val_loss = np.mean(val_loss)\n    train_loss = np.mean(train_loss)\n\n    score_g = recall_score(val_true[:, 0], val_pred[:, 0], average='macro')\n    score_v = recall_score(val_true[:, 1], val_pred[:, 1], average='macro')\n    score_c = recall_score(val_true[:, 2], val_pred[:, 2], average='macro')\n\n    final_score = np.average([score_g, score_v, score_c], weights=[2, 1, 1])\n\n    if final_score > best_score:\n        best_score = final_score\n\n        state_dict = model.cpu().state_dict()\n        model = model.cuda()\n        torch.save(state_dict, os.path.join('/kaggle/working/', \"model.pt\"))\n\n    print(f'train)loss: {train_loss:.5f}; val_loss: {val_loss:.5f}; score: {final_score:.5f}')\n    print(f'score_g: {score_g:.5f}; score_v: {score_v:.5f}; score_c: {score_c:.5f}')","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}