U-net细胞分割项目

简介: U-net细胞分割项目

1 实验概述


实验目的:精确提取提取图片中的细胞部分像素点

实验数据集:实验数据集

实验语言:Python

实验所需的库:PIL 、numpy 、torch、opencv(若安装后无法使用,请参照这篇博文opencv

实验数据集示例:

(原图)


(标注)

2 U-net讲解


语义分割在生物医学图像分析中有着广泛的应用:x射线、MRI扫描、数字病理、显微镜、内窥镜等。https://grand-challenge.org/challenges上有许多不同的有趣和重要的问题有待探索。

详细讲解请至U-net详细讲解浏览。



3 实验代码以及过程


step1:导入相关的包

import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, models, transforms
from torch.utils.data import Dataset, DataLoader
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.autograd import Variable
from torchsummary import summary
from PIL import Image
import cv2
import os
import numpy as np
import matplotlib.pyplot as plt

step2:加载数据

img_size = (512, 512)
transform = transforms.Compose([
    transforms.ToTensor()])
class MyData(Dataset):
    def __init__(self, path, img_size, transform):
        self.path = path
        self.files = os.listdir(self.path+"/images")
        self.img_size = img_size
        self.transform = transform
    def __getitem__(self, index):
        fn = self.files[index]
        img = Image.open(self.path + "/images/" + fn).resize(self.img_size)
        mask = Image.open(self.path + "/masks/" + fn).resize(self.img_size)
        if self.transform:
            img = self.transform(img)
            mask = self.transform(mask)
        return img, mask
    def __len__(self):
        return len(self.files)
train_path = "train"
train_data = MyData(train_path, img_size, transform)
train_data_size = len(train_data)
train_dataloader = DataLoader(train_data, batch_size = 8, shuffle=True)
test_path = "test"
test_data = MyData(test_path, img_size, transform)
test_data_size = len(test_data)
test_dataloader = DataLoader(test_data, batch_size = 1, shuffle=True)
img, mask = train_data.__getitem__(0)
img, mask = img.mul(255).byte(), mask.mul(255).byte() 
img, mask = img.numpy().transpose((1, 2, 0)), mask.numpy().transpose((1, 2, 0))
print("img.shape = {}, mask.shape = {}".format(img.shape, mask.shape))
fig, ax = plt.subplots(1, 3, figsize=(30, 10))
ax[0].imshow(img)
ax[0].set_title('Img')
ax[1].imshow(mask.squeeze())
ax[1].set_title('Mask')
ax[2].imshow(img)
ax[2].contour(mask.squeeze(), colors='k', levels=[0.5])
ax[2].set_title('Mixed')


step3 U-net模型构建

# 连续两次卷积的模块
class Double_Conv2d(nn.Module):
    def __init__(self,in_channel,out_channel):
        super(Double_Conv2d,self).__init__()
        self.conv1=nn.Sequential(
            nn.Conv2d(in_channel,out_channel,kernel_size=3,stride=1,padding=1),
            nn.BatchNorm2d(out_channel),
            nn.ReLU(inplace=True))
        self.conv2=nn.Sequential(
            nn.Conv2d(out_channel,out_channel,kernel_size=3,stride=1,padding=1),
            nn.BatchNorm2d(out_channel),
            nn.ReLU(inplace=True))
    def forward(self, inputs):
        outputs=self.conv1(inputs)
        outputs=self.conv2(outputs)
        return outputs
# 上采样块
class Up_Block(nn.Module):
    def __init__(self,in_channel,out_channel):
        super(Up_Block,self).__init__()
        self.conv=Double_Conv2d(in_channel,out_channel)#卷积
        self.up=nn.ConvTranspose2d(in_channel,out_channel,kernel_size=2,stride=2)#反卷积上采样
    def forward(self, inputs1,inputs2):
        outputs2 = self.up(inputs2)# 上采样
        padding = (outputs2.size()[-1]-inputs1.size()[-1])//2 #shape(batch, channel, width, height)
        outputs1 = F.pad(inputs1, 2*[padding, padding])
        outputs = torch.cat([outputs1,outputs2],1)# 合并
        return self.conv(outputs)# 卷积
#Unet网络
class Unet(nn.Module):
    def __init__(self, in_channel=3):
        super(Unet,self).__init__()
        self.in_channel = in_channel
        #特征缩放
        #filters=[64,128,256,512,1024]# 特征数列表
        filters=[16,32,64,128,256]
        #下采样
        self.conv1 = Double_Conv2d(self.in_channel, filters[0])#卷积
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)#最大池化
        self.conv2 = Double_Conv2d(filters[0], filters[1])
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)
        self.conv3 = Double_Conv2d(filters[1], filters[2])
        self.maxpool3 = nn.MaxPool2d(kernel_size=2)
        self.conv4 = Double_Conv2d(filters[2], filters[3])
        self.maxpool4 = nn.MaxPool2d(kernel_size=2)
        #center
        self.center = Double_Conv2d(filters[3],filters[4])
        #上采样
        self.Up_Block4 = Up_Block(filters[4],filters[3])
        self.Up_Block3 = Up_Block(filters[3],filters[2])
        self.Up_Block2 = Up_Block(filters[2],filters[1])
        self.Up_Block1 = Up_Block(filters[1],filters[0])
        #final conv
        self.final=nn.Conv2d(filters[0], 1, kernel_size=1)
        self.out = nn.Sigmoid()
    def forward(self, inputs):
        conv1=self.conv1(inputs)
        maxpool1=self.maxpool1(conv1)
        conv2=self.conv2(maxpool1)
        maxpool2=self.maxpool2(conv2)
        conv3=self.conv3(maxpool2)
        maxpool3=self.maxpool3(conv3)
        conv4=self.conv4(maxpool3)
        maxpool4=self.maxpool4(conv4)
        center=self.center(maxpool4)
        up4=self.Up_Block4(conv4, center)
        up3=self.Up_Block3(conv3, up4)
        up2=self.Up_Block2(conv2, up3)
        up1=self.Up_Block1(conv1, up2)
        final = self.final(up1)
        return self.out(final)
#创建模型实例,并查看3*512*512的输入图像在每层的参数和输出shape
model = Unet()#创建Unet模型实例
if use_gpu:model = model.cuda()#如果有GPU可用,则将模型转移到GPU上
print(summary(model,(3,512,512)))#输出模型参数

step4:模型训练

def train_model(model, dataloader, data_size, use_gpu, criterion, optimizer, scheduler, num_epochs):
    best_model_wts = model.state_dict()#定义存储最佳模型的字典
    best_loss = np.inf#定义最佳模型的损失
    losslist = []
    for epoch in range(num_epochs):
        print('-' * 10, 'Epoch {}/{}'.format(epoch+1, num_epochs),'-' * 10)
        model.train(True)  # 设置模型为训练模式
        running_loss = 0.0#定义当前轮迭代损失
        for inputs, labels in dataloader:
            if use_gpu:inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())#将输入输入转移到对应设备上
            else:inputs, labels = Variable(inputs), Variable(labels)
            optimizer.zero_grad()# 初始化梯度
            outputs = model(inputs)# Forward得到输出
            loss = criterion(outputs.squeeze(1), labels.squeeze(1))#计算损失
            loss.backward()#损失梯度反传
            optimizer.step()#参数更新
            running_loss += loss.item() * inputs.size(0)#训练损失求和
        epoch_loss = running_loss / data_size
        print('Loss: {:.4f}'.format(epoch_loss))#输出当前轮迭代损失平均值
        scheduler.step()#学习率衰减
        losslist.append(epoch_loss)
        #保存最佳模型
        if epoch_loss < best_loss:
            print('Best Loss improved from {} to {}'.format(best_loss, epoch_loss))
            best_loss = epoch_loss
            best_model_wts = model.state_dict()
    print('Best Loss: {:4f}'.format(best_loss))#输出最佳模型的损失
    model.load_state_dict(best_model_wts)#加载最佳模型
    return model, losslist
criterion = nn.BCEWithLogitsLoss()#定义损失函数
optimizer_ft = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)#参数优化器
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)#每7个epoch学习率下降0.1
num_epochs = 50#机器较差 仅训练10个epoch
#训练模型
model, losslist = train_model(
    model=model,
    dataloader=train_dataloader,
    data_size=train_data_size,
    use_gpu=use_gpu,
    criterion=criterion,
    optimizer=optimizer_ft,
    scheduler=exp_lr_scheduler,
    num_epochs=num_epochs)
#可视化训练过程中损失变化
plt.xlim(0, len(losslist))
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.ylim(0, 1)
plt.plot(losslist)
plt.title('Loss curve')


step5:模型预测及评估

计算混淆矩阵和精度Acc的函数

# 获得混淆矩阵
def BinaryConfusionMatrix(prediction, groundtruth):
    TP = np.float64(np.sum((prediction == 1) & (groundtruth == 1)))
    FP = np.float64(np.sum((prediction == 1) & (groundtruth == 0)))
    FN = np.float64(np.sum((prediction == 0) & (groundtruth == 1)))
    TN = np.float64(np.sum((prediction == 0) & (groundtruth == 0)))
    return TN, FP, FN,TP
# 准确率的计算方法
def get_accuracy(prediction, groundtruth):
    TN, FP, FN,TP = BinaryConfusionMatrix(prediction, groundtruth)
    accuracy = float(TP+TN)/(float(TP + FP + FN + TN) + 1e-6)
    return accuracy
#加载测试数据
acc = []#用于存储每一张test图片的精度
model = model.to('cpu')
model.eval()#不使用BN和Dropout,防止预测图片失真
#Forward不存储梯度
with torch.no_grad():
    for img, mask in test_dataloader:
        pre = model(img)#Forward输出预测结果
        pre = pre.mul(255).byte().squeeze().numpy()#转为uint8的array,方便计算精度
        mask = mask.mul(255).byte().squeeze().numpy()
        _, pre = cv2.threshold(pre,0,1,cv2.THRESH_BINARY | cv2.THRESH_OTSU)#THRESH_OTSU大津法二值化图像,方便计算精度
        _, mask = cv2.threshold(mask,0,1,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
        acc.append(get_accuracy(pre, mask))#计算并存储精度
print('Acc:', [x for x in acc])#输出每张图的精度及平均精度
print('Mean_Acc:{}'.format(np.mean(acc)))

step6:可视化展示

img = img.mul(255).byte().squeeze().numpy().transpose((1, 2, 0))
print("img.shape={}, mask.shape={}, pre.shape={}".format(img.shape, mask.shape, pre.shape))
fig, ax = plt.subplots(1, 3, figsize=(30, 10))
ax[0].imshow(img)
ax[0].set_title('Img')
ax[1].imshow(mask)
ax[1].set_title('Mask')
ax[2].imshow(pre)
ax[2].set_title('Pre')

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
1月前
|
开发框架 网络协议 .NET
C#/.NET/.NET Core优秀项目和框架2024年10月简报
C#/.NET/.NET Core优秀项目和框架2024年10月简报
|
2月前
|
开发框架 前端开发 API
C#/.NET/.NET Core优秀项目和框架2024年9月简报
C#/.NET/.NET Core优秀项目和框架2024年9月简报
|
3月前
|
开发框架 .NET C#
VSCode开发.net项目时调试无效
【9月更文挑战第22天】在使用 VSCode 开发 .NET 项目时遇到调试问题,可从项目配置、调试配置、调试器安装、运行环境、日志和错误信息等方面排查。确认项目类型及文件配置,检查 `launch.json` 文件及配置项,确保调试器扩展已安装并启用,验证 .NET 运行时版本和环境变量,查看 VSCode 输出窗口和项目日志文件,检查权限及代码错误。若问题仍未解决,可查阅官方文档或社区论坛。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
2月前
|
存储 消息中间件 前端开发
.NET常见的几种项目架构模式,你知道几种?
.NET常见的几种项目架构模式,你知道几种?
101 0
|
2月前
|
边缘计算 开发框架 人工智能
C#/.NET/.NET Core优秀项目和框架2024年8月简报
C#/.NET/.NET Core优秀项目和框架2024年8月简报
|
2月前
|
Cloud Native API C#
.NET云原生应用实践(一):从搭建项目框架结构开始
.NET云原生应用实践(一):从搭建项目框架结构开始
|
4月前
|
jenkins 测试技术 持续交付
解锁.NET项目高效秘籍:从理论迷雾到实践巅峰,持续集成与自动化测试如何悄然改变游戏规则?
【8月更文挑战第28天】在软件开发领域,持续集成(CI)与自动化测试已成为提升效率和质量的关键工具。尤其在.NET项目中,二者的结合能显著提高开发速度并保证软件稳定性。本文将从理论到实践,详细介绍CI与自动化测试的重要性,并以ASP.NET Core Web API项目为例,演示如何使用Jenkins和NUnit实现自动化构建与测试。每次代码提交后,Jenkins自动触发构建流程,通过编译和运行NUnit测试确保代码质量。这种方式不仅节省了时间,还能快速发现并解决问题,推动.NET项目开发迈向更高水平。
51 8
|
4月前
|
架构师 开发者
【悬念揭秘】DDD:那片隐藏在软件深处的业务乐土——.NET项目如何借力领域驱动设计,让复杂业务逻辑迎刃而解?
【8月更文挑战第28天】领域驱动设计(DDD)在.NET项目中的应用聚焦于将业务领域知识与软件开发紧密结合,通过构建清晰的领域模型管理复杂业务逻辑。DDD的核心概念包括限界上下文、聚合、实体等,确保模型与实现的统一。在.NET中,通过CQRS和事件源等模式提高系统响应性和可扩展性,实现业务事件驱动的解耦与协作。DDD不仅是一种设计方法,更是要求开发者深入理解业务的文化,助力.NET项目应对复杂挑战,实现业务与技术的融合。
68 6
|
4月前
|
设计模式 存储 前端开发
揭秘.NET架构设计模式:如何构建坚不可摧的系统?掌握这些,让你的项目无懈可击!
【8月更文挑战第28天】在软件开发中,设计模式是解决常见问题的经典方案,助力构建可维护、可扩展的系统。本文探讨了.NET中三种关键架构设计模式:MVC、依赖注入与仓储模式,并提供了示例代码。MVC通过模型、视图和控制器分离关注点;依赖注入则通过外部管理组件依赖提升复用性和可测性;仓储模式则统一数据访问接口,分离数据逻辑与业务逻辑。掌握这些模式有助于开发者优化系统架构,提升软件质量。
61 5