深度学习语义分割篇——FCN源码解析篇

这篇具有很好参考价值的文章主要介绍了深度学习语义分割篇——FCN源码解析篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题

🍊往期回顾:深度学习语义分割篇——FCN原理详解篇

🍊近期目标:写好专栏的每一篇文章

🍊支持小苏:点赞👍🏼、收藏⭐、留言📩

 

深度学习语义分割篇——FCN源码解析篇

写在前面

​  本篇文章参考霹雳吧啦Wz在B站上的视频进行讲解,点击☞☞☞下载FCN源码。阅读本文之前建议先阅读上篇对FCN原理讲解的文章。

​  本文将从数据集读取、模型训练、模型推理和模型搭建几部分为大家讲解,每次做代码的讲解我都要说一句话,就是不管是看视频还是看文章只是对你了解代码起辅助的作用,你应花更多的时间自己调试,这样你会对整个代码的流程无比熟悉!!!🥝🥝🥝

​  废话也不多说了,让我们一起来看看FCN的源码吧。🥂🥂🥂

 

数据集读取——my_dataset.py

​  在读取数据集部分,我们定义了一个VOCSegmentation类,首先我们需要获取输入(image)和标签(target)的路径,相关代码如下:

class VOCSegmentation(data.Dataset):
    def __init__(self, voc_root, year="2012", transforms=None, txt_name: str = "train.txt"):
        super(VOCSegmentation, self).__init__()
        assert year in ["2007", "2012"], "year must be in ['2007', '2012']"
        root = os.path.join(voc_root, "VOCdevkit", f"VOC{year}")
        assert os.path.exists(root), "path '{}' does not exist.".format(root)
        image_dir = os.path.join(root, 'JPEGImages')
        mask_dir = os.path.join(root, 'SegmentationClass')

        txt_path = os.path.join(root, "ImageSets", "Segmentation", txt_name)
        assert os.path.exists(txt_path), "file '{}' does not exist.".format(txt_path)
        with open(os.path.join(txt_path), "r") as f:
            file_names = [x.strip() for x in f.readlines() if len(x.strip()) > 0]

        self.images = [os.path.join(image_dir, x + ".jpg") for x in file_names]
        self.masks = [os.path.join(mask_dir, x + ".png") for x in file_names]

​  这部分非常简单啦,voc_root我们应该传入VOCdevkit所在的文件夹,以我的数据路径为例,我应指定voc_root="D:\数据集\VOC\VOCtrainval_11-May-2012"

深度学习语义分割篇——FCN源码解析篇

​  最终self.image和self.masks里存储的就是我们输入和标签的路径了。接着我们对输入图片和标签进行transformer预处理,本代码主要进行了随机缩放、水平翻转、随机裁剪、toTensor和Normalize【训练集采用了这些,验证集仅使用了随机缩放、toTensor和Normalize】,相关代码如下:【这部分代码其实是在train.py文件中的,这里放在了此部分讲解】

#训练集所用预处理方法
class SegmentationPresetTrain:
    def __init__(self, base_size, crop_size, hflip_prob=0.5, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):
        min_size = int(0.5 * base_size)
        max_size = int(2.0 * base_size)

        trans = [T.RandomResize(min_size, max_size)]
        if hflip_prob > 0:
            trans.append(T.RandomHorizontalFlip(hflip_prob))
        trans.extend([
            T.RandomCrop(crop_size),
            T.ToTensor(),
            T.Normalize(mean=mean, std=std),
        ])
        self.transforms = T.Compose(trans)

    def __call__(self, img, target):
        return self.transforms(img, target)


# 验证集所用预处理方法
class SegmentationPresetEval:
    def __init__(self, base_size, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):
        self.transforms = T.Compose([
            T.RandomResize(base_size, base_size),
            T.ToTensor(),
            T.Normalize(mean=mean, std=std),
        ])

    def __call__(self, img, target):
        return self.transforms(img, target)

​  上述代码中crop_size设置为480,即训练图片都会裁剪到480*480大小,而验证时没有使用随机裁剪方法,因此验证集的图片尺寸是不一致的。

​  在数据集读取类中,还定义了collate_fn方法,其实在训练过程中加载数据时用到的,定义了我们数据是如何打包的,代码如下:

def collate_fn(batch):
    images, targets = list(zip(*batch))
    batched_imgs = cat_list(images, fill_value=0)
    batched_targets = cat_list(targets, fill_value=255)
    return batched_imgs, batched_targets


def cat_list(images, fill_value=0):
    # 计算该batch数据中,channel, h, w的最大值
    max_size = tuple(max(s) for s in zip(*[img.shape for img in images]))
    batch_shape = (len(images),) + max_size
    batched_imgs = images[0].new(*batch_shape).fill_(fill_value)
    for img, pad_img in zip(images, batched_imgs):
        pad_img[..., :img.shape[-2], :img.shape[-1]].copy_(img)
    return batched_imgs

​  这个方法即是将我们一个batch的数据打包到一块儿,一起输入网络。这里光看代码可能不好理解,打上断点调试调试吧!!!🌿🌿🌿

 

模型训练——train.py

​  其实,模型的训练步骤大致都差不多,不熟悉的可以先参考我的这篇博文:使用pytorch自己构建网络模型实战🥫🥫🥫

​  下面一起来看看FCN的训练过程吧!!!🍚🍚🍚

数据集读取和加载

# VOCdevkit -> VOC2012 -> ImageSets -> Segmentation -> train.txt
train_dataset = VOCSegmentation(args.data_path,
                                year="2012",
                                transforms=get_transform(train=True),
                                txt_name="train.txt")

# VOCdevkit -> VOC2012 -> ImageSets -> Segmentation -> val.txt
val_dataset = VOCSegmentation(args.data_path,
                              year="2012",
                              transforms=get_transform(train=False),
                              txt_name="val.txt")


train_loader = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size,
                                           num_workers=num_workers,
                                           shuffle=True,
                                           pin_memory=True,
                                           collate_fn=train_dataset.collate_fn)

val_loader = torch.utils.data.DataLoader(val_dataset,
                                         batch_size=1,
                                         num_workers=num_workers,
                                         pin_memory=True,
                                         collate_fn=val_dataset.collate_fn)

​  我想这部分大家肯定没什么问题啦,每个网络训练基本都是这样的数据读取和加载步骤,我就不过多介绍了。☘☘☘

 

创建网络模型

model = create_model(aux=args.aux, num_classes=num_classes)

​  这里大家现在大家就可以理解为是FCN原理部分所创建的模型,即以VGG为backbone构建的网络。有关网络模型的搭建我会在下文讲述。🥦🥦🥦

 

设置损失函数、优化器

# 设置优化器
optimizer = torch.optim.SGD(
        params_to_optimize,
        lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay
    )

​  此代码损失函数的设置是在训练一个epoch数据时定义的,使用的是cross_entropy损失函数,后文会重点解释。🥗🥗🥗

 

网络训练✨✨✨

for epoch in range(args.start_epoch, args.epochs):
    mean_loss, lr = train_one_epoch(model, optimizer, train_loader, device, epoch,
    lr_scheduler=lr_scheduler, print_freq=args.print_freq, scaler=scaler)

​ 上面定义了一个train_one_epoch方法,我们一起来看看:

def train_one_epoch(model, optimizer, data_loader, device, epoch, lr_scheduler, print_freq=10, scaler=None):
    model.train()
    metric_logger = utils.MetricLogger(delimiter="  ")
    metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value:.6f}'))
    header = 'Epoch: [{}]'.format(epoch)

    for image, target in metric_logger.log_every(data_loader, print_freq, header):
        image, target = image.to(device), target.to(device)
        with torch.cuda.amp.autocast(enabled=scaler is not None):
            output = model(image)
            loss = criterion(output, target)

        optimizer.zero_grad()
        if scaler is not None:
            scaler.scale(loss).backward()
            scaler.step(optimizer)
            scaler.update()
        else:
            loss.backward()
            optimizer.step()

        lr_scheduler.step()

        lr = optimizer.param_groups[0]["lr"]
        metric_logger.update(loss=loss.item(), lr=lr)

    return metric_logger.meters["loss"].global_avg, lr

​  这部分是不是很难看懂呢,大家动起手来调试调试吧,其实这部分和其它网络训练过程也基本差不多。我重点讲一下 loss = criterion(output, target),即损失函数的部分,criterion函数的定义如下:

def criterion(inputs, target):
    losses = {}
    for name, x in inputs.items():
        # 忽略target中值为255的像素,255的像素是目标边缘或者padding填充
        losses[name] = nn.functional.cross_entropy(x, target, ignore_index=255)

    if len(losses) == 1:
        return losses['out']

    return losses['out'] + 0.5 * losses['aux']

​  关于损失函数部分要讲解的内容还是很多的,因此我放在了附录–>损失函数cross_entropy详解中,大家可去查看。🍵🍵🍵

 

网络测试

confmat = evaluate(model, val_loader, device=device, num_classes=num_classes)

​  网络测试部分原视频中介绍的很详细,用到了混淆矩阵,我就不带大家进evaluate中一行一行的看了。但这里我来说一下这部分的调试小技巧,因为测试是在网络训练一个epoch后执行的,但我们肯定很难等训练一个epoch后再调试测试部分,因此我们在调试前先注释掉训练部分,这样就可以很快速的跳到测试部分啦,快去试试吧!!!🥤🥤🥤

 

模型保存

save_file = {"model": model.state_dict(),
                     "optimizer": optimizer.state_dict(),
                     "lr_scheduler": lr_scheduler.state_dict(),
                     "epoch": epoch,
                     "args": args}
                     
torch.save(save_file, "save_weights/model_{}.pth".format(epoch))

 

模型预测——predict.py✨✨✨

​  这部分有很多和训练部分重复的代码哈,我就不一一的去分析了。重点看一下如何由模型输出的结果得到最终的P模式的图片,相关代码如下:

output = model(img.to(device))
prediction = output['out'].argmax(1).squeeze(0)
prediction = prediction.to("cpu").numpy().astype(np.uint8)
mask = Image.fromarray(prediction)
mask.putpalette(pallette)
mask.save("test_result.png")

​  上述代码中我认为这句prediction = output['out'].argmax(1).squeeze(0)是最重要的,其主要作用是在输出中的chanel维度求最大值对应的类别索引,为方便大家理解,作图如下:

深度学习语义分割篇——FCN源码解析篇

​  我们来解释一下上图,输出为 1 × c × h × w 1×c×h×w 1×c×h×w,因为这是预测,故batch=1,这里使用的是VOC数据,故这里的c=num_class=21。【包含一个背景类】首先我们会取输出中每个像素在21个通道中的最大值,如第一个像素在21个通道的最大值在通道0上取得,即上图橙色的通道。这个通道对应的索引是0,在VOC中是背景类,故这个像素所属类别为背景。其它像素同理。

​  我们可以来看看模型预测的结果,如下图所示:

深度学习语义分割篇——FCN源码解析篇

​ 是不是发现这只可爱的小猫咪被分割出来了呢,大家快去试试吧!!!🌼🌼🌼

 

模型搭建

​  这部分我之所以放在最后一部分,是因为我觉得这部分是相对最好理解的。我们只要照着我们理论部分一步步的搭建就好。需要注意的是理论部分我们介绍时采用的时VGG做为backbone,这是因为当时论发表在15年,resnet网络也是15出来的,所以论文中没用到,但是很多年过去,resnet的有效性得到实践证明,pytorch官方也采用了resnet作为FCN的backbone,并且使用了空洞卷积。对空洞卷积不了解的请点击☞☞☞查看相关解释。这里放上backbone的整体结构图,大家作为参考,剩下的时间就去调试吧!!!🌹🌹🌹

深度学习语义分割篇——FCN源码解析篇

              图片来自霹雳吧啦Wz

 

参考链接

FCN源码解析(Pytorch)🍁🍁🍁

 

附录

损失函数cross_entropy详解✨✨✨

​  在讲解损失函数之前,我有必要在为大家分析一波VOC的标注,在FCN原理详解篇的附录我向大家说明说明了标注是单通道的P模式图片,不清楚的请点击☞☞☞了解详情。

​  单仅知道标注是单通道的图片还不够,我们先来看看这张标注图片:

深度学习语义分割篇——FCN源码解析篇

​  这张图片大致可以分为三部分,一部分是蓝框框住的人,一部分是绿框框住的飞机,还有一部分是黄框框住的神秘物体。我先来说说人和飞机部分,你可以发现,它们一个是粉红色(人),一个是大红色(飞机),这是因为在我们调色板中人和飞机索引对应的类别分别为粉红色和大红色,如下图所示:

深度学习语义分割篇——FCN源码解析篇

​  我们也可以来看看标注图片的背景,它是黑色的,背景类别为0,因此在调色板中0所对应的RGB值为[0,0,0],为黑色,如下图所示:

        深度学习语义分割篇——FCN源码解析篇

​  接着我们来看看这个白色的神秘物体,这是什么呢?我们可以看看此标注图像对应的原图,如下:

深度学习语义分割篇——FCN源码解析篇

​  通过上图可以看到,这个白色的物体其实也是一个小飞机,但很难分辨,故标注时用白色像素给隐藏起来了,最后白色对应的像素也不会参与损失计算。如果你足够细心的话,你会发现在人和飞机的边缘其实都是存在一圈白色的像素的,这是为了更好的区分不同类别对应的像素。同样,这里的白色也不会参与损失计算。【至于怎么不参与马上就会讲解,不用急】

​  接下来我们可以用程序来看看标注图像中是否有白色像素,代码如下:

from PIL import Image
import numpy as np
img = Image.open('D:\\数据集\\VOC\\VOCtrainval_11-May-2012\\VOCdevkit\\VOC2012\\SegmentationClass\\2007_000032.png')
img_np = np.array(img)

​ 我们可以看看img_np里的部分数据,如下图所示:

深度学习语义分割篇——FCN源码解析篇

​  可以看到地下的像素是1,表示飞机(大红色),上面的像素为0,表示背景(黑色),中间的像素为255,这就对应着飞机周围的白色像素。我们可以看一下255对应的RGB值,如下:【这里的255需要大家记住哦,后面计算损失时白色部分不计算正是通过忽略这个值实现的】

          深度学习语义分割篇——FCN源码解析篇

​ [224,224,192]表示的RGB颜色为白色。



​  有了上面的先验知识,就可以来介绍cross_entropy函数了。我们直接来看求损失的公式,如下:

深度学习语义分割篇——FCN源码解析篇

​  我举个例子来解释一下上面的公式。设输入为[0.1,0.2,0.3],即x=[0.1,0.2,0.3],标签为1,即class=1,则

l o s s ( x , c l a s s ) = − x [ c l a s s ] + log ⁡ ( ∑ j exp ⁡ ( x [ j ] ) ) = − 0.2 + l o g ( e x [ 0 ] + e x [ 1 ] + e x [ 2 ] ) = − 0.2 + l o g ( e 0.1 + e 0.2 + e 0.3 ) loss(x,class) = - x\left[ {class} \right] + \log (\sum\limits_j {\exp (x[j])})=-0.2+log(e^{x[0]}+e^{x[1]}+e^{x[2]})=-0.2+log(e^{0.1}+e^{0.2}+e^{0.3}) loss(x,class)=x[class]+log(jexp(x[j]))=0.2+log(ex[0]+ex[1]+ex[2])=0.2+log(e0.1+e0.2+e0.3)

​  通过上文的例子我想你大概知道了损失的计算方法,上文的x是一维的,现在我们来看一下二维的x是怎么计算,首先先定义输入和标签,代码如下:

import torch
import numpy as np
import math
input = torch.tensor([[0.1, 0.2, 0.3],[0.1, 0.2, 0.3],[0.1, 0.2, 0.3]])
target = torch.tensor([0, 1, 2])

​ 可以来看一下input和target的值:

深度学习语义分割篇——FCN源码解析篇

​ 接着我们可以先用函数来计算损失,如下:

loss = torch.nn.functional.cross_entropy(input, target)

​ 计算得到的loss值如下:

              深度学习语义分割篇——FCN源码解析篇

​  接着我们手动来计算损失,看其是否和直接用函数计算一致,即loss=1.1019。手动计算代码如下:【对于多维数据,需要计算target对应的x的损失,然后求平均】

res0 = -0.1+np.log(math.exp(0.1)+math.exp(0.2)+math.exp(0.3))
res1 = -0.2+np.log(math.exp(0.1)+math.exp(0.2)+math.exp(0.3))
res2 = -0.3+np.log(math.exp(0.1)+math.exp(0.2)+math.exp(0.3))
res = (res0 + res1 + res2)/3

​  计算得到的结果如下,和利用函数计算时结果一致,仅精度有差别,所以这证明了我们的计算方式是没有错的。

             深度学习语义分割篇——FCN源码解析篇

​  我们上文在介绍VOC标注时说,计算损失是会忽略白色的像素,其就对应着标签中的255。这里我们用这个小例子来说明程序是怎么实现忽略的,其实很简单,只要在函数调用时传入ignore_index并指定对应的值即可。如对本例来说,现我打算忽略target中标签为2的数据,即不让其参与损失计算,我们来看看如何使用cross_entropy函数来实现:

loss = torch.nn.functional.cross_entropy(input, target, ignore_index=2)

​ 上述loss结果如下:

              深度学习语义分割篇——FCN源码解析篇

​ 现在我们手动计算一下忽略target=2时的损失结果,如下:

res0 = -0.1+np.log(math.exp(0.1)+math.exp(0.2)+math.exp(0.3))
res1 = -0.2+np.log(math.exp(0.1)+math.exp(0.2)+math.exp(0.3))
res = (res0 + res1)/2

​ 上述代码中target=2没有参与损失计算,其结果如下:

              深度学习语义分割篇——FCN源码解析篇

​ 上述实验都证明了我们的计算方式是没有偏差的。🥂🥂🥂


​  相信你读了上文对cross_entropy解释,已经基本对cross_entropy这个函数了解了。但是大家可能会发现在我们程序中输入cross_entropy函数中的x通常是4维的tensor,即[N,C,H,W],这时候训练损失是怎么计算的呢?我们以x的维度为[1,2,2,2]为例为大家讲解,首先定义输入和target,如下:

import torch
import numpy as np
import math
input = torch.tensor([[[[0.1, 0.2],[0.3, 0.4]], [[0.5, 0.6],[0.7, 0.8]]]])    #shape(1 2 2 2 )
target = torch.tensor([[[0, 1],[0, 1]]])

​ 来看看input和target的值:

深度学习语义分割篇——FCN源码解析篇

​ 接着来看看通过函数计算的loss,代码如下:

loss = torch.nn.functional.cross_entropy(input, target)

​ 此时loss的值为:

              深度学习语义分割篇——FCN源码解析篇

​ 接下来我们就来看看手动计算的步骤,在用代码实现前,我先来解释下大致步骤,如下图所示:

深度学习语义分割篇——FCN源码解析篇

​ 我们会将数据按通道方向展开,然后分别计算cross_entropy,最后求平均,代码如下:

res0 = -0.1+np.log(math.exp(0.1)+math.exp(0.5))
res1 = -0.6+np.log(math.exp(0.2)+math.exp(0.6))
res2 = -0.3+np.log(math.exp(0.3)+math.exp(0.7))
res3 = -0.8+np.log(math.exp(0.4)+math.exp(0.8))
res = (res0 + res1 + res2 + res3)/4

​ res的结果如下,其和使用函数计算一致。

             深度学习语义分割篇——FCN源码解析篇


​ 那我们不妨在来看看忽略某个target时loss的结果,以忽略target=0为例:

loss = torch.nn.functional.cross_entropy(input, target, ignore_index=0)

​ loss的结果如下:

              深度学习语义分割篇——FCN源码解析篇

​ 我们来看看手动计算的步骤:

深度学习语义分割篇——FCN源码解析篇

​ 代码如下:

res1 = -0.6+np.log(math.exp(0.2)+math.exp(0.6))
res3 = -0.8+np.log(math.exp(0.4)+math.exp(0.8))
res = (res0 + res3)/2

​ res的结果如下,同样和使用函数计算是一致的。

              深度学习语义分割篇——FCN源码解析篇



​ 到这里,我们在来看FCN中的代码,如下:

losses[name] = nn.functional.cross_entropy(x, target, ignore_index=255)

​ 我想大家就很清楚了叭,这里忽略了255像素,不让其参与到损失的计算中。

​ 这一节我觉得是整个FCN最难理解的地方,我已经介绍的非常详细了,大家自己也要花些时间理解理解。🌱🌱🌱

 


如若文章对你有所帮助,那就🛴🛴🛴

         深度学习语义分割篇——FCN源码解析篇文章来源地址https://www.toymoban.com/news/detail-467497.html

到了这里,关于深度学习语义分割篇——FCN源码解析篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【深度学习实战(6)】搭建通用的语义分割推理流程

    无论输入的图片尺寸多大,都会经过letter_box后,变为512x512尺寸 21个channel代表(20+1)个类别,512x512为模型输入及输入尺寸 经过softmax后,512x512的mask图中,每个位置(x,y)对应的21个channel的值和为1。 pr类型是np,array,所以可以通过这种方式进行逆letter_box操作,将mask的宽高,还原

    2024年04月16日
    浏览(39)
  • 深度学习在语义分割中的进展与应用

    埃弗顿·戈梅德(Everton Gomede) 

    2024年02月03日
    浏览(39)
  • 【图像分割】Unet系列深度讲解(FCN、UNET、UNET++)

    1.1 背景介绍: 自2015年以来,在生物医学图像分割领域,U-Net得到了广泛的应用,目前已达到四千多次引用。至今,U-Net已经有了很多变体。目前已有许多新的卷积神经网络设计方式,但很多仍延续了U-Net的核心思想,加入了新的模块或者融入其他设计理念。 编码和解码,早在

    2024年02月03日
    浏览(41)
  • 计算机视觉与深度学习-图像分割-视觉识别任务01-语义分割-【北邮鲁鹏】

    给每个像素分配类别标签。 不区分实例,只考虑像素类别。 滑动窗口缺点 重叠区域的特征反复被计算,效率很低。 所以针对该问题提出了新的解决方案–全卷积。 让整个网络只包含卷积层,一次性输出所有像素的类别预测。 全卷积优点 不用将图片分为一个个小区域然后再

    2024年02月07日
    浏览(74)
  • 基于深度学习的自动驾驶汽车语义分割与场景标注算法研究。

    自动驾驶汽车是当前研究的热点领域之一,其中基于深度学习的语义分割与场景标注算法在自动驾驶汽车的视觉感知中具有重要作用。本文将围绕自动驾驶汽车的语义分割与场景标注算法展开研究。 一、研究背景 随着人工智能技术的不断发展,自动驾驶汽车逐渐成为汽车产

    2024年02月07日
    浏览(43)
  • PointNet:利用深度学习对点云进行3D分类和语义分割

    参考自,PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation 代码仓库地址为:https://github.com/charlesq34/pointnet/ 介绍 这次介绍的是一个比较基础的工作,针对空间点云,进行分类或者语义分割的框架,现在通常也被用作对RGB-D图像进行特征提取的部分。 该工作的目的就是

    2024年02月03日
    浏览(70)
  • 使用爬虫代码获得深度学习目标检测或者语义分割中的图片。

    问题描述:目标检测或者图像分割需要大量的数据,如果手动从网上找的话会比较慢,这时候,我们可以从网上爬虫下来,然后自己筛选即可。 代码如下(不要忘记安装代码依赖的库): 这里以搜索明星的图片为例,运行代码,然后根据提示输入搜索图片的名字→搜索图片

    2024年02月10日
    浏览(48)
  • 可解释深度学习:从感受野到深度学习的三大基本任务:图像分类,语义分割,目标检测,让你真正理解深度学习

    目录   前言 一、初识感受野 1.1猜一猜他是什么? 1.2人眼视觉系统下的感受野 1.3深度神经网络中的感受野 1.3.1感受野的性质 1.3.2感受野的定义 1.3.3举一个例子 1.3.4以VGG网络为例 二、感受野的计算 2.1 哪些操作能够改变感受野? 2.2 感受野的计算公式 2.3 感受野的中心位置计算

    2024年02月02日
    浏览(53)
  • 深度学习:使用UNet做图像语义分割,训练自己制作的数据集,详细教程

    语义分割(Semantic Segmentation)是图像处理和机器视觉一个重要分支。与分类任务不同,语义分割需要判断图像每个像素点的类别,进行精确分割。语义分割目前在自动驾驶、自动抠图、医疗影像等领域有着比较广泛的应用。我总结了使用UNet网络做图像语义分割的方法,教程很详

    2024年02月03日
    浏览(43)
  • 深度学习实战23(进阶版)-语义分割实战,实现人物图像抠图的效果(计算机视觉)

    大家好,我是微学AI,今天给大家带来深度学习实战23(进阶版)-语义分割实战,实现人物图像抠图的效果。语义分割是计算机视觉中的一项重要任务,其目标是将图像中的每个像素都分配一个语义类别标签。与传统的目标检测或分类任务不同,语义分割不仅需要识别图像中存在

    2024年02月13日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包