{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🤗  Hugging Face Ecosystem: transformers + datasets¶ 🤗\n# Swin finetuning + balanced accuracy\n","metadata":{}},{"cell_type":"markdown","source":"# ⚙️ Env setup","metadata":{}},{"cell_type":"code","source":"!pip install -q evaluate","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-10-21T07:04:00.231348Z","iopub.execute_input":"2023-10-21T07:04:00.231643Z","iopub.status.idle":"2023-10-21T07:04:13.324544Z","shell.execute_reply.started":"2023-10-21T07:04:00.231617Z","shell.execute_reply":"2023-10-21T07:04:13.323392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport shutil\n\nimport numpy as np\nimport pandas as pd\nimport torch\n\nfrom datasets import load_dataset\nfrom torchvision.transforms import Compose, RandomResizedCrop, GaussianBlur, RandomAdjustSharpness, RandomEqualize, ToTensor\n\nfrom transformers import TrainingArguments, Trainer\nfrom transformers import Swinv2ForImageClassification\nfrom transformers import AutoImageProcessor, AutoModelForImageClassification\n\nimport evaluate","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-10-21T07:04:27.876907Z","iopub.execute_input":"2023-10-21T07:04:27.8772Z","iopub.status.idle":"2023-10-21T07:04:27.889184Z","shell.execute_reply.started":"2023-10-21T07:04:27.877176Z","shell.execute_reply":"2023-10-21T07:04:27.888471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🗂️ Dataset preparation\n","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/UBC-OCEAN/train.csv\")\ntest_df = pd.read_csv(\"/kaggle/input/UBC-OCEAN/test.csv\")\n\nSOURCE_DIRS = [\"/kaggle/input/UBC-OCEAN/train_thumbnails/\", \"/kaggle/input/UBC-OCEAN/test_thumbnails/\"]\nTARGET_DIR = \"/kaggle/working/dataset\"","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:04:27.8902Z","iopub.execute_input":"2023-10-21T07:04:27.890431Z","iopub.status.idle":"2023-10-21T07:04:27.912669Z","shell.execute_reply.started":"2023-10-21T07:04:27.890411Z","shell.execute_reply":"2023-10-21T07:04:27.911949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:04:27.914422Z","iopub.execute_input":"2023-10-21T07:04:27.914673Z","iopub.status.idle":"2023-10-21T07:04:27.938968Z","shell.execute_reply.started":"2023-10-21T07:04:27.914651Z","shell.execute_reply":"2023-10-21T07:04:27.938103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def organize_images_by_label(df: pd.DataFrame, source_dir: str, target_dir: str) -> None:\n    for _, row in df.iterrows():\n        image_id = row[\"image_id\"]\n        label = row[\"label\"]\n\n        label_dir = os.path.join(target_dir, label)\n        os.makedirs(label_dir, exist_ok=True)\n\n        source_path = os.path.join(source_dir, f\"{image_id}_thumbnail.png\")\n        target_path = os.path.join(label_dir, f\"{image_id}_thumbnail.png\")\n\n        try:\n            shutil.copy(source_path, target_path)\n        except FileNotFoundError:\n            continue\n\n\ntrain_dir = f\"{TARGET_DIR}/train\"\norganize_images_by_label(train_df, SOURCE_DIRS[0], train_dir)\nos.makedirs(os.path.join(train_dir, \"Other\"), exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:04:27.939965Z","iopub.execute_input":"2023-10-21T07:04:27.940289Z","iopub.status.idle":"2023-10-21T07:05:18.907403Z","shell.execute_reply.started":"2023-10-21T07:04:27.940259Z","shell.execute_reply":"2023-10-21T07:05:18.906324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset = load_dataset(\"imagefolder\", data_dir=\"/kaggle/working/dataset\", split=\"train\")\ndataset = dataset.train_test_split(test_size=0.3)\ndataset","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:10:34.626979Z","iopub.execute_input":"2023-10-21T07:10:34.627821Z","iopub.status.idle":"2023-10-21T07:10:35.714882Z","shell.execute_reply.started":"2023-10-21T07:10:34.627784Z","shell.execute_reply":"2023-10-21T07:10:35.714047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset[\"train\"].features['label'].names.append('Other')\ndataset[\"train\"].features['label']","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:10:35.716736Z","iopub.execute_input":"2023-10-21T07:10:35.717468Z","iopub.status.idle":"2023-10-21T07:10:35.723298Z","shell.execute_reply.started":"2023-10-21T07:10:35.717435Z","shell.execute_reply":"2023-10-21T07:10:35.722431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = dataset[\"train\"].features[\"label\"].names\nlabel2id, id2label = dict(), dict()\n\nfor i, label in enumerate(labels):\n    label2id[label] = i\n    id2label[i] = label\n    \nid2label","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:10:35.724433Z","iopub.execute_input":"2023-10-21T07:10:35.725355Z","iopub.status.idle":"2023-10-21T07:10:35.737041Z","shell.execute_reply.started":"2023-10-21T07:10:35.725322Z","shell.execute_reply":"2023-10-21T07:10:35.736226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CHECKPOINT = \"microsoft/swinv2-tiny-patch4-window8-256\"\n\nimage_processor = AutoImageProcessor.from_pretrained(CHECKPOINT)\n\nSIZE = (\n    image_processor.size[\"shortest_edge\"]\n    if \"shortest_edge\" in image_processor.size\n    else (image_processor.size[\"height\"], image_processor.size[\"width\"])\n)\n\n_transforms = Compose([\n    RandomResizedCrop(size=SIZE, antialias=True),\n    GaussianBlur(kernel_size=(1, 5)),\n    RandomAdjustSharpness(sharpness_factor=2),\n    RandomEqualize(),\n    ToTensor()\n])","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:23:35.469531Z","iopub.execute_input":"2023-10-21T07:23:35.469919Z","iopub.status.idle":"2023-10-21T07:23:35.939468Z","shell.execute_reply.started":"2023-10-21T07:23:35.469884Z","shell.execute_reply":"2023-10-21T07:23:35.938537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def transforms(examples):\n    examples[\"pixel_values\"] = [_transforms(img.convert(\"RGB\")) for img in examples[\"image\"]]\n    del examples[\"image\"]\n    return examples\n\n\ndataset = dataset.with_transform(transforms)","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:23:41.768652Z","iopub.execute_input":"2023-10-21T07:23:41.76905Z","iopub.status.idle":"2023-10-21T07:23:41.786063Z","shell.execute_reply.started":"2023-10-21T07:23:41.769018Z","shell.execute_reply":"2023-10-21T07:23:41.78514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset","metadata":{"execution":{"iopub.status.busy":"2023-10-21T08:16:52.141527Z","iopub.execute_input":"2023-10-21T08:16:52.141889Z","iopub.status.idle":"2023-10-21T08:16:52.147936Z","shell.execute_reply.started":"2023-10-21T08:16:52.141862Z","shell.execute_reply":"2023-10-21T08:16:52.147073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📐 Metrics definition","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import balanced_accuracy_score\n\n\ndef compute_metrics(pred):\n    labels = pred.label_ids\n    preds = pred.predictions.argmax(-1)\n    return {\"balanced_accuracy\": balanced_accuracy_score(labels, preds)}","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:23:48.086357Z","iopub.execute_input":"2023-10-21T07:23:48.086701Z","iopub.status.idle":"2023-10-21T07:23:48.091755Z","shell.execute_reply.started":"2023-10-21T07:23:48.086676Z","shell.execute_reply":"2023-10-21T07:23:48.090815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🏋 Model definition and training¶\n","metadata":{}},{"cell_type":"code","source":"def collate_fn(examples):\n    pixel_values = torch.stack([example[\"pixel_values\"] for example in examples])\n    labels = torch.tensor([example[\"label\"] for example in examples])\n    return {\"pixel_values\": pixel_values, \"labels\": labels}","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:23:50.115733Z","iopub.execute_input":"2023-10-21T07:23:50.116476Z","iopub.status.idle":"2023-10-21T07:23:50.122083Z","shell.execute_reply.started":"2023-10-21T07:23:50.11644Z","shell.execute_reply":"2023-10-21T07:23:50.120891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = Swinv2ForImageClassification.from_pretrained(\n    CHECKPOINT,\n    num_labels=len(labels),\n    id2label=id2label,\n    label2id=label2id,\n    ignore_mismatched_sizes=True,\n)\n\nmodel.to(\"cuda\")","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:23:50.779152Z","iopub.execute_input":"2023-10-21T07:23:50.78Z","iopub.status.idle":"2023-10-21T07:24:10.663815Z","shell.execute_reply.started":"2023-10-21T07:23:50.779971Z","shell.execute_reply":"2023-10-21T07:24:10.662885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.num_parameters()","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:24:10.665692Z","iopub.execute_input":"2023-10-21T07:24:10.666472Z","iopub.status.idle":"2023-10-21T07:24:10.675278Z","shell.execute_reply.started":"2023-10-21T07:24:10.666437Z","shell.execute_reply":"2023-10-21T07:24:10.674164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"STRATEGY = \"epoch\"\nOUTPUT_DIR = \"swinv2\"\n\ntraining_args = TrainingArguments(\n    output_dir=OUTPUT_DIR,\n    evaluation_strategy=STRATEGY,\n    save_strategy=STRATEGY,\n    logging_steps=10,\n    \n    remove_unused_columns=False,\n\n    learning_rate=1e-6,\n    per_device_train_batch_size=8,\n    gradient_accumulation_steps=4,\n    per_device_eval_batch_size=8,\n    num_train_epochs=25,\n    warmup_ratio=0.1,\n    \n    metric_for_best_model=\"balanced_accuracy\",\n    load_best_model_at_end=True,\n    \n    push_to_hub=False,\n    report_to=\"none\"\n)\n\ntrainer = Trainer(\n    model=model,\n    args=training_args,\n    data_collator=collate_fn,\n    train_dataset=dataset[\"train\"],\n    eval_dataset=dataset[\"test\"],\n    tokenizer=image_processor,\n    compute_metrics=compute_metrics,\n)\n\ntrainer.train()\n#trainer.train(resume_from_checkpoint=True)","metadata":{"execution":{"iopub.status.busy":"2023-10-21T07:24:35.562027Z","iopub.execute_input":"2023-10-21T07:24:35.562443Z","iopub.status.idle":"2023-10-21T08:06:19.019943Z","shell.execute_reply.started":"2023-10-21T07:24:35.562411Z","shell.execute_reply":"2023-10-21T08:06:19.018996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_dir = f\"model/{OUTPUT_DIR}\"\ntrainer.save_model(save_dir)","metadata":{"execution":{"iopub.status.busy":"2023-10-21T08:23:40.062394Z","iopub.execute_input":"2023-10-21T08:23:40.063231Z","iopub.status.idle":"2023-10-21T08:23:40.313147Z","shell.execute_reply.started":"2023-10-21T08:23:40.063188Z","shell.execute_reply":"2023-10-21T08:23:40.311693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔮 Prediction","metadata":{}},{"cell_type":"code","source":"test_df","metadata":{"execution":{"iopub.status.busy":"2023-10-21T08:23:44.734676Z","iopub.execute_input":"2023-10-21T08:23:44.735573Z","iopub.status.idle":"2023-10-21T08:23:44.745338Z","shell.execute_reply.started":"2023-10-21T08:23:44.73553Z","shell.execute_reply":"2023-10-21T08:23:44.744186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset = load_dataset(\"imagefolder\", data_dir=SOURCE_DIRS[1], split=\"train\")\nimage = test_dataset[\"image\"][0]\n\nCHECKPOINT_DIR = save_dir\n\nDEVICE = \"cpu\"\nimage_processor = AutoImageProcessor.from_pretrained(CHECKPOINT_DIR)\n\ninputs = image_processor(image, return_tensors=\"pt\")\ninputs = inputs.to(DEVICE)\n\nmodel = AutoModelForImageClassification.from_pretrained(CHECKPOINT_DIR)\nmodel = model.to(DEVICE)\n\nwith torch.no_grad():\n    logits = model(**inputs).logits\n    \npredicted_label = logits.argmax(-1).item()\npredicted_label_name = model.config.id2label[predicted_label]\npredicted_label_name","metadata":{"execution":{"iopub.status.busy":"2023-10-21T08:23:45.697198Z","iopub.execute_input":"2023-10-21T08:23:45.697862Z","iopub.status.idle":"2023-10-21T08:23:47.406943Z","shell.execute_reply.started":"2023-10-21T08:23:45.697829Z","shell.execute_reply":"2023-10-21T08:23:47.405978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import plotly.express as px\nimport plotly.io as pio\npio.renderers.default = 'notebook'\n\nimage_array = np.array(image)\n\nfig = px.imshow(image_array)\n\nfig.update_layout(\n    title=f\"Predicted label: {predicted_label_name}\",\n    xaxis_title=\"Width\",\n    yaxis_title=\"Height\"\n)\n\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2023-10-21T08:23:49.247909Z","iopub.execute_input":"2023-10-21T08:23:49.248288Z","iopub.status.idle":"2023-10-21T08:23:52.321663Z","shell.execute_reply.started":"2023-10-21T08:23:49.248257Z","shell.execute_reply":"2023-10-21T08:23:52.320566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}