深度学习落地实战:基于UNet实现血管瘤超声图像分割

前言

大家好,我是机长

本专栏将持续收集整理市场上深度学习的相关项目,旨在为准备从事深度学习工作或相关科研活动的伙伴,储备、提升更多的实际开发经验,每个项目实例都可作为实际开发项目写入简历,且都附带完整的代码与数据集。可通过百度云盘进行获取,实现开箱即用

正在跟新中~

项目背景

(基于UNet实现血管瘤超声图像分割)

血管瘤是一种常见的血管异常疾病,尤其在婴幼儿中具有较高的发病率。超声检查作为一种无创的诊断手段,能够为临床提供血管瘤的位置、形状及累及范围等重要信息,对指导医生进一步治疗至关重要。然而,目前血管瘤病灶的分割主要依赖于专家的人工勾画,这不仅耗时耗力,还容易受到临床经验水平的影响,导致分割结果存在人为误差。因此,利用深度学习技术实现血管瘤超声图像的自动精准分割,成为了一个医学应用与研究的热点方向方向。

项目环境

  • 平台:windows 10
  • 语言环境:python 3.8
  • 编辑器:PyCharm
  • PyThorch版本:1.8

1.创建并跳转到虚拟环境

python -m venv myenvmyenv\Scripts\activate.bat

2. 虚拟环境pip命令安装其他工具包

pip install torch torchvision torchaudio

注:此处只示范安装pytorch,其他工具包安装类似,可通过运行代码查看所确实包提示进行安装

3.pycharm 运行环境配置

进入pytcharm =》点击file =》点击settings=》点击Project:...=》点击 Python Interpreter,进入如下界面

点击add =》点击Existing environment  =》 点击 ... =》选择第一步1创建虚拟环境目录myenv\Scripts\下的python.exe文件点击ok完成环境配置

数据集介绍

数据集分分训练数据集与标签数据集

                

       训练数据样式                                                               标注数据样式

训练数据获取:

私信博主获取

UNet网络介绍

U-Net网络的以其独特的U型结构著称,这种结构由编码器(Encoder)和解码器(Decoder)两大部分组成,非常适合于医学图像分割等任务。下面我将进一步解释您提到的关键点,并补充一些细节。

Encoder(编码器)
  • 结构:编码器的左半部分主要负责特征提取。它通过多个卷积层(通常是3x3的卷积核)和ReLU激活函数来逐层提取图像的特征。在每个卷积层组合之后,通常会添加一个2x2的最大池化层(Max Pooling)来降低特征图的分辨率,并增加感受野。这种下采样操作有助于捕获图像中的全局信息。
  • 作用:编码器通过逐层提取和抽象化图像特征,为后续的分割任务提供丰富的信息。
Decoder(解码器)
  • 结构:解码器的右半部分则负责将编码器提取的特征图恢复到原始图像的分辨率,以便进行像素级别的分类。它首先通过上采样(通常是转置卷积或双线性插值)来增加特征图的尺寸,然后通过特征拼接(Concatenation)将上采样后的特征图与编码器对应层级的特征图进行融合。之后,再通过卷积层和ReLU激活函数进一步处理融合后的特征图。
  • 特征拼接:与FCN(全卷积网络)的逐点相加不同,U-Net使用特征拼接来融合不同层级的特征图。这种拼接方式能够保留更多的特征信息,形成更“厚”的特征图,但同时也需要更多的显存来存储这些特征。
  • 作用:解码器通过逐步上采样和特征融合,将编码器提取的高级特征与低级特征相结合,恢复出精细的图像分割结果。
优点与挑战
  • 优点:U-Net网络结构简洁,但性能强大,特别适用于医学图像分割等任务。其独特的U型结构和特征拼接方式使得网络能够同时捕获全局和局部特征,从而实现高精度的分割。
  • 挑战:尽管U-Net在性能上表现出色,但其对显存的需求也相对较高。特别是当处理高分辨率图像或进行大规模训练时,显存消耗可能会成为限制因素。此外,网络的设计和训练也需要大量的专业知识和经验。

综上所述,U-Net网络通过其独特的编码器-解码器结构和特征拼接方式,在医学图像分割等领域取得了显著成效。然而,在实际应用中仍需注意显存消耗等挑战,并不断探索更高效的优化方法。

pytorch实现UNet网络

class double_conv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=3, strides=1, padding=1):super(double_conv2d_bn, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.conv2 = nn.Conv2d(out_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)self.bn2 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = F.relu(self.bn2(self.conv2(out)))return outclass deconv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=2, strides=2):super(deconv2d_bn, self).__init__()self.conv1 = nn.ConvTranspose2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))return outclass Unet(nn.Module):def __init__(self):super(Unet, self).__init__()self.layer1_conv = double_conv2d_bn(1, 8)self.layer2_conv = double_conv2d_bn(8, 16)self.layer3_conv = double_conv2d_bn(16, 32)self.layer4_conv = double_conv2d_bn(32, 64)self.layer5_conv = double_conv2d_bn(64, 128)self.layer6_conv = double_conv2d_bn(128, 64)self.layer7_conv = double_conv2d_bn(64, 32)self.layer8_conv = double_conv2d_bn(32, 16)self.layer9_conv = double_conv2d_bn(16, 8)self.layer10_conv = nn.Conv2d(8, 1, kernel_size=3,stride=1, padding=1, bias=True)self.deconv1 = deconv2d_bn(128, 64)self.deconv2 = deconv2d_bn(64, 32)self.deconv3 = deconv2d_bn(32, 16)self.deconv4 = deconv2d_bn(16, 8)self.sigmoid = nn.Sigmoid()def forward(self, x):conv1 = self.layer1_conv(x)pool1 = F.max_pool2d(conv1, 2)conv2 = self.layer2_conv(pool1)pool2 = F.max_pool2d(conv2, 2)conv3 = self.layer3_conv(pool2)pool3 = F.max_pool2d(conv3, 2)conv4 = self.layer4_conv(pool3)pool4 = F.max_pool2d(conv4, 2)conv5 = self.layer5_conv(pool4)convt1 = self.deconv1(conv5)concat1 = torch.cat([convt1, conv4], dim=1)conv6 = self.layer6_conv(concat1)convt2 = self.deconv2(conv6)concat2 = torch.cat([convt2, conv3], dim=1)conv7 = self.layer7_conv(concat2)convt3 = self.deconv3(conv7)concat3 = torch.cat([convt3, conv2], dim=1)conv8 = self.layer8_conv(concat3)convt4 = self.deconv4(conv8)concat4 = torch.cat([convt4, conv1], dim=1)conv9 = self.layer9_conv(concat4)outp = self.layer10_conv(conv9)outp = self.sigmoid(outp)return outp

自定义加载数据集

class LiverDataset(data.Dataset):def __init__(self, root, transform=None, target_transform=None, mode='train'):n = len(os.listdir(root + '/images'))imgs = []if mode == 'train':for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])else:for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])self.imgs = imgsself.transform = transformself.target_transform = target_transformdef __getitem__(self, index):x_path, y_path = self.imgs[index]img_x = Image.open(x_path)img_y = Image.open(y_path)if self.transform is not None:img_x = self.transform(img_x)if self.target_transform is not None:img_y = self.target_transform(img_y)return img_x, img_ydef __len__(self):return len(self.imgs)

完整代码

import osimport PIL.Image as Image
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg')
#module 'backend_interagg' has no attribute 'FigureCanvas',报错执行pip install matplotlib==3.5.0
import numpy as np
#关于numpy 报错时执行 pip install numpy==1.23.5
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as data
from torchvision import transforms
from tqdm import tqdmepochs = 1
batch_size = 32
device = 'cpu'
best_model = None
best_loss = 999
save_path = './checkpoints/best_model.pkl'
directory_path = './checkpoints'# 检查目录是否存在
if not os.path.exists(directory_path):# 如果目录不存在,则创建它os.makedirs(directory_path)class double_conv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=3, strides=1, padding=1):super(double_conv2d_bn, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.conv2 = nn.Conv2d(out_channels, out_channels,kernel_size=kernel_size,stride=strides, padding=padding, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)self.bn2 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = F.relu(self.bn2(self.conv2(out)))return outclass deconv2d_bn(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=2, strides=2):super(deconv2d_bn, self).__init__()self.conv1 = nn.ConvTranspose2d(in_channels, out_channels,kernel_size=kernel_size,stride=strides, bias=True)self.bn1 = nn.BatchNorm2d(out_channels)def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))return outclass Unet(nn.Module):def __init__(self):super(Unet, self).__init__()self.layer1_conv = double_conv2d_bn(1, 8)self.layer2_conv = double_conv2d_bn(8, 16)self.layer3_conv = double_conv2d_bn(16, 32)self.layer4_conv = double_conv2d_bn(32, 64)self.layer5_conv = double_conv2d_bn(64, 128)self.layer6_conv = double_conv2d_bn(128, 64)self.layer7_conv = double_conv2d_bn(64, 32)self.layer8_conv = double_conv2d_bn(32, 16)self.layer9_conv = double_conv2d_bn(16, 8)self.layer10_conv = nn.Conv2d(8, 1, kernel_size=3,stride=1, padding=1, bias=True)self.deconv1 = deconv2d_bn(128, 64)self.deconv2 = deconv2d_bn(64, 32)self.deconv3 = deconv2d_bn(32, 16)self.deconv4 = deconv2d_bn(16, 8)self.sigmoid = nn.Sigmoid()def forward(self, x):conv1 = self.layer1_conv(x)pool1 = F.max_pool2d(conv1, 2)conv2 = self.layer2_conv(pool1)pool2 = F.max_pool2d(conv2, 2)conv3 = self.layer3_conv(pool2)pool3 = F.max_pool2d(conv3, 2)conv4 = self.layer4_conv(pool3)pool4 = F.max_pool2d(conv4, 2)conv5 = self.layer5_conv(pool4)convt1 = self.deconv1(conv5)concat1 = torch.cat([convt1, conv4], dim=1)conv6 = self.layer6_conv(concat1)convt2 = self.deconv2(conv6)concat2 = torch.cat([convt2, conv3], dim=1)conv7 = self.layer7_conv(concat2)convt3 = self.deconv3(conv7)concat3 = torch.cat([convt3, conv2], dim=1)conv8 = self.layer8_conv(concat3)convt4 = self.deconv4(conv8)concat4 = torch.cat([convt4, conv1], dim=1)conv9 = self.layer9_conv(concat4)outp = self.layer10_conv(conv9)outp = self.sigmoid(outp)return outpclass LiverDataset(data.Dataset):def __init__(self, root, transform=None, target_transform=None, mode='train'):n = len(os.listdir(root + '/images'))imgs = []if mode == 'train':for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])else:for i in range(n):img = os.path.join(root, 'images',"%d.png" % (i + 1))mask = os.path.join(root, 'mask', "%d.png" % (i + 1))imgs.append([img, mask])self.imgs = imgsself.transform = transformself.target_transform = target_transformdef __getitem__(self, index):x_path, y_path = self.imgs[index]img_x = Image.open(x_path)img_y = Image.open(y_path)if self.transform is not None:img_x = self.transform(img_x)if self.target_transform is not None:img_y = self.target_transform(img_y)return img_x, img_ydef __len__(self):return len(self.imgs)x_transform = transforms.Compose([transforms.ToTensor(),transforms.RandomResizedCrop(224),transforms.Grayscale(num_output_channels=1)
])y_transform = transforms.Compose([transforms.ToTensor(),transforms.RandomResizedCrop(224)
])liver_dataset = LiverDataset("./data/train", transform=x_transform, target_transform=y_transform)
dataloader = torch.utils.data.DataLoader(liver_dataset, batch_size=batch_size, shuffle=True)model = Unet()
criterion = torch.nn.BCELoss()
#criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())for epoch in range(epochs):model.train()epoch_loss = 0train_bar = tqdm(dataloader)for x, y in train_bar:optimizer.zero_grad()inputs = x.to(device)labels = y.to(device)outputs = model(inputs)labels=labels.bool().float()loss = criterion(outputs, labels)loss.backward()optimizer.step()epoch_loss += loss.item()print("【EPOCH: 】%s" % str(epoch + 1))print("训练损失为%s" % str(epoch_loss))if epoch_loss < best_loss:best_loss = epoch_lossbest_model = model.state_dict()# 在训练结束保存最优的模型参数if epoch == epochs - 1:# 保存模型torch.save(best_model, save_path)print('Finished Training')plt.figure('测试一张图片')
pil_img = Image.open('./data/train/images/1.png')
np_img = np.array(pil_img)
plt.imshow(np_img)
plt.show()plt.figure('测试一张蒙版图片')
pil_img = Image.open('./data/train/mask/1.png')
np_img = np.array(pil_img)
plt.imshow(np_img)
plt.show()

开启训练

训练结果展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/47107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

minimap2安装与使用(v 2.28)生物信息学工具26

01 背景 Minimap2 是一个多功能的序列比对程序&#xff0c;可以将 DNA 或 mRNA 序列与大型参考数据库进行比对。典型的使用案例包括&#xff1a;&#xff08;1&#xff09;将 PacBio 或 Oxford Nanopore 基因组读长映射到人类基因组&#xff1b;&#xff08;2&#xff09;在误…

类和对象(补充)

1.static成员 1>静态成员变量在类外进行初始化 2>静态成员变量为所有类对象所共享&#xff0c;不属于任何具体对象&#xff0c;存放在静态区中 3>静态成员函数没有this指针&#xff0c;可访问其他静态成员&#xff0c;但不可访问非静态的 4>非静态成员函数可以…

jmeter做接口压力测试_jmeter接口性能测试

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是免…

SQL Server 使用 OPTION (RECOMPILE) 和查询存储的查询

设置 我们正在使用 WideWorldImporters 数据库&#xff0c;您可以从 Github 下载【sql-server-samples/samples/databases/wide-world-importers at master microsoft/sql-server-samples GitHub】。我正在运行SQL Server 2017 的最新 CU【https://sqlserverbuilds.b…

[Vulnhub] digitalworld.local-JOY snmp+ProFTPD权限提升

信息收集 IP AddressOpening Ports192.168.101.150TCP:21,22,25,80,110,139,143,445,465,587,993,995 $ nmap -p- 192.168.101.150 --21,22,25,min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD | ftp-anon: Anonymous FTP logi…

基于Java中的SSM框架实现求职招聘网站系统项目【项目源码】

基于Java中的SSM框架实现线求职招聘网站系统演示 研究方法 本文的研究方法主要有&#xff1a; &#xff08;1&#xff09;调查法 调查法就是在系统的构思阶段&#xff0c;设计者对系统的功能和系统的现状有些不了解&#xff0c;需要去实地的去和本系统相关的区域进行调查&am…

函数的形状怎么定义?

在TypeScript中&#xff0c;函数的形状可以通过多种方式定义&#xff0c;以下是几种主要的方法&#xff1a; 1、函数声明&#xff1a;使用function关键字声明函数&#xff0c;并直接在函数名后的括号内定义参数&#xff0c;通过冒号&#xff08;:&#xff09;指定参数的类型&a…

Mojo AI编程语言(六)异常处理:提升代码健壮性

目录 1. 概述 2. 异常处理的基本概念 2.1 什么是异常 2.2 异常处理的重要性 3. Mojo语言中的异常处理机制 3.1 异常的定义 3.2 抛出异常 3.3 捕获异常 4. 异常处理的详细实现 4.1 多重异常捕获 4.2 异常链 4.3 使用自定义异常 4.4 异常的嵌套捕获 4.5 使用 asser…

数据结构——单链表详解(超详细)(2)

前言&#xff1a; 上一篇文章小编简单的介绍了单链表的概念和一些函数的实现&#xff0c;不过为了保证文章的简洁&#xff0c;小编把它分成了两篇来写&#xff0c;这一篇小编紧接上一篇文章继续写单链表函数功能的实现&#xff1a; 目录&#xff1a; 1.单链表剩余函数的编写 1.…

Lua 运算符

Lua 运算符 Lua 是一种轻量级的编程语言&#xff0c;广泛用于游戏开发、脚本编写和其他应用程序。它具有一套丰富的运算符&#xff0c;用于执行各种数学和逻辑操作。本文将详细介绍 Lua 中的运算符&#xff0c;包括算术运算符、关系运算符、逻辑运算符和其他特殊运算符。 算术…

高级java每日一道面试题-2024年7月17日

面试官: java中都有哪些引用类型? 我回答: 强引用&#xff08;Strong Reference&#xff09; 描述&#xff1a;这是最常见和最直观的引用类型&#xff0c;我们通常在代码中创建的对象引用就是强引用。例如&#xff0c;Object obj new Object();。只要强引用存在&#xff0c;…

Idea如何快速高效的修改项目的包名

文章目录 前言一、全局替换的快捷键二、弹出如下的界面 前言 当我们有时候在做项目迁移的时候&#xff0c;需要快速的修改项目的包名&#xff01;那么如何快速高效的修改项目的报名呢&#xff1f; 经过尝试了很多方法&#xff01;最简单的方法就是利用全局替换来直接替换报名&…

微服务到底是个什么东东?

微服务架构是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间互相协调、互相配合&#xff0c;为用户提供最终价值。 每个服务运行在其独立的进程中&#xff0c;服务和服务间采用轻量级的通信机制互相沟通&#xff08;通常是基于 HTTP 的…

通过反射机制给已知属性赋值

最近在看spring&#xff0c;在手写spring框架之前&#xff0c;需要巩固一下反射。 反射有这样一个简单的例子&#xff0c;记录一下。 假如你知道age这个属性名&#xff0c;但是不知道属性类型&#xff0c;也可以写&#xff1a; 可以获取到属性的类型

昇思25天学习打卡营第11天 | mindspore 实现 ResNet 50 迁移学习

1. 背景&#xff1a; 使用 mindspore 学习神经网络&#xff0c;打卡第 11 天&#xff1b;主要内容也依据 mindspore 的学习记录。 2. 迁移学习介绍&#xff1a; mindspore 实现 ResNet 50 迁移学习&#xff1b; 具体 ResNet 50 的模型原理以及实现&#xff0c;可以参考本博客…

谈谈我对李彦宏说的“不要卷模型,要卷应用”的理解

我理解李彦宏的发言是强调人工智能技术应该关注应用而不是仅仅关注模型的发展。他认为AI技术已经从辨别式&#xff08;discriminative&#xff09;转向了生成式&#xff08;generative&#xff09;&#xff0c;意味着AI不再仅仅是识别和分类问题&#xff0c;而是能够创造新的内…

设计模式-领域逻辑模式-事务脚本(Transaction Script)

事务脚本的特点 多数应用可看成由多个事务组成事务脚本将多个业务逻辑组织成单个过程事务间相互修改各自产生的数据 事务脚本的运行机制 使用事务脚本时&#xff0c;领域逻辑主要通过系统所执行的事务来组织。例如&#xff1a;预定酒店过程。 事务脚本的组织 将整个事务脚本放…

【BUG】已解决:IndexError: list index out of range

已解决&#xff1a;IndexError: list index out of range 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区…

微信小程序:2.全局开发

app实例 简介 app.js中注册小程序实例的方法App拥有生命周期回调函数、错误监听函数、页面不存在监听函数等 生命周期回调函数 onLaunch(options) {//监听小程序初始化 console.log("监听小程序初始化",options); }, onShow (options) {//监听小程序启动或切前台…

Ubuntu串口调试单片机

来自🥬🐶程序员 Truraly | 田园 的博客,最新文章首发于:田园幻想乡 | 原文链接 | github (欢迎关注) 文章目录 brltty 导致 USB 转串口连接失败串口调试工具直接操作串口puttySerial Monitor | vscode 插件minicom(推荐)舍友在搞 c-sky 的单片机,囚来了一块玩玩,尝…