{"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":"In this kernel, we will use Weights and Biases's Semantic Segmentation logger to interactively visualize the dataset. We will also visualize the ENTIRE dataset easily using W&B Tables.\n\nIf you like the work, consider upvoting. :D","metadata":{}},{"cell_type":"markdown","source":"## Imports and Setup","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\n\nimport wandb\nwandb.login()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-10-19T21:16:54.386320Z","iopub.execute_input":"2021-10-19T21:16:54.387288Z","iopub.status.idle":"2021-10-19T21:18:03.098076Z","shell.execute_reply.started":"2021-10-19T21:16:54.387178Z","shell.execute_reply":"2021-10-19T21:18:03.097361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load Dataset","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv('../input/sartorius-cell-instance-segmentation/train.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-10-19T21:18:06.621486Z","iopub.execute_input":"2021-10-19T21:18:06.621842Z","iopub.status.idle":"2021-10-19T21:18:07.318827Z","shell.execute_reply.started":"2021-10-19T21:18:06.621804Z","shell.execute_reply":"2021-10-19T21:18:07.317686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Utilities","metadata":{}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/inversion/run-length-decoding-quick-start\ndef rle_decode(mask_rle, shape, color=1):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height, width, channels) of array to return \n    color: color for the mask\n    Returns numpy array (mask)\n\n    '''\n    s = mask_rle.split()\n    \n    starts = list(map(lambda x: int(x) - 1, s[0::2]))\n    lengths = list(map(int, s[1::2]))\n    ends = [x + y for x, y in zip(starts, lengths)]\n    \n    img = np.zeros((shape[0] * shape[1], shape[2]), dtype=np.float32)\n            \n    for start, end in zip(starts, ends):\n        img[start : end] = color\n    \n    return img.reshape(shape)","metadata":{"execution":{"iopub.status.busy":"2021-10-19T21:18:10.187820Z","iopub.execute_input":"2021-10-19T21:18:10.188110Z","iopub.status.idle":"2021-10-19T21:18:10.197234Z","shell.execute_reply.started":"2021-10-19T21:18:10.188081Z","shell.execute_reply":"2021-10-19T21:18:10.196229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_id2label = {\n    1: 'shsy5y',\n    2: 'cort', \n    3: 'astro'\n}\n\nclass_label2id = {v:k for k, v in class_id2label.items()}\n\n# Note the use of wandb.Image\ndef wandb_mask(bg_img, gt_mask):\n  return wandb.Image(bg_img, masks={\n      \"ground_truth\" : {\n          \"mask_data\" : gt_mask,\n          \"class_labels\": class_id2label\n      }\n    }\n  )","metadata":{"execution":{"iopub.status.busy":"2021-10-19T21:18:10.409779Z","iopub.execute_input":"2021-10-19T21:18:10.410064Z","iopub.status.idle":"2021-10-19T21:18:10.416606Z","shell.execute_reply.started":"2021-10-19T21:18:10.410035Z","shell.execute_reply":"2021-10-19T21:18:10.415706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Log the Masks","metadata":{}},{"cell_type":"code","source":"VISUALIZE_SAMPLES = 10\n\nids = df.id.unique()\nsample_idx = np.random.choice(len(ids), VISUALIZE_SAMPLES)\nsample_ids = ids[sample_idx]\n\n# Initialize W&B\nrun = wandb.init(project='sartorius-viz', \n                 config={'competition': 'sartorius', '_wandb_kernel':'ayut'}) # The config variable is to show that you can pass in any dict (hyperparameters)\n\nfor i in range(VISUALIZE_SAMPLES):\n    image_id = sample_ids[i]\n    sample_df = df[df[\"id\"] == image_id].reset_index(drop=True)\n    # Empty mask\n    mask = np.zeros((520, 704, 1))\n    # Fill mask\n    for j in range(len(sample_df)):\n        row = sample_df.loc[j]\n        mask += rle_decode(row.annotation, \n                           shape=(520, 704, 1))\n        \n    mask[np.where(mask>0)] = class_label2id[row.cell_type]\n    mask = np.squeeze(mask, axis=-1)\n            \n    # Log to W&B\n    image_path = f\"../input/sartorius-cell-instance-segmentation/train/{image_id}.png\"\n    wandb.log({f\"Segmentation Viz\" : [wandb_mask(image_path, mask)]})\n    \n# Close W&B run\nwandb.finish()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-10-19T19:49:35.389965Z","iopub.execute_input":"2021-10-19T19:49:35.39058Z","iopub.status.idle":"2021-10-19T19:49:55.658282Z","shell.execute_reply.started":"2021-10-19T19:49:35.390532Z","shell.execute_reply":"2021-10-19T19:49:55.657594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## [Check out the run page here $\\rightarrow$](https://wandb.ai/ayut/sartorius-viz/runs/30jbuljv?workspace=user-ayut)\n\n![img](https://i.imgur.com/5FDCLQK.gif)","metadata":{}},{"cell_type":"markdown","source":"## 🎉🎉 Visualizing dataset interactively with W&B Tables 🎆🎆\n\nW&B Tables let you to log, query, and analyze data interactively. This can help you understand your dataset, visualize model predictions, and share insights in a central dashboard.\n\nThe code cell below logs the entire dataset of this competition along with the metadata from `train.csv` file. You can use this table to get useful insights. \n\n### Why should you use W&B Tables?\n\n* It is suited for quick EDA.\n* It helps understand the data better with few lines of code. Here's a [quick colab notebook](http://wandb.me/tables-quickstart).\n* It lets you see the \"actual\" data in it's entirety. With matplotlib based visualization you will have to plot everything in batches and it not very scalable.\n* You can filter, sort and group data which can help answer some fundamental questions.\n* It is well suited to visualize model predictions and compare models on example level. You can check out [this Kaggle kernel](https://www.kaggle.com/ayuraj/better-data-understanding-with-w-b-tables) to learn more about model prediction visualization.\n\nRead more about Tables [here](https://wandb.ai/wandb/posts/reports/Announcing-W-B-Tables-Iterate-on-Your-Data--Vmlldzo4NTMxNDU).\n\n### What these metadata columns are?\n\n![img](https://i.imgur.com/UZtbwox.png) <br>\n([Source](https://www.microscopyu.com/techniques/phase-contrast/introduction-to-phase-contrast-microscopy))\n\nCheck out the source link, it's a great introduction to phase contrast microscopy. \n\n* `id` - unique identifier for object\n* `cell_type` - the cell line \n* `plate_time` - time plate was created (The plate as shown in the figure is where the specimen is kept.)\n* `sample_date` - date sample was created  \n* `sample_id` - sample identifier\n* `elapsed_timedelta` - time since first image taken of sample\n\n❗ Note: I have excluded `width` and `height` since they are same for every sample. ","metadata":{}},{"cell_type":"code","source":"# Initialize a W&B run to log images\nrun = wandb.init(project='sartorius-viz', \n                 config={'competition': 'sartorius', '_wandb_kernel':'ayut'}) # W&B Code 1\n\n# Inialize an empty W&B tables\ndata_at = wandb.Table(columns=['id', 'image', 'cell_type', \n                               'plate_time', 'sample_date', \n                               'sample_id', 'elapsed_timedelta']) # W&B Code 2\n\n# Setup a WandB Classes object. This will give additional metadata for visuals\n# Note that we need to pass class_set to wandb.Image. In future, we might not to do this extra step. \nclass_set = wandb.Classes([{'name': name, 'id': id} \n                           for name, id in zip(class_label2id.keys(), class_label2id.values())]) # W&B Code 3\n\nfor image_id, tmp_df in tqdm(df.groupby('id')):\n    tmp_df = tmp_df.reset_index(drop=True)\n    image_path = f\"../input/sartorius-cell-instance-segmentation/train/{image_id}.png\"\n    \n    # Create mask\n    mask = np.zeros((520, 704, 1))\n    for j in range(len(tmp_df)):\n        row = tmp_df.loc[j]\n        mask += rle_decode(row.annotation,\n                           shape=(520, 704, 1))\n        \n    mask[np.where(mask>0)] = class_label2id[row.cell_type]\n    mask = np.squeeze(mask, axis=-1)\n    \n    # Get W&B image\n    wandb_mask = wandb.Image(image_path, classes=class_set, masks={\n                      \"ground_truth\" : {\n                          \"mask_data\" : mask\n                      }})\n\n    # Append data \n    data_at.add_data(image_id,                                            \n                     wandb_mask,\n                     *tuple(row)[4:]) # W&B Code 4\n    \nwandb.log({'Sartorius Dataset': data_at}) # W&B Code 5\nwandb.finish() # W&B Code 6","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-10-19T17:33:36.633417Z","iopub.execute_input":"2021-10-19T17:33:36.634427Z","iopub.status.idle":"2021-10-19T17:35:35.294018Z","shell.execute_reply.started":"2021-10-19T17:33:36.634357Z","shell.execute_reply":"2021-10-19T17:35:35.293264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## [Check out the run page here $\\rightarrow$](https://wandb.ai/ayut/sartorius-viz/runs/289xy46z?workspace=user-ayut)\n\n![img](https://i.imgur.com/LQDRI25.gif)","metadata":{}}]}