图像语义分割-----SegNet学习笔记+tensorflow

本文介绍了SegNet网络的原理和功能,这是一个用于像素级语义分割的模型。SegNet通过4层下采样和4层上采样实现图像分类,并使用softmax进行像素分类。文章详细阐述了模型搭建、损失函数定义以及训练方法,包括变量声明、卷积层和反卷积层的封装,以及训练过程中的优化器和样本加载。同时,文中还提到了模型的测试与可视化问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SegNet网络是一个像素级的语义分割模型,即会针对图像中的每一个像素,对每一个像素进行分类,去识别该像素属于的类别,整个网络分为4层下采样以及4层上采样,最后将一个[W, H, 3]的输入图像处理成[W, H, NUM_CLASSES]的向量,再通过softmax进行分类,转化为[W, H, 1]的张量,再对属于不同种类的像素分别涂上不同的颜色,从新变成[W, H, 3]的图像,但是其中的物体以不同的颜色进行了标记区分,这就是SegNet网络的功能:

代码地址:https://github.com/tkuanlun350/Tensorflow-SegNet

代码在model.py中完成了模型搭建,loss定义,以及训练方法,下面就分块记录其实现方式。

一、模型搭建

网络模型并不是很复杂,作者在搭建时将其分为了三个部分,由下向上依次是封装带L2正则化的变量定义,封装带bn层的卷积层与反卷积层定义,封装整个网络,下面也是分开来看:

1.1 变量声明封装

变量声明中又分为向量式变量与矩阵式变量,分别在Utils.py中定义如下:

# 很简单的直接初始化一个shape型向量
def _variable_on_cpu(name, shape, initializer):
  with tf.device('/cpu:0'):
    var = tf.get_variable(name, shape, initializer=initializer)
  return var
# 初始化一个带L2正则化的矩阵变量
def _variable_with_weight_decay(name, shape, initializer, wd):
  # 先初始化一个shape型矩阵变量
  var = _variable_on_cpu(
      name,
      shape,
      initializer)
  # 再根据权重,附加L2正则化并将其正则化loss加入总loss中
  if wd is not None:
    weight_decay = tf.multiply(tf.nn.l2_loss(var), wd, name='weight_loss')
    tf.add_to_collection('losses', weight_decay)
  return var

1.2 卷积层与反卷积层封装

 

卷积层定义:

# 这里作者自己复现了卷积过程,对某一被卷积区域s,通过s*w + b来计算卷积结果
def conv_layer_with_bn(inputT, shape, train_phase, activation=True, name=None):
    # 通过输出通道数目来确定b的维数
    out_channel = shape[3]
    # 初始化卷积核矩阵以及偏移变量
    # 完成卷积计算
    with tf.variable_scope(name) as scope:
      kernel = _variable_with_weight_decay('ort_weights', shape=shape, initializer=orthogonal_initializer(), wd=None)
      conv = tf.nn.conv2d(inputT, kernel, [1, 1, 1, 1], padding='SAME')
      biases = _variable_on_cpu('biases', [out_channel], tf.constant_initializer(0.0))
      bias = tf.nn.bias_add(conv, biases)
      # 通过传入参数中是否使用激活函数标志位
      # 输出bn层输出或者再通过一次relu激活函数
      # bn层定义在下面介绍
      if activation is True:
        conv_out = tf.nn.relu(batch_norm_layer(bias, train_phase, scope.name))
      else:
        conv_out = batch_norm_layer(bias, train_phase, scope.name)
    return conv_out
# bn层在使用时需要确定是否在训练,因为bn层中本身有两个参数是需要训练的
# 非训练模式下,可以直接加载训练后的参数
def batch_norm_layer(inputT, is_training, scope):
  return tf.cond(is_training,
          lambda: tf.contrib.layers.batch_norm(inputT, is_training=True,
                           center=False, updates_collections=None, scope=scope+"_bn"),
          lambda: tf.contrib.layers.batch_norm(inputT, is_training=False,
                           updates_collections=None, center=False, scope=scope+"_bn", reuse = True))

反卷积定义:

def deconv_layer(inputT, f_shape, output_shape, stride=2, name=None):
  strides = [1, stride, stride, 1]
  with tf.variable_scope(name):
    # 首先要用特殊的初始化方式来初始化卷积核,下面给出定义
    weights = get_deconv_filter(f_shape)
    # 进行反卷积操作,这里的反卷积定义可以自行查阅,大概就是先扩充再卷积
    deconv = tf.nn.conv2d_transpose(inputT, weights, output_shape,
                                        strides=strides, padding='SAME')
  return deconv
def get_deconv_filter(f_shape):
  # 此处所用的反卷积核都是2*2的核
  # 其每个位置的参数的初始值由该参数的位置与矩阵尺寸确定,公式如下:
  width = f_shape[0]
  heigh = f_shape[0]
  f = int(width/2.0)
  c = (2 * f - 1 - f % 2) / (2.0 * f)
  bilinear = np.zeros([f_shape[0], f_shape[1]])
  for x in range(width):
      fo
### 使用 U-Net 和 SegNet 实现遥感图像语义分割 #### U-Net 的实现方式 U-Net 是一种常用于医学影像分析的卷积神经网络架构,同样适用于遥感图像语义分割。该模型的特点在于其跳跃连接的设计,使得低层特征可以直接传递到高层,从而保留更多细节信息。 对于遥感图像而言,U-Net 可以通过以下 Python 代码来构建: ```python from keras.models import Model from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, concatenate def unet(input_size=(256, 256, 3)): inputs = Input(input_size) conv1 = Conv2D(64, (3, 3), activation='relu', padding='same')(inputs) pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) conv2 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool1) pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) conv3 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool2) up4 = concatenate([UpSampling2D(size=(2, 2))(conv3), conv2], axis=3) conv4 = Conv2D(128, (3, 3), activation='relu', padding='same')(up4) up5 = concatenate([UpSampling2D(size=(2, 2))(conv4), conv1], axis=3) conv5 = Conv2D(64, (3, 3), activation='relu', padding='same')(up5) output = Conv2D(1, (1, 1), activation='sigmoid')(conv5) model = Model(inputs=[inputs], outputs=[output]) return model ``` 此部分展示了如何定义一个基本版本的 U-Net 架构[^2]。 #### SegNet实现方式 不同于 U-Net,SegNet 并不依赖于跳跃连接而是记录并利用最大池化的索引来完成上采样的过程。这种设计简化了网络结构的同时也减少了参数量。下面是一个简单的 SegNet 模型实例: ```python import tensorflow as tf from tensorflow.keras import layers class SegNet(tf.keras.Model): def __init__(self): super(SegNet, self).__init__() # Encoder Layers self.enc_conv1_1 = layers.Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1)) ... self.pooling_indices_list = [] @tf.function def call(self, input_tensor, training=False): x = input_tensor # Encoding phase with max pooling and storing indices. for i in range(len(encoder_layers)): x = encoder_layers[i](x) if isinstance(x, tuple): pooled_output, argmax = nn.functional.max_pool2d_with_indices( x, kernel_size=encoder_kernel_sizes[i], stride=encoder_strides[i], return_indices=True ) self.pooling_indices_list.append(argmax) x = pooled_output # Decoding phase using stored indices from encoding phase to perform upsampling. for j in reversed(range(len(decoder_layers))): index_to_use = self.pooling_indices_list.pop() x = decoder_upsample_layers[j](index_to_use)(x) final_layer = layers.Conv2DTranspose(...)(x) # Adjust according to your needs. return final_layer ``` 请注意上述代码片段仅作为概念展示用途,并未完全按照实际项目需求编写完整的类成员变量声明以及详细的解码器逻辑[^1]。 为了更好地理解这两个框架的应用场景和技术特点,建议参考具体案例研究或开源项目文档获取更详尽的信息[^3]。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值