RFNet学习
RFNet是一个深度学习模型,用于医学图像分割任务。下面是目录中各个文件的功能说明:
-
data文件夹:包含数据处理相关的文件。
- init.py:一个空文件,用于标识该文件夹是一个Python包。
- data_utils.py:包含一些用于数据处理的实用函数。
- datasets.py:定义了数据集的类,用于加载和处理训练和测试数据。
- datasets_nii.py:包含处理.nii格式数据的类。
- rand.py:包含生成随机数的函数。
- sampler.py:定义了数据采样器,用于从数据集中获取样本。
- transforms.py::定义了数据增强操作
-
pertrain文件夹:包含预训练的模型文件。
- model_last_brast2020.pth:预训练模型文件。
- model_last_brats2015.pth:预训练模型文件。
- model_last_brats2018_split1.pth:预训练模型文件。
- model_last_brats2018_split2.pth:预训练模型文件。
- model_last_brats2018_split3.pth:预训练模型文件。
-
utils文件夹:包含一些实用工具和脚本文件。
criterions.py:包含用于定义损失函数(criterion)的类和函数。generate.py:包含生成一些辅助数据的函数。lr_scheduler.py:包含学习率调度器(lr_scheduler)的类和函数,用于在训练过程中调整学习率。parser.py:包含用于解析命令行参数的类和函数。str2bool.py:包含将字符串转换为布尔值的函数。
-
主文件夹:
- layers.py:定义了一些自定义的神经网络层。
- miccai.sh:一个Shell脚本文件,可能是用于运行训练或测试的脚本。
- miccai2020.log:日志文件,可能包含训练或测试过程中的输出和记录。
- models_miccai.py:定义了RFNet模型的网络结构。
- piex_contrast_loss.py:定义了自定义的损失函数。
- predict.py:用于进行图像分割预测的脚本。
- train_miccai.py:用于进行模型训练的脚本。
配置shell脚本。
查询pythonname
which python3
查询cudapath
whereis cuda
models_miccai.py
总体:
-
定义了一个名为Encoder的类,用于实现编码器部分的网络结构。编码器由四个阶段组成,每个阶段包含三个卷积层。输入经过不同阶段的卷积层后,输出特征图。编码器的作用是逐渐提取图像特征。
-
定义了一个名为Decoder_sep的类,用于实现解码器部分的网络结构。解码器采用分离的方式进行解码,即对每个输入通道单独进行解码操作。解码器的结构与编码器相反,使用反卷积和上采样操作将特征图恢复到原始输入图像的尺寸,并最终生成预测结果。
-
定义了一个名为Decoder_fuse的类,用于实现解码器部分的网络结构。解码器采用融合的方式进行解码,即对不同输入通道的特征图进行融合后再进行解码操作。解码器利用区域感知的模态融合和渐进的融合机制,通过多层次的融合生成预测结果。
-
定义了一个名为Model的类,用于组合编码器和解码器,构成完整的网络模型。模型包括四个通道的编码器和两个解码器(分离解码器和融合解码器)。模型的前向传播过程中,将输入图像的不同通道分别送入对应的编码器,然后将编码器的输出作为解码器的输入,生成最终的预测结果。
-
在模型的初始化过程中,设置了一些参数和初始化权重的操作。
-
模型的前向传播过程中,根据是否训练的标志位,选择使用分离解码器还是融合解码器生成预测结果。如果训练模式下,还会返回其他中间结果,如分离解码器的预测结果和权重、融合解码器的权重等。
Encoder
#9 basic_dims = 16是什么?
basic_dims是一个表示基本维度或基本通道数的变量,其值为16。它用于定义卷积神经网络中的通道数(通道数在卷积神经网络中是指特征图中的特征通道数量,用于表示不同的特征信息),控制特征图的深度和模型的复杂度。
#12 调用super(Encoder, self).__init__()的目的是什么?
通过调用super().__init__(),可以确保在创建Encoder实例时,父类的构造函数被调用,从而初始化必要的属性和状态。
这里是为了调用父类nn.Module的构造函数,通过继承nn.Module,Encoder类获得了许多用于构建神经网络模型的方法和属性,例如参数管理、前向传播等。通过将Encoder类定义为nn.Module的子类,可以方便地使用PyTorch提供的功能,构建和管理神经网络模型。
#18 stride=2是什么?
stride=2是卷积操作中的一个参数,用于指定卷积核在输入数据上的滑动步长。
在卷积操作中,卷积核会在输入数据上进行滑动,每次滑动的步长由stride参数决定。常见的步长设置为1,表示卷积核每次滑动1个像素;而stride=2表示卷积核每次滑动2个像素,即跳过一个像素进行下一次卷积。
使用stride=2的卷积操作可以减小输出特征图的尺寸,因为卷积核每次滑动的步长增大了。这在一些情况下可以起到下采样的效果,即通过减小特征图尺寸来提取更加抽象的特征。
#14 - #28 这些卷积层的作用是构建编码器的不同层级,通过多次卷积和池化操作逐渐提取输入数据的抽象特征。每个卷积层之后都有一个使用反射填充的卷积操作,用于增加网络的非线性能力。
#30 - #41 在forward方法中,将输入数据依次传递给这些卷积层,得到相应的特征表示输出。具体的过程是,将输入数据x分别传递给e1_c1、e1_c2和e1_c3,然后将输出与e1_c2的输出相加。接着,将得到的结果作为输入传递给下一层的卷积层,依次进行类似的操作,直到得到最后一层的特征表示。
Decoder_sep
#49 上采样层参数详解
self.d3 的作用是对输入特征图进行上采样操作,将其空间尺寸放大两倍。上采样后的特征图将用于后续的卷积操作,以恢复空间细节和特征的分辨率。
-
scale_factor=2:指定了上采样的尺度因子。在这种情况下,输入特征图的空间尺寸将会放大两倍。例如,如果输入特征图的尺寸为 (H, W, D),那么经过上采样后的输出特征图的尺寸将变为 (2H, 2W, 2D)。 -
mode='trilinear':指定了上采样的插值模式。在这里,使用了trilinear插值,它适用于三维数据,对于每个通道在三个维度上进行线性插值,以生成新的像素值。这种插值方法能够保持相对较好的空间一致性。 -
align_corners=True:指定是否将原始图像的角点与新图像的角点对齐。当align_corners=True时,上采样操作会保持输入和输出图像的角点对齐,这有助于避免图像拉伸或扭曲。这在处理像素级任务时通常是希望的设置。
#52 卷积层参数详解
self.d3_out 是一个包含 1x1x1 卷积核的卷积层,用于将输入特征图的通道数从 basic_dims*4 调整为 basic_dims*4,输出的特征图保持与输入特征图相同的空间尺寸。该层的作用是进行通道数的调整和特征的变换。
-
in_channels=basic_dims*4:指定输入特征图的通道数,即卷积操作的输入通道数。 -
out_channels=basic_dims*4:指定输出特征图的通道数,即卷积操作的输出通道数。 -
k_size=1:指定卷积核的大小。在这种情况下,卷积核的大小为 1x1x1,表示沿着三个维度的空间大小都为 1。 -
padding=0:指定卷积操作的填充大小。在这里,填充大小为 0,表示不进行填充操作。 -
pad_type='reflect':指定填充的类型。使用反射填充(reflect padding)意味着在边界上使用镜像反射的方式进行填充。
#64 解释该卷积层的目的
self.seg_layer是一个1x1x1的卷积层,将最后一组卷积层的输出特征图映射到num_cls个通道,即最终的分割结果的通道数。
#65 这是一个softmax层,用于对分割结果进行归一化,使每个通道的值在0到1之间,并且所有通道的和为1。
#70 将 de_x4 和输入张量 x3 在通道维度上进行拼接,dim参数用于指定在哪个维度上进行张量的拼接操作。在这种情况下,dim=1表示在通道维度上进行拼接。
Decoder_fuse
#102 self.seg_layer 是一个卷积层对象,用于生成最终的分割结果。它将输入特征图的通道数从 basic_dims 转换为 num_cls,即分类的数量。
#103 self.softmax 是一个 Softmax 函数,用于对输出的 logits 进行归一化,以得到每个类别的概率分布。
对输出的 logits 进行归一化是指将 logits 转换为概率分布,使得每个类别的预测概率值落在 [0, 1] 的范围内,并且所有类别的概率之和为 1。
Logits 是模型在最后一层(通常是线性层)输出的未经过激活函数的预测结果。这些值可以是任意实数,且没有固定的范围。为了将 logits 转换为概率分布,常用的方法是应用 Softmax 函数。
Softmax 函数接受一个向量作为输入,对向量中的每个元素进行指数运算,然后将指数结果除以所有元素的指数和,从而得到每个元素对应的概率值。
#114-117 self.prm_generator1 是四个逐层关系建模(PRM)生成器对象,用于捕捉特征图之间的上下文信息,并生成关联性权重。
Model
当给定输入数据x和掩码mask时,该代码段实现了前向传播函数forward。下面是逐行分析的解释:
-
提取不同层的特征:
- 通过
self.flair_encoder对x的第一个通道进行编码,得到flair_x1, flair_x2, flair_x3, flair_x4四个特征。 - 通过
self.t1ce_encoder对x的第二个通道进行编码,得到t1ce_x1, t1ce_x2, t1ce_x3, t1ce_x4四个特征。 - 通过
self.t1_encoder对x的第三个通道进行编码,得到t1_x1, t1_x2, t1_x3, t1_x4四个特征。 - 通过
self.t2_encoder对x的第四个通道进行编码,得到t2_x1, t2_x2, t2_x3, t2_x4四个特征。
- 通过
-
将特征进行堆叠:
- 使用
torch.stack函数将不同通道的特征进行堆叠,得到x1, x2, x3, x4四个张量。每个张量的维度为Bx4xCxHWZ,其中B是批量大小,C是通道数,H, W, Z是空间维度。
- 使用
-
调用
self.decoder_fuse进行融合解码:- 将
x1, x2, x3, x4作为输入,以及掩码mask,调用self.decoder_fuse进行融合解码,得到融合预测fuse_pred、部件级预测prm_preds和融合预测的logitsfuse_logits。
- 将
-
如果处于训练模式:
- 进一步使用
self.decoder_sep对每个编码器的特征进行单独解码,得到各个部件的预测flair_pred, t1ce_pred, t1_pred, t2_pred和logitst1ce_logits, t1_logits, t2_logits。 - 返回融合预测、部件预测、部件级预测和各项中间结果。
- 进一步使用
-
如果不处于训练模式:
- 仅返回融合预测结果。
#178 if self.is_training:是什么意思
self.is_training是一个布尔值,用于表示当前模型是否处于训练模式。这个条件判断语句 if self.is_training: 是用来检查当前模型是否处于训练模式。
在训练模式下,模型通常会执行额外的操作,如计算损失、更新参数等。因此,当 self.is_training 为 True 时,表示模型处于训练模式,接下来的代码块将会执行。
而在非训练模式(如测试或推断)下,模型通常只需要生成预测结果,而不需要执行训练相关的操作。因此,如果 self.is_training 为 False,则相应的训练模式下的代码块将被跳过。
通常,self.is_training 的值由用户在使用模型时进行设置,以指示模型所处的模式。
layers.py
data
Datasets_nii.py
(287条消息) os.path.join()用法_os.path.join()函数用法_MclarenSenna的博客-CSDN博客
心得体会
代码的每一个内容都很重要。之前看代码,觉得数据输入、处理等这些部分的代码可以不用看。但是2023年6月29日在训练软件杯飞桨小汪赛道目标检测的模型时,亲身体会到数据处理这一块的不容易,特别是格式问题,标签不均衡等等一系列问题,这些问题太细了,而且对训练的结果影响很大,所以说代码的每一个内容都很重要。
之前一直在思考一个问题,什么是复现?一直疑惑一个地方:自己实现代码的时候,不就是对着源代码抄吗?所以意义是什么?意义在于在复现的过程中体会为什么有这一步,比如RFNet采用区域感知融合解决多模态缺失的问题,他是怎么控制好缺失模态的权重的?是怎么引入注意力机制的...不光是跟着抄代码然后跑出结果,还要从一个宏观的角度,从数据集开始出发,思考这些方法的意义。
平时的空闲时间要到处找其他的项目去看,多看看别人的思路,对自己的提升很大。或者学一些其他方向的东西,都是对自己有启发的。

浙公网安备 33010602011771号