resnet18病理图像二分类
简介
简单的数字病理图像分类。首先将分为三个数据集,训练集,验证集,和测试集。这三个数据集由同一种类不同的图片切割组合。训练集由两个图片切割的小图片组成 ,验证集由另一个该类别的图片切割的小图片组成,测试集由另一个该类别的图片切割的小图片组成。
在训练集中类别1的有24张,类别0的有29张。测试集中包含15张有病的图片,一张没有标记的图片。利用resnet18对这些图片进行二分类。
图片的剪裁
由于病理图像很大,需要对其进行剪裁。病理图像为.svs图片,很大,我们需要借助openslide来处理这些图像。病理图片上有标注,哪些是患病区域,同时每个.svs对应的都有一个.xml标注文件。首先将.xml文件生成.svs对应的掩膜图像。将对应标注有病的区域为白色,其他没有标注的区域为黑色,将掩膜和.svs对应起来,在切割的过程中,如果掩膜对应区域的白色像素个数的总和大于要切割面积的一半,就切割.svs对应的区域,保存切割下来的图片在train/1文件夹下。如果白色区域的面积过小,则丢弃该图片。对于黑色区域,我们要区分该区域是有图像还是空白的,判断依据是根据.svs对应区域的像素值来判断。
图片切割大小的选择:原始的.svs图片很大,且大多数.svs上的标注有的是小的连通区域,有的是大的连通区域,而且图片中的空白区域也较多。因此,将切割图片的大小设置为2000,3000,4500.对比切割之后的效果发现,4500大小的结果最好,切割的标记不是那么的边边角角,2000,3000,太小。
切割有病区域的图片:
for i in range(len(names)):
#paths=os.path.join('./Image/1/svs/', names[i] + '.svs')
na=names[i]
slide = openslide.OpenSlide(os.path.join('./Image/1/svs/', names[i] + '.svs'))
IM_ROWS = slide.dimensions[1] # 对应图像的高
IM_COLS = slide.dimensions[0]
Image.MAX_IMAGE_PIXELS = None
tumor_mask = np.array(Image.open('./Image/1/mask' + '/' + names[i] + '.png'))
#image = openslide.OpenSlide(paths) # 读取svs
for i in range(0, IM_ROWS - cut_size, spacing):
for j in range(0, IM_COLS - cut_size, spacing):
tumor_mask_np = tumor_mask[i:i + cut_size, j:j + cut_size]
if (tumor_mask_np == 255).sum() >= area:
save_name = '{}_{}_{}_{}.png'.format(na, i, j, cut_size)#剪裁图片命名字
#image=image[j:j+cut_size,i:i+cut_size]#剪裁对应位置的图片
save_path2=os.path.join(save_path,save_name)#剪裁有病图片的存储路径
#cv2.imwrite(save_name,image)
try:
img = np.array(slide.read_region((j, i), 0, (cut_size, cut_size)), dtype=np.uint8)[..., 0:3]
except:
slide.close()
slide = openslide.OpenSlide('./Image/1/svs' + '/' + names[i] + '.svs')
continue
Image.fromarray(img).save(save_path2)
在剪裁图片的过程中要将 Image.MAX_IMAGE_PIXELS 的值设置为None,否则的话会报超出范围的错误,带不开图片。
使用Resnet18进行二分类
使用迁移学习:
model=models.resnet18(pretrained=True)
for para in model.parameters():
para.require_grad=False
model.fc=nn.Linear(512,2)
数据预处理:
只进行了简单的数据预处理
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
transform = transforms.Compose([
transforms.Resize(size=(227, 227)),
transforms.RandomRotation(20),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalize
])
由于图片数量较少,所以batch_size也设置的相对较少,batch_size=4,epoch=100.
利用迁移学习,将已经训练好的resnet18迁移过来,改变最后一层全连接层的输出。损失函数使用的是CrossEntropyLoss,optimizer使用的是Adam,,learning rate 是0.01.
训练的结果:发现当epoch为55左右的时候准确率很高了
验证集和测试集的结果
使用Vgg网络进行分类
训练的结果:当epoch为100时训练效果仍然不好,loss仍然很大,爱acc也不高,调整learning rate为0.001.效果仍然不好,所以增大epoch,改变optimizer为SGD,修改learning rate继续训练。
验证和测试的结果:
从测试的结果来看,resnet的效果较好。
上一篇: 深度学习-批标准化(Batch Normalization)
下一篇: 损失函数(MSE和交叉熵)