憨批的语义分割4——pspnet模型详解以及训练自己的pspnet模型(划分斑马线)

注意事项

PSPnet已经出了新版的库啦,建议使用新构架,训练效果更好,结构更完善!
新版的PSPnet-Kerashttps://blog.csdn.net/weixin_44791964/article/details/106933112

新版的PSPnet-Pytorchhttps://blog.csdn.net/weixin_44791964/article/details/107687696

学习前言

在这一个BLOG里,我会跟大家讲一下什么是pspnet模型,以及如何训练自己的pspnet模型,其训练过程依然与之前的语义分割模型类似,但是结构上差距较大……如果想要先有语义分割的基础,可以看我的博文憨批的语义分割2——训练自己的segnet模型(划分斑马线)

在这里插入图片描述

模型部分

想要看视频教程的可以去这里Keras 搭建自己的语义分割模型https://www.bilibili.com/video/av75562599/

什么是pspnet模型

为什么叫它pspnet模型呢,其实是因为其主要采用了pspblock也就是psp模块。
psp模块的样式如下,其psp的核心重点是采用了步长不同,pool_size不同的平均池化层进行池化,然后将池化的结果重新resize到一个hw上后,再concatenate。
即:
红色:这是在每个特征map上执行全局平均池的最粗略层次,用于生成单个bin输出。
橙色:这是第二层,将特征map划分为2×2个子区域,然后对每个子区域进行平均池化。
蓝色:这是第三层,将特征 map划分为3×3个子区域,然后对每个子区域进行平均池化。
绿色:这是将特征map划分为6×6个子区域的最细层次,然后对每个子区域执行池化。
在这里插入图片描述
psp模块的实际层结构如下,这个是当主干网络mobilenet的输入为一个[576,576,3]图像时的stride和pool_size。
其内容依然为采用了步长不同,pool_size不同的平均池化层进行池化,然后将池化的结果重新resize到一个hw上后,再concatenate
pspnet不再使用上采样,而是利用resize_image中的线性插值进行hw的扩张:
在这里插入图片描述
整个pspnet模型的结构如下,本文只对f5层进行hw的扩张,所采用的扩张方式仍然是resize_image中的线性插值
如果想要提升pspnet的性能,可以对多个特征层进行特征提取与扩张,实际操作方法为对f4、f3、f2进行resize_image再Concatenate(与unet类似)。
在这里插入图片描述

pspnet模型的代码实现

pspnet模型的代码分为两部分。

1、主干模型Mobilenet。

该部分用于特征提取,实际上就是常规的mobilenet结构,想要了解mobilenet结构的朋友们可以看看我的另一篇博客神经网络学习小记录23——MobileNet模型的复现详解

from keras.models import *
from keras.layers import *
import keras.backend as K
import keras

IMAGE_ORDERING = 'channels_last'

def relu6(x):
	return K.relu(x, max_value=6)

def _conv_block(inputs, filters, alpha, kernel=(3, 3), strides=(1, 1)):

	channel_axis = 1 if IMAGE_ORDERING == 'channels_first' else -1
	filters = int(filters * alpha)
	x = ZeroPadding2D(padding=(1, 1), name='conv1_pad', data_format=IMAGE_ORDERING  )(inputs)
	x = Conv2D(filters, kernel , data_format=IMAGE_ORDERING  ,
										padding='valid',
										use_bias=False,
										strides=strides,
										name='conv1')(x)
	x = BatchNormalization(axis=channel_axis, name='conv1_bn')(x)
	return Activation(relu6, name='conv1_relu')(x)

def _depthwise_conv_block(inputs, pointwise_conv_filters, alpha,
													depth_multiplier=1, strides=(1, 1), block_id=1):

	channel_axis = 1 if IMAGE_ORDERING == 'channels_first' else -1
	pointwise_conv_filters = int(pointwise_conv_filters * alpha)

	x = ZeroPadding2D((1, 1) , data_format=IMAGE_ORDERING , name='conv_pad_%d' % block_id)(inputs)
	x = DepthwiseConv2D((3, 3) , data_format=IMAGE_ORDERING ,
														 padding='valid',
														 depth_multiplier=depth_multiplier,
														 strides=strides,
														 use_bias=False,
														 name='conv_dw_%d' % block_id)(x)
	x = BatchNormalization(
			axis=channel_axis, name='conv_dw_%d_bn' % block_id)(x)
	x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)

	x = Conv2D(pointwise_conv_filters, (1, 1), data_format=IMAGE_ORDERING ,
										padding='same',
										use_bias=False,
										strides=(1, 1),
										name='conv_pw_%d' % block_id)(x)
	x = BatchNormalization(axis=channel_axis,
																name='conv_pw_%d_bn' % block_id)(x)
	return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)

def get_mobilenet_encoder( input_height=224 ,  input_width=224 , pretrained='imagenet' ):

	alpha=1.0
	depth_multiplier=1
	dropout=1e-3


	img_input = Input(shape=(input_height,input_width , 3 ))


	x = _conv_block(img_input, 32, alpha, strides=(2, 2))
	x = _depthwise_conv_block(x, 64, alpha, depth_multiplier, block_id=1) 
	f1 = x

	x = _depthwise_conv_block(x, 128, alpha, depth_multiplier,
														strides=(2, 2), block_id=2)  
	x = _depthwise_conv_block(x, 128, alpha, depth_multiplier, block_id=3) 
	f2 = x

	x = _depthwise_conv_block(x, 256, alpha, depth_multiplier,
														strides=(2, 2), block_id=4)  
	x = _depthwise_conv_block(x, 256, alpha, depth_multiplier, block_id=5) 
	f3 = x

	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier,
														strides=(2, 2), block_id=6) 
	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=7) 
	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=8) 
	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=9) 
	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=10) 
	x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=11) 
	f4 = x 

	x = _depthwise_conv_block(x, 1024, alpha, depth_multiplier,
														strides=(2, 2), block_id=12)  
	x = _depthwise_conv_block(x, 1024, alpha, depth_multiplier, block_id=13) 
	f5 = x 

	return img_input , [f1 , f2 , f3 , f4 , f5 ]

2、pspnet的Decoder解码部分

这一部分对应着上面pspnet模型中的解码部分。
其关键就是把获得的特征重新映射到比较大的图中的每一个像素点,用于每一个像素点的分类。

from keras.models import *
from keras.layers import *
from nets.mobilenet import get_mobilenet_encoder

from keras_segmentation.models.model_utils import get_segmentation_model

IMAGE_ORDERING = 'channels_last'
MERGE_AXIS = -1


def resize_image( inp ,  s , data_format ):
	import tensorflow as tf

	return Lambda( 
		lambda x: tf.image.resize_images(
			x , ( K.int_shape(x)[1]*s[0] ,K.int_shape(x)[2]*s[1] ))  
		)( inp )

def pool_block( feats , pool_factor ):


	if IMAGE_ORDERING == 'channels_first':
		h = K.int_shape( feats )[2]
		w = K.int_shape( feats )[3]
	elif IMAGE_ORDERING == 'channels_last':
		h = K.int_shape( feats )[1]
		w = K.int_shape( feats )[2]

	# strides = [18,18],[9,9],[6,6],[3,3]
	pool_size = strides = [int(np.round( float(h) /  pool_factor)), int(np.round(  float(w )/  pool_factor))]
 
	# 进行不同程度的平均
	x = AveragePooling2D(pool_size , data_format=IMAGE_ORDERING , strides=strides, padding='same')( feats )
	
	# 进行卷积
	x = Conv2D(512, (1 ,1 ), data_format=IMAGE_ORDERING , padding='same' , use_bias=False )( x )
	x = BatchNormalization()(x)
	x = Activation('relu' )(x)

	x = resize_image( x , strides , data_format=IMAGE_ORDERING ) 

	return x


def _pspnet( n_classes , encoder ,  input_height=384, input_width=576  ):

	assert input_height%192 == 0
	assert input_width%192 == 0

	img_input , levels = encoder( input_height=input_height,input_width=input_width)
	[f1 , f2 , f3 , f4 , f5 ] = levels 

	o = f5

	# 对f5进行不同程度的池化
	pool_factors = [ 1,2,3,6]
	pool_outs = [o ]

	for p in pool_factors:
		pooled = pool_block(  o , p  )
		pool_outs.append( pooled )
	
	# 连接
	o = Concatenate( axis=MERGE_AXIS)(pool_outs )

	# 卷积
	o = Conv2D(512, (1,1), data_format=IMAGE_ORDERING, use_bias=False )(o)
	o = BatchNormalization()(o)
	o = Activation('relu' )(o)

	# 此时输出为[144,144,nclasses]
	o = Conv2D( n_classes,(3,3),data_format=IMAGE_ORDERING, padding='same' )(o)
	o = resize_image(o,(8,8),data_format=IMAGE_ORDERING)
	o = Reshape((-1,n_classes))(o)
	o = Softmax()(o)
	model = Model(img_input,o)
	return model



def mobilenet_pspnet( n_classes ,  input_height=224, input_width=224 ):

	model =  _pspnet( n_classes , get_mobilenet_encoder ,  input_height=input_height, input_width=input_width  )
	model.model_name = "mobilenet_pspnet"
	return model

代码测试

将上面两个代码分别保存为mobilenet.py和pspnet.py。按照如下方式存储:
在这里插入图片描述
此时我们运行test.py的代码:

from nets.pspnet import mobilenet_pspnet
model = mobilenet_pspnet(2,576,576)
model.summary()

如果没有出错的话就会得到如下的结果:
在这里插入图片描述
其模型比segnet稍微大一点。
到这里就完成了基于Mobile模型的pspnet的搭建。

训练部分

训练的是什么

虽然把代码贴上来大家就会点运行然后就可以训练自己的模型,但是我还是想要大家知道,语义分割模型训练的是什么。

1、训练文件详解

这个要从训练文件讲起。

语义分割模型训练的文件分为两部分。
第一部分是原图,像这样:
在这里插入图片描述
第二部分标签,像这样:
在这里插入图片描述
当你们看到这个标签的时候你们会说,我靠,你给我看的什么辣鸡,全黑的算什么标签,其实并不是这样的,这个标签看起来全黑,但是实际上在斑马线的部分其RGB三个通道的值都是1。

其实给你们换一个图你们就可以更明显的看到了。
这是voc数据集中语义分割的训练集中的一幅图:
在这里插入图片描述
这是它的标签。
在这里插入图片描述
为什么这里的标签看起来就清楚的多呢,因为在voc中,其一共需要分21类,所以火车的RGB的值可能都大于10了,当然看得见。

所以,在训练集中,如果像本文一样分两类,那么背景的RGB就是000,斑马线的RGB就是111,如果分多类,那么还会存在222,333,444这样的。这说明其属于不同的类。

2、LOSS函数的组成

关于loss函数的组成我们需要看两个loss函数的组成部分,第一个是预测结果。

	# 此时输出为[144,144,nclasses]
	o = Conv2D( n_classes,(3,3),data_format=IMAGE_ORDERING, padding='same' )(o)
	o = resize_image(o,(8,8),data_format=IMAGE_ORDERING)
	o = Reshape((-1,n_classes))(o)
	o = Softmax()(o)
	model = Model(img_input,o)

Concatenate的输出为18,18,512,首先将其filter层的数量改为nclasses,再进行resize,结果对应着每一个hw像素点上的种类,最后输出为[144,144,nclasses]。之后利用Softmax估计属于每一个种类的概率。

其最后预测y_pre其实就是每一个像素点属于哪一个种类的概率

第二个是真实值,真实值是这样处理的。

# 从文件中读取图像
img = Image.open(r".\dataset2\png" + '/' + name)
img = img.resize((int(WIDTH/4),int(HEIGHT/4)))
img = np.array(img)
seg_labels = np.zeros((int(HEIGHT/4),int(WIDTH/4),NCLASSES))
for c in range(NCLASSES):
    seg_labels[: , : , c ] = (img[:,:,0] == c ).astype(int)
seg_labels = np.reshape(seg_labels, (-1,NCLASSES))
Y_train.append(seg_labels)

其将png图先进行resize,resize后其大小与预测y_pre的hw相同,然后读取每一个像素点属于什么种类,并存入。

其最后真实y_true其实就是每一个像素点确实属于哪个种类

最后loss函数的组成就是y_true和y_pre的交叉熵。

训练代码

大家可以在我的github上下载完整的代码。
https://github.com/bubbliiiing/Semantic-Segmentation
数据集的链接为:
链接:https://pan.baidu.com/s/1uzwqLaCXcWe06xEXk1ROWw
提取码:pp6w

1、文件存放方式

如图所示:
在这里插入图片描述
其中img和img_out是测试文件。

2、训练文件

训练文件如下:

from nets.pspnet import mobilenet_pspnet
from keras.optimizers import Adam
from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from PIL import Image
import keras
from keras import backend as K
import numpy as np

NCLASSES = 2
HEIGHT = 576
WIDTH = 576

def generate_arrays_from_file(lines,batch_size):
    # 获取总长度
    n = len(lines)
    i = 0
    while 1:
        X_train = []
        Y_train = []
        # 获取一个batch_size大小的数据
        for _ in range(batch_size):
            if i==0:
                np.random.shuffle(lines)
            name = lines[i].split(';')[0]
            # 从文件中读取图像
            img = Image.open(r".\dataset2\jpg" + '/' + name)
            img = img.resize((WIDTH,HEIGHT))
            img = np.array(img)
            img = img/255
            X_train.append(img)

            name = (lines[i].split(';')[1]).replace("\n", "")
            # 从文件中读取图像
            img = Image.open(r".\dataset2\png" + '/' + name)
            img = img.resize((int(WIDTH/4),int(HEIGHT/4)))
            img = np.array(img)
            seg_labels = np.zeros((int(HEIGHT/4),int(WIDTH/4),NCLASSES))
            for c in range(NCLASSES):
                seg_labels[: , : , c ] = (img[:,:,0] == c ).astype(int)
            seg_labels = np.reshape(seg_labels, (-1,NCLASSES))
            Y_train.append(seg_labels)

            # 读完一个周期后重新开始
            i = (i+1) % n
        yield (np.array(X_train),np.array(Y_train))

def loss(y_true, y_pred):
    crossloss = K.binary_crossentropy(y_true,y_pred)
    loss = 16 * K.sum(crossloss)/HEIGHT/WIDTH
    return loss

if __name__ == "__main__":
    log_dir = "logs/"
    # 获取model
    model = mobilenet_pspnet(n_classes=NCLASSES,input_height=HEIGHT, input_width=WIDTH)
    # model.summary()
    BASE_WEIGHT_PATH = ('https://github.com/fchollet/deep-learning-models/'
										'releases/download/v0.6/')
    model_name = 'mobilenet_%s_%d_tf_no_top.h5' % ( '1_0' , 224 )
   
    weight_path = BASE_WEIGHT_PATH + model_name
    weights_path = keras.utils.get_file(model_name, weight_path )
    print(weight_path)
    model.load_weights(weights_path,by_name=True,skip_mismatch=True)

    # model.summary()
    # 打开数据集的txt
    with open(r".\dataset2\train.txt","r") as f:
        lines = f.readlines()

    # 打乱行,这个txt主要用于帮助读取数据来训练
    # 打乱的数据更有利于训练
    np.random.seed(10101)
    np.random.shuffle(lines)
    np.random.seed(None)

    # 90%用于训练,10%用于估计。
    num_val = int(len(lines)*0.1)
    num_train = len(lines) - num_val

    # 保存的方式,1世代保存一次
    checkpoint_period = ModelCheckpoint(
                                    log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
                                    monitor='val_loss', 
                                    save_weights_only=True, 
                                    save_best_only=True, 
                                    period=1
                                )
    # 学习率下降的方式,val_loss三次不下降就下降学习率继续训练
    reduce_lr = ReduceLROnPlateau(
                            monitor='val_loss', 
                            factor=0.5, 
                            patience=3, 
                            verbose=1
                        )
    # 是否需要早停,当val_loss一直不下降的时候意味着模型基本训练完毕,可以停止
    early_stopping = EarlyStopping(
                            monitor='val_loss', 
                            min_delta=0, 
                            patience=10, 
                            verbose=1
                        )

    # 交叉熵
    model.compile(loss = loss,
            optimizer = Adam(lr=1e-3),
            metrics = ['accuracy'])
    batch_size = 2
    print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
    
    # 开始训练
    model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),
            steps_per_epoch=max(1, num_train//batch_size),
            validation_data=generate_arrays_from_file(lines[num_train:], batch_size),
            validation_steps=max(1, num_val//batch_size),
            epochs=50,
            initial_epoch=0,
            callbacks=[checkpoint_period, reduce_lr])

    model.save_weights(log_dir+'last1.h5')

3、预测文件

预测文件如下:

from nets.pspnet import mobilenet_pspnet
from PIL import Image
import numpy as np
import random
import copy
import os


class_colors = [[0,0,0],[0,255,0]]
NCLASSES = 2
HEIGHT = 576
WIDTH = 576


model = mobilenet_pspnet(n_classes=NCLASSES,input_height=HEIGHT, input_width=WIDTH)
model.load_weights("logs/ep011-loss0.067-val_loss0.108.h5")
imgs = os.listdir("./img")

for jpg in imgs:

    img = Image.open("./img/"+jpg)
    old_img = copy.deepcopy(img)
    orininal_h = np.array(img).shape[0]
    orininal_w = np.array(img).shape[1]

    img = img.resize((WIDTH,HEIGHT))
    img = np.array(img)
    img = img/255
    img = img.reshape(-1,HEIGHT,WIDTH,3)
    pr = model.predict(img)[0]

    pr = pr.reshape((int(HEIGHT/4), int(WIDTH/4),NCLASSES)).argmax(axis=-1)

    seg_img = np.zeros((int(HEIGHT/4), int(WIDTH/4),3))
    colors = class_colors

    for c in range(NCLASSES):
        seg_img[:,:,0] += ( (pr[:,: ] == c )*( colors[c][0] )).astype('uint8')
        seg_img[:,:,1] += ((pr[:,: ] == c )*( colors[c][1] )).astype('uint8')
        seg_img[:,:,2] += ((pr[:,: ] == c )*( colors[c][2] )).astype('uint8')

    seg_img = Image.fromarray(np.uint8(seg_img)).resize((orininal_w,orininal_h))

    image = Image.blend(old_img,seg_img,0.3)
    image.save("./img_out/"+jpg)

训练结果

原图:
在这里插入图片描述
处理后:
在这里插入图片描述
pspnet模型虽然是一个很好的模型,但是似乎因为我只用了最后一个特征层,导致内容提取的不够好,修改之后应该会有更好的效果。

模型的改进

在前面的时候我写道:似乎因为我只用了最后一个特征层,导致内容提取的不够好,修改之后应该会有更好的效果。
写了一个demo,将f4,f3的内容也提取到最后的结果中。

1、实现代码

只要将pspnet的内容修改即可:

from keras.models import *
from keras.layers import *
from nets.mobilenet import get_mobilenet_encoder

from keras_segmentation.models.model_utils import get_segmentation_model

IMAGE_ORDERING = 'channels_last'
MERGE_AXIS = -1


def resize_image( inp ,  s , data_format ):
	import tensorflow as tf

	return Lambda( 
		lambda x: tf.image.resize_images(
			x , ( K.int_shape(x)[1]*s[0] ,K.int_shape(x)[2]*s[1] ))  
		)( inp )

def pool_block( feats , pool_factor ):


	if IMAGE_ORDERING == 'channels_first':
		h = K.int_shape( feats )[2]
		w = K.int_shape( feats )[3]
	elif IMAGE_ORDERING == 'channels_last':
		h = K.int_shape( feats )[1]
		w = K.int_shape( feats )[2]

	# strides = [18,18],[9,9],[6,6],[3,3]
	pool_size = strides = [int(np.round( float(h) /  pool_factor)), int(np.round(  float(w )/  pool_factor))]
 
	# 进行不同程度的平均
	x = AveragePooling2D(pool_size , data_format=IMAGE_ORDERING , strides=strides, padding='same')( feats )
	
	# 进行卷积
	x = Conv2D(512, (1 ,1 ), data_format=IMAGE_ORDERING , padding='same' , use_bias=False )( x )
	x = BatchNormalization()(x)
	x = Activation('relu' )(x)

	x = resize_image( x , strides , data_format=IMAGE_ORDERING ) 

	return x


def _pspnet( n_classes , encoder ,  input_height=384, input_width=576  ):

	assert input_height%192 == 0
	assert input_width%192 == 0

	img_input , levels = encoder( input_height=input_height,input_width=input_width)
	[f1 , f2 , f3 , f4 , f5 ] = levels 

	o = f5
	# 对f5进行不同程度的池化
	pool_factors = [ 1,2,3,6]
	pool_outs = [o ]
	for p in pool_factors:
		pooled = pool_block(  o , p  )
		pool_outs.append( pooled )
	# 连接
	o = Concatenate( axis=MERGE_AXIS)(pool_outs )
	o = ( Conv2D(512, (1, 1), padding='valid', data_format=IMAGE_ORDERING))(o)
	o = ( BatchNormalization())(o)
	o = resize_image(o,(2,2),data_format=IMAGE_ORDERING)
	o = Concatenate( axis=MERGE_AXIS)([o,f4])

	o = ( Conv2D(512, (1, 1), padding='valid', data_format=IMAGE_ORDERING))(o)
	o = ( BatchNormalization())(o)
	o = Activation('relu' )(o)
	pool_outs = [o ]
	# 对f4进行不同程度的池化
	for p in pool_factors:
		pooled = pool_block(  o , p  )
		pool_outs.append( pooled )
	# 连接
	o = Concatenate( axis=MERGE_AXIS)(pool_outs )
	o = ( Conv2D(512, (1, 1), padding='valid', data_format=IMAGE_ORDERING))(o)
	o = ( BatchNormalization())(o)
	o = resize_image(o,(2,2),data_format=IMAGE_ORDERING)

	o = Concatenate( axis=MERGE_AXIS)([o,f3])
	o = ( Conv2D(512, (1, 1), padding='valid', data_format=IMAGE_ORDERING))(o)
	o = ( BatchNormalization())(o)
	o = Activation('relu' )(o)
	pool_outs = [o ]
	# 对f3进行不同程度的池化
	for p in pool_factors:
		pooled = pool_block(  o , p  )
		pool_outs.append( pooled )
	# 连接
	o = Concatenate( axis=MERGE_AXIS)(pool_outs )

	# 卷积
	o = Conv2D(512, (1,1), data_format=IMAGE_ORDERING, use_bias=False )(o)
	o = BatchNormalization()(o)
	o = Activation('relu' )(o)

	# 此时输出为[144,144,nclasses]
	o = Conv2D( n_classes,(3,3),data_format=IMAGE_ORDERING, padding='same' )(o)
	o = resize_image(o,(2,2),data_format=IMAGE_ORDERING)
	o = Reshape((-1,n_classes))(o)
	o = Softmax()(o)
	model = Model(img_input,o)
	return model



def mobilenet_pspnet( n_classes ,  input_height=224, input_width=224 ):

	model =  _pspnet( n_classes , get_mobilenet_encoder ,  input_height=input_height, input_width=input_width  )
	model.model_name = "mobilenet_pspnet"
	return model

2、实现结果

在这里插入图片描述

  • 30
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 53
    评论
PSPNet是一种用于语义分割的深度学习网络模型,它通过使用金字塔池化模块来整合基于不同区域的上下文信息,从而提供了有效的全局上下文先验。相比于其他最先进的方法,PSPNet在效果上表现更好。\[1\] 金字塔池化模块可以收集具有层级的信息,比全局池化更有代表性。同时,PSPNet的计算量并没有比原来的空洞卷积FCN网络有很大的增加。在端到端学习中,全局金字塔池化模块和局部FCN特征可以被同时训练。\[2\] PSPNet语义分割任务中具有优越的性能。它利用金字塔池化模块和金字塔场景解析网络来聚合不同区域的全局上下文信息,从而生成高质量的场景解析结果。该方法在不同的数据集上实现了最先进的性能,例如在PASCAL VOC 2012和Cityscapes数据集上的mIoU准确性分别为85.4%和80.2%。\[3\] #### 引用[.reference_title] - *1* [PSPNet | 语义分割及场景分析](https://blog.csdn.net/qq_42722197/article/details/125611648)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [语义分割-PSPNet](https://blog.csdn.net/weixin_43925119/article/details/109706219)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 53
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bubbliiiing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值