20 | 图像分割(下):如何构建一个图像分割模型?
数据部分
分割图像的标记
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何使用UNet实现图像分割项目。作者首先介绍了数据准备部分,包括对训练数据进行标记和数据读取工作。标记工作需要使用Labelme工具,作者详细介绍了标记的七个步骤,并提供了相应的代码示例。数据读取部分则使用PyTorch将数据读入,并展示了相关的代码。接着,文章介绍了UNet的网络结构,包括Encoder-Decoder类型的分割网络、重复的卷积块、上采样过程以及对二分类问题的处理。作者还介绍了Dice Loss作为常用的损失函数,并提供了相应的代码实现。最后,文章展示了模型训练的流程,包括模型实例化、损失函数定义、优化方法选择以及训练过程的代码示例。整篇文章结合理论知识和实际操作,为读者提供了一个完整的图像分割项目实现过程。文章内容涵盖了数据准备、网络结构、损失函数和训练流程,适合对图像分割感兴趣的读者快速了解UNet的实现方法。文章还介绍了模型预测和评估的过程,以及对学习任务的小结和每课一练的建议,为读者提供了进一步学习和实践的方向。
《PyTorch 深度学习实战》,新⼈⾸单¥59
全部留言(22)
- 最新
- 精选
- 克bug体质老师你好,Loss也要放到放到gpu后也会报和之前一样的错误:【 Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu! (when checking argument for argument weight in method wrapper__cudnn_batch_norm) File "D:\U-Net\unet.py", line 25, in forward x = nn.BatchNorm2d(num_features=self.features)(x) File "D:\U-Net\unet.py", line 67, in forward conv_encoder_1_1 = self.conv_encoder_1(x) File "D:\U-Net\train.py", line 50, in main y_pred = unet(x) File "D:\U-Net\train.py", line 136, in <module> main(args) 】 我尝试在unet.py文件中的创建class UNet中self.conv_encoder_1 = Block(in_channels, features)改为:self.conv_encoder_1 = Block(in_channels, features).to(device)后也没解决这个问题,会报一样的错。
作者回复: hi,原因是如果在forward中使用了nn调用网络中的层的话,它默认会放在cpu上计算。 解决的办法就是把bn和relu放到__init__中,如下代码所示。 class Block(nn.Module): def __init__(self, in_channels, features): super().__init__() self.features = features self.conv1 = nn.Conv2d( in_channels=in_channels, out_channels=features, kernel_size=3, padding='same', ) self.bn1 = nn.BatchNorm2d(num_features=self.features) self.relu1 = nn.ReLU() self.conv2 = nn.Conv2d( in_channels=features, out_channels=features, kernel_size=3, padding='same', ) self.bn2 = nn.BatchNorm2d(num_features=self.features) self.relu2 = nn.ReLU() def forward(self, input): x = self.conv1(input) x = self.bn1(x) x = self.relu1(x) x = self.conv2(x) x = self.bn2(x) x = self.relu2(x) return x 同理U-Net中的pooling也要放到__init__()中。
2022-02-1445 - ..................真的很棒,我要亲手操作一遍
作者回复: ^^ 感谢支持,加油
2022-05-062 - 蓝色天空 好萌啊老师你好,请问有这节课的完整代码地址吗?
作者回复: hello,你好,我传到这里了。 https://github.com/syuu1987/geekTime-semantic-segmentation/tree/main
2022-01-211 - Geek_a95f0e方老师,可不可以解释一下自定义类中 super().__init__() 和super(class_name,self).__init__() 有什么区别?
作者回复: hi 你好。感谢你的留言。 这块可能我误导你了,都是一样的。 Python3中super().__init__()代替了Python2中的super(class_name,self).__init__()
2021-12-1321 - vcjmhg老师您好,我自己有尝试复现deeplab v3+这个比较主流的语义分割网络,然后发现针对一些尺寸较大的目标其分割效果还是比较不错的,但是对小的目标分割效果很差,甚至好多时候都分割不到,请问针对这种小目标,除了在数据集上做处理外,还有哪些好的处理或者优化方法呢?
作者回复: hello,小物体分割不好的一个原因是在backbone的特征提取过程中,小物体的信息已经被忽略了。 举个例子,假设输入是256x256的数据,经过多层的特征提取后特征图依次为128x128,64x64,32x32,16x16。有可能小物体的信息在32x32那里就消失了。 从这个角度出发,可以看看能不能调整网络最小的特征图的大小,来解决小物体分割不好的问题(比如Unet中,删除最后一次下采样)。另外,你也要看看小物体是不是resize到训练数据尺寸的时候已经没有了。
2021-11-2721 - Geek_niu老师你好,请问数据准备中,标记好的图片有什么作用呢,谢谢
作者回复: 你好,标记好数据就是label,也就是告诉模型需要学什么。
2024-03-05归属地:北京 - 学渣汪在央企打怪升级老师你好,非常感谢老师的耐心,我成功的跑通了自己的一个实例。但目前遇到如下问题,麻烦老师有空的时候能提点一下。 使用unet训练,还是老师的代码,差不多是40 epoch之后,预测出来的图像分割,预测对的点的概率非常集中,大概都在[1,...,0.99999535 0.9999949 0.9999943 0.9999933 0.999992 0.9999907 0.9999889 0.99998796 0.99998724 0.9999856 0.99998343 0.99998116 0.99997723 0.99997675 0.9999764 0.9999703 0.9999577 0.9999535 0.9999486 0.9999453 0.999944 0.99992955 0.99992025 0.9999181 0.9999089 0.9999058 0.9998952 0.99984705 0.9998202 0.9996326 0.9996008 0.9995078 0.99922884 0.9967386 0.99539775 0.995391 0.991197 0.9906724 0.9892915 0.9892553 0.9782649 0.96968466 0.95937544 0.9416338 0.93462884 0.91682875 0.8949944 0.87671226 0.75603426 0.7475551 0.7284518 0.6420492 0.62891126 0.5325708 0.52544403, ... ] 请教一下,这样是不是过拟合了。有没有什么好的方法可以使得预测概率有阈值可选?丰富样本吗?麻烦老师了。
作者回复: 感觉不像过拟合。数据标的没有问题吗?可以看看前几个epoch结果什么样子。
2022-11-29归属地:辽宁2 - 学渣汪在央企打怪升级方老师,请教一下: 如果我不是对图片进行语义分割,而是对类似视频,比如(400,384,288)的数据立方体进行语义分割,还可以使用unet吗?如果使用的话,这个示例里的通道数是从3->512->32->1,那么这种400通道的该怎么处理? 谢谢。
作者回复: 理论上,代码是肯定能执行通过的。不过我对视频没有研究,不知道分割效果如何。
2022-10-30归属地:北京 - gavin方老师,请问一下如果是多分类,特征图输出要怎么弄?
作者回复: 您好,多分类时让网络最终输出的个数等于类别数,然后加softmax即可。
2022-09-16归属地:辽宁 - John(易筋)predict_single.py 代码改了一下文件的相对路径可以跑通,发现output.jpg 大小为256x256. 原图微1024x640. 请教方老师,为啥语义分割出来的图片不是原始图片的等比缩小呢? 谢谢 ``` import torch import numpy as np from PIL import Image img_size = (256, 256) unet = torch.load('./ckpts/unet_epoch_51.pth') unet.eval() im = np.asarray(Image.open('./data/JPEGImages/6.jpg').resize(img_size)) im = im / 255. im = im.transpose(2, 0, 1) im = im[np.newaxis, :, :] im = im.astype('float32') output = unet(torch.from_numpy(im)).detach().numpy() output = np.squeeze(output) output = np.where(output>0.5, 150, 0).astype(np.uint8) print(output.shape, type(output)) im = Image.fromarray(output) im.save('./output.jpg') ```
作者回复: hi,你好。感谢留言。 这个尺寸是取决于网络的设计。 256x256的分割结果是可以resize回1024x640的。 当然,如果你设计的网络的输入输出支持1024x640的等比例缩放,也是可以的。
2022-08-23归属地:北京