{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JAeWcsvLF2_6"
   },
   "source": [
    "## Introduction\n",
    "\n",
    "In this notebook, we will learn how to use [LoRA](https://huggingface.co/papers/2106.09685) from 🤗 PEFT to fine-tune a SegFormer model variant for semantic segmentation by ONLY using **14%** of the original trainable parameters of the model. \n",
    "\n",
    "LoRA adds low-rank \"update matrices\" to certain blocks in the underlying model (in this case the attention blocks) and ONLY trains those matrices during fine-tuning. During inference, these update matrices are _merged_ with the original model parameters. For more details, check out the [original LoRA paper](https://huggingface.co/papers/2106.09685). \n",
    "\n",
    "Let's get started by installing the dependencies. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "lveGHtBcGNyc"
   },
   "source": [
    "## Install dependencies\n",
    "\n",
    "Here we're installing `peft` from source to ensure we have access to all the bleeding edge features of `peft`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "lbYTKXv4ZTwg",
    "outputId": "5a033ebd-6bbd-4bf4-802c-a1bac6a48a07"
   },
   "outputs": [],
   "source": [
    "!pip install transformers accelerate evaluate datasets==3.6.0 git+https://github.com/huggingface/peft -q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "B0fmCvTsGPah"
   },
   "source": [
    "## Authentication\n",
    "\n",
    "We will share our fine-tuned model at the end of training. So, to do that we just authenticate using our 🤗 token. This token is available from [here](https://huggingface.co/settings/tokens). If you don't have a 🤗 account already, we highly encourage you to do so; it's free!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 331,
     "referenced_widgets": [
      "f2a722f371904cce80dc1c087b153ad6",
      "6c88a55a635b4c9f946a1aa838d69f20",
      "6c6d19cd893e4d82bae9972fa10c6d74",
      "fc48ee28c2e44f1daa03149c8004c314",
      "cb4053f102fc4207a1c9513f81ad6415",
      "0dcc5a2866a349e0843673bef499dc66",
      "b7431f99d93b4e9b8c8177ac4a7b4070",
      "14ac809ba0bc4cd5bcd51f83105947b0",
      "e7393e78f41b496495982490b72ef2a3",
      "42a7b8268d8945b5bbe9d3f20bc8840c",
      "554b55f29a5e4d5a81608d912d3635e8",
      "3f69c7b15e5e48039777e4b6b1a51f53",
      "5bcfe3da0ffb41ccbb9404ac35ae8945",
      "21bf954f54db41e6ba78f76195721614",
      "f83dd354396e4aa3acd214a6fd98efb2",
      "24fde588dc1a49a397e379cda320ed71",
      "9746875e74b845daab06619393b4d46b"
     ]
    },
    "id": "OYhwMOj5ZTwm",
    "outputId": "ff2d4cc4-4363-4093-8bdc-763761cbe3ef"
   },
   "outputs": [],
   "source": [
    "from huggingface_hub import notebook_login\n",
    "\n",
    "notebook_login()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "B9Cu7j_QGVbH"
   },
   "source": [
    "## Load a dataset\n",
    "\n",
    "We're only loading the first 150 instances from the training set of the [SceneParse150 dataset](https://huggingface.co/datasets/scene_parse_150) to keep this example runtime short. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "sGJWDwtHZTwn",
    "outputId": "260c874e-1844-42ba-9dc2-0f727e2930cc"
   },
   "outputs": [],
   "source": [
    "from datasets import load_dataset\n",
    "\n",
    "ds = load_dataset(\"scene_parse_150\", split=\"train[:150]\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "RpSPx8EHGeLM"
   },
   "source": [
    "## Prepare train and test splits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "id": "ydWKIqCUZTwo"
   },
   "outputs": [],
   "source": [
    "ds = ds.train_test_split(test_size=0.1)\n",
    "train_ds = ds[\"train\"]\n",
    "test_ds = ds[\"test\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yHtqAQ2WGhlR"
   },
   "source": [
    "## Prepare label mappers\n",
    "\n",
    "We create two dictionaries:\n",
    "\n",
    "* `label2id`: maps the semantic classes of the dataset to integer ids.\n",
    "* `id2label`: `label2id` reversed. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Hu8Y4dEIZTwq",
    "outputId": "eba72235-c1a7-4c95-8c89-5ef5588d6581"
   },
   "outputs": [],
   "source": [
    "import json\n",
    "from huggingface_hub import hf_hub_download\n",
    "\n",
    "repo_id = \"huggingface/label-files\"\n",
    "filename = \"ade20k-id2label.json\"\n",
    "id2label = json.load(open(hf_hub_download(repo_id=repo_id, filename=filename, repo_type=\"dataset\"), \"r\"))\n",
    "id2label = {int(k): v for k, v in id2label.items()}\n",
    "label2id = {v: k for k, v in id2label.items()}\n",
    "num_labels = len(id2label)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5V8nhdt0HBsk"
   },
   "source": [
    "## Prepare datasets for training and evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "fNi_TKYpZTwq",
    "outputId": "a28647b4-0deb-49cc-a1b8-c4a2ab99bb4d"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.11/dist-packages/transformers/image_processing_base.py:412: UserWarning: The following named arguments are not valid for `SegformerImageProcessor.__init__` and were ignored: 'reduce_labels'\n",
      "  image_processor = cls(**image_processor_dict)\n"
     ]
    }
   ],
   "source": [
    "from transformers import AutoImageProcessor\n",
    "\n",
    "checkpoint = \"nvidia/mit-b0\"\n",
    "image_processor = AutoImageProcessor.from_pretrained(checkpoint, do_reduce_labels=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "id": "JAjiYzklZTwr"
   },
   "outputs": [],
   "source": [
    "from torchvision.transforms import ColorJitter\n",
    "\n",
    "jitter = ColorJitter(brightness=0.25, contrast=0.25, saturation=0.25, hue=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "id": "_HaS12U0ZTwr"
   },
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def handle_grayscale_image(image):\n",
    "    np_image = np.array(image)\n",
    "    if np_image.ndim == 2:\n",
    "        tiled_image = np.tile(np.expand_dims(np_image, -1), 3)\n",
    "        return Image.fromarray(tiled_image)\n",
    "    else:\n",
    "        return Image.fromarray(np_image)\n",
    "\n",
    "\n",
    "def train_transforms(example_batch):\n",
    "    images = [jitter(handle_grayscale_image(x)) for x in example_batch[\"image\"]]\n",
    "    labels = [x for x in example_batch[\"annotation\"]]\n",
    "    inputs = image_processor(images, labels)\n",
    "    return inputs\n",
    "\n",
    "\n",
    "def val_transforms(example_batch):\n",
    "    images = [handle_grayscale_image(x) for x in example_batch[\"image\"]]\n",
    "    labels = [x for x in example_batch[\"annotation\"]]\n",
    "    inputs = image_processor(images, labels)\n",
    "    return inputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "id": "Qyjsvup2ZTws"
   },
   "outputs": [],
   "source": [
    "train_ds.set_transform(train_transforms)\n",
    "test_ds.set_transform(val_transforms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Lu8RjicxHJiO"
   },
   "source": [
    "## Evaluation function\n",
    "\n",
    "Including a metric during training is often helpful for evaluating your model’s performance. You can quickly load a evaluation method with the [🤗 Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [mean Intersection over Union (IoU)](https://huggingface.co/spaces/evaluate-metric/accuracy) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "id": "TMSnlebfZTwt"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Downloading builder script: 12.9kB [00:00, 34.2MB/s]\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "import evaluate\n",
    "\n",
    "metric = evaluate.load(\"mean_iou\")\n",
    "\n",
    "\n",
    "def compute_metrics(eval_pred):\n",
    "    with torch.no_grad():\n",
    "        logits, labels = eval_pred\n",
    "        logits_tensor = torch.from_numpy(logits)\n",
    "        # scale the logits to the size of the label\n",
    "        logits_tensor = nn.functional.interpolate(\n",
    "            logits_tensor,\n",
    "            size=labels.shape[-2:],\n",
    "            mode=\"bilinear\",\n",
    "            align_corners=False,\n",
    "        ).argmax(dim=1)\n",
    "\n",
    "        pred_labels = logits_tensor.detach().cpu().numpy()\n",
    "        # currently using _compute instead of compute\n",
    "        # see this issue for more info: https://github.com/huggingface/evaluate/pull/328#issuecomment-1286866576\n",
    "        metrics = metric._compute(\n",
    "            predictions=pred_labels,\n",
    "            references=labels,\n",
    "            num_labels=len(id2label),\n",
    "            ignore_index=0,\n",
    "            reduce_labels=image_processor.do_reduce_labels,\n",
    "        )\n",
    "\n",
    "        # add per category metrics as individual key-value pairs\n",
    "        per_category_accuracy = metrics.pop(\"per_category_accuracy\").tolist()\n",
    "        per_category_iou = metrics.pop(\"per_category_iou\").tolist()\n",
    "\n",
    "        metrics.update({f\"accuracy_{id2label[i]}\": v for i, v in enumerate(per_category_accuracy)})\n",
    "        metrics.update({f\"iou_{id2label[i]}\": v for i, v in enumerate(per_category_iou)})\n",
    "\n",
    "        return metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "r304cnpxHxp5"
   },
   "source": [
    "## Load a base model\n",
    "\n",
    "For this example, we use the [SegFormer B0 variant](https://huggingface.co/nvidia/mit-b0). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "id": "Krvppe44a_7y"
   },
   "outputs": [],
   "source": [
    "def print_trainable_parameters(model):\n",
    "    \"\"\"\n",
    "    Prints the number of trainable parameters in the model.\n",
    "    \"\"\"\n",
    "    trainable_params = 0\n",
    "    all_param = 0\n",
    "    for _, param in model.named_parameters():\n",
    "        all_param += param.numel()\n",
    "        if param.requires_grad:\n",
    "            trainable_params += param.numel()\n",
    "    print(\n",
    "        f\"trainable params: {trainable_params} || all params: {all_param} || trainable%: {100 * trainable_params / all_param:.2f}\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "q_Wwl_ewID9I"
   },
   "source": [
    "We pass the `label2id` and `id2label` dictionaries to let the `AutoModelForSemanticSegmentation` class know that we're interested in a custom base model where the decoder head should be randomly initialized w.r.t our custom dataset. Note, however, that the rest of the model parameters are pre-trained and will be fine-tuned in a regular transfer learning setup.\n",
    "\n",
    "We also notice that the 100% parameters in the `model` are trainable. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "kcdLdvIlZTwt",
    "outputId": "a6b71dce-905e-4389-dcf6-46b43e769fcc"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of SegformerForSemanticSegmentation were not initialized from the model checkpoint at nvidia/mit-b0 and are newly initialized: ['decode_head.batch_norm.bias', 'decode_head.batch_norm.num_batches_tracked', 'decode_head.batch_norm.running_mean', 'decode_head.batch_norm.running_var', 'decode_head.batch_norm.weight', 'decode_head.classifier.bias', 'decode_head.classifier.weight', 'decode_head.linear_c.0.proj.bias', 'decode_head.linear_c.0.proj.weight', 'decode_head.linear_c.1.proj.bias', 'decode_head.linear_c.1.proj.weight', 'decode_head.linear_c.2.proj.bias', 'decode_head.linear_c.2.proj.weight', 'decode_head.linear_c.3.proj.bias', 'decode_head.linear_c.3.proj.weight', 'decode_head.linear_fuse.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trainable params: 3752694 || all params: 3752694 || trainable%: 100.00\n"
     ]
    }
   ],
   "source": [
    "from transformers import AutoModelForSemanticSegmentation, TrainingArguments, Trainer\n",
    "\n",
    "model = AutoModelForSemanticSegmentation.from_pretrained(\n",
    "    checkpoint, id2label=id2label, label2id=label2id, ignore_mismatched_sizes=True\n",
    ")\n",
    "print_trainable_parameters(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4yhyYVTCInF0"
   },
   "source": [
    "## Wrap `model` as a `PeftModel` for LoRA training\n",
    "\n",
    "This involves two steps:\n",
    "\n",
    "* Defining a config with `LoraConfig`\n",
    "* Wrapping the original `model` with `get_peft_model()` with the config defined in the step above. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "YPg4W5eFB__n",
    "outputId": "9995eb44-1c30-43e7-cc4e-691ecb1b1878"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trainable params: 566422 || all params: 4317068 || trainable%: 13.12\n"
     ]
    }
   ],
   "source": [
    "from peft import LoraConfig, get_peft_model\n",
    "\n",
    "config = LoraConfig(\n",
    "    r=32,\n",
    "    lora_alpha=32,\n",
    "    target_modules=[\"query\", \"value\"],\n",
    "    lora_dropout=0.1,\n",
    "    bias=\"lora_only\",\n",
    "    modules_to_save=[\"decode_head\"],\n",
    ")\n",
    "lora_model = get_peft_model(model, config)\n",
    "print_trainable_parameters(lora_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4M3wYekOI95X"
   },
   "source": [
    " Let's unpack what's going on here. \n",
    "\n",
    "In order for LoRA to take effect, we need to specify the target modules to `LoraConfig` so that `PeftModel` knows which modules inside our model needs to be amended with LoRA matrices. In this case, we're only interested in targetting the query and value matrices of the attention blocks of the base model. Since the parameters corresponding to these matrices are \"named\" with `query` and `value` respectively, we specify them accordingly in the `target_modules` argument of `LoraConfig`. \n",
    "\n",
    "We also specify `modules_to_save`. After we wrap our base model `model` with `PeftModel` along with the `config`, we get a new model where only the LoRA parameters are trainable (so-called \"update matrices\") while the pre-trained parameters are kept frozen. These include the parameters of the randomly initialized classifier parameters too. This is NOT we want when fine-tuning the base model on our custom dataset. To ensure that the classifier parameters are also trained, we specify `modules_to_save`. This also ensures that these modules are serialized alongside the LoRA trainable parameters when using utilities like `save_pretrained()` and `push_to_hub()`.  \n",
    "\n",
    "Regarding the other parameters:\n",
    "\n",
    "* `r`: The dimension used by the LoRA update matrices.\n",
    "* `alpha`: Scaling factor.\n",
    "* `bias`: Specifying if the `bias` parameters should be trained. `lora_only` denotes only the LoRA `bias` parameters will be trained. \n",
    "\n",
    "`r` and `alpha` together control the total number of final trainable parameters when using LoRA giving us the flexbility to balance a trade-off between end performance and compute efficiency.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XTF68xfjJEci"
   },
   "source": [
    "We can also how many parameters we're actually training. Since we're interested in performing **parameter-efficient fine-tuning**, we should expect to notice a less number of trainable parameters from the `lora_model` in comparison to the original `model` which is indeed the case here. \n",
    "\n",
    "For sanity, let's also manually verify the modules that are actually trainable in `lora_model`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "PUe1Gzvd1PEP",
    "outputId": "7b8ba17f-01fd-4ab4-d703-9a0c01cff31b"
   },
   "outputs": [],
   "source": [
    "for name, param in lora_model.named_parameters():\n",
    "    if param.requires_grad:\n",
    "        print(name, param.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can confirm that only the LoRA parameters appended to the attention blocks and the `decode_head` parameters are trainable."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rX75AyI7JYVC"
   },
   "source": [
    "## Train!\n",
    "\n",
    "This is a two-step process: \n",
    "\n",
    "1. Define your training hyperparameters in [TrainingArguments](https://huggingface.co/docs/transformers/v4.26.0/en/main_classes/trainer#transformers.TrainingArguments). It is important you don’t remove unused columns because this’ll drop the image column. Without the image column, you can’t create `pixel_values`. Set `remove_unused_columns=False` to prevent this behavior! The only other required parameter is output_dir which specifies where to save your model. At the end of each epoch, the `Trainer` will evaluate the IoU metric and save the training checkpoint.\n",
    "2. Pass the training arguments to [Trainer](https://huggingface.co/docs/transformers/v4.26.0/en/main_classes/trainer#transformers.Trainer) along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.\n",
    "3. Call `train()` to finetune your model.\n",
    "\n",
    "\n",
    "**Note** that This example is meant to walk you through the workflow when using PEFT for semantic segmentation. We didn't perform extensive hyperparameter tuning to achieve optimal results. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "K6HVcNkDZTwu",
    "outputId": "1b28a072-0e16-4b1a-ec32-d78e93630ef3"
   },
   "outputs": [],
   "source": [
    "model_name = checkpoint.split(\"/\")[-1]\n",
    "\n",
    "training_args = TrainingArguments(\n",
    "    output_dir=f\"{model_name}-scene-parse-150-lora\",\n",
    "    learning_rate=5e-4,\n",
    "    num_train_epochs=50,\n",
    "    per_device_train_batch_size=4,\n",
    "    per_device_eval_batch_size=2,\n",
    "    save_total_limit=3,\n",
    "    eval_strategy=\"epoch\",\n",
    "    save_strategy=\"epoch\",\n",
    "    logging_steps=5,\n",
    "    remove_unused_columns=False,\n",
    "    push_to_hub=True,\n",
    "    label_names=[\"labels\"],\n",
    ")\n",
    "\n",
    "trainer = Trainer(\n",
    "    model=lora_model,\n",
    "    args=training_args,\n",
    "    train_dataset=train_ds,\n",
    "    eval_dataset=test_ds,\n",
    "    compute_metrics=compute_metrics,\n",
    ")\n",
    "\n",
    "trainer.train()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dacaBLE6KLdu"
   },
   "source": [
    "## Saving the model and inference \n",
    "\n",
    "Here we use the `save_pretrained()` method of the `lora_model` to save the *LoRA-only parameters* locally. However, you can also use thr `push_to_hub()` method to upload these parameters directly to the Hugging Face Hub (as shown [here](https://colab.research.google.com/github/huggingface/peft/blob/main/examples/image_classification/image_classification_peft_lora.ipynb)). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "id": "pvkLkrQo-6l6"
   },
   "outputs": [],
   "source": [
    "model_id = \"segformer-scene-parse-150-lora\"\n",
    "lora_model.save_pretrained(model_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Ur8n41kBK4uj"
   },
   "source": [
    "We can see that the LoRA-only parameters are just **2.2 MB in size**! This greatly improves the portability when using very large models. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "grzLeOT-__ht",
    "outputId": "1ce26a27-2f38-43f3-9454-8ba11f2cfc59"
   },
   "outputs": [],
   "source": [
    "!ls -lh {model_id}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "KFYC6Z3FLB5F"
   },
   "source": [
    "Let's now prepare our `inference_model` and run an inference. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "T7zeMQTaACur",
    "outputId": "762b7fbc-07d4-4572-f107-c836e3e7928a"
   },
   "outputs": [],
   "source": [
    "from peft import PeftConfig, PeftModel\n",
    "\n",
    "config = PeftConfig.from_pretrained(model_id)\n",
    "model = AutoModelForSemanticSegmentation.from_pretrained(\n",
    "    checkpoint, id2label=id2label, label2id=label2id, ignore_mismatched_sizes=True\n",
    ")\n",
    "# Load the Lora model\n",
    "inference_model = PeftModel.from_pretrained(model, model_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2L1R0LDWLImd"
   },
   "source": [
    "Fetch an image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 444
    },
    "id": "lwjRvZOmA7Hh",
    "outputId": "44ab267d-e2b9-4bda-a52b-91968eabce29"
   },
   "outputs": [
    {
     "data": {
      "image/jpeg": "[encoded data, 45936 characters]",
      "image/png": "[encoded data, 396176 characters]",
      "text/plain": [
       "<PIL.PngImagePlugin.PngImageFile image mode=RGB size=640x427>"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "url = \"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/semantic-seg-image.png\"\n",
    "image = Image.open(requests.get(url, stream=True).raw)\n",
    "image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kdK_bGhsLKKE"
   },
   "source": [
    "Preprocess the image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "G0z-3R-PBKc9",
    "outputId": "56c91198-0116-4c2c-fc63-147dc7431b89"
   },
   "outputs": [],
   "source": [
    "# prepare image for the model\n",
    "encoding = image_processor(image.convert(\"RGB\"), return_tensors=\"pt\")\n",
    "print(encoding.pixel_values.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "hJRijta4LLu9"
   },
   "source": [
    "Run an inference. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "id": "z1p-QDoiBP56"
   },
   "outputs": [],
   "source": [
    "with torch.no_grad():\n",
    "    outputs = inference_model(pixel_values=encoding.pixel_values)\n",
    "    logits = outputs.logits\n",
    "\n",
    "upsampled_logits = nn.functional.interpolate(\n",
    "    logits,\n",
    "    size=image.size[::-1],\n",
    "    mode=\"bilinear\",\n",
    "    align_corners=False,\n",
    ")\n",
    "\n",
    "pred_seg = upsampled_logits.argmax(dim=1)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gmYIcfL4LNtj"
   },
   "source": [
    "Visualize the results.\n",
    "\n",
    "We need a color palette to visualize the results. Here, we use [one provided by the TensorFlow Model Garden repository](https://github.com/tensorflow/models/blob/3f1ca33afe3c1631b733ea7e40c294273b9e406d/research/deeplab/utils/get_dataset_colormap.py#L51)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "id": "jy5c6vmzBqzC"
   },
   "outputs": [],
   "source": [
    "def ade_palette():\n",
    "    \"\"\"Creates a label colormap used in ADE20K segmentation benchmark.\n",
    "    Returns:\n",
    "    A colormap for visualizing segmentation results.\n",
    "    \"\"\"\n",
    "    return np.asarray(\n",
    "        [\n",
    "            [0, 0, 0],\n",
    "            [120, 120, 120],\n",
    "            [180, 120, 120],\n",
    "            [6, 230, 230],\n",
    "            [80, 50, 50],\n",
    "            [4, 200, 3],\n",
    "            [120, 120, 80],\n",
    "            [140, 140, 140],\n",
    "            [204, 5, 255],\n",
    "            [230, 230, 230],\n",
    "            [4, 250, 7],\n",
    "            [224, 5, 255],\n",
    "            [235, 255, 7],\n",
    "            [150, 5, 61],\n",
    "            [120, 120, 70],\n",
    "            [8, 255, 51],\n",
    "            [255, 6, 82],\n",
    "            [143, 255, 140],\n",
    "            [204, 255, 4],\n",
    "            [255, 51, 7],\n",
    "            [204, 70, 3],\n",
    "            [0, 102, 200],\n",
    "            [61, 230, 250],\n",
    "            [255, 6, 51],\n",
    "            [11, 102, 255],\n",
    "            [255, 7, 71],\n",
    "            [255, 9, 224],\n",
    "            [9, 7, 230],\n",
    "            [220, 220, 220],\n",
    "            [255, 9, 92],\n",
    "            [112, 9, 255],\n",
    "            [8, 255, 214],\n",
    "            [7, 255, 224],\n",
    "            [255, 184, 6],\n",
    "            [10, 255, 71],\n",
    "            [255, 41, 10],\n",
    "            [7, 255, 255],\n",
    "            [224, 255, 8],\n",
    "            [102, 8, 255],\n",
    "            [255, 61, 6],\n",
    "            [255, 194, 7],\n",
    "            [255, 122, 8],\n",
    "            [0, 255, 20],\n",
    "            [255, 8, 41],\n",
    "            [255, 5, 153],\n",
    "            [6, 51, 255],\n",
    "            [235, 12, 255],\n",
    "            [160, 150, 20],\n",
    "            [0, 163, 255],\n",
    "            [140, 140, 140],\n",
    "            [250, 10, 15],\n",
    "            [20, 255, 0],\n",
    "            [31, 255, 0],\n",
    "            [255, 31, 0],\n",
    "            [255, 224, 0],\n",
    "            [153, 255, 0],\n",
    "            [0, 0, 255],\n",
    "            [255, 71, 0],\n",
    "            [0, 235, 255],\n",
    "            [0, 173, 255],\n",
    "            [31, 0, 255],\n",
    "            [11, 200, 200],\n",
    "            [255, 82, 0],\n",
    "            [0, 255, 245],\n",
    "            [0, 61, 255],\n",
    "            [0, 255, 112],\n",
    "            [0, 255, 133],\n",
    "            [255, 0, 0],\n",
    "            [255, 163, 0],\n",
    "            [255, 102, 0],\n",
    "            [194, 255, 0],\n",
    "            [0, 143, 255],\n",
    "            [51, 255, 0],\n",
    "            [0, 82, 255],\n",
    "            [0, 255, 41],\n",
    "            [0, 255, 173],\n",
    "            [10, 0, 255],\n",
    "            [173, 255, 0],\n",
    "            [0, 255, 153],\n",
    "            [255, 92, 0],\n",
    "            [255, 0, 255],\n",
    "            [255, 0, 245],\n",
    "            [255, 0, 102],\n",
    "            [255, 173, 0],\n",
    "            [255, 0, 20],\n",
    "            [255, 184, 184],\n",
    "            [0, 31, 255],\n",
    "            [0, 255, 61],\n",
    "            [0, 71, 255],\n",
    "            [255, 0, 204],\n",
    "            [0, 255, 194],\n",
    "            [0, 255, 82],\n",
    "            [0, 10, 255],\n",
    "            [0, 112, 255],\n",
    "            [51, 0, 255],\n",
    "            [0, 194, 255],\n",
    "            [0, 122, 255],\n",
    "            [0, 255, 163],\n",
    "            [255, 153, 0],\n",
    "            [0, 255, 10],\n",
    "            [255, 112, 0],\n",
    "            [143, 255, 0],\n",
    "            [82, 0, 255],\n",
    "            [163, 255, 0],\n",
    "            [255, 235, 0],\n",
    "            [8, 184, 170],\n",
    "            [133, 0, 255],\n",
    "            [0, 255, 92],\n",
    "            [184, 0, 255],\n",
    "            [255, 0, 31],\n",
    "            [0, 184, 255],\n",
    "            [0, 214, 255],\n",
    "            [255, 0, 112],\n",
    "            [92, 255, 0],\n",
    "            [0, 224, 255],\n",
    "            [112, 224, 255],\n",
    "            [70, 184, 160],\n",
    "            [163, 0, 255],\n",
    "            [153, 0, 255],\n",
    "            [71, 255, 0],\n",
    "            [255, 0, 163],\n",
    "            [255, 204, 0],\n",
    "            [255, 0, 143],\n",
    "            [0, 255, 235],\n",
    "            [133, 255, 0],\n",
    "            [255, 0, 235],\n",
    "            [245, 0, 255],\n",
    "            [255, 0, 122],\n",
    "            [255, 245, 0],\n",
    "            [10, 190, 212],\n",
    "            [214, 255, 0],\n",
    "            [0, 204, 255],\n",
    "            [20, 0, 255],\n",
    "            [255, 255, 0],\n",
    "            [0, 153, 255],\n",
    "            [0, 41, 255],\n",
    "            [0, 255, 204],\n",
    "            [41, 0, 255],\n",
    "            [41, 255, 0],\n",
    "            [173, 0, 255],\n",
    "            [0, 245, 255],\n",
    "            [71, 0, 255],\n",
    "            [122, 0, 255],\n",
    "            [0, 255, 184],\n",
    "            [0, 92, 255],\n",
    "            [184, 255, 0],\n",
    "            [0, 133, 255],\n",
    "            [255, 214, 0],\n",
    "            [25, 194, 194],\n",
    "            [102, 255, 0],\n",
    "            [92, 0, 255],\n",
    "        ]\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 595
    },
    "id": "3KJFvgENBih0",
    "outputId": "63d42e4f-3867-4d33-8ac0-83bebf8819ca"
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 834272 characters]",
      "text/plain": [
       "<Figure size 1500x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "color_seg = np.zeros((pred_seg.shape[0], pred_seg.shape[1], 3), dtype=np.uint8)\n",
    "palette = np.array(ade_palette())\n",
    "\n",
    "for label, color in enumerate(palette):\n",
    "    color_seg[pred_seg == label, :] = color\n",
    "color_seg = color_seg[..., ::-1]  # convert to BGR\n",
    "\n",
    "img = np.array(image) * 0.5 + color_seg * 0.5  # plot the image with the segmentation map\n",
    "img = img.astype(np.uint8)\n",
    "\n",
    "plt.figure(figsize=(15, 10))\n",
    "plt.imshow(img)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "q1aGuHYFLP7i"
   },
   "source": [
    "The results are definitely not as expected and as mentioned above, this example is not meant to provide a state-of-the-art model. It exists to familiarize you with the end-to-end workflow. \n",
    "\n",
    "On the other hand, if you perform full fine-tuning on the same setup (same model variant, same dataset, same training schedule, etc.), the results would not have been any different. This is a crucial aspect of parameter-efficient fine-tuning -- to be able to match up to the results of the full fine-tuning but with a fraction of total trainable parameters. \n",
    "\n",
    "Here are some things that you can try to get better results:\n",
    "\n",
    "* Increase the number of training samples. \n",
    "* Try a larger SegFormer model variant (know about the available model variants [here](https://huggingface.co/models?search=segformer)). \n",
    "* Try different values for the arguments available in `LoraConfig`. \n",
    "* Tune the learning rate and batch size. "
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "machine_shape": "hm",
   "provenance": []
  },
  "gpuClass": "premium",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "0dcc5a2866a349e0843673bef499dc66": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_24fde588dc1a49a397e379cda320ed71",
      "placeholder": "​",
      "style": "IPY_MODEL_9746875e74b845daab06619393b4d46b",
      "value": "\n<b>Pro Tip:</b> If you don't already have one, you can create a dedicated\n'notebooks' token with 'write' access, that you can then easily reuse for all\nnotebooks. </center>"
     }
    },
    "14ac809ba0bc4cd5bcd51f83105947b0": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "21bf954f54db41e6ba78f76195721614": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "24fde588dc1a49a397e379cda320ed71": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "3f69c7b15e5e48039777e4b6b1a51f53": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "42a7b8268d8945b5bbe9d3f20bc8840c": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "554b55f29a5e4d5a81608d912d3635e8": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "5bcfe3da0ffb41ccbb9404ac35ae8945": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "6c6d19cd893e4d82bae9972fa10c6d74": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "PasswordModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "PasswordModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "PasswordView",
      "continuous_update": true,
      "description": "Token:",
      "description_tooltip": null,
      "disabled": false,
      "layout": "IPY_MODEL_42a7b8268d8945b5bbe9d3f20bc8840c",
      "placeholder": "​",
      "style": "IPY_MODEL_554b55f29a5e4d5a81608d912d3635e8",
      "value": ""
     }
    },
    "6c88a55a635b4c9f946a1aa838d69f20": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_14ac809ba0bc4cd5bcd51f83105947b0",
      "placeholder": "​",
      "style": "IPY_MODEL_e7393e78f41b496495982490b72ef2a3",
      "value": "<center> <img\nsrc=https://huggingface.co/front/assets/huggingface_logo-noborder.svg\nalt='Hugging Face'> <br> Copy a token from <a\nhref=\"https://huggingface.co/settings/tokens\" target=\"_blank\">your Hugging Face\ntokens page</a> and paste it below. <br> Immediately click login after copying\nyour token or it might be stored in plain text in this notebook file. </center>"
     }
    },
    "9746875e74b845daab06619393b4d46b": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "b7431f99d93b4e9b8c8177ac4a7b4070": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": "center",
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": "flex",
      "flex": null,
      "flex_flow": "column",
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": "50%"
     }
    },
    "cb4053f102fc4207a1c9513f81ad6415": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ButtonModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ButtonModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ButtonView",
      "button_style": "",
      "description": "Login",
      "disabled": false,
      "icon": "",
      "layout": "IPY_MODEL_21bf954f54db41e6ba78f76195721614",
      "style": "IPY_MODEL_f83dd354396e4aa3acd214a6fd98efb2",
      "tooltip": ""
     }
    },
    "e7393e78f41b496495982490b72ef2a3": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "f2a722f371904cce80dc1c087b153ad6": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "VBoxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "VBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "VBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_6c88a55a635b4c9f946a1aa838d69f20",
       "IPY_MODEL_6c6d19cd893e4d82bae9972fa10c6d74",
       "IPY_MODEL_fc48ee28c2e44f1daa03149c8004c314",
       "IPY_MODEL_cb4053f102fc4207a1c9513f81ad6415",
       "IPY_MODEL_0dcc5a2866a349e0843673bef499dc66"
      ],
      "layout": "IPY_MODEL_b7431f99d93b4e9b8c8177ac4a7b4070"
     }
    },
    "f83dd354396e4aa3acd214a6fd98efb2": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ButtonStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ButtonStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "button_color": null,
      "font_weight": ""
     }
    },
    "fc48ee28c2e44f1daa03149c8004c314": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "CheckboxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "CheckboxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "CheckboxView",
      "description": "Add token as git credential?",
      "description_tooltip": null,
      "disabled": false,
      "indent": true,
      "layout": "IPY_MODEL_3f69c7b15e5e48039777e4b6b1a51f53",
      "style": "IPY_MODEL_5bcfe3da0ffb41ccbb9404ac35ae8945",
      "value": true
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
