{"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":"# I. Giới thiệu chung\n## 1. Giới thiệu bài toán\n<span style=\"font-size: 18px\">\n    Ta có thể thấy protein đóng vai trò thiết yếu trong hầu như tất các quá trình của tế bào. Thông thường, nhiều protein kết hợp với nhau tại một vị trí cụ thể để thực hiện 1 nhiệm vụ, kết quả chính xác của nhiệm vụ này phụ thuộc vào loại protein nào có mặt. Như bạn thấy, sự phân bố của protein ở các tế bào khác nhau là khác nhau, làm phát sinh sự không đồng nhất về chức năng giữa các tế bào. Việc tìm ra những điểm khác biệt như vậy và lý do tại sao có sự phân bố khác nhau của protein giữa các tế bào có cùng chức năng là điều quan trọng để hiểu được cách thức hoạt động của các tế bào, tìm ra cách các căn bệnh phát triển, sau đó tìm ra các phương pháp điều trị tốt hơn cho những bệnh đó.\n</span>\n\n## 2. Dữ liệu\n<b style=\"font-size: 18px\">Human Protein Atlas - Single Cell Classification</b>\n<br>\n<span style=\"font-size: 18px\">Bộ dữ liệu có 3 loại ảnh PNG bao gồm các kích thước:</span>\n    \n<ul style=\"font-size: 18px\">\n    <li>1728x1728</li>\n    <li>2048x2048</li>\n    <li>3072x3072</li>\n</ul>\n\n<span style=\"font-size: 18px\">\n    Tất cả đều được chụp bằng kính hiển vi đồng tiêu (Confocal Microscopy)\n    <br>\n    Mỗi ảnh được chụp trên 4 kênh → 4 ảnh:\n<br>\n</span>\n<ul style=\"font-size: 18px\">\n    <li><code>red:</code> microtubule channels (<a href=\"https://vi.wikipedia.org/wiki/Vi_ống\">Vi ống</a>)</li>\n    <li><code>blue:</code> nuclei channels (<a href=\"https://vi.wikipedia.org/wiki/Nhân_tế_bào\">Nhân tế bào</a>)</li>\n    <li><code>yellow:</code> Endoplasmic Reticulum (ER) channels (<a href=\"https://vi.wikipedia.org/wiki/Mạng_lưới_nội_chất\">Lưới nội chất</a>)</li>\n    <li><code>green:</code> protein of interest (<a href=\"https://www.google.com/search?q=protein+of+interest&oq=protein+of+interest&aqs=edge..69i57j0l3j0i22i30l3.760j0j1&sourceid=chrome&ie=UTF-8\">???</a>)</li>\n</ul>\n\n## 3. Nhiệm vụ\n<span style=\"font-size: 18px\">\n    Có tất cả 19 nhãn cần phân lớp, 18 nhãn cho 18 loại tế bào và 1 nhãn cho những tế bào không xác định được cụ thể. \n    \n    \n</span>\n\n<pre style=\"font-size: 18px\">\n0.  Nucleoplasm  \n1.  Nuclear membrane   \n2.  Nucleoli   \n3.  Nucleoli fibrillar center   \n4.  Nuclear speckles   \n5.  Nuclear bodies   \n6.  Endoplasmic reticulum   \n7.  Golgi apparatus   \n8.  Intermediate filaments  \n9.  Actin filaments  \n10.  Microtubules      \n11.  Mitotic spindle   \n12.  Centrosome   \n13.  Plasma membrane   \n14.  Mitochondria   \n15.  Aggresome   \n16.  Cytosol   \n17.  Vesicles and punctate cytosolic patterns   \n18.  Negative  \n</pre>\n\n<span style=\"font-size: 18px\">\n    Tất cả các ảnh được thể hiện bằng 4 bộ lọc:\n</span>\n<ul style=\"font-size: 18px\">\n    <li>Bộ lọc màu xanh(<code>green</code>) được sử dụng để dự đoán và gán nhãn</li>\n    <li>3 bộ lọc còn lại(<code>red, blue, yellow</code>) được sử dụng để làm tài liệu tham khảo, cho thấy sự tương quan của tế bào giữa các bộ lọc</li>\n</ul>\n    \n### Nhiệm vụ chính\n<span style=\"font-size: 18px\">\nVới mỗi ảnh chúng ta đã được cho sẵn các nhãn của các tế bào xuất hiện trong ảnh.\n<br><b> Nhiệm vụ của chúng ta là segment ra các tế bào và gán nhãn cho các tế bào đó.</b>\n</span>","metadata":{}},{"cell_type":"markdown","source":"# II. Thực hiện","metadata":{}},{"cell_type":"markdown","source":"## 1. Phân tích dữ liệu","metadata":{}},{"cell_type":"code","source":"!pip install https://github.com/CellProfiling/HPA-Cell-Segmentation/archive/master.zip","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install ipyplot -q","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import hpacellseg.cellsegmentator as cellsegmentator\nfrom hpacellseg.utils import label_cell, label_nuclei\nimport glob\nimport os\n\nimport os\nimport numpy as np\nimport pandas as pd\n\nimport hpacellseg.cellsegmentator as cellsegmentator\nfrom hpacellseg.utils import label_cell, label_nuclei\n\nfrom sklearn.preprocessing import MultiLabelBinarizer\n\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport plotly.graph_objects as go\nimport plotly.express as px\n\nfrom fastai.vision.all import *\nimport ipyplot\nimport imageio\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Khởi tạo đường dẫn đến dữ liệu và đọc dữ liệu vào biến train","metadata":{}},{"cell_type":"code","source":"DATA_DIR = \"/kaggle/input/hpa-single-cell-image-classification\"\ntrain = pd.read_csv(os.path.join(DATA_DIR,'train.csv'))\n\n\ncolours = ['_red.png', '_blue.png', '_yellow.png', '_green.png']\nTRAIN = '../input/hpa-single-cell-image-classification/train'\npaths = [[os.path.join(TRAIN, train.iloc[idx,0])+ colour for colour in colours] for idx in range(len(train))]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Tạo ra 1 từ điển để biết dữ liệu dạng số ứng với tên tế bào nào.","metadata":{"execution":{"iopub.status.busy":"2021-06-10T15:44:42.371905Z","iopub.execute_input":"2021-06-10T15:44:42.3723Z","iopub.status.idle":"2021-06-10T15:44:42.378525Z","shell.execute_reply.started":"2021-06-10T15:44:42.372268Z","shell.execute_reply":"2021-06-10T15:44:42.377193Z"}}},{"cell_type":"code","source":"LABELS= {\n    0: \"Nucleoplasm\",\n    1: \"Nuclear membrane\",\n    2: \"Nucleoli\",\n    3: \"Nucleoli fibrillar center\",\n    4: \"Nuclear speckles\",\n    5: \"Nuclear bodies\",\n    6: \"Endoplasmic reticulum\",\n    7: \"Golgi apparatus\",\n    8: \"Intermediate filaments\",\n    9: \"Actin filaments\",\n    10: \"Microtubules\",\n    11: \"Mitotic spindle\",\n    12: \"Centrosome\",\n    13: \"Plasma membrane\",\n    14: \"Mitochondria\",\n    15: \"Aggresome\",\n    16: \"Cytosol\",\n    17: \"Vesicles and punctate cytosolic patterns\",\n    18: \"Negative\"\n}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thực hiện đưa dữ liệu đầu vào thành dạng vector one-hot để thống kê sự phân bố của các nhãn dữ liệu\n\nDựa trên label đã được cung cấp, tạo ra 1 vector one-hot tương ứng với 19 nhãn.\n\nHiển thị 5 dòng đầu dữ liệu sau khi one-hot\n\n<img src=\"https://i.imgur.com/uupfzQU.png\">\n\n\n","metadata":{}},{"cell_type":"code","source":"train_csv = train.copy()\ntrain_csv['Label'] = train_csv['Label'].apply(lambda x: list(map(int,x.split(\"|\"))))\nmlb = MultiLabelBinarizer()\ntrain_csv[list(range(19))] = mlb.fit_transform(train_csv['Label'])\ntrain_csv.columns = [\"ID\", \"Label\"] + list(LABELS.values())\ntrain_csv.head(5)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Vẽ biểu đồ thể hiện sự chênh lệch giữa các nhãn trong dữ liệu.\n\nTính tổng theo cột của các vector one-hot đã thu được ở bước trên.\n\n<img src=\"https://i.imgur.com/i5eR460.png\">\n\nDễ thấy có sự chênh lệch lớn giữa các nhãn ở trong dữ liệu.","metadata":{}},{"cell_type":"code","source":"label_count = train_csv.iloc[:, 2:].sum()\npx.bar(label_count)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thử đếm số lượng các nhãn có trong 1 ảnh để xem phân bố thế nào?\n\nNhận thấy các nhãn của 1 ảnh cách nhau bởi dấu | nên split ra và đếm số lượng để biết số lượng nhãn trong ảnh đó.\n\n<img src=\"https://i.imgur.com/gMdGNNX.png\">\n\nDễ thấy đa số các ảnh chỉ có 1 nhãn hoặc 2 nhãn là chính, các ảnh có số nhãn là 3, 4, 5 không đáng kể.","metadata":{}},{"cell_type":"code","source":"train['num_classes'] = train['Label'].apply(lambda r: len(r.split('|')))\ntrain['num_classes'].value_counts().plot.bar(title='Examples with multiple labels', xlabel='number of labels per example', ylabel='# train examples')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Xem thử các kênh màu của 3 ảnh đầu tiên trông như nào?\n\n<img src=\"https://i.imgur.com/ar9djAI.png\">\n\nTrông ảnh các kênh hơi áng xanh và mỗi kênh thể hiện rõ một phần của tế bào.","metadata":{}},{"cell_type":"code","source":"titles = ['microtubules', 'nuclei', 'endoplasmic reticulum', 'protein of interest']\nfig, axs = plt.subplots(3, 4, figsize =(16,8))\nfor entry in range(3):\n    for channel in range(4):\n        img = plt.imread(paths[entry][channel])\n        axs[entry, channel].imshow(img)        \n        if entry == 0:\n            axs[0, channel].set_title(titles[channel])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Vậy thì xem thử 3 ảnh đầu tiên của dữ liệu khi kết hợp các kênh màu vào trông sẽ như nào?\n\nĐọc 4 ảnh tương ứng của mỗi ảnh theo ID ảnh cộng với đuôi _red, _green, _blue, _yellow ứng với 4 kênh màu. Sau đó sử dụng np.dstack để chồng các kênh màu lên nhau.\n\nĐây là kết quả của 4 cách dstack r_g_b_y, r_g_b, r_y_b, b_y_g\n\n<h4>Ảnh 1</h4>\n<img src=\"https://i.imgur.com/yQ539pA.png\"/>\n\n<h4>Ảnh 2</h4>\n<img src=\"https://i.imgur.com/aVYb3s7.png\">\n\n<h4>Ảnh 3</h4>\n<img src=\"https://i.imgur.com/9WOOP6u.png\">\n\n\nKhi chồng cả 4 kênh màu lên thì dữ liệu khá khó nhìn vì hầu như tất cả các điểm ảnh đều chuyển thành màu trắng. \n\nỞ ảnh r_g_b thì cho kết quả tương đối, tuy nhiên phần hào quang xung quanh các tế bào hơi mờ nhạt.\n\nỞ ảnh r_y_b thì cho kết quả rõ nét về tế bào, nổi bật hơn là phần bao quanh nhân tế bào.\n\nỞ ảnh b_y_g thì cho kết quả rõ nét về tế bào, nổi bật hơn là phần nhân tế bào.","metadata":{}},{"cell_type":"code","source":"for i in range(3):\n    img_visual = TRAIN + '/' + train_csv['ID'].iloc[i]\n    r = plt.imread(img_visual + '_red' + '.png')\n    g = plt.imread(img_visual + '_green' + '.png')    \n    b = plt.imread(img_visual + '_blue' + '.png')\n    y = plt.imread(img_visual + '_yellow' + '.png')\n    fig, ax = plt.subplots(1,4, figsize=(10,20))\n    img = np.dstack((r, g, b, y))\n    ax[0].set_title('r_g_b_y')\n    ax[0].imshow(img)\n    ax[0].axis('off')\n\n    img = np.dstack((r, g, b))\n    ax[1].set_title('r_g_b')\n    ax[1].imshow(img)\n    ax[1].axis('off')\n\n    img = np.dstack((r, y, b))\n    ax[2].set_title('r_y_b')\n    ax[2].imshow(img)\n    ax[2].axis('off')\n\n    img = np.dstack((b, y, g))\n    ax[3].set_title(\"b_y_g\")\n    ax[3].imshow(img)\n    ax[3].axis('off')\n\n    plt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"Thử nhìn qua xem mỗi nhãn tế bào trông sẽ thế nào?\n\nThực hiện đi tìm ảnh đầu tiên có 1 nhãn tương ứng với từng nhãn trong 19 nhãn tế bào đã cho và chồng 3 kênh màu red, yellow, blue lên để plot ra 1 ảnh hoàn chỉnh.\n\nTrông nó sẽ như thế này\n\n<div class=\"row\">\n    <h4>Nucleoplasm</h4>\n    <img src=\"https://i.imgur.com/9xd8ZKY.png\">\n</div>\n<div class=\"row\">\n    <h4>Nuclear membrane</h4>\n    <img src=\"https://i.imgur.com/tPx5F3d.png\">\n</div>\n<div class=\"row\">\n    <h4>Nucleoli</h4>\n    <img src=\"https://i.imgur.com/9tudPrE.png\">\n</div>\n<div class=\"row\">\n    <h4>Nucleoli fibrillar center</h4>\n    <img src=\"https://i.imgur.com/TQ9UdzE.png\">\n</div>\n<div class=\"row\">\n    <h4>Nuclear speckles</h4>\n    <img src=\"https://i.imgur.com/sUhlCAp.png\">\n</div>\n<div class=\"row\">\n    <h4>Nuclear bodies</h4>\n    <img src=\"https://i.imgur.com/FF9TP98.png\">\n</div>\n<div class=\"row\">\n    <h4>Endoplasmic reticulum</h4>\n    <img src=\"https://i.imgur.com/lQCnMX9.png\">\n</div>\n<div class=\"row\">\n    <h4>Golgi apparatus</h4>\n    <img src=\"https://i.imgur.com/YIxOoE9.png\">\n</div>\n<div class=\"row\">\n    <h4>Intermediate filaments</h4>\n    <img src=\"https://i.imgur.com/3qju9Hb.png\">\n</div>\n<div class=\"row\">\n    <h4>Actin filaments</h4>\n    <img src=\"https://i.imgur.com/t8LM06U.png\">\n</div>\n<div class=\"row\">\n    <h4>Microtubules</h4>\n    <img src=\"https://i.imgur.com/cyx1zel.png\">\n</div>\n<div class=\"row\">\n    <h4>Mitotic spindle</h4>\n    <img src=\"https://i.imgur.com/1rGfY8b.png\">\n</div>\n<div class=\"row\">\n    <h4>Centrosome</h4>\n    <img src=\"https://i.imgur.com/d6uQZiW.png\">\n</div>\n<div class=\"row\">\n    <h4>Plasma membrane</h4>\n    <img src=\"https://i.imgur.com/JnX6iz5.png\">\n</div>\n<div class=\"row\">\n    <h4>Mitochondria</h4>\n    <img src=\"https://i.imgur.com/suJezhj.png\">\n</div>\n<div class=\"row\">\n    <h4>Aggresome</h4>\n    <img src=\"https://i.imgur.com/Ubsfqvk.png\">\n</div>\n<div class=\"row\">\n    <h4>Cytosol</h4>\n    <img src=\"https://i.imgur.com/faLdlaT.png\">\n</div>\n<div class=\"row\">\n    <h4>Vesicles and punctate cytosolic patterns</h4>\n    <img src=\"https://i.imgur.com/wjWC8F4.png\">\n</div>\n<div class=\"row\">\n    <h4>Negative</h4>\n    <img src=\"https://i.imgur.com/pcCDnRU.png\">\n</div>\n","metadata":{}},{"cell_type":"code","source":"labels = [str(i) for i in range(19)]\nclass_images = []\nfor label in labels:\n    r_img = train[train.Label == label].reset_index(drop=True).ID.loc[0] + '_red.png'\n    y_img = train[train.Label == label].reset_index(drop=True).ID.loc[0] + '_yellow.png'\n    b_img = train[train.Label == label].reset_index(drop=True).ID.loc[0] + '_blue.png'\n    r = imageio.imread(TRAIN + '/' + r_img)\n    y = imageio.imread(TRAIN + '/' + y_img)\n    b = imageio.imread(TRAIN + '/' + b_img)\n    rgb = np.dstack((r,y,b))\n    class_images.append(PILImage.create(rgb))\n\nipyplot.plot_images(images=class_images, labels=list(LABELS.values()), max_images=19, img_width=300)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Sử dụng công cụ CellSegmentator để segment các tế bào trong 1 ảnh, tạo ra 1 Mask cho mỗi ID ảnh.\n\nBộ dữ liệu bảo nên sử dụng ảnh _green để huấn luyện nên segment các tế bào trong ảnh cũng sẽ segment chỉ ảnh _green.","metadata":{}},{"cell_type":"code","source":"NUC_MODEL = \"./nuclei-model.pth\"\nCELL_MODEL = \"./cell-model.pth\"\nsegmentator = cellsegmentator.CellSegmentator(\n    NUC_MODEL,\n    CELL_MODEL,\n    scale_factor=0.25,\n    padding=False,\n    multi_channel_model=True,\n)\n\nimage = paths[4]\narrays = image_to_arrays(image)\nnuclei = arrays[1]\ncell = arrays[:-1]\n\nnuc_segmentations = segmentator.pred_nuclei([nuclei])\n\ninter_step = [[i] for i in image[:-1]]\ncell_segmentations = segmentator.pred_cells(inter_step)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hình dáng Cell Mask của 1 ảnh trông như sau\n\n<img src=\"https://i.imgur.com/pkBBJOE.png\">\n\n\nTrông khá chuẩn, tuy nhiên vẫn thấy 1 vài tế bào quá gần nhau thì chỉ segment thành 1 tế bào (Ví dụ ở góc dưới bên trái 2 tế bào chỉ segment thành 1 vùng)","metadata":{}},{"cell_type":"code","source":"# Nuclei mask\nnuclei_mask = label_nuclei(nuc_segmentations[0])\n# Cell masks\ncell_nuclei_mask, cell_mask = label_cell(nuc_segmentations[0], cell_segmentations[0])\n# Plotting\n\nr = plt.imread(image[0])\nb = plt.imread(image[1])\ny = plt.imread(image[2])\n\nf, ax = plt.subplots(1, 2, figsize=(16,16))\nax[0].imshow(np.dstack((r,b,y)))\nax[0].set_title('image', size=20)\nax[1].imshow(cell_mask)\nax[1].set_title('Cell Mask', size=20)\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Huấn luyện","metadata":{}},{"cell_type":"markdown","source":"## Ghi chú\nDo việc tạo Mask cho từng ảnh khá tốn thời gian và Kaggle chỉ cho 9 tiếng 1 phiên làm việc\n\nNên em sử dụng thêm bộ dữ liệu Mask (hpa-mask) do Kaggle cung cấp để không mất thời gian tạo ra các Mask cho bộ dữ liệu.\n\nSử dụng mô hình mask-rnn từ mmdetection để huấn luyện.\n","metadata":{}},{"cell_type":"markdown","source":"Cài đặt thêm 1 vài thứ gì đó","metadata":{}},{"cell_type":"code","source":"conda install cudatoolkit=10.2","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rsync -a ../input/mmdetection-v280/mmdetection ../\n!pip install ../input/mmdetection-v280/src/mmdet-2.8.0/mmdet-2.8.0/\n!pip install ../input/mmdetection-v280/src/mmpycocotools-12.0.3/mmpycocotools-12.0.3/\n!pip install ../input/mmdetection-v280/src/addict-2.4.0-py3-none-any.whl\n!pip install ../input/mmdetection-v280/src/yapf-0.30.0-py2.py3-none-any.whl\n!pip install ../input/mmdetection-v280/src/mmcv_full-1.2.6-cp37-cp37m-manylinux1_x86_64.whl","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -r ../input/mmdetection-v280/mmdetection/requirements.txt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from itertools import groupby\nfrom pycocotools import mask as mutils\nimport numpy as np\nfrom tqdm import tqdm\nimport pandas as pd\nimport os\nimport pickle\nimport cv2\nfrom multiprocessing import Pool\nimport matplotlib.pyplot as plt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Chuẩn bị định nghĩa đường dẫn cho bộ Mask sẽ sử dụng và đọc dữ liệu ","metadata":{}},{"cell_type":"code","source":"cell_mask_dir = '../input/hpa-mask/hpa_cell_mask'    \nROOT = '../input/hpa-single-cell-image-classification/'\nMAX_THRE = 4\ntrain_or_test = 'train'\n\nimg_dir = f'../work/mmdet_v1_train'\n!mkdir -p {img_dir}\ndf = pd.read_csv(os.path.join(ROOT, 'train.csv'))\n# df = df[:100]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện đọc ảnh gốc bằng OpenCV","metadata":{}},{"cell_type":"code","source":"def read_img(image_id, color, train_or_test='train', image_size=None):\n    filename = f'{ROOT}/{train_or_test}/{image_id}_{color}.png'\n    assert os.path.exists(filename), f'not found {filename}'\n    img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)\n    if image_size is not None:\n        img = cv2.resize(img, (image_size, image_size))\n    if img.max() > 255:\n        img_max = img.max()\n        img = (img/255).astype('uint8')\n    return img","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Coco_rle_encode dùng để encode binary masks thành rles format.\n\nĐầu vào là binary masks 2 chiều và đầu ra là dữ liệu rles format với mục đích giảm kích thước lưu trữ xuống.\n\nTham khảo rles format là gì [ ở đây](https://stackoverflow.com/questions/49494337/encode-numpy-array-using-uncompressed-rle-for-coco-dataset)\n","metadata":{}},{"cell_type":"code","source":"def coco_rle_encode(mask):\n    '''\n    implement storing binary masks by rles format\n    input:\n        mask: mask of image\n    output:\n        rle encode format\n    '''\n    rle = {'counts': [], 'size': list(mask.shape)}\n    counts = rle.get('counts')\n    for i, (value, elements) in enumerate(groupby(mask.ravel(order='F'))):\n        if i == 0 and value == 1:\n            counts.append(0)\n        counts.append(len(list(elements)))\n    return rle","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện biểu diễn các Mask của từng tế bào trong ảnh\n\nTách riêng Mask thành nhiều Mask nhỏ, mỗi Mask nhỏ ứng với 1 tế bào trong ảnh.","metadata":{}},{"cell_type":"code","source":"def get_rles_from_mask(image_id):\n    '''\n    implement get rle of all masks in image\n    input:\n        image_id : id of image\n    return:\n        list of rle\n        height of image\n        width of image\n    '''\n    img = np.load(f'{cell_mask_dir}/{image_id}.npz')['arr_0']\n    rle_list = []\n    for val in np.unique(img):\n        if val == 0:\n            continue\n        binary_mask = np.where(img == val, val, 0).astype(bool)\n        counts = []\n        rle = coco_rle_encode(binary_mask)\n        rle_list.append(rle)\n    return rle_list, img.shape[0], img.shape[1]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện convert ảnh thành coco format dataset.\n\nDo sử dụng model mask-rnn của mmdectection yêu cầu dữ liệu được chuẩn hoá về coco format hoặc pascal format.\n\nỞ đây, em chọn sử dụng coco format.","metadata":{}},{"cell_type":"code","source":"def mk_mmdet_custom_data(image_id):\n    '''\n    convert data to coco format\n    input:\n        image_id: id of image\n    return:\n        annotation json files in coco format\n    '''\n    rles, height, width = get_rles_from_mask(image_id)\n    if len(rles) == 0:\n        return {\n            'filename': image_id+'.jpg',\n            'width': width,\n            'height': height,\n            'ann': {}\n        }\n    rles = mutils.frPyObjects(rles, height, width)\n    masks = mutils.decode(rles)\n    bboxes = mutils.toBbox(mutils.encode(np.asfortranarray(masks.astype(np.uint8))))\n    bboxes[:, 2] += bboxes[:, 0]\n    bboxes[:, 3] += bboxes[:, 1]\n    return {\n        'filename': image_id+'.jpg',\n        'width': width,\n        'height': height,\n        'ann':\n            {\n                'bboxes': np.array(bboxes, dtype=np.float32),\n                'labels': np.zeros(len(bboxes)),\n                'masks': rles\n            }\n    }","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện stack 3 kênh màu R G B lại với nhau theo ID của ảnh","metadata":{}},{"cell_type":"code","source":"def load_RGB_image(image_id, train_or_test='train', image_size=None):\n    '''\n    load image with each channels follow by stack them\n    '''\n    red = read_img(image_id, \"red\", train_or_test, image_size)\n    green = read_img(image_id, \"green\", train_or_test, image_size)\n    blue = read_img(image_id, \"blue\", train_or_test, image_size)\n    # using rgb only here\n    #yellow = read_img(image_id, \"yellow\", train_or_test, image_size)\n    stacked_images = np.transpose(np.array([red, green, blue]), (1,2,0))\n    return stacked_images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện show ảnh gốc với 3 kênh màu RGB, Mask của ảnh và (Mask + ảnh gốc)","metadata":{}},{"cell_type":"code","source":"def print_masked_img(image_id, mask):\n    '''\n    visualize image\n    input:\n        image_id: id of image\n        mask: mask of image with above image_id\n    '''\n    img = load_RGB_image(image_id, train_or_test)\n    \n    plt.figure(figsize=(15, 15))\n    plt.subplot(1, 3, 1)\n    plt.imshow(img)\n    plt.title('Image')\n    plt.axis('off')\n    \n    plt.subplot(1, 3, 2)\n    plt.imshow(mask)\n    plt.title('Mask')\n    plt.axis('off')\n    \n    plt.subplot(1, 3, 3)\n    plt.imshow(img)\n    plt.imshow(mask, alpha=0.6)\n    plt.title('Image + Mask')\n    plt.axis('off')\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm thực hiện tạo annotation cho ảnh.\n\nLà dữ liệu đầu vào cho quá trình huấn luyện.","metadata":{}},{"cell_type":"code","source":"def mk_ann(idx):\n    '''\n    get the annotation json files in coco format for each image\n    input:\n        idx\n    output:\n        anno: the annotation json\n        image_id : id of image\n    '''\n    image_id = df.iloc[idx].ID\n    anno = mk_mmdet_custom_data(image_id)\n    img = load_RGB_image(image_id, train_or_test)\n    cv2.imwrite(f'{img_dir}/{image_id}.jpg', img)\n    return anno, idx, image_id","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Xem thử 3 ảnh đầu tiên với 3 kênh màu RGB, Mask của ảnh và (Mask + ảnh gốc)\n\nKết quả như sau\n\n<h4>Ảnh 1<h4>\n<img src=\"https://i.imgur.com/7QhYvR8.png\">\n    \n<h4>Ảnh 2</h4>\n<img src=\"https://i.imgur.com/NFOUVqQ.png\">\n    \n        \n<h4>Ảnh 3</h4>\n<img src=\"https://i.imgur.com/WM84d1k.png\">\n    \nMask segment khá chuẩn các tế bào trong ảnh.","metadata":{}},{"cell_type":"code","source":"cell_mask_dir = '../input/hpa-mask/hpa_cell_mask'    \nfor idx in range(3):\n    image_id = df.iloc[idx].ID\n    cell_mask = np.load(f'{cell_mask_dir}/{image_id}.npz')['arr_0']\n    print_masked_img(image_id, cell_mask)\n    load_RGB_image(image_id)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Do bộ dữ liệu quá lớn và độ phức tập của bài toán cao. \n\nNhận thấy việc phân lớp nhãn trong 1 ảnh có nhiều nhãn quá sức và cũng không đủ tài nguyên để huấn luyện nên em chỉ huấn luyện các ảnh chỉ có 1 nhãn. Cũng không có quá nhiều dữ liệu với 3,4,5 nhãn, đa phần là 1,2 nhãn chiếm phần lớn trong bộ dữ liệu.\n\nCác ảnh chỉ có 1 nhãn là các ảnh không có ký tự | trong Label nên em thực hiện lấy ra các dòng dữ liệu chỉ có 1 nhãn.\n\nEm tìm được <b>10412</b> ảnh chỉ có 1 nhãn trong bộ dữ liệu\n\n<b>Một ảnh tương ứng với 4 kênh màu, tức là 4 ảnh khác  </b>\n\n<b>10412 ảnh là 41648 ảnh</b>","metadata":{}},{"cell_type":"code","source":"num_sample = df.ID.iloc[[idxx for idxx in range(len(df)) if '|' not in df['Label'].iloc[idxx]]]\nlen(list(num_sample))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Xem lại dữ liệu sau khi lấy ra các ảnh chỉ có 1 nhãn.\n\nCột đầu tiên là index của các ảnh chỉ có 1 nhãn trong bộ dữ liệu gốc phục vụ cho quá trình huấn luyện phía dưới.\n\n<img src=\"https://i.imgur.com/k2ZG2yT.png\">","metadata":{}},{"cell_type":"code","source":"num_sample.to_frame()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Do giới hạn của Kaggle là 9 tiếng, việc huấn luyện với <b>10412</b> ảnh trong 9 tiếng liên tục bị crash mà không thu được kết quả\n\nNên em chỉ lấy ra 1000 ảnh (tức là 4000 ảnh) dùng để huấn luyện tự ước tính đủ trong 9 tiếng của 1 phiên làm việc.\n\nĐọc dữ liệu và tạo annotation cho từng ảnh để làm đầu vào của quá trình huấn luyện.","metadata":{}},{"cell_type":"code","source":"p = Pool(processes=MAX_THRE)\nannos = []\nc = 0\nfor i, (anno, idx, image_id) in enumerate(p.imap(mk_ann, range(len(df)))):\n    if len(anno['ann']) > 0 and image_id in list(num_sample):\n        annos.append(anno)\n        c += 1\n    if c % 100 == 0:\n        print (idx, image_id)\n    if c > 1000:\n        break","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Chia bộ dữ liệu huấn luyện thành 2 tập train và validation theo tỉ lệ <b>(train : val) : (80 : 20)</b>","metadata":{}},{"cell_type":"code","source":"lbl_cnt_dict = df.set_index('ID').to_dict()['Label']\ntrn_annos = []\nval_annos = []\nval_len = int(len(annos)*20/100)\nfor idx in range(len(annos)):\n    ann = annos[idx]\n    filename = ann['filename'].replace('.jpg','').replace('.png','')\n    label_id = lbl_cnt_dict[filename]\n    if '|' not in label_id:\n        label_id = int(label_id)\n        ann['ann']['labels'] = np.full(len(ann['ann']['bboxes']), label_id)\n        if idx < val_len:\n            val_annos.append(ann)\n        else:\n            trn_annos.append(ann)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print (len(trn_annos))\nprint (len(val_annos))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(f'../work/mmdet_v1_full.pkl', 'wb') as f:\n    pickle.dump(annos, f)\nwith open(f'../work/mmdet_v1_trn.pkl', 'wb') as f:\n    pickle.dump(trn_annos, f)\nwith open(f'../work/mmdet_v1_val.pkl', 'wb') as f:\n    pickle.dump(val_annos, f)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Do cấu hình mặc định của mô hình mask-rnn huấn luyện không sử dụng tập validation\n\nNên em phải viết lại config để mô hình có thể huấn luyện sử dụng tập validation để tự đánh giá lại mô hình.\n\nQuá trình train được để bên dưới\n\nDo Kaggle chỉ có 9 tiếng cho 1 phiên làm việc làm việc train hay bị crash nên em có chụp lại kết quả quá trình train, chỉ chạy được đến epoch thứ 10 là bị crash do hết phiên làm việc.\n\nEm phải copy lại kết quả trong quá trình train để vẽ lại Train/Val loss\n\n\n\n<img src=\"https://i.imgur.com/FAqWUQb.png\">\n\n<img src=\"https://i.imgur.com/E6UwG8D.png\">","metadata":{}},{"cell_type":"code","source":"# config = f'configs/hpa_{exp_name}/mask_rcnn_r50_fpn_1x_coco.py'\nconfig = f'configs/mask_rcnn_unique/mask_rcnn_r50_fpn_1x_coco.py'\n\n# using --no-validate to avoid some errors for custom dataset metrics\n# additional_conf = '--no-validate '\nadditional_conf = ' --cfg-options workflow=\"[(train,1),(val,1)]\"'\nadditional_conf += f' --cfg-options optimizer.lr=0.0025'\nadditional_conf += f' --cfg-options work_dir=../working/work_dir'\nadditional_conf += f' --cfg-options load_from=../input/mmdetection-v280/pretrained/mask_rcnn_r50_fpn_2x_coco_bbox_mAP-0.392__segm_mAP-0.354_20200505_003907-3e542a40.pth'\ncmd = f'bash -x tools/dist_train.sh {config} 1 {additional_conf}'\n!cd ../mmdetection; {cmd}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3. Test","metadata":{}},{"cell_type":"markdown","source":"Định nghĩa lại một vài biến để phục vụ quá trình test.\n\nĐọc dữ liệu test dựa trên file sample_submission mà Kaggle cung cấp.","metadata":{}},{"cell_type":"code","source":"from pycocotools import _mask as coco_mask\nimport matplotlib.pyplot as plt\nimport os\nimport base64\nimport typing as t\nimport zlib\nimport random\nrandom.seed(0)\n\nexp_name = \"mmdet_v1\"\nimage_size = None\nROOT = '../input/hpa-single-cell-image-classification/'\ntrain_or_test = 'test'\ndf = pd.read_csv(os.path.join(ROOT, 'sample_submission.csv'))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Tạo annotation cho dữ liệu test vì đầu vào của mô hình sử dụng annotation dưới dạng coco format","metadata":{}},{"cell_type":"code","source":"out_image_dir = f'../work/mmdet_v1_test/'\n!mkdir -p {out_image_dir}\n\nannos = []\nfor idx in tqdm(range(len(df))):\n    image_id = df.iloc[idx].ID\n    img = load_RGB_image(image_id, train_or_test, image_size)\n    \n    cv2.imwrite(f'{out_image_dir}/{image_id}.jpg', img)\n    ann = {\n        'filename': image_id+'.jpg',\n        'width': img.shape[1],\n        'height': img.shape[0],\n        'ann': {\n            'bboxes': None,\n            'labels': None,\n            'masks': None\n        }\n    }\n    annos.append(ann)\n    \nwith open(f'../work/mmdet_v1_tst.pkl', 'wb') as f:\n    pickle.dump(annos, f)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thực hiện quá trình gán nhãn cho các ảnh trong tập test","metadata":{}},{"cell_type":"code","source":"config = 'configs/mask_rcnn_unique/mask_rcnn_r50_fpn_1x_coco.py'\nmodel_file = './epoch_10.pth'\nresult_pkl = '../work/mask_rcnn_r50_fpn_1x_epoch_10.pkl'\ncmd = f'python tools/test.py {config} {model_file} --out {result_pkl}'\n!cd ../mmdetection; {cmd}\nresult = pickle.load(open('../mmdetection/'+result_pkl, 'rb'))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Xem thử kết quả của 3 ảnh đầu tiên trong tập test.\n\nKết quả cho thấy \n* class_id: là nhãn được gán nhãn ứng với ảnh đó\n* image_id: là ID của ảnh trong tập test\n* confidence: là độ tin cậy mà mô hình gán nhãn cho tế bào trong ảnh\n\n\n<img src=\"https://i.imgur.com/O13HpT3.jpg\">","metadata":{}},{"cell_type":"code","source":"for ii in range(3):\n    image_id = annos[ii]['filename'].replace('.jpg','').replace('.png','')\n    for class_id in range(19):\n        bbs = result[ii][0][class_id]\n        sgs = result[ii][1][class_id]\n        for bb, sg in zip(bbs,sgs):\n            box = bb[:4]\n            cnf = bb[4]\n            h = sg['size'][0]\n            w = sg['size'][0]\n            if cnf > 0.3:\n                print(f'class_id:{class_id}, image_id:{image_id}, confidence:{cnf}')\n                mask = mutils.decode(sg).astype(bool)\n                print_masked_img(image_id, mask)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}