语义分割——FCN模型pytorch实现

article/2025/9/16 16:50:27

FCN网络简介

全卷积网络(Fully Convolutional Networks,FCN)是Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图像语义分割的一种框架,是首个端对端的针对像素级预测的全卷积网络。FCN将传统CNN后面的全连接层换成了卷积层,这样网络的输出将是热力图而非类别;同时,为解决卷积和池化导致图像尺寸的变小,使用上采样方式对图像尺寸进行恢复。

网络结构

FCN网络结构主要分为两个部分:全卷积部分和反卷积部分。其中全卷积部分为一些经典的CNN网络(如VGG,ResNet等),用于提取特征;反卷积部分则是通过上采样得到原尺寸的语义分割图像。FCN的输入可以为任意尺寸的彩色图像,输出与输入尺寸相同,通道数为n(目标类别数)+1(背景),(原始FCN是在PASCAL数据集上训练的所以一共有20+1类)。FCN-8s网络结构如下:

21张概率图中每个像素处是一个概率,表明当前像素属于哪一种类别

 这里为什么会产生568*568大小的图片呢,是因为原论文的源码中在第一个卷积层处将padding设置为100,这样做的目的是防止图片下采样32倍后尺寸小于7x7(因为下采样32倍后会经过7x7大小的卷积层),之后上采样32倍后会产生与原图不一样大小的图片,需要进行裁剪才能得到原图大小的输出。

PS:卷积向下取整,池化向上取整

官方模型是采用了VGG16作为backbone

VGG16网络结果如下图所示:

其中最大池化层为2x2 步长为2

 论文中提出了三个模型分别是FCN-32s、FCN-16s、FCN-8s。

FCN-32s

pool5的输出直接上采样32倍恢复到原图大小,将损失了原图很多细节信息的特征图直接上采样,效果较差

  1. 现在的FCN的源码中FC6的卷积层的padding为3,这样可以使输出的图片高宽不变,防止输入图片过小导致该卷积层报错,例如若没有该padding,那么输入192x192的图片FC6的输入会是6x6大小的图片,FC6就报错了。

  2. 论文源码中的转置卷积的参数是冻结的,因为作者发现冻结和不冻结的结果相差不大,为了提高效率,所以就冻结了。此时转置卷积层相当于是双线性插值。这里效果不明显的原因是上采样倍数太大了

FCN-16s

pool5的输出上采样2倍(采样后大小与pool4的输出相同)然后与pool4输出相加然后再直接上采样16倍恢复到原图大小

 FCN-8s

pool5的输出上采样2倍(采样后大小与pool4的输出相同)然后与pool4输出相加然后再上采样2倍(采样后大小与pool3的输出相同),然后与pool3输出相加然后再直接上采样8倍恢复到原图大小。

转置卷积计算公式:

o'为卷积输出大小,i‘为卷积输入大小,s为卷积核stride,k为卷积核大小,p为填充

 实现FCN-8s时的参数如下

参数名称参数值
f6.stride1
f6.padding3
f7.stride1
f7.padding1
转置卷积1.padding1
转置卷积1.stride2
转置卷积2.padding1
转置卷积2.stride2
转置卷积3.padding4
转置卷积3.stride8

规律:设倍率为x,当转置卷积的2*padding -x = k.size、 s为上采样倍率x时恰好可以上采样  

原论文中FCN-32s、16s、8s中效果比较

 Pytorch实现FCN-8s

网络结构

数据处理

数据集

数据集采用的是PASCAL VOC2012数据集

root样例  root = 'F:\VOCtrainval_11-May-2012\VOCdevkit\VOC2012' 到VOC2012

class VOC_Segmentation(Dataset):def __init__(self,root,text_name='train.txt',trans=None):super(VOC_Segmentation, self).__init__()#数据划分信息路径txt_path = os.path.join(root,'ImageSets','Segmentation',text_name)#图片路径image_path = os.path.join(root,'JPEGImages')#mask(label)路径mask_path = os.path.join(root,'SegmentationClass')#读入数据集文件名称with open(txt_path,'r') as f:file_names = [name.strip() for name in f.readlines() if len(name.strip()) > 0]#文件名拼接拼接路径self.images = [os.path.join(image_path,name+'.jpg') for name in file_names]self.mask = [os.path.join(mask_path,name+'.png') for name in file_names]self.trans = transdef __len__(self):return len(self.images)def __getitem__(self, index):'''albumentations图像增强库是基于cv2库的,cv2.imread()读入后图片的类型是numpy类型所以需要保证与cv2读入类型一致'''img = np.asarray(Image.open(self.images[index]))mask = np.asarray(Image.open(self.mask[index]),dtype=np.int32)if self.trans is not None:img,mask = self.trans(img,mask)return img,mask

为什么不直接使用cv2呢?

cv2.imread(path, flags)path: 该参数制定图片的路径,可以使用相对路径,也可以使用绝对路径;
flags:指定以何种方式加载图片,有三个取值:
cv2.IMREAD_COLOR:读取一副彩色图片,图片的透明度会被忽略,默认为该值,实际取值为1;
cv2.IMREAD_GRAYSCALE:以灰度模式读取一张图片,实际取值为0
cv2.IMREAD_UNCHANGED:加载一副彩色图像,透明度不会被忽略

起初也想着是直接使用cv2.imread,但是PASCAL VOC2012中mask是调色板模式(单通道,像素取值为[0,255])存储的,cv2.IMREAD_UNCHANGED和cv2.IMREAD_COLOR读入后会创建三通道的数据,使用cv2.IMREAD_GRAYSCALE读入后原有像素值会发生改变(255变成了220).

而PIL的image.open可以直接读入调色板模式的图片,只需要对数据类型进行改变即可。

Transforms

使用的是albumentations图像处理库,这个库中有很多高度封装的transform函数,可以实现傻瓜式同时对image和mask进行转换(pytorch自带的transform无法傻瓜式同时转换)

训练集

数据增强操作

  1. 随机变化原图,使用双线插值的模式,随机将原图放大到[0.5,2]倍的大小
  2. 模型训练默认的输入大小为480x480图片,数据集中的有些图片随机变化后无法满足要求,所以要进行填充,这里要注意image填充0也就是背景,mask填充255(后续计算损失时可以忽略掉像素值为255的像素,就不会产生影响了)
  3. 随机剪切处480x480大小的图片
  4. 随机进行水平翻转

还要注意image需要调用ToTensor函数,但mask不能直接调用ToTensor函数,因为ToTensor操作会进行归一化,而mask是调色板模式的图片,其中的像素值是处于[0,255]之间的,转化后会出错,只需要手动将他转化为Tensor即可

这里还要注意 mask不需要加通道!!! 最后保证mask是(batch,height,width)格式就行,否则会影响到后续nn.CrossEntropyLoss的计算

class Train_transforms():def __init__(self,output_size=480,scale_prob=0.5,flip_prob=0.5,mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):self.aug1 = A.Compose([#随机变换原图A.RandomScale(scale_limit=[0.5,1.5],interpolation=cv2.INTER_NEAREST,p=scale_prob),#小于480x480的img和mask进行填充A.PadIfNeeded(min_height=output_size,min_width=output_size,value=0,mask_value=255),#剪切A.RandomCrop(height=output_size,width=output_size,p=1),#翻转A.HorizontalFlip(p=flip_prob)])self.aug2 = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=mean,std=std)])def __call__(self,image,mask):augmented = self.aug1(image=image,mask=mask)image,mask = augmented['image'],augmented['mask']image = self.aug2(image)mask = torch.as_tensor(np.array(mask),dtype=torch.int64)return image,mask

 测试集

转换了图片大小到480x480

class Validate_trans():def __init__(self,output_size=480,mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):self.aug1 = A.Resize(output_size,output_size,interpolation=cv2.INTER_NEAREST)self.aug = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=mean,std=std)])def __call__(self,image,mask):augmented = self.aug1(image=image,mask=mask)image,mask = augmented['image'],augmented['mask']image = self.aug(image)mask = torch.as_tensor(np.array(mask),dtype=torch.int64)return image,mask

模型搭建

backbone使用的是VGG模型,具体使用的是VGG16也就是下图中的D

#vgg块
def vgg_block(in_channels,out_channels,num):block = []for _ in range(num):block.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1, stride=1))block.append(nn.ReLU())in_channels = out_channelsblock.append(nn.MaxPool2d(kernel_size=2,stride=2))return nn.Sequential(*block)class VGG(nn.Module):def __init__(self,num_classes,struct,in_channel=3):super(VGG, self).__init__()blk = []out_channels = []conv_nums = []for num,out_channel in struct:out_channels.append(out_channel)conv_nums.append(num)#这里这样写便于后续取出某层的输出self.layer1 = vgg_block(in_channel,out_channels[0],conv_nums[0])self.layer2 = vgg_block(out_channels[0], out_channels[1], conv_nums[1])self.layer3 = vgg_block(out_channels[1], out_channels[2], conv_nums[2])self.layer4 = vgg_block(out_channels[2], out_channels[3], conv_nums[3])self.layer5 = vgg_block(out_channels[3], out_channels[4], conv_nums[4])blk=[nn.Flatten(),nn.Linear(7*7*512,4096),nn.Dropout(0.5),nn.ReLU(),nn.Linear(4096,4096),nn.Dropout(0.5),nn.ReLU(),nn.Linear(4096,num_classes)]self.top = nn.Sequential(*blk)self.__init_net()def forward(self,x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.layer5(x)x = self.top(x)return xdef __init_net(self):for layer in self.modules():if type(layer) == nn.Conv2d:nn.init.kaiming_normal_(layer.weight,mode='fan_out',nonlinearity='relu')elif type(layer) == nn.Linear:nn.init.xavier_normal_(layer.weight)elif type(layer) == nn.BatchNorm2d:nn.init.constant_(layer.weight,1) #均值为0nn.init.constant_(layer.bias,0) #方差为1

FCN-Head

FCN-Head也就是网络结构中的FC6和FC7

class FCN_Head(nn.Module):def __init__(self,in_channel,out_channel):super(FCN_Head, self).__init__()self.fc6 = nn.Sequential(nn.Conv2d(in_channel,out_channel,kernel_size=7,stride=1,padding=3),nn.BatchNorm2d(out_channel),nn.ReLU(),nn.Dropout(0.1))self.fc7 = nn.Sequential(nn.Conv2d(out_channel,out_channel,kernel_size=1),nn.BatchNorm2d(out_channel),nn.ReLU(),nn.Dropout(0.1))def forward(self,x):x = self.fc6(x)x = self.fc7(x)return x

 FCN-8s

class FCN(nn.Module):def __init__(self,backbone,head,num_classes,channel_nums):super(FCN, self).__init__()self.backbone = backboneself.head = head#调整通道数self.layer3_conv = nn.Conv2d(channel_nums[0],num_classes,kernel_size=1)    #256self.layer4_conv = nn.Conv2d(channel_nums[1],num_classes,kernel_size=1)    #512self.layer5_conv = nn.Conv2d(channel_nums[2],num_classes,kernel_size=1)    #4096#转置卷积层1self.transpose_conv1 =nn.Sequential(nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, padding=1),nn.BatchNorm2d(num_classes),nn.ReLU())# 转置卷积层2self.transpose_conv2 = nn.Sequential(nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, padding=1),nn.BatchNorm2d(num_classes),nn.ReLU())# 转置卷积层3self.transpose_conv3 = nn.Sequential(nn.ConvTranspose2d(num_classes,num_classes,kernel_size=16,stride=8,padding=4),nn.BatchNorm2d(num_classes),nn.ReLU())def forward(self,x):#out = OrderedDict {layer4:{},layer5:{},layer3:{}}out = self.backbone(x)layer5_out, layer4_out,layer3_out = out['layer5'],out['layer4'],out['layer3']layer5_out = self.head(layer5_out)layer5_out = self.layer5_conv(layer5_out)layer4_out = self.layer4_conv(layer4_out)layer3_out = self.layer3_conv(layer3_out)x = self.transpose_conv1(layer5_out)x = self.transpose_conv2(x + layer4_out)x = self.transpose_conv3(x + layer3_out)return x
def fcn_vgg16(num_classes=20,pretrain_backbone=False):num_classes += 1struct = [(2, 64), (2, 128), (3, 256), (3, 512), (3, 512)]backbone = VGG(num_classes=num_classes,struct=struct)if pretrain_backbone is True:#https://download.pytorch.org/models/vgg16-397923af.pthload_weights(backbone,'../weights/vgg16.pth')return_layers = {'layer3':"layer3",'layer4':'layer4','layer5':"layer5"}backbone = torchvision.models._utils.IntermediateLayerGetter(backbone,return_layers)# x = torch.randn((1,3,224,224))# x = backbone(x)head = FCN_Head(in_channel=512,out_channel=4096)model = FCN(backbone=backbone,head=head,num_classes=num_classes,channel_nums=[256,512,4096])return model

fcn_vgg16模型

def fcn_vgg16(num_classes=20,pretrain_backbone=False):num_classes += 1#vgg16结构struct = [(2, 64), (2, 128), (3, 256), (3, 512), (3, 512)]backbone = VGG(num_classes=num_classes,struct=struct)if pretrain_backbone is True:#https://download.pytorch.org/models/vgg16-397923af.pthload_weights(backbone,'../weights/vgg16.pth')return_layers = {'layer3':"layer3",'layer4':'layer4','layer5':"layer5"}backbone = torchvision.models._utils.IntermediateLayerGetter(backbone,return_layers)# x = torch.randn((1,3,224,224))# x = backbone(x)head = FCN_Head(in_channel=512,out_channel=4*512)#layer3 layer4 fcn_head输出通道数model = FCN(backbone=backbone,head=head,num_classes=num_classes,channel_nums=[256,512,4096])return model

训练

辅助函数

语义分割混淆矩阵:用于计算global acc、acc、IoU

class ConfusionMatrix():def __init__(self,num_classes):self.n = num_classesself.mat = Nonedef update(self,a,b):if self.mat is None:self.mat = torch.zeros(self.n,self.n,device=a.device)#统计所有有效预测像素的索引k = (a>=0) & (a < self.n)#计数indexs = self.n * a[k].to(torch.int64) + b[k]self.mat += torch.bincount(indexs,minlength=self.n**2).reshape(self.n,self.n)def reset(self):self.mat.zero_()def compute(self):h = self.mat.float()global_acc = torch.diag(h).sum() / h.sum()acc = torch.diag(h)/h.sum(1)iou = torch.diag(h) / (h.sum(1)+h.sum(0) - torch.diag(h))return global_acc,acc,iou

 训练函数

def train(model,train_iter,validate_iter,loss,optimizer,epochs,num_classes=21):confusion_matrix = ConfusionMatrix(num_classes=num_classes)device = get_device()best_mean_iou = 0for epoch in range(1,epochs):train_loss = 0batch_id = 0train_num = 0model.train()for X,y in train_iter:batch_id += 1train_num += len(X)X,y = X.to(device),y.to(device)y_hat = model(X)l = loss(y_hat,y)train_loss += l.item()optimizer.zero_grad()l.backward()optimizer.step()if batch_id % 30 == 0:print(f"epoch{epoch}[{batch_id}/{len(train_iter)}]:loss:{train_loss / train_num}")model.eval()vaild_loss = 0valid_num = 0for X, y in validate_iter:with torch.no_grad():X, y = X.to(device), y.to(device)y_hat = model(X)l = loss(y_hat, y)vaild_loss += l.item()valid_num += len(X)confusion_matrix.update(y.flatten(), y_hat.argmax(1).flatten())global_acc, acc, IoU = confusion_matrix.compute()print(f"epoch:{epoch},train_loss:{train_loss / train_num},valid_loss:{vaild_loss / valid_num},global_acc:{global_acc},acc:{acc.mean()},mean_IoU:{IoU.mean()}")if best_mean_iou < IoU:weights = model.state_dict()torch.save(weights, './weights/fcn_vgg16.pth')confusion_matrix.reset()

预测

辅助函数

使用下述代码可以读入mask中的调色板模式,也就是每个像素值对应的RGB值,这样在得到预测后的图片时就可以使用调色板进行调色了。

# 读取mask标签
target = Image.open("2007_000039.png")
# 获取调色板
palette = target.getpalette()
palette = np.reshape(palette, (-1, 3)).tolist()
# 转换成字典子形式
pd = dict((i, color) for i, color in enumerate(palette))json_str = json.dumps(pd)
with open("palette.json", "w") as f:f.write(json_str)

预测函数

def main():classes = 20weights_path = './weights/fcn_vgg16.pth'img_path = './test.jpg'pallette_path = "./utils/palette.json"with open(pallette_path,'rb') as f:pallette_dict = json.load(f)pallette = []for v in pallette_dict.values():pallette += v#获取设备device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")print("using {} deviece".format(device))#创建模型model = fcn_vgg16().to(device)weights_dict = torch.load(weights_path,map_location='cpu')# #去除辅助分类器# for k in list(weights_dict.keys()):#     if "aux" in k:#         del weights_dict[k]#加载权重model.load_state_dict(weights_dict)model.to(device)#加载图片original_img = Image.open(img_path)#转换data_transform = transforms.Compose([transforms.Resize((480,480)),transforms.ToTensor(),transforms.Normalize(mean=(0.485, 0.456, 0.406),std=(0.229, 0.224, 0.225))])img = data_transform(original_img)#添加batch维度img = torch.unsqueeze(img,dim=0)model.eval()with torch.no_grad():output = model(img.to(device))prediction = output.argmax(1).squeeze(0) #消除batch维度prediction = prediction.to('cpu').numpy().astype(np.uint8)mask = Image.fromarray(prediction)mask.putpalette(pallette)mask.save("test_result.png")#原图和分割图混在一起
def blend():image1 = Image.open("test.jpg")image2 = Image.open("test_result.png")image1 = image1.convert('RGBA')image2 = image2.convert('RGBA')#blended_img = img1 * (1 – alpha) + img2* alpha 进行image1 = image1.resize(image2.size)image = Image.blend(image1,image2,0.4)image.show()

参考链接:

FCN网络结构详解(语义分割)_哔哩哔哩_bilibiliFCN讲解:FCN网络结构详解(语义分割)_哔哩哔哩_bilibili


FCN源码实现:GitHub - WZMIAOMIAO/deep-learning-for-image-processing: deep learning for image processing including classification and object-detection etc.

安利一个宝藏UP主~

b站 霹雳吧啦Wz 


http://chatgpt.dhexx.cn/article/GWNqPln5.shtml

相关文章

全卷积网络 FCN 详解

原文链接&#xff1a;全卷积网络 FCN 详解 FCN是深度学习应用在图像分割的代表作, 是一种端到端(end to end)的图像分割方法, 让网络做像素级别的预测直接得出label map, 下面我们来看看FCN是如何做到像素级别的分类的 论文 : Fully Convolutional Networks for Semantic Segme…

图像分割-FCN全卷积神经网络(完整代码详解)

目录 FCN全卷积神经网络 实现过程 全卷积 反卷积 FCN的三点创新 code FCN全卷积神经网络 FCN为深度学习在语义分割领域的开山之作&#xff0c;提出使用卷积层代替CNN中的全连接操作&#xff0c;生成热力图heat map而不是类别。 实现过程 图1 FCN网络结构 包括全卷积过程…

FCN网络学习笔记

目录 前言1. 网络结构2. 损失计算&#xff1a;Cross Entropy Loss参考 前言 FCN网络是首个端对端的针对像素级预测的全卷积网络。 其中&#xff0c;全卷积的含义是将分类网络的全连接层全部替换成了卷积层。使用了分类网络作为backbone&#xff0c;将会复用分类网路在ImageNet…

深度学习-全卷积神经网络(FCN)

1. 简介 全卷积神经网络&#xff08;Fully Convolutional Networks&#xff0c;FCN&#xff09;是Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图像语义分割的一种框架&#xff0c;是深度学习用于语义分割领域的开山之…

FCN全卷积网络理解及代码实现(来自pytorch官方实现)

视频链接&#xff1a;https://www.bilibili.com/video/BV1J3411C7zd?vd_sourcea0d4f7000e77468aec70dc618794d26f 代码&#xff1a;https://github.com/WZMIAOMIAO/deep-learning-for-image-processing FCN是2015年提出的首个端对端的针对像素级预测的全卷积网络。 如今的pyt…

FCN网络结构解析

daily&#xff1a;作为深度学习图片分割第一个学习的网络结构 Q1&#xff1a; 为什么要用FCN&#xff1f; A1&#xff1a;应为和以前网络R-CNN&#xff0c;SDS相比提升比较大 Q2&#xff1a;与CNN什么区别&#xff1f; A2:使用全卷积层代替全连接层 Q3&#xff1a;为什么要进行…

FCN网络详解

参考视频&#xff1a;FCN网络结构详解(语义分割)_哔哩哔哩_bilibili FCN是首个端对端的针对像素级预测的全卷积网络 这是作者提出的网络中的输出对比图&#xff0c;可以看到当FCN-8s效果接近真实分割图。 普通卷积分类网络与FCN对比 在这个模型提出之前&#xff0c;我们来看一下…

FCN全卷积神经网络

目录 前言 一、FCN的意义 二、先验知识 1.FCN-32S,FCN-16S,FCN-8S 2.上采样&#xff0c;下采样 3.大体网络结构 4.与传统网络&#xff08;带全连接层的网络&#xff09;区别 5.传统网络VGG网络结构 三、FCN网络结构解析 1.FCN-32S 2.FCN-16S 3.FCN-8S !!!重要&…

FCN算法详解

基于全卷积网络的语义分割 1. 摘要 卷积网络是一种强大的视觉模型,可产生特征的层次结构。卷积网络在语义分割方面的应用已超过了最先进的水平。本文关键是建立“全卷积”网络,它接受任意大小的输入,并通过有效的前向传播产生相应大小的输出。本文定义并详细描述了全卷积网…

FCN网络(Fully Convolutional Networks)

首个端到端的针对像素级预测的全卷积网络 原理&#xff1a;将图片进行多次卷积下采样得到chanel为21的特征层&#xff0c;再经过上采样得到和原图一样大的图片&#xff0c;最后经过softmax得到类别概率值 将全连接层全部变成卷积层&#xff1a;通常的图像分类网络最后几层是全…

FCN网络(Fully Convolutional Networks for Semantic Segmentation)

一.概述 FCN是深度学习应用在图像分割的代表作, 是一种端到端(end to end)的图像分割方法, 让网络做像素级别的预测直接得出label map。因为FCN网络中所有的层都是卷积层&#xff0c;故称为全卷积网络。 全卷积神经网络主要使用了三种技术&#xff1a; 卷积化&#xff08;Con…

FCN的代码解读

目录 模型初始化 VGG初始化 FCN初始化 图片的预处理 图片处理 图片编码 计算相关参数 模型训练 一个小问题 完整代码 参考 最近浅研究了一下关于图像领域的图像分割的相关知识&#xff0c;发现水还是挺深的&#xff0c;因为FCN差不多也是领域的开山鼻祖&#xff0c;所以就先从…

FCN网络介绍

目录 前言一.FCN网络二.网络创新点 前言 在图像分割领域&#xff0c;有很多经典的网络&#xff0c;如MASK R-CNN&#xff0c;U-Net&#xff0c;SegNet&#xff0c;DeepLab等网络都是以FCN为基础进行设计的。我们这里简单介绍一下这个网络。 一.FCN网络 FCN 即全卷积网络&#…

FCN简单理解

文章目录 整体把握卷积层替换全连接层的意义卷积层替换全连接层的具体方法网络结构中“放大”、“缩小”跳级的思想损失函数 整体把握 FCN的论文主要集中于语义分割&#xff0c;当然这种结构现在已经运用在计算机视觉的各种任务中。FCN创造性的将传统CNN的全连接层都转换成了卷…

全卷积神经网络(FCN)

目录 卷积化上采样跳跃结构卷积化上采样跳跃结构 卷积化 上采样 跳跃结构 论文&#xff1a;Fully Convolutional Networks for Semantic Segmentation(2015) 参考&#xff1a;https://zhuanlan.zhihu.com/p/80715481 全卷积神经网络&#xff08;Fully Convolutional Networks…

全卷积网络(FCN)实战:使用FCN实现语义分割

全卷积网络&#xff08;FCN&#xff09;实战&#xff1a;使用FCN实现语义分割 FCN对图像进行像素级的分类&#xff0c;从而解决了语义级别的图像分割&#xff08;semantic segmentation&#xff09;问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类&…

FCN

转载自: http://blog.csdn.net/taigw/article/details/51401448 在上述原文的基础上结合自己理解做出了部分修改。 从图像分类到图像分割 卷积神经网络&#xff08;CNN&#xff09;自2012年以来&#xff0c;在图像分类和图像检测等方面取得了巨大的成就和广泛的应用。 CNN的强大…

FCN的理解

直观展现网络结构&#xff1a;http://ethereon.github.io/netscope/#/editor 卷积与逆卷积的动图https://github.com/vdumoulin/conv_arithmetic 【原文图】“Fully convolutional networks for semantic segmentation.” 上图中&#xff0c;32x即为扩大32倍。 Pool5扩…

FCN(全卷积网络)详解

FCN详解 全卷积网络就是在全连接网络的基础上&#xff0c;通过用卷积网络替换全连接网络得到的。 首先看一下什么是全连接网络&#xff0c;以及全连接网络的缺点。 通常的CNN网络中&#xff0c;在最后都会有几层全连接网络来融合特征信息&#xff0c;然后再对融合后的特征信…

FCN的学习及理解(Fully Convolutional Networks for Semantic Segmentation)

论文Fully Convolutional Networks for Semantic Segmentation 是图像分割的milestone论文。 理清一下我学习过程中关注的重点。 fcn开源代码 github下载地址https://github.com/shelhamer/fcn.berkeleyvision.org 核心思想 该论文包含了当下CNN的三个思潮 - 不含全连接层(…