这部分主要是个人在阅读相关代码时,发现其中使用到了部分之前较少见过的方式方法,为了便于今后的学习,因此在这里进行总结。
可能在叙述顺序上缺乏一定的逻辑,如果论文能够顺利发表,再进行详细布局。
深度监督(Deep Supervision)是指在神经网络的训练过程中,同时利用神经网络中不同层次的输出结果来进行多任务训练,以帮助网络更好地学习特征和提高模型的性能。在一些任务中,模型的最终输出结果可能受到训练数据的噪声、样本数量不足等问题的影响,因此利用中间层次的输出结果来进行监督,有助于提高模型的鲁棒性和泛化能力。
#一共生成了六张注意力机制张量,编码器有三张,解码器中有三张
if args.sadencoder == 1:
# attentions 0, 1, 2
gamma_sad = [0.1, 0.1, 0.1] #决定了每个注意力张量的损失函数在总体损失函数中的权重
for iter_sad in range(2):
# sad_loss函数计算了两个注意力张量之间的余弦相似度
loss += (gamma_sad[iter_sad])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=True)
if args.saddecoder == 1:
# attentions 3, 4, 5, 6
gamma_sad = [0.1, 0.1, 0.1]
for iter_sad in range(3, 6):
loss += (gamma_sad[iter_sad-3])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=False)
对于一个三维CT图像,模型在进行注意力机制时,每个切片都会对应一个注意力张量,可以理解为每个切片都有自己的注意力分布。在实现时,可以将每个切片看作一个batch进行计算,即将每个切片作为一个输入,然后得到对应的注意力张量,这些张量可以组成一个三维的张量,对应输入CT图像的形状。
在观察代码时,发现在训练的train_casenet中,有关于自注意力机制张量的代码部分如下所示:
#一共生成了六张注意力机制张量,编码器有三张,解码器中有三张
if args.sadencoder == 1:
# attentions 0, 1, 2
gamma_sad = [0.1, 0.1, 0.1] #决定了每个注意力张量的损失函数在总体损失函数中的权重
for iter_sad in range(2):
# sad_loss函数计算了两个注意力张量之间的余弦相似度
loss += (gamma_sad[iter_sad])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=True)
if args.saddecoder == 1:
# attentions 3, 4, 5, 6
gamma_sad = [0.1, 0.1, 0.1]
for iter_sad in range(3, 6):
loss += (gamma_sad[iter_sad-3])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=False)
从上述代码中可以看出,在编码器啊计算一共使用了3个自注意力机制张量,但是在解码阶段使用了4个自注意力机制张量,这是因为解码器需要将低分辨率的特征图恢复到原始特征图的尺寸,因此需要保存更多的空间信息,解码器需要更多的自注意力机制张量来实现更好的分割效果。
SAD(Structure-Aware Distillation)损失函数是一种用于多尺度注意力机制的监督方法。它可以帮助网络学习结构信息和空间信息,从而提高模型的性能。SAD损失函数的定义包括了两个步骤:
1、计算多尺度注意力张量之间的相似度,具体地,对于一个多尺度注意力张量,它会被切成多个大小相同的子块,然后对这些子块之间的相似度进行计算。
2、计算多尺度注意力张量之间的距离,具体地,将两个多尺度注意力张量的所有子块分别取出来,然后计算它们之间的欧几里得距离。
最终,SAD损失函数可以通过以上两个步骤来监督网络的多尺度注意力机制,帮助网络更好地学习结构信息和空间信息。
在注意力机制中,SAD(Spatial Attention Difference)损失函数的作用是衡量相邻的两个注意力张量之间的相似度。这样做的目的是在训练过程中强制模型生成相似的注意力张量,从而确保模型生成的注意力张量具有相关性,能够更好地捕捉特征。
在计算SAD损失函数时,通常会比较相邻两个注意力张量之间的相似度,然后将相似度作为损失函数的一部分,通过反向传播调整网络参数,使得模型可以生成更加相似的注意力张量。通过这种方式,可以确保在训练过程中,模型能够生成具有相关性的注意力张量,从而提高模型的性能。
#一共生成了六张注意力机制张量,编码器有三张,解码器中有三张
if args.sadencoder == 1:
# attentions 0, 1, 2
gamma_sad = [0.1, 0.1, 0.1] #决定了每个注意力张量的损失函数在总体损失函数中的权重
for iter_sad in range(2):
# sad_loss函数计算了两个注意力张量之间的余弦相似度
loss += (gamma_sad[iter_sad])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=True)
if args.saddecoder == 1:
# attentions 3, 4, 5, 6
gamma_sad = [0.1, 0.1, 0.1]
for iter_sad in range(3, 6):
loss += (gamma_sad[iter_sad-3])*sad_loss(attentions[iter_sad], attentions[iter_sad+1], encoder_flag=False)
首先可以明确的是,如果输入数据是3D形式,在预处理阶段往往会对其进行切片处理,使其变成2D数据,并且切片的数量与输入数据channel的数量是一致的。
CT图像中所给标签是二维像素级别的标签,而不是体素级别的标签,并且是多类别的,也就是每个像素点可能属于多个类别,而不是简单的二值标签,例如一个肿瘤可能被划分为不同的类型,而不同的类型会被赋予不同的标签值,因此在分割任务中,往往需要将多类别的标签转换为二值标签,以便可以进行分类任务。
这个二值化过程一般通过设置一个阈值来完成,大于某值被认为是分割部分的区域,赋值为1,小于则认为是周围区域,赋值为0。
# for evaluation
lossHist.append(loss.item()) #将每一次计算得到了loss值存入列表lossHist中
# segmentation calculating metrics#######################
outdata = casePred.cpu().data.numpy() #获取模型的预测结果,并将其转为numpy数组
segdata = y.cpu().data.numpy() #获取真实真实标签,并将其转为numpy数组
segdata = (segdata > th_bin) #将真实标签中大于th_bin的像素值转为1,其余转为0,这里的th_bin是一个二值化的阈值,用于将连续的像素值转换为二值化的标签
对于3D数据的输入模型,在切片的情况下,网络输出是对每个切片中每个像素的预测标签。如果要得到对应的体素的预测标签,可以通过对每个切片中预测结果的叠加来得到,即将每个切片的预测结果按照其在原始体积中的位置进行叠加,然后通过某种策略(例如简单地取每个体素预测结果中的众数)来得到对应体素的预测标签。这样就可以得到对整个3D体积的预测结果。
策略的方式:
1、平均投票法(Majority Voting):对于每个像素位置,在每个切片上的预测标签进行投票,得票数最多的标签作为该像素位置的最终预测结果。
2、最大投票法(Max Voting):对于每个像素位置,在每个切片上的预测标签中出现次数最多的标签作为该像素位置的最终预测结果。
3、级联法(Cascade):先使用一个网络对整个3D数据进行预测,再使用另一个网络对预测结果进行修正。
4、三维全卷积网络(3D Fully Convolutional Network):使用一个网络对整个3D数据进行预测,得到每个像素位置的预测结果。
在机器学习中,样本的敏感度通常是指训练数据中每个样本对于模型预测结果的影响程度。通常情况下,样本的敏感度与其在训练数据中的重要性相关,即在训练数据中起到更重要作用的样本更加敏感。在一些场景下,例如对于异常检测和离群点检测,样本的敏感度可以帮助我们发现那些对于模型预测结果影响较大的异常样本或者离群点。
sensiti = sensitivity_np(segpred, segdata[j, 0]) #计算当前样本的敏感度
物理坐标通常是以图像的左上角(即坐标轴的原点)为基准点,因为计算机中图像的存储方式也是以左上角为起点的。但是在医学图像中,物理坐标也可能以某个特定的物理点为基准点,例如CT图像中的切片位置可能会以扫描仪的中心点作为物理坐标的基准点。
在医学图像处理中,org常常是指采样的原点,即采样时采集到的体素中的第一个体素在物理坐标系中的位置,通常也称为图像的原点或起始点。org记录的是采样时的原点在物理坐标系中的位置,通常是一个三元组 (x0, y0, z0),分别表示x、y、z三个方向上的位置。org的记录方式可以是具体的坐标值,也可以是采样原点在物理坐标系中的索引值,具体要看具体的实现方式。在医学图像处理中,org的记录通常会被用来计算体素的物理坐标位置,方便后续的处理和分析。
之前没有接触过PyTorch的相关结构,因此在阅读代码是存在部分困难,在这里做部分总结学习。
for i, (x, y, coord, org, spac, NameID, SplitID, nzhw, ShapeOrg) in enumerate(tqdm(data_loader)):
.cpu() 是 PyTorch 中 Tensor 对象的一个方法,用于将 Tensor 从 GPU 设备移动到 CPU 设备上。在机器学习模型的训练过程中,通常需要将输入数据和模型参数存储在 GPU 上进行计算,以提高计算效率。但在某些情况下,如需要将 Tensor 转换为 NumPy 数组以便进行后续处理时,需要将其移回 CPU 上。
outdata = casePred.cpu().data.numpy()
.cuda()是PyTorch中的一个方法,用于将模型或数据转移到GPU上进行加速运算。它会将对象移动到默认的CUDA设备上。在使用.cuda()方法时,需要保证CUDA已经被正确安装并且可用。
x = x.cuda() # 将x转移到GPU上
y = y.cuda()
split_id() 方法用于对原始3D图像进行划分,将其分成若干个子体积。这个过程通常是为了减少训练过程中需要处理的数据量,从而提高训练效率。split_id() 方法返回一个元组,其中第一个元素是划分后的子体积的坐标范围组成的列表,即 splits。例如,splits 中的一个元素可能是 [(0, 32), (32, 64), (64, 96)],表示这个子体积的 x 轴坐标范围是从 0 到 32,y 轴坐标范围是从 32 到 64,z 轴坐标范围是从 64 到 96。
splits, nzhw, orgshape = self.split_comber.split_id(imgs) #根据原始数据,使用split_comber对其进行拆分。返回:拆分后的数据坐标范围、拆分的数量、原始数据的形状
.append() 方法:.append() 是列表对象的一个方法,用于向列表的末尾添加单个元素。例如,语句cubelist.append(cube_train) 将一个名为 cube_train 的列表添加到 cubelist 列表的末尾。
+= 运算符:+= 运算符也可以用于向一个列表中添加另一个列表。但是,与 .append() 不同,+= 会将另一个列表中的所有元素添加到目标列表中,而不是将整个列表作为单个元素添加。语句 cubelist += cube_train 将 cubelist 和 cube_train 中的元素合并为一个新列表,并将其赋值给 cubelist。
为方便理解起见,下面将给出一个具体的例子:
cubelist1 = [1, 2, 3]
cubelist2 = [1, 2, 3]
cube_train = [4, 5, 6]
# 使用 .append() 方法将 cube_train 添加到 cubelist 中
cubelist1.append(cube_train)
print(cubelist1) # 输出:[1, 2, 3, [4, 5, 6]]
# 使用 += 运算符将 cube_train 添加到 cubelist 中
cubelist2 += cube_train
print(cubelist2) # 输出:[1, 2, 3, 4, 5, 6]
输出结果如下所示:
[1, 2, 3, [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
进程已结束,退出代码0
在医学图像领域,部分变量的名称已经变得”约定俗成“,因此在这里对所遇到的代码进行总结,以便后期进行代码编写时方便查找
变量名 | 含义 |
---|---|
augtype | 数据增强的类型或方法 |
stridet | batch的边长 |
cubesize | 输入的立方体的边长 |
stridev | 输入图像被切割成块的滑动窗口的步长 |
split_conmber | 用于图像分割或重组的函数 |