论文代码复现之DSMIL (Dual-stream Multiple Instance Learning Network)

参考了“天天炫橘子”的博文:DSMIL论文代码复现,Dual-stream Multiple Instance Learning Network for Whole Slide Image Classification with-CSDN博客

论文原文和原始代码:

https://arxiv.org/abs/2011.08939

GitHub - binli123/dsmil-wsi: DSMIL: Dual-stream multiple instance learning networks for tumor detection in Whole Slide Image

第一点:新建虚拟环境,并根据env.yml配置虚拟环境(对应Github上的Installation)

操作和心得:试了它的conda env create -d dsmil...,但是不太行,有"conda Malformed version string ‘~’: invalid character(s)"报错,联系管理员也不太好解决。但我确定conda create肯定是没错的,就没有必要在这上面纠结了。我的做法是先conda creaate -d dsmil python=3.6,然后再根据env.yml里需要的东西分别pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple。值得注意的是,如果直接安最新的opencv-python,会出现假死的情况,大概要等一个多小时,因为opencv-python要编译一大堆东西。如果你不想费劲等一个多小时,那就直接安装opencv-python==3.4.2.17,几秒钟就装好,用起来也没有什么问题。如果有问题就到时候再升级吧。

第二点:下载数据集(对应Github上的Download feature vectors for MIL network)

操作和心得:我没有通过代码下载,直接打开download.py文件,在里面找到下载链接下载,一共7个下载链接。下载比较耗时,需要特殊上网技能,大概一个下午完成,主要是dataset文件很大(如果有同学需要的话可以留言或者联系我,我用百度网盘分享给你)

第三点:解压数据集

操作和心得:我是先将压缩包传到服务器上,然后通过unzip xxx.zip ./dir来解压,注意,解压路径要参考download.py!其中c16-dataset-test.zip需要手动解压,直接解压会报错。这点在DSMIL的github网站上也提到了。

另外,一大发现是datasets中的mil的数据集竟然不是图像格式,而是一种神奇的格式(.svm和.svm.info),我以为数据集的格式都是图像,这个格式让我大受震撼。

第四点:使用给定数据集和权重进行训练(对应Github上的Training on default datasets)

操作和心得:在linux服务器上,只要数据集和权重文件路径放的对,能直接跑通。但是需要注意:① epoch可以先用小的试一下,看看会出什么结果,比如设置epoch=5看看。② 如果想同时执行多个train的指令的话(我同时想把tcga和camelyon16都运行了),我强烈建议你先运行一个,看到weight/%Y%m%d文件夹下有权重文件保存之后再执行另一个命令,否则就像我面对的一样,这两个指令保存的结果相互覆盖,分不清哪个是哪个了,很凉凉。此外,我一口气设置了epoch=200,等了快一天只运行到120/200,这个和服务器性能也有一定关系。

MIL benchmark datasets:没太看懂在干什么,很快就跑通了

python train_mil.py [--datasets]  # musk1, musk2, elephant, fox, tiger

WSI datasets:TCGA和Camelyon16先后运行,不要同时运行;注意设置epoch,可以先设置小的再设置大的。

python train_tcga.py --dataset=Camelyon16 --num_classes=1 --feats_size=512 --num_epochs=10

作者在readme中对arguments进行了特别说明:这里的num_classes指的是non-negative classes,对于Camelyon16而言,二分类中tumor就是positive,normal就是negative,所以non-negatived的类别数量就是1。另外,此处的feats_size指的是feature vector的size,并且因CNN主干网络的不同而不同(也就对应代码里的ResNet18和34是512,ResNet50和101对应2048)

另外,这里训练的是aggregator,是用于测试的两个关键权重之一(另一个是embedder)。此步生成的文件是./weights/xxx/x.pth。但是,如果你在下一步测试并生成detection maps时下载权重的话,实际上没有用到此步生成的pth文件,而是直接用作者给的权重测试了。以Camelyon16数据集为例,如果希望用训练的权重,则需要将此步生成的pth文件复制到./test-c16/weights里并重命名为aggregator.pth。

第五点:测试并生成detection maps(对应Github上的Testing and generating detection maps from WSI)

对于TCGA数据集,先执行切patch(python test_crop_single.py --dataset=tcga),然后执行python testing_tcga.py时,有报错1:

  File "testing_tcga.py", line 87, in test
    bag_prediction = (bag_prediction+max_prediction)/2
TypeError: unsupported operand type(s) for +: 'numpy.ndarray' and 'Tensor'

报错1的解决办法:

将原有代码:

bag_prediction = (bag_prediction+max_prediction)/2

变更为:

bag_prediction = (torch.from_numpy(bag_prediction).to('cuda:0')+max_prediction)/2

然后又有报错2:

  File "testing_tcga.py", line xxxxx, in test
    attentions = attentions.cpu().numpy()
AttributeError: 'numpy.ndarray' object has no attribute 'cpu'

报错2的解决办法:

将原有代码:

attentions = attentions.cpu().numpy()

变更为:

if isinstance(attentions, torch.Tensor):
                attentions = attentions.cpu().numpy()

debug完后代码能够调通,会在test/output文件夹下生成5个图片(其中第一张图片之所以是全黑色,是因为它的诊断结果是benign,即良性的):

对于Camelyon16数据集,先执行切patch(python test_crop_single.py --dataset=c16),然后执行python testing_c16.py,直接运行,在test-c16/output中直接运行得到结果(这四张图都有颜色,说明这四张图都诊断为肿瘤):

第六点:使用WSI数据从头训练(对应Github上的Processing raw WSI data)

1、下载WSI 略 本人使用Camelyon16,数据集很大,在Camelyon16官网有百度网盘链接

2、切patch 按要求来即可,完成后需要看看这个文件夹分类对不对。此处注意,deepzoom_tiler.py中默认根目录就是dsmil工程文件,因此保存tiler是在./WSI下面,数据集也应该放在./WSI下面。如果你的数据集和工程文件不在一起,教你一招:

当一个磁盘塞不下所有数据集 但代码里希望该数据集在该目录下的时候,可以建立软连接:ln -s dir_source dir_target,这样dir_target下就有一个链接文件,会链接到dir_source,不需要将整个数据集移动到dir_target下了。

实际上,这个方式也是我非常推荐的方式。数据集和工程文件分离单独存放。

3、训练SimCLR

需要安装tensorboard!天啊!回头看看tensorboard的图生成在哪里,看看能不能查看!据我观察,tensorboard的图是保存在./simclr/runs里面,y64文件就是,可以用tensorboard打开。

注意,如果是使用Camelyon16的话,不能只运行:cd simclr; python run.py

而要运行:cd simclr; python run.py --dataset Camelyon16

安装apex 注意不要安装最新的,可能会有报错。建议下载22.04-dev版本的apex,感谢墨大哥!(已解决)安装apex——报错:AttributeError: module ‘torch.distributed‘ has no attribute ‘_all_gather_base‘_attributeerror: module 'torch.distributed' has no -CSDN博客

使用pip install -v --disable-pip-version-check --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./完整安装会报错,但是去掉cpp_ext和cuda_ext,只安装python是ok的,不纠结了,能装上就行。

直接运行run.py可能会出现报错TypeError: 'int' object is not iterable,这里是因为代码读取的config.yaml的gpu_ids初始为(0),但是eval('(0)')为整数0,而不是tuplue,所以报错。建议直接将gpu_ids改为(0,1)或者其他只要不是一个就行。如果非要1个,需要自己把run.py和simclr.py中关于gpu_ids的设置给手动改一下n_gpu仍然是1,不用改),能用两个gpu避免报错还是最好在config.yaml中改为用两个gpu,最好不在run.py里改。此外,在修改gpu号的时候务必同时把config.yaml中的n_gpu也同步成对应的gpu数量!要不然就白忙活了。

此外,batch_size也太大了,config.yaml里是4096,运行报错RuntimeError: CUDA out of memory ,得把batch_size改小一些,比如2048或者1024或者512...() 特别注意,修改batch_size不要在run.py里改config['batch_size'],否则运行到后面会发现不一致而报错,一定要在config.yaml里修改batch_size!

另外,如果希望知道训练的epoch进展到哪里了,极度建议在sinclr.py的第95行for epoch_counter in range(self.config['epochs']) 下面加上:

import logging
import time
cur_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())
logging.basicConfig(level=logging.INFO)
logging.info(epoch_counter)
logging.info(cur_time)
print('epoch:', epoch_counter, 'time:', cur_time)

这样通过前台查看输出或者后台查看nohup_simclr.log知道进展到哪里了(注意,如果你使用print且用nohup的话,后天是看不到输出的,因为你执行的是run.py,而run.py调用的simclr.py,所以simclr.py的打印是不记录在nohup_simclr.log里的)。

时间很长需要后台训练的话,可以执行:nohup python run.py --dataset Camelyon16 >nohup_simclr.log 2>&1 &

训练完成后,查看./simclr/runs里的events.out.tfevents文件:

确认电脑安装了tensorboard:

pip install tensorboard -i https://pypi.douban.com/simple

可视化:

tensorboard --logdir=D:\...simclr\runs\Febxxx --port=8008

D:\xxx是events.out.tfevents文件所在的文件目录;--port=8008 是开启可视化的“地址”,修改 --port= 后面的数字可以同时可视化多个不同的events.out.tfevents文件

观察到cosine_lr_decay, train loss, valid loss三个曲线。

4、按照说明,若训练Camelyon16且为单放大倍数,想用多gpu,使用指令:

python compute_feats.py --dataset=Camelyon16 --gpu 0 1 2 3

--magnification=single(因为默认就是single 所以可省)

只有一行进度条 很快就结束了 不会占用太长时间。此步会加载之前在./simclr/runs/*里生成的pth权重,并将该pth权重进行一些变换并写入到./embedder/Camelyon16/embedder.pth文件中。这个文件将作为推理时所用的两个权重中的一个,非常重要!此外,还将输出各种csv文件到./dataset/Camelyon16文件夹中

此步生成的csv,列数一共有512列,标号0-511,以normal_004.tif为例,其生成csv行数与./WSI/Camelyon16/single/normal/normal_004文件夹下的patch数是一致的。

以上是生成的Camelyon16.csv的部分内容

以上分别是生成的normal.csv和tumor.csv的部分内容。另外,此步的代码第156行中的num_feats=512(resnet18/resnet34)或2048(resnet50/resnet101)应当表示的是一个WSI中的patch所对应的向量维度数量。

5、按照说明,若训练Camelyon16且想用多gpu,我这里想让train和valid来split一下,valid占比0.4,因此使用指令:

nohup python train_tcga.py --dataset Camelyon16 --num_classes 1 --split 0.4 --gpu_index 0 1 2 >nohup_train_tcga.log 2>&1 &

可以使用“--gpu 0 1 2”,但不能用“gpu_index=0 1 2”,否则linux只认为gpu_index=0,其他的1 2是非法输入。

然而不知道是我的什么东西设置小了,GPU0占用了1000MB/15000MB,其他GPU都基本上没用到,无语住了,不知道怎么调让它升上去。另外,经过确认,这里的feats_size和上一步compute_feats.py中的num_feats应该指的是一个意思

6、最后,就回到一开始:

python test_crop_single.py --dataset=c16

上述代码要测试Camelyon16 必须将测试图片放在./test-c16/input文件夹下,会生成./test-c16/patches和./test-c16/weights

python testing_c16.py

上述代码使用patches和thumbnails作为输入,使用./test-c16/weights进行输出,输出结果在./test-c16/output文件夹中。如果输入切片都不变的话,可以直接新增个weights文件夹替换掉原先的weights文件夹再运行。实际上这个testing_c16.py没有args参数输入,显得不太友好,但是也还尚可运行。

总的来说,因为我之前对Camelyon16比较熟,所以才用的Camelyon16数据集,总的来说也是可以运行下来的。但如果能下载他论文里提到的TCGA会更友好一些。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值