命题背景
MRI是确定基于神经胶质瘤的肿瘤的广泛使用的成像方法。 在图像处理期间,MRI提供大量图像信息,因此,必须在临床实践中进行准确的图像处理。
一、前期准备
数据集
为了计算MSMCNN的性能,我们使用BRATS 15作为图像数据集进行测试和训练。包括各类病例的220幅HGG和54幅LGG MR图像。实验中使用34 HGG和120 LGG作为训练集,20HGG和70 LGG作为测试集。除了针对t1_weighted (t1)、t1_weighted imaging with gadoliniumenhanced differentiation (t1c)、t2_weighted (t2)和flair图像的每个患者改进的四种MRI过滤安排外,BRATS 15数据集中的每个患者都可以获得MRI信息。对于每一位患者,t1、t2和flair图像被编入t1c信息中,需要精挑细选的空间判定,重新取样,并通过大小240 9 240 9 155调节成19 191 mm3。主要步骤是对每个患者从三维空间中提取的15个二维图像切片进行预处理,利用强度归一化和不均匀性改变。随后,从每幅预处理图像中提取两组主要的特征。在手动分割,通过necrosis_(1)、edema_(2)、non-enhancing_(3)和enhanced tumor_(4)等不同标签来区分四种肿瘤内类型。在本研究中,我们使用t1、t2、t1c和flair图像来分割整个肿瘤区域。
典型算法介绍
较大的脑瘤的肿瘤内部结构是不可预测的和具有挑战性的过程,为了减少这种并发症,我们设计了一种基于msmcnn - lstm的肿瘤级LGG和HGG语义分割方法。图1显示了MSMCNN的框图。在这个模型中,来自15个孩子的MRI被作为输入,它有四种模式,如t10, t10c, t20和flair0。为了提高patch结构的性能,采用了多尺度的多路径每一个都使用一个不同大小的patch。每个modality又被进一步划分为三个不同大小的patch,分别是6464、128128和240*240。这三个patch的生产率由LSTM网络汇总,并训练LSTM网络正确地对给定的类别标签进行分类。 来自不同模态的相同标度值patch被提供给LSTM进行分类。 最终,通过softmax层获得了结果。
工具集介绍
Intel® Extension for PyTorch*是英特尔发起的一个开源扩展项目,它基于PyTorch的扩展机制实现,通过提供额外的软件优化极致地发挥硬件特性,帮助用户在原生PyTorch的基础上更最大限度地提升英特尔 CPU 上的深度学习推理计算和训练性能。这个扩展项目针对命令模式(imperative mode)和图模式进行了优化,并针对PyTorch的三个关键模块进行了优化:运算符、图和运行时。优化的运算符和内核通过PyTorch调度机制完成调用。这个扩展项目不仅可以直接用于提升PyTorch在英特尔CPU上的性能,还可以为英特尔的硬件提供更好的支持,使得PyTorch用户能够更加及时地受益于英特尔硬件的最新功能,并在第一时间体验软件优化带来的最佳性能和部署便利。除了CPU,这个扩展项目还将在不久的将来为英特尔GPU带来支持和优化
评测指标
MAE(Mean Absolute Error)和MSE(Mean Squared Error)是常见的两个评测指标,用于评估预测结果和真实值之间的差异。
MAE是指预测值和真实值之间绝对值的平均差,它可以衡量预测值和真实值之间的绝对误差大小。MAE的计算公式为:
MAE = (|预测值-真实值|)/n
其中,n为样本数量。
MSE是指预测值和真实值之间平方差的平均数,它可以衡量预测值和真实值之间的误差大小,并且考虑了误差的正负。MSE的计算公式为:
MSE = ((预测值-真实值)^2)/n
其中,n为样本数量。
在人群计数任务中,MAE和MSE可以用来评估模型预测结果和真实值之间的差异。MAE可以衡量模型预测的绝对误差大小,MSE可以衡量模型预测的误差大小,并且考虑了误差的正负。通过比较MAE和MSE的值,可以评估模型的性能好坏。
二、设计思路
1.数据处理
完成数据清洗:清理缺失值、异常值、重复值等,以确保数据的准确性和一致性。
数据转换:对数据进行转换和预处理,以满足后续分析和建模的需求。例如,进行特征工程、数据标准化、归一化等操作
# 随机调整大小
short = min(img_width, img_height)
if short < 512:
scale = 512 / short
img_width = round(img_width * scale)
img_height = round(img_height * scale)
img = img.resize((img_width, img_height), Image.BILINEAR)
density = cv2.resize(density, (img_width, img_height), interpolation=cv2.INTER_LINEAR) / scale / scale
scale = random.uniform(0.8, 1.2)
img_width = round(img_width * scale)
img_height = round(img_height * scale)
img = img.resize((img_width, img_height), Image.BILINEAR)
density = cv2.resize(density, (img_width, img_height), interpolation=cv2.INTER_LINEAR) / scale / scale
# crop
h, w = 400, 400
dh = random.randint(0, img_height - h)
dw = random.randint(0, img_width - w)
img = img.crop((dw, dh, dw + w, dh + h))
density = density[dh:dh + h, dw:dw + w]
# 随机地交换两个数据点的标签
if random.random() < 0.5:
img = img.transpose(Image.FLIP_LEFT_RIGHT)
density = density[:, ::-1]
# gamma
if random.random() < 0.3:
gamma = random.uniform(0.5, 1.5)
img = functional.adjust_gamma(img, gamma)
# 灰度图像
if random.random() < 0.1:
img = functional.to_grayscale(img, num_output_channels=3)
img = self.transforms(img)
density = cv2.resize(density, (density.shape[1] // self.scale, density.shape[0] // self.scale),
interpolation=cv2.INTER_LINEAR) * self.scale * self.scale
density = density[np.newaxis, :, :]
return img, density
2.模型定义
MCNN,包含三列卷积神经网络,滤波器大小不同,三列对应具有不同的感受野,因此每个列cnn所学习的特征都能适应由于角度不同而导致的人头大小不均匀而引起的变化
MCNN中,用1*1卷积代替全连接层,因此,模型的输入可以是任意大小的,很大程度上避免了失真的情况。网络的输出为密度图,通过对密度图进行积分即可计算得出总人数
定义一个基于 VGG 网络的 PSNet 模型,提供了一个加载预训练权重的方法。
PSNet 类继承自 PyTorch 的 nn.Module,它包含两个主要部分:vgg 和 dmp。vgg 部分是一个 VGG 模型,而 dmp 部分是 BackEnd 模块,PSNet 类的 forward 方法接收一个输入,首先通过 vgg 部分处理输入,然后将处理后的结果传递给 dmp 部分进行处理。最终,该方法返回 dmp 部分的输出结果。
下面贴出_load_vgg 16的代码
def _load_vgg(self):
state_dict = model_zoo.load_url('https://download.pytorch.org/models/vgg16_bn-6c64b313.pth')
old_name = [0, 1, 3, 4, 7, 8, 10, 11, 14, 15, 17, 18, 20, 21, 24, 25, 27, 28, 30, 31, 34, 35, 37, 38, 40, 41]
new_name = ['1_1', '1_2', '2_1', '2_2', '3_1', '3_2', '3_3', '4_1', '4_2', '4_3', '5_1', '5_2', '5_3']
new_dict = {}
for i in range(10):
new_dict['conv' + new_name[i] + '.conv.weight'] = \
state_dict['features.' + str(old_name[2 * i]) + '.weight']
new_dict['conv' + new_name[i] + '.conv.bias'] = \
state_dict['features.' + str(old_name[2 * i]) + '.bias']
new_dict['conv' + new_name[i] + '.bn.weight'] = \
state_dict['features.' + str(old_name[2 * i + 1]) + '.weight']
new_dict['conv' + new_name[i] + '.bn.bias'] = \
state_dict['features.' + str(old_name[2 * i + 1]) + '.bias']
new_dict['conv' + new_name[i] + '.bn.running_mean'] = \
state_dict['features.' + str(old_name[2 * i + 1]) + '.running_mean']
new_dict['conv' + new_name[i] + '.bn.running_var'] = \
state_dict['features.' + str(old_name[2 * i + 1]) + '.running_var']
self.vgg.load_state_dict(new_dict)
3.模型训练
1.定义训练和测试的数据集的路径,以及一些训练参数,如学习率、训练的周期数、批大小、等。
2.设定最佳的平均绝对误差(MAE)和均方误差(MSE)为无穷大(“inf”)。
加载数据,并对图像进行预处理,包括转换为张量(ToTensor)和归一化(Normalize)。
3.定义训练和验证的数据加载器,用于在训练和验证过程中提供数据。
4.定义用于训练和验证的PSNet模型,并使用Intel拓展。
5.开始训练
下面放出部分代码
......
import intel_pytorch_extension as ipex
ipex.enable_auto_optimization(mixed_dtype = torch.bfloat16)
......
TRAIN_IMG_DIR = 'datasets/ShanghaiTech_Dataset/part_A_final/train_data/images'
TEST_IMG_DIR = 'datasets/ShanghaiTech_Dataset/part_A_final/test_data/images'
LR = 1e-4
EPOCH = 460
BATCH_SIZE = 12
start_epoch = 0
resume = False
workers = 4
hyper_param_D = 1
BEST_MAE = 300
BEST_MSE = 300
# load data
MEAN = [0.485, 0.456, 0.406] # mean
STD = [0.229, 0.224, 0.225] # std
normalize = transforms.Normalize(
mean=MEAN,
std=STD
)
train_transform = transforms.Compose([
transforms.ToTensor(),
normalize]
)
val_transform = transforms.Compose([
transforms.ToTensor(),
normalize]
)
# define trainloader
train_dataset = CrowdCountingDataset(TRAIN_IMG_DIR, transforms = train_transform, scale = 8, mode = 'train')
train_loader = DataLoader(train_dataset, batch_size = BATCH_SIZE, shuffle = True, num_workers=workers)
# define valloader
val_dataset = CrowdCountingDataset(TEST_IMG_DIR, transforms = val_transform, scale = 8, mode = 'test')
val_loader = DataLoader(val_dataset, batch_size = 1, num_workers=workers)
# define model
model = PSNet().float()
model = model.to(ipex.DEVICE)
# define optimizer
optimizer = optim.Adam(model.parameters(), lr=LR)
4.测试模型
评估模型在验证集上的性能,特别是计算模型的平均绝对误差(MAE)和均方误差(MSE),以及注意力损失
with torch.no_grad():
for data in val_loader:
cnt += 1
image, gt, gt_density = data
image, gt_density = image.float(), gt_density.float()
image, gt_density = image.to(device), gt_density.to(device)
# 前后传播
pr_density, attention_map_1, attention_map_2, attention_map_3 = model(image)
attention_loss = 0.
for attention_map in (attention_map_1, attention_map_2, attention_map_3):
attention_map_sum = attention_map[:, 0:1] + attention_map[:, 1:2] + attention_map[:, 2:3] + \
attention_map[:, 3:4]
attention_loss_temp = 0.
for i in range(4):
attention_loss_temp += torch.sum(
cosloss(attention_map[:, i:(i + 1)].contiguous().view(image.size(0), -1),
((attention_map_sum - attention_map[:, i:(i + 1)]) / 3).contiguous().view(image.size(0), -1))) / image.size(0)
attention_loss += (attention_loss_temp / 4)
attention_loss /= 3
sum_att_loss += attention_loss.item()
# 记录结果
pr_density = pr_density.cpu().detach().numpy()
pr = np.sum(pr_density)
mae += np.abs(gt - pr)
mse += np.abs(gt - pr) ** 2
mae_loss = mae / cnt
mse_loss = np.sqrt(mse / cnt)
att_loss = sum_att_loss / cnt
效果展示及总结
准确度:
partA: MAE 56.1 MSE 89.7
partB: MAE 6.4 MSE 10.1