mcpField
D
digital-pathology

digital-pathology

github.com/awslabsデータ・データベース6880 回インストール4 週間前に更新
リポジトリ

digital-pathology について

digital-pathology は、病理画像解析やモデル展開に使う全スライド画像(WSI)処理コードを生成するためのスキルです。TIAToolbox の処理手順、特徴抽出、CAMELYON データセット、SageMaker への展開方法を扱います。

主な機能

  1. 01WSI の検査とタイル分割
  2. 02組織マスクと染色正規化
  3. 03TIAToolbox による特徴抽出
  4. 04H-optimus-0 の利用ガイダンス
  5. 05CAMELYON データセット処理
  6. 06SageMaker への展開パターン

活用シーン

  1. 01WSI のタイル分割・特徴抽出パイプライン構築
  2. 02CAMELYON データによるスライド分類モデルの学習
  3. 03組織領域の処理と染色の正規化
  4. 04WSI モデルのバッチスコアリングへの展開

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/awslabs/hcls-agent-skills --skill digital-pathology

インストール後、Claude Code で/digital-pathologyを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

.gitkeep
hoptimus0-endpoint/
build_and_push.sh
Dockerfile
inference.py

詳細

デジタル病理

概要

このスキルでは、全スライド画像(WSI)パイプライン向けの、正しく実行可能なコードをエージェントが生成できるようにします。TIAToolbox CLI と Python API、基盤モデル H-optimus-0、標準的な組織→タイル→特徴量→集約→予測のパターン、CAMELYON データセット、規制対象ワークロード向けの SageMaker デプロイパターンを扱います。

スライド I/O を再実装するのではなく、TIAToolbox のプリミティブ(WSIReader、PatchPredictor、DeepFeatureExtractor)をデフォルトで使用します。タスクで別途指定されていない限り、デフォルトでは 0.5 mpp/224×224 の H-optimus-0 を使用します。

使用方法

ユーザーから次の依頼があった場合に、このスキルを呼び出します。

  • WSI(SVS、NDPI、MRXS、ピラミッド TIFF)を検査、タイル化、または染色正規化する。
  • 病理学基盤モデルで特徴量を抽出する。
  • CAMELYON または同様のコホートで、スライドレベルの分類器を構築する。
  • WSI モデルを AWS SageMaker にデプロイする。

解像度、モデル、または出力成果物が曖昧な場合にのみ、詳細を確認してください。それ以外の場合は、「解像度のルール」セクションのデフォルトを適用します。

応答形式

  • 必要なコマンドまたはコードを最初に示し、その後に説明を加える
  • 次の順に構成する:入力の確認 → 動作するコード → 主要なパラメーターの説明 → 注意点
  • タスクごとに、完全に動作する例を 1 つ示す。すべての代替案は示さない
  • コードコメントは最小限にし、実用的な内容(存在理由ではなく、何をするか)にする
  • 目安:コード 50~100 行と、簡潔な説明

基本概念

  • ピラミッド型 WSI:複数解像度の画像(レベル)。baseline = レベル 0(ネイティブ、最高解像度)。指定には resolution と units ∈ {mpp, power, level, baseline} を使用します。
  • mpp:1 ピクセルあたりのマイクロメートル数。0.5 mpp ≈ 20×、0.25 mpp ≈ 40×。ダウンサンプル率 = baseline_mpp / target_mpp。
  • 組織マスク:低解像度(例:1.25×または 4 mpp)で計算する二値前景マスク。背景タイルを除外するために使用します。
  • パッチ/タイル:ターゲット mpp で読み込む固定サイズの切り出し画像(例:224×224)。モデル入力として使用します。
  • 基盤モデルの埋め込み:事前学習済み ViT によるタイルごとの特徴ベクトル(H-optimus-0 → 1536 次元)。
  • 集約:タイル特徴量からスライドレベルの予測を行います(ABMIL、CLAM、TransMIL、SlideGraph)。

クイックリファレンス — 標準パイプライン

WSI 分類タスクには、このエンドツーエンドのパターンをコピーして調整してください。

import torch
from tiatoolbox.wsicore.wsireader import WSIReader
from tiatoolbox.models.architecture.vanilla import TimmBackbone
from tiatoolbox.models.engine.semantic_segmentor import IOSegmentorConfig
from tiatoolbox.models.engine.patch_predictor import IOPatchPredictorConfig
from tiatoolbox.models import DeepFeatureExtractor

SLIDE = "slide.svs"
OUT = "./out"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

# 1. Inspect
reader = WSIReader.open(SLIDE)
info = reader.info.as_dict()
print(info["mpp"], info["level_dimensions"])

# 2. Tissue mask (Otsu at low res — do NOT pass as external mask)
mask_reader = reader.tissue_mask(method="otsu", resolution=4, units="mpp")

# 3. Tile + extract H-optimus-0 features @ 0.5 mpp, 224x224
ioconfig = IOPatchPredictorConfig(
    input_resolutions=[{"units": "mpp", "resolution": 0.5}],
    patch_input_shape=[224, 224],
    stride_shape=[224, 224],
)
extractor = DeepFeatureExtractor(
    model=TimmBackbone("H-optimus-0", pretrained=True),
    batch_size=16,
    num_loader_workers=4,
)
output = extractor.run(
    images=[SLIDE],
    masks=[mask_reader],
    patch_mode=False,
    ioconfig=ioconfig,
    save_dir=OUT,
    device=DEVICE,
)
# output[0] -> (positions.npy, features.npy)

次に、features.npy に対して集約(ABMIL/SlideGraph/平均プーリング)を行い、スライドレベルの予測をします。

TIAToolbox CLI

すべての CLI コマンドで、--img-input(ファイルまたはディレクトリ)、--output-path、--resolution、--units、--batch-size、--device cuda を指定できます。

# Slide metadata
tiatoolbox slide-info --img-input slide.svs --mode show

# Tissue mask (binary PNG)
tiatoolbox tissue-mask --img-input slide.svs --output-path ./mask --method otsu \
  --resolution 1.25 --units power

# Tile classification with built-in ResNet18 on Kather100k
tiatoolbox patch-predictor --img-input slide.svs \
  --pretrained-model resnet18-kather100k \
  --output-path ./pred --batch-size 32 --device cuda \
  --resolution 0.5 --units mpp

# Stain normalization (Reinhard / Macenko / Vahadane)
tiatoolbox stain-norm --img-input tiles/ --method reinhard --output-path ./norm

入力があらかじめ抽出された PNG タイルの場合は、--units baseline を使用して「unknown scale」警告を回避します。

TIAToolbox Python API

WSIReader
from tiatoolbox.wsicore.wsireader import WSIReader

reader = WSIReader.open("slide.svs")
reader.info.as_dict()                              # mpp, levels, vendor
reader.slide_dimensions(resolution=0.5, units="mpp")

tile = reader.read_rect(
    location=(10000, 10000),    # baseline coords
    size=(224, 224),
    resolution=0.5, units="mpp",
)
region = reader.read_bounds(
    bounds=(0, 0, 4096, 4096),
    resolution=2.0, units="mpp",
)
mask = reader.tissue_mask(method="otsu", resolution=4, units="mpp")
PatchPredictor
from tiatoolbox.models import PatchPredictor
from tiatoolbox.models.engine.patch_predictor import IOPatchPredictorConfig

ioconfig = IOPatchPredictorConfig(
    input_resolutions=[{"units": "mpp", "resolution": 0.5}],
    patch_input_shape=[224, 224],
    stride_shape=[224, 224],
)
predictor = PatchPredictor(pretrained_model="resnet18-kather100k", batch_size=32)
out = predictor.run(
    images=["slide.svs"], masks=[mask],
    patch_mode=False, ioconfig=ioconfig,
    save_dir="./pred", device="cuda",
)
DeepFeatureExtractor + TimmBackbone
from tiatoolbox.models import DeepFeatureExtractor
from tiatoolbox.models.architecture.vanilla import TimmBackbone

extractor = DeepFeatureExtractor(
    model=TimmBackbone("H-optimus-0", pretrained=True),
    batch_size=16, num_loader_workers=4,
)
SlideGraph の構築
import numpy as np
from tiatoolbox.tools.graph import SlideGraphConstructor

positions = np.load("out/0.position.npy")   # (N, 4) x1,y1,x2,y2
features  = np.load("out/0.features.npy")   # (N, D)
graph = SlideGraphConstructor.build(
    positions=positions[:, :2], features=features,
)
# graph -> {"x": features, "edge_index": (2,E), "coords": (N,2)}
染色正規化
from tiatoolbox.tools.stainnorm import get_normalizer

norm = get_normalizer("reinhard")   # or "macenko", "vahadane"
norm.fit(target_tile)               # RGB ndarray HxWx3
normed = norm.transform(source_tile)

H-optimus-0 基盤モデル

11 億パラメーターの ViT-G/14 です。入力は 0.5 mpp の 224×224 RGB、出力は 1536 次元の埋め込みです。ライセンスにはアクセス制限があります。Hugging Face で規約に同意し、huggingface-cli login を実行してください。

timm の直接使用
import timm, torch
from torchvision import transforms

model = timm.create_model(
    "hf-hub:bioptimus/H-optimus-0",
    pretrained=True,
    init_values=1e-5,
    dynamic_img_size=False,
).eval().to("cuda")

preprocess = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(
        mean=(0.707223, 0.578729, 0.703617),
        std=(0.211883, 0.230117, 0.177517),
    ),
])

with torch.inference_mode(), torch.autocast("cuda", dtype=torch.float16):
    feats = model(preprocess(tile).unsqueeze(0).to("cuda"))   # (1, 1536)

fp16 自動混合精度を使用する 24 GB GPU では、batch_size=16 を使用します。TIAToolbox が正しい前処理を自動的に適用するため、DeepFeatureExtractor 内では TimmBackbone("H-optimus-0", pretrained=True) を優先してください。

解像度のルール

モデルmppパッチサイズ
H-optimus-0 / UNI / Prov-GigaPath0.5224×224
HoVer-Net (PanNuke)0.25256×256
SlideGraph CNN features0.25512×512
組織マスク(Otsu)4 mpp または 1.25×—

ダウンサンプル率 = baseline_mpp / target_mpp。0.25 mpp のスライドを 0.5 mpp で処理する場合、ダウンサンプル率は 2 です。

CAMELYON データセット

  • 形式:ピラミッド型 .tif。OpenSlide 互換で、ベースラインのサイズは約 100 000 × 100 000 px です。
  • アノテーション:ASAP XML。ポリゴン座標はベースライン(レベル 0)ピクセル単位です。
  • CAMELYON16:トレーニング用スライド 270 枚(normal/ + tumor/)とテスト用スライド 130 枚があり、ラベルは reference.csv にあります。タスク:スライド単位の腫瘍分類と腫瘍セグメンテーション。
  • CAMELYON17:100 人の患者にわたる 1000 枚のスライド(患者 1 人あたり 5 枚)。患者単位の pN ステージは stages.csv にあります。公式の 5 分割は患者単位です。スライド単位で分割しないでください。
import xml.etree.ElementTree as ET
tree = ET.parse("slide.xml")                 # ASAP format
for ann in tree.iter("Annotation"):
    pts = [(float(c.get("X")), float(c.get("Y")))
           for c in ann.iter("Coordinate")]   # baseline coords

SageMaker のデプロイ

WSI はギガピクセル規模です。呼び出し経路を通じて生バイト列を送信しないでください。リクエストには S3 URI を渡し、コンテナが s3fs/boto3 経由で読み込むようにします。

  • エンドポイントの種類:非同期推論(長時間実行、リクエスト単位)またはバッチ変換(コホートのスコアリング)。
  • ベースコンテナ:763104351884.dkr.ecr.<region>.amazonaws.com/pytorch-inference:2.x-gpu-py310 を拡張します。
  • Apt パッケージ:openslide-tools libpixman-1-dev libvips。
  • Pip:tiatoolbox timm huggingface_hub s3fs。
  • インスタンス:H-optimus-0 fp16(24 GB A10G)には、最低でも ml.g5.2xlarge を使用します。バッチには ml.g5.12xlarge を使用します。
  • 非同期設定:invocations_timeout=3600、max_concurrent_invocations_per_instance=2。
from sagemaker.async_inference import AsyncInferenceConfig
async_config = AsyncInferenceConfig(
    output_path="s3://bucket/async-out/",
    max_concurrent_invocations_per_instance=2,
)
predictor = model.deploy(
    instance_type="ml.g5.2xlarge", initial_instance_count=1,
    async_inference_config=async_config,
)
predictor.predict_async(input_path="s3://bucket/slides/slide.svs")

Dockerfile の概要:

FROM 763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-inference:2.3.0-gpu-py310
RUN apt-get update && apt-get install -y openslide-tools libpixman-1-dev libvips \
 && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir tiatoolbox timm huggingface_hub s3fs

よくある間違い

  • 誤り: OpenSlide で古い pixman ライブラリ(<0.40)を使用する
    正しい方法: apt-get install libpixman-1-dev を実行して再ビルドするか、libvips ≥ 8.12 を使用します
    理由: レンダリングのバグにより、read_rect からすべて黒いタイルが返されます

  • 誤り: スライドのネイティブ mpp より細かい解像度を指定する
    正しい方法: より粗い resolution を使用するか、先に reader.info.mpp を確認します
    理由: UserWarning: Scale > 1 が発生し、アップサンプリング(補間)されたデータが生成されます

  • 誤り: ゲート付きモデルの利用規約に同意せずに H-optimus-0 を読み込もうとする
    正しい方法: Hugging Face のモデルページで利用規約に同意してから、huggingface-cli login を実行します
    理由: OSError: 401 認証エラーが発生します

  • 誤り: DeepFeatureExtractor で GPU メモリに対して大きすぎるバッチサイズを使用する
    正しい方法: batch_size を小さくし(16→8→4)、fp16 autocast が有効になっていることを確認します
    理由: CUDA のメモリ不足エラーが発生します

  • 誤り: ピラミッド型でない TIFF を OpenSlide に渡す
    正しい方法: まず vips tiffsave in.tif out.tif --tile --pyramid --compression jpeg で変換します
    理由: OpenSlide はピラミッド型の形式を必要とするため、OpenSlideUnsupportedFormatError が発生します

  • 誤り: WSI のピラミッドと形状が一致しない NumPy 配列を外部マスクとして渡す
    正しい方法: reader.tissue_mask(...) を直接使用し、返された reader オブジェクトを渡します
    理由: 解像度/形状が一致せず、DimensionMismatchError が発生します

  • 誤り: 解像度の単位を指定せずに PNG タイルを処理する
    正しい方法: units="baseline" と明示的な resolution=1.0 を渡します
    理由: タイルには mpp メタデータがなく、「unknown scale」警告が発生します

  • 誤り: CAMELYON17 のデータを患者単位ではなくスライド単位で分割する
    正しい方法: 公式プロトコルに従い、patient_id 単位で分割します(5 分割)
    理由: 各患者には 5 枚のスライドがあるため、患者データのリークが発生します

  • 誤り: 特徴抽出時に H-optimus-0 の正規化(平均/標準偏差)を省略する
    正しい方法: 正規化が自動で適用される TimmBackbone を使用するか、平均/標準偏差を明示的に適用します
    理由: 適切な入力正規化を行わないと、特徴がランダムに見え、AUC が低くなります

  • 誤り: アノテーション座標に誤ったピラミッドレベルを使用する
    正しい方法: ASAP XML の座標は常にベースラインレベルです。低解像度で読み込む場合は座標をスケーリングします
    理由: レベルの不一致を考慮しないと、座標が 2 倍または 4 倍ずれます

最小限の依存関係

tiatoolbox>=1.5
timm>=1.0
torch>=2.1
openslide-python
huggingface_hub

システム:openslide-tools、libpixman-1-dev、libvips(ピラミッド型でない TIFF の変換用)。

参考文献

コメント