保姆级教程,带你复现病理AI的经典模型CLAM(一)|项目复现·24-08-19

罗小罗同学 2024-10-09 11:31:04 阅读 62

小罗碎碎念

推文概述

复现CLAM的第一期推文

通过这期推文你首先会学会如何在服务器端使用jupyter编程,比你用其他的编译器(例如PyCharm、VS)会更加的清晰,对新手也更友好。

接着我会介绍如何进行数据预处理,以及你应该如何准备自己的数据;随后我会介绍如何对WSI进行分割并切成patches;最后,我会讲解如何利用切片级的标签进行特征提取。

注意,我这篇推文的数据只用了两张切片,前面这些步骤是没有影响的,如果想要进行后面的步骤,两张切片是不够的,因为要划分训练集、验证集和测试集。

这篇推文是所有后续项目复现的基础,一定要掌握这个流程。


如果想了解文献具体讲了什么内容,可以移步我的另一篇推文

CLAM:病理AI发展里程碑,建议每一个研究病理AI的人都了解的文章|24-08-16


模型概述

CLAM(Clustering-constrained Attention Multiple Instance Learning)是一种基于深度学习的弱监督方法,用于高效和弱监督的全切片级分析。

CLAM的工作步骤:

自动分割:CLAM首先对全切片图像进行自动分割,识别出组织区域。这通常涉及到将图像转换到HSV颜色空间,并使用饱和度通道进行阈值处理,以提取组织区域。特征提取:在分割之后,CLAM利用深度卷积神经网络(CNN)为每个分割出的补丁计算低维特征表示。这通常涉及到使用预训练的CNN模型,如ResNet50,来提取特征。注意力机制:CLAM使用注意力机制来确定每个补丁对最终切片级预测的贡献程度。这涉及到计算每个补丁的不归一化注意力分数,并将其转换为百分位数分数,然后缩放到0到1.0之间。实例级聚类:CLAM使用实例级聚类来约束和优化特征空间。具体来说,CLAM模型有多个并行的注意力分支,每个分支计算一个独特的切片级表示,该表示由网络视为多类诊断任务中某一类的强阳性证据的高度关注区域确定。分类预测:每个类别特定的切片表示被分类层检查,以获得整个切片的最终概率分数预测。模型训练:CLAM模型使用弱监督学习进行训练,只需要切片级标签,不需要像素级或补丁级注释。这使得CLAM能够高效地利用数据,并能够在训练数据有限的情况下取得良好的性能。

总的来说,CLAM通过使用注意力机制和实例级聚类,实现了高效和弱监督的全切片级分析,能够自动识别高诊断价值的子区域,并准确地对整个切片进行分类。


CLAM的最新更新

关于CLAM的最新更新,以下是关键点:

2024年4月6日

发布了UNI和CONCH,作为预训练的编码器,现在可以作为CLAM的预训练模型(后续推文中会介绍)。

请确保通过安装最新的env.yml文件,并使用相应的clam_latestconda环境,正确安装所有依赖项。


2024年3月19日

发布了UNI和CONCH,这是一对在计算病理学工作流程上表现卓越的预训练编码器,包括基于MIL的CLAM工作流程。


2021年5月24日

热图可视化脚本create_heatmaps.py现在可用,配置模板位于<code>heatmaps/configs。


2021年3月1日

由于CLAM只需要图像特征进行训练,因此不需要保存实际的图像补丁,新的流水线消除了这一开销,而是只在“补丁”过程中保存图像补丁的坐标,并在特征提取时从WSI中实时加载这些区域。

这比旧流水线快得多,通常只需1-2秒进行“补丁”,以及几分钟的时间来特征化一个WSI。

要使用新的流水线,请确保调用create_patches_fp.pyextract_features_fp.py而不是旧的create_patches.pyextract_features.py脚本。README已经更新,默认使用新的、更快的流水线。

如果您仍然希望使用旧的流水线,请参考:README_old.md。它保存组织补丁,这比使用特征嵌入要慢得多,并且会占用大量的存储空间,但如果您需要处理原始图像补丁而不是特征嵌入,它仍然很有用。


注意

最新更新默认会将图像补丁调整大小为224 x 224,然后使用预训练编码器提取特征。这一改变是为了与UNI、CONCH和其他研究中使用的评估协议保持一致。

如果您希望保留补丁生成的原始图像补丁的大小,或者使用特征提取时不同的图像尺寸,可以在extract_features_fp.py中指定--target_patch_size


一、安装

注意:我下面的操作在服务器内完成,个人电脑的操作流程一样,只是后续运行时间有差别

1-1:服务器端

首先登录服务器(个人电脑就打开终端操作),然后创建一个新的文件夹,并进入

mkdir CLAM

cd CLAM

克隆仓库

git clone https://github.com/mahmoodlab/CLAM.git

接下来,使用环境配置文件创建一个conda环境:

cd CLAM

conda env create -f env.yml

如果此时配置环境的时候,遇到了下列问题,可以遵照下列流程处理

没遇到问题就跳过,不过建议收藏,以后可能会遇到类似的问题,例如你新建一个虚拟环境,一直在solving enviroment……

image-20240815152143483

<code>#确定通道优先级

conda config --show channel_priority

#关闭通道优先级

conda config --set channel_priority false

#查看当前通道

conda config --show channels

image-20240815151751945


激活环境

<code>conda activate clam_latest

如果您想使用CONCH作为预训练的编码器,可以在环境中安装该包,通过运行以下命令:

pip install git+https://github.com/Mahmoodlab/CONCH.git

完成实验后,要停用环境:

conda deactivate clam_latest

如有任何问题,可以在交流群内讨论。


1-2:jupyter端

因为我个人比较喜欢在jupyter内写代码,不喜欢服务器黑乎乎只有代码的窗口,所以我会调用jupyter的可视化界面来辅助自己编程,如果你也喜欢这种方式,或者没有尝试过,不妨跟着我一起试试。

在终端输入

#你要记住你的jupyter是在哪个环境安装的,你激活的环境里是不会安装的

jupyter notebook --no-browser

在个人电脑的终端输入

ssh -N -L localhost:8888:localhost:8888 用户名@IP地址

输入上述代码之后,会让你输入密码,即为服务器账户密码。正确输入密码之后,打开你的浏览器,在网址栏输入localhost:8888后,进入登录界面。


进入以后,我们会发现CLAM的虚拟环境不在内核里,所以我们需要安装一下。这里提一嘴,我这里还安装了R的内核,可以用jupyter写R语言哈,之前的推文也都介绍过。

image-20240818161916786

进入你克隆的仓库,新建一个终端

image-20240818162848317

<code>#我这里是因为自己想存放一些与CLAM相关的代码,所以套了一个CLAM,你们随意

cd CLAM/CLAM

#检查一下是否进入正确位置

ls

#激活虚拟环境

conda activate clam_latest

# 在当前激活的环境中安装ipykernel,这是一个允许Jupyter Notebook使用conda环境内核的工具

conda install ipykernel

# 激活名为base的conda环境,也可以激活其他环境

conda activate base

# 在当前激活的环境中安装nb_conda_kernels,这是一个允许Jupyter Notebook识别并使用conda环境中安装的内核的工具

conda install nb_conda_kernels

然后刷新一下界面,就可以将刚刚创立的虚拟环境作为新的内核了。

image-20240818163501074


二、准备数据集

不建议一上来就用自己的数据哦,所以你可以先跟着我处理一下公开数据集,正好也趁着这个机会了解一下如何利用公开数据集。

<code>#我选的是camelyon16的数据,官网提供百度网盘的链接

https://camelyon17.grand-challenge.org/Data

按箭头指示操作

image-20240818172203324

然后上传数据到你的服务器(个人电脑端不需要这一步)

image-20240818173820177


三、WSI 分割&切片

第一步专注于分割组织并排除任何孔洞。特定幻灯片的分割可以通过调整个别参数来调整(例如,某些肉瘤可能需要考虑扩张的血管作为孔洞)。

以下示例假设以广为人知的标准格式(.svs、.ndpi、.tiff等)存储的数字全切片图像数据位于名为<code>DATA_DIRECTORY的文件夹中。

DATA_DIRECTORY/

├── slide_1.svs

├── slide_2.svs

└── ...

3-1:基础纯自动分割

# 调用create_patches_fp.py脚本,用于从源图像中创建补丁

python create_patches_fp.py \

# 指定源图像文件夹的路径

--source /home/mailab015/08-18/wsi_processing_tools/test/测试图像 \

# 指定保存生成的补丁图像的文件夹路径

--save_dir /home/mailab015/CLAM/test \

# 设置生成的补丁图像的大小为256x256像素

--patch_size 256 \

# 表示脚本会进行图像分割,即将图像分成多个部分或区域

--seg \

# 表明脚本的主要功能是创建图像补丁

--patch \

# 表示脚本在创建补丁之后,还会将这些补丁拼接回原始图像或者一个新的图像

--stitch

上述命令将使用默认参数分割DATA_DIRECTORY文件夹中的每个幻灯片,从分割的组织区域中提取所有补丁,为每个幻灯片使用其提取的补丁创建拼接重建(可选),并在指定的RESULTS_DIRECTORY生成以下文件结构:

RESULTS_DIRECTORY/

├── masks

├── slide_1.png

├── slide_2.png

└── ...

├── patches

├── slide_1.h5

├── slide_2.h5

└── ...

├── stitches

├── slide_1.png

├── slide_2.png

└── ...

└── process_list_autogen.csv

image-20240818175506386


注意

<code>masks文件夹包含分割结果(每个幻灯片一个图像)。patches文件夹包含从每个幻灯片中提取的组织补丁数组(每个幻灯片一个.h5文件,其中每个条目对应于补丁的左上角坐标)。stitches文件夹包含从拼接的组织补丁中下采样的可视化(每个幻灯片一个图像)(可选,不用于下游任务)。自动生成的CSV文件process_list_autogen.csv包含所有处理过的幻灯片的列表,以及它们使用的分割/补丁参数。

其他标志

--custom_downsample:自定义降采样的因子(不推荐,最好首先检查是否存在本地的降采样)--patch_level:从哪个下采样金字塔级别提取补丁(默认是0,最高分辨率)--no_auto_skip:默认情况下,脚本会跳过目标文件夹中已存在的补丁.h5文件,这个切换可以用来覆盖这种行为

参数模板

bwh_biopsy.csv:用于分割在BWH扫描的活检幻灯片(使用Hamamatsu S210和Aperio GT450扫描)bwh_resection.csv:用于分割在BWH扫描的切除幻灯片tcga.csv:用于分割TCGA幻灯片

只需将模板文件的名称传递给--preset参数,例如,要使用活检模板(biopsy template):

这将使用bwh_biopsy.csv中指定的参数来处理您的数据。

python create_patches_fp.py --source DATA_DIRECTORY --save_dir RESULTS_DIRECTORY --patch_size 256 --preset bwh_biopsy.csv --seg --patch --stitch


3-2:自定义默认分割参数(可选)

对于高级使用,除了使用脚本create_patches_fp.py中定义的默认、单个参数集之外,用户还可以根据数据集定义自定义的参数模板。这些模板应存储在presets文件夹下,包含分割和补丁期间使用的每个参数的值。

分割参数列表

seg_level:在哪个下采样级别上对WSI进行分割(默认:-1,使用WSI中最接近64x下采样的下采样级别)sthresh:分割阈值(正整数,默认:8,使用更高的阈值会导致前景更少,背景检测更多)mthresh:中值滤波大小(正奇数,默认:7)use_otsu:使用Otsu方法而不是简单的二值阈值(默认:False)close:在初始阈值处理后应用的额外形态学闭合(正整数或-1,默认:4)

用户可以根据自己的需求和数据集的特点,为这些参数设置不同的值,以获得最佳的分割效果。


轮廓过滤参数列表

a_t:组织面积过滤阈值(正整数,用于确定检测到的前景轮廓的最小大小,相对于参考的512 x 512大小的补丁,在级别0,例如,一个值为10意味着只处理大于10个512 x 512大小补丁的前景轮廓,默认:100)a_h:孔洞面积过滤阈值(正整数,用于确定检测到的前景轮廓中的孔洞/空腔的最小大小,同样相对于512 x 512大小的补丁,在级别0,默认:16)max_n_holes:每个检测到的前景轮廓考虑的最大孔洞数量(正整数,默认:10,更高的最大值会导致更准确的补丁,但会增加计算成本)

这些参数用于在分割后的组织区域中进一步过滤和选择前景轮廓,以优化后续的补丁提取过程。用户可以根据自己的需求和数据集的特点,为这些参数设置不同的值。例如,如果您的数据集包含大量小孔洞,您可能需要调整a_hmax_n_holes的值,以避免在前景轮廓中包含这些小孔洞。


分割可视化参数列表

vis_level:用于可视化分割结果的下采样级别(默认:-1,使用WSI中最接近64x下采样的下采样级别)line_thickness:用于绘制分割结果的线条粗细(正整数,以像素为单位,表示在级别0时绘制的线条所占用的像素数,默认:250)

这些参数用于在WSI上可视化分割结果,以便用户可以直观地检查分割的质量。用户可以根据自己的需求和数据集的特点,为这些参数设置不同的值。例如,如果分割结果中的线条太细,可能难以在WSI上清晰地看到,用户可以增加line_thickness的值以提高可见性。


补丁化参数列表

use_padding:是否对幻灯片的边缘进行填充(默认:True)contour_fn:轮廓检查函数,用于决定一个补丁是否应被视为前景或背景(可选择’four_pt’ - 检查补丁中心周围的小网格中的四个点是否都在轮廓内,‘center’ - 检查补丁中心是否在轮廓内,‘basic’ - 检查补丁的左上角是否在轮廓内,默认:‘four_pt’)

这些参数用于在分割后的组织区域中提取补丁。用户可以根据自己的需求和数据集的特点,为这些参数设置不同的值。例如,如果某些补丁经常包含非组织区域(例如,由于切片制备过程中的污染),用户可能需要调整contour_fn的值,以更准确地确定哪些补丁应被视为前景。


3-3:两步运行(可选)

为了确保高质量的组织分割和提取相关的组织补丁,用户可以选择先执行分割(通常每张幻灯片大约需要1秒),检查分割结果,并根据需要调整特定幻灯片的参数,然后使用调整后的参数提取补丁。

也就是说,首先运行:

python create_patches_fp.py --source DATA_DIRECTORY --save_dir RESULTS_DIRECTORY --patch_size 256 --seg

这将只执行分割,而不提取补丁。分割完成后,用户可以手动检查每个幻灯片的分割结果,并根据需要调整分割参数。然后,用户可以再次运行CLAM脚本,这次使用调整后的参数来提取补丁。

上述命令将使用默认参数分割DATA_DIRECTORY中的每个幻灯片,并生成csv文件,但不会立即补丁(patchesstitches文件夹将为空)。

csv文件可以针对特定幻灯片进行调整,并通过–process_list CSV_FILE_NAME传递给脚本,以便脚本使用用户更新的规格。在调整分割参数之前,用户应先复制csv文件并为其指定新名称(例如,process_list_edited.csv),因为否则下次运行命令时会覆盖具有默认名称的文件。

然后,用户可以选择通过修改csv文件中相应字段的值来调整特定幻灯片的参数。process列存储了一个二进制变量(0或1),用于指示脚本是否应处理特定幻灯片。这允许用户只打开选择的几张幻灯片,以快速确认调整后的参数是否产生满意的结果。

例如,要使用用户更新的参数重新分割slide_1.svs,请根据需要修改其字段,将process单元格更改为1,保存csv文件,并将其名称传递给上述命令:

python create_patches_fp.py --source DATA_DIRECTORY --save_dir RESULTS_DIRECTORY --patch_size 256 --seg --process_list process_list_edited.csv

当对分割结果满意时,用户应将需要处理的幻灯片的process单元格更改为1,保存csv文件,并使用保存的csv文件进行补丁处理(就像在完全自动化的运行用例中一样,只需添加额外的csv文件参数):

python create_patches_fp.py --source DATA_DIRECTORY --save_dir RESULTS_DIRECTORY --patch_size 256 --seg --process_list CSV_FILE_NAME --patch --stitch

这样,脚本将根据csv文件中的参数和设置,对所有标记为需要处理的幻灯片进行补丁提取和后续处理。

这种两步运行的方法允许用户在分割阶段手动调整参数,并在确认分割结果后,使用这些调整后的参数进行最终的补丁提取,从而提高分割和补丁提取的质量。


四、使用切片级标签进行特征提取

注意,以下实验会调用GPU

image-20240818180744479

image-20240818180704516

<code># 设置环境变量CUDA_VISIBLE_DEVICES,指定使用的GPU设备编号为0

CUDA_VISIBLE_DEVICES=0

# 调用extract_features_fp.py脚本,用于从指定的数据集中提取特征

python extract_features_fp.py \

# 指定存储HDF5格式数据的目录路径

--data_h5_dir /home/mailab015/CLAM/test \

# 指定存储切片图像的目录路径

--data_slide_dir /home/mailab015/08-18/wsi_processing_tools/test/测试图像 \

# 指定CSV文件的路径,就是上一步生成的csv文件

--csv_path /home/mailab015/CLAM/test/process_list_autogen.csv \

# 指定提取的特征将保存的目录路径

--feat_dir /home/mailab015/CLAM/testFEATURES_DIRECTORY \

# 设置批处理大小,即每次处理的样本数量

--batch_size 512 \

# 指定切片图像文件的扩展名(你的是svs,就改成.svs)

--slide_ext .tif

执行上述代码以后报错,在尝试从Hugging Face Hub下载预训练模型时出现了网络连接问题。

image-20240818182916089

在执行代码前添加下列代码即可解决问题

<code>import os

os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"

image-20240818183352776

上述代码产生以下文件结构:

<code>FEATURES_DIRECTORY/

├── h5_files

├── slide_1.h5

├── slide_2.h5

└── ...

└── pt_files

├── slide_1.pt

├── slide_2.pt

└── ...

每个.h5文件包含一组提取的特征及其补丁坐标。为了加快训练速度,每个幻灯片还创建了一个.pt文件,其中只包含补丁特征。CSV文件应包含一个幻灯片文件名列表(不带文件名扩展名)以供处理。


五、使用UNI或CONCH模型(可选)

这一部分不是本期推文的重点,后面会有推文详细介绍如何使用,感兴趣的可以自己先研究一下

如果您打算使用UNI或CONCH模型,首先需要访问它们的HF页面来请求和下载模型权重。

UNI: https://huggingface.co/MahmoodLab/UNICONCH: https://huggingface.co/MahmoodLab/CONCH

成功下载模型检查点后,您需要在运行特征提取脚本之前设置CONCH_CKPT_PATHUNI_CKPT_PATH环境变量到预训练编码器的检查点路径。

例如,如果您已将预训练的UNI和CONCH检查点分别下载并放置在checkpoints/conchcheckpoints/uni文件夹中,您可以设置环境变量如下:

export CONCH_CKPT_PATH=checkpoints/conch/pytorch_model.bin

export UNI_CKPT_PATH=checkpoints/uni/pytorch_model.bin

运行extract_features_fp.py时,也请将--model_name设置为’uni_v1’或’conch_v1’以使用相应的编码器。

请注意,这些编码器模型(尤其是UNI,它使用ViT-L)比默认的ResNet50编码器在计算上更昂贵,需要更多的GPU内存,所以如果您用完GPU内存,预计运行时间会更长,批次大小会相应减少。UNI将产生1024维特征,而CONCH将产生512维特征。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。