ใน ep นี้ เราจะมาสร้างโมเดลที่ใช้จำแนก โรคมะเร็งระยะลุกลาม Metastatic Cancer จากรูปภาพ Patch เล็ก ๆ ของ Whole Slide Imaging ที่ตัดมาจาก Digital Pathology Scans รูปใหญ่

มะเร็งระยะลุกลาม (Metastatic Cancer) คืออะไร

Illustration showing hematogenous metastasis. Credit https://en.wikipedia.org/wiki/File:Metastasis_illustration.jpg
Illustration showing hematogenous metastasis. Credit https://en.wikipedia.org/wiki/File:Metastasis_illustration.jpg

Metastatic Cancer หรือ มะเร็งระยะลุกลาม คือ การที่เซลล์มะเร็งแพร่กระจายลุกลามไปยังอวัยวะอื่น ๆ ภายในร่างกาย โดยมักจะแพร่กระจายไปทางต่อมน้ำเหลือง และกระแสเลือด Metastatic Cancer หรือ Metastatic Tumor คือรูปแบบหนึ่งของการแพร่กระจายจากเซลล์มะเร็งต้นตอ ไปยังส่วนต่าง ๆ ของร่างกาย

Cross section of a human liver, taken at autopsy examination, showing multiple large pale tumor deposits. The tumor is an adenocarcinoma derived from a primary lesion in the body of the pancreas. Credit https://en.wikipedia.org/wiki/File:Secondary_tumor_deposits_in_the_liver_from_a_primary_cancer_of_the_pancreas.jpg
Cross section of a human liver, taken at autopsy examination, showing multiple large pale tumor deposits. The tumor is an adenocarcinoma derived from a primary lesion in the body of the pancreas. Credit https://en.wikipedia.org/wiki/File:Secondary_tumor_deposits_in_the_liver_from_a_primary_cancer_of_the_pancreas.jpg

Metastasis คืออะไร

Metastasis ที่มักพบบ่อย. Credit https://en.wikipedia.org/wiki/File:Metastasis_sites_for_common_cancers.svg
Metastasis ที่มักพบบ่อย. Credit https://en.wikipedia.org/wiki/File:Metastasis_sites_for_common_cancers.svg

Metastasis คือ ตัวแพร่จากเซลล์มะเร็งต้นตอ ไปยังส่วนอื่น ๆ ของร่างการผู้ป่วย ส่วนของอวัยวะใหม่ที่ติดโรคมะเร็งจะเรียกว่า Metastases (Mets) ที่มักจะถูกจำแนก แยกจากเนื้องอกมะเร็ง Cancer Invasion ที่ขยายขึ้นโดยตรง และลุกลามไปยังเซลล์เนื้อเยื่อรอบ ๆ บริเวณเดียวกัน

Metastasis proven by liver biopsy (tumor (adenocarcinoma)—lower two-thirds of image). H&E stain. Credit https://en.wikipedia.org/wiki/File:Adenocarcinoma_liver_metastasis.jpg
Metastasis proven by liver biopsy (tumor (adenocarcinoma)—lower two-thirds of image). H&E stain. Credit https://en.wikipedia.org/wiki/File:Adenocarcinoma_liver_metastasis.jpg

ข้อมูล Whole Slide Imaging (WSI) ใน Dataset จาก Kaggle นี้มาจาก PatchCamelyon (PCam) benchmark dataset

Whole Slide Imaging Scanner. Credit https://commons.wikimedia.org/wiki/File:WSI_Scanner.jpg
Whole Slide Imaging Scanner. Credit https://commons.wikimedia.org/wiki/File:WSI_Scanner.jpg

Ranger Optimizer

จากที่ ep ก่อน ๆ ใช้ Optimizer ชื่อ Adam ใน ep นี้ เราจะเปลี่ยนไปใช้ Ranger ที่มาจากการรวม RAdam และ Look Ahead จะอธิบายต่อไป

DenseNet Architecture

จากที่ ep ก่อน ๆ ใช้ Model Architecture ชื่อ ResNet ใน ep นี้ เราจะเปลี่ยนไปใช้ DenseNet ที่ซับซ้อนมากขึ้น จะอธิบายต่อไป

Cross Entropy Loss + Label Smoothing

Loss Function เราจะใช้ Label Smoothing Cross Entropy Loss Function

Test-Time Augmentation (TTA)

ในการวินิจฉัย เราจะใช้เทคนิค Test-Time Augmentation (TTA) เป็นการนำเทคนิค Data Augmentation มาใช้กับ Test Set มาช่วยเพิ่มความแม่นยำ จะอธิบายต่อไป

เรามาเริ่มกันเลยดีกว่า

Open In Colab

ใน ep นี้ เราจะมาสร้างโมเดลที่ใช้จำแนก โรคมะเร็งระยะลุกลาม Metastatic Cancer จากรูปภาพ Patch เล็ก ๆ ที่ตัดมาจาก Digital Pathology Scans รูปใหญ่

ข้อมูลใน Dataset จาก Kaggle นี้มาจาก PatchCamelyon (PCam) benchmark dataset

0. Install

In [0]:
%reload_ext autoreload
%autoreload 2
%matplotlib inline

เราจะต้อง Install kaggle เพื่อ Download Dataset

In [3]:
## Colab
! curl -s https://course.fast.ai/setup/colab | bash
! pip install kaggle --upgrade
Updating fastai...
Done.
Requirement already up-to-date: kaggle in /usr/local/lib/python3.6/dist-packages (1.5.6)
Requirement already satisfied, skipping upgrade: urllib3<1.25,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from kaggle) (1.24.3)
Requirement already satisfied, skipping upgrade: tqdm in /usr/local/lib/python3.6/dist-packages (from kaggle) (4.28.1)
Requirement already satisfied, skipping upgrade: requests in /usr/local/lib/python3.6/dist-packages (from kaggle) (2.21.0)
Requirement already satisfied, skipping upgrade: python-slugify in /usr/local/lib/python3.6/dist-packages (from kaggle) (4.0.0)
Requirement already satisfied, skipping upgrade: six>=1.10 in /usr/local/lib/python3.6/dist-packages (from kaggle) (1.12.0)
Requirement already satisfied, skipping upgrade: certifi in /usr/local/lib/python3.6/dist-packages (from kaggle) (2019.9.11)
Requirement already satisfied, skipping upgrade: python-dateutil in /usr/local/lib/python3.6/dist-packages (from kaggle) (2.6.1)
Requirement already satisfied, skipping upgrade: idna<2.9,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests->kaggle) (2.8)
Requirement already satisfied, skipping upgrade: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests->kaggle) (3.0.4)
Requirement already satisfied, skipping upgrade: text-unidecode>=1.3 in /usr/local/lib/python3.6/dist-packages (from python-slugify->kaggle) (1.3)

Restart Colab Runtime after install Ranger.

In [4]:
# !pip install git+https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer

! git clone https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer
! pip install -e ./Ranger-Deep-Learning-Optimizer/ 
fatal: destination path 'Ranger-Deep-Learning-Optimizer' already exists and is not an empty directory.
Obtaining file:///content/Ranger-Deep-Learning-Optimizer
Requirement already satisfied: torch in /usr/local/lib/python3.6/dist-packages (from ranger==0.0.1) (1.3.1)
Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from torch->ranger==0.0.1) (1.17.4)
Installing collected packages: ranger
  Found existing installation: ranger 0.0.1
    Can't uninstall 'ranger'. No files were found to uninstall.
  Running setup.py develop for ranger
Successfully installed ranger
In [0]:
# ## Check GPU
# ! nvidia-smi

1. Import Library

Import Libray ที่เราต้องการใช้

In [0]:
import math
import numpy as np
import pandas as pd

from pathlib import Path
from matplotlib import cm
from matplotlib import pyplot as plt
import seaborn as sns

import fastai
from fastai.vision import *
from fastai.callbacks import *
from fastai.callbacks.mem import *

from ranger import Ranger
In [7]:
fastai.__version__
Out[7]:
'1.0.59'

2. เตรียม Path สำหรับดาวน์โหลดข้อมูล

กำหนด path ของ Config File และ Dataset ว่าจะอยู่ใน Google Drive ถ้าเราใช้ Google Colab หรือ อยู่ใน HOME ถ้าเราใช้ VM ธรรมดา และกำหนด Environment Variable ไปยังโฟลเดอร์ที่เก็บ kaggle.json

ในกรณีใช้ Colab ให้ Mount Google Drive เพื่อดึง Config File มาจาก Google Drive ส่วนตัวของเรา เมื่อเรารัน Cell ด้านล่างจะมีลิงค์ปรากฎขึ้นมาให้เรา Login กด Approve แล้ว Copy Authorization Code มาใส่ในช่องด้านล่าง แล้วกด Enter

In [8]:
dataset = 'histopathologic-cancer-detection'
dataset2 = 'tywangty/histopathologiccancerwsi'

# Google Colab
config_path = Path('/content/drive')
data_path_base = Path('/content/datasets/')

data_path = data_path_base/dataset
data_path2 = data_path_base/dataset2

from google.colab import drive
drive.mount(str(config_path))
os.environ['KAGGLE_CONFIG_DIR'] = f"{config_path}/My Drive/.kaggle"

# # VM
# config_path = Path(os.getenv("HOME"))
# data_path = config_path/"datasets"/dataset
# data_path2 = config_path/"datasets"/dataset2

# data_path.mkdir(parents=True, exist_ok=True)
# os.environ['KAGGLE_CONFIG_DIR'] = f"{config_path}/.kaggle"
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&response_type=code&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly

Enter your authorization code:
··········
Mounted at /content/drive

3. Dataset

ในเคสนี้ เราจะ Download ข้อมูล Dataset ที่เกี่ยวข้องทั้งหมดมาเก็บไว้ แบ่งเป็นรูปฟิล์ม X-Ray ขนาดต่าง ๆ ข้อมูลต้นฉบับ ข้อมูล Test Set, etc.

Dataset เราจะดึงจาก Kaggle วิธี Download kaggle.json ให้ดูจาก ep ที่แล้ว

เมื่อได้ kaggle.json มาแล้ว ในกรณีใช้ Google Colab ให้นำมาใส่ไว้ในโฟลเดอร์ My Drive/.kaggle ใน Google Drive ของเรา เป็น My Drive/.kaggle/kaggle.json ถ้าใช้ VM ให้ใส่ใน HOME/.kaggle/

สั่งดาวน์โหลด Dataset จาก Kaggle พร้อมทั้ง unzip ไว้ใน data_path

In [9]:
# !kaggle competitions download -c {dataset} -p "{data_path}"
# !kaggle datasets download {dataset2} -p "{data_path2}" --unzip
Warning: Looks like you're using an outdated API Version, please consider updating (server 1.5.6 / client 1.5.4)
Downloading sample_submission.csv.zip to /content/datasets/histopathologic-cancer-detection
  0% 0.00/1.33M [00:00<?, ?B/s]
100% 1.33M/1.33M [00:00<00:00, 90.2MB/s]
Downloading train_labels.csv.zip to /content/datasets/histopathologic-cancer-detection
  0% 0.00/5.10M [00:00<?, ?B/s]
100% 5.10M/5.10M [00:00<00:00, 46.9MB/s]
Downloading test.zip to /content/datasets/histopathologic-cancer-detection
 99% 1.29G/1.30G [00:41<00:00, 29.4MB/s]
100% 1.30G/1.30G [00:41<00:00, 34.0MB/s]
Downloading train.zip to /content/datasets/histopathologic-cancer-detection
100% 4.96G/4.98G [00:40<00:00, 133MB/s]
100% 4.98G/4.98G [00:40<00:00, 132MB/s]
Downloading histopathologiccancerwsi.zip to /content/datasets/tywangty/histopathologiccancerwsi
 80% 4.00M/5.02M [00:00<00:00, 33.8MB/s]
100% 5.02M/5.02M [00:00<00:00, 32.1MB/s]

Unzip ไฟล์ที่ดาวน์โหลดจาก Kaggle Competition

In [11]:
data_path.ls()
Out[11]:
[PosixPath('/content/datasets/histopathologic-cancer-detection/train_labels.csv'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/test'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train_labels.csv.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/test.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/sample_submission.csv'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/sample_submission.csv.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train.zip')]
In [0]:
## VM
# ! unzip -q {data_path}/histopathologic-cancer-detection.zip -d {data_path}
In [0]:
# ! unzip -q {data_path}/train.zip -d {data_path}/train
# ! unzip -q {data_path}/test.zip -d {data_path}/test
# ! unzip -q {data_path}/sample_submission.csv.zip -d {data_path}
# ! unzip -q {data_path}/train_labels.csv.zip -d {data_path}

4. Data

4.1 Image File and Label CSV

In [12]:
data_path.ls()
Out[12]:
[PosixPath('/content/datasets/histopathologic-cancer-detection/train_labels.csv'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/test'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train_labels.csv.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/test.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/sample_submission.csv'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/sample_submission.csv.zip'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train.zip')]
In [13]:
(data_path/'train').ls()[:5]
Out[13]:
[PosixPath('/content/datasets/histopathologic-cancer-detection/train/527409d75b6548b6922034239d239b63121bc26c.tif'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train/f0e72f8bdc9d74a3194576958b9f2b46d075a12f.tif'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train/81fd1cfe0f06988b09e01c5d2b25f83d5318381c.tif'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train/239e6c7942452a45d1ee37ffd5e6640ba0d591e3.tif'),
 PosixPath('/content/datasets/histopathologic-cancer-detection/train/a58e189868f5d9868f60d63ae1f9422d6ed6c2d8.tif')]
In [14]:
fig, axes = plt.subplots(4, 6, figsize=(12, 8))
for ax, f in zip(axes.flatten(), (data_path/'train').ls()[:24]):
    ax.imshow(PIL.Image.open(f), origin='lower')
    ax.axis('off')
plt.tight_layout()