【セマンティックセグメンテーション】0から1へのLinkNetとコード実装


序文

すでに U-net を持っていますが、なぜ linkNet が必要なのでしょうか?
unet については、この記事を参照してください。 [セマンティック セグメンテーション] unet の構造とコードの実装: https://blog.csdn.net/weixin_40293999/article/details/129648032
自動運転用の RealTime リアルタイム システムに焦点を当てた resNet が紹介されています。 、など。返された結果のフィールド。unet は、医療診断などのリアルタイム性が低い場所に適しています。また、オートエンコーダーの構造も借用しています。
論文: https://arxiv.org/pdf/1707.03718.pdf は 2017 年の記事で、わずか 5 ページですが、読む価値があります。新しいディープ ニューラル ネットワーク アーキテクチャが導入され、視覚的なシーンを理解するためのピクセル レベルのセマンティック セグメンテーションが効率的に行われます。わずか 1,150 万個のパラメータと 21.2 GFLOP を使用するネットワークは、正確かつ高速です。


1. ネットワーク構造

1.1 ネットワーク構造の模式図

ここに画像の説明を挿入
ここに画像の説明を挿入
紙にコピーしてありますので、紙を直接読むことをお勧めします。

1.2 LinkNet モデルの作成

LinkNet は、4 つの基本モジュールからモデル全体を構築できます。
1. コンボリューション モジュール (コンボリューション + BN + アクティブ化)
2. デコンボリューション (デコンボリューション + BN + アクティブ化)
3. エンコーダー (4 つのコンボリューション モジュール)
4. デコーダー (コンボリューション モジュール + デコンボリューション モジュール + コンボリューション) 5.
全体的なネットワーク構造を実現します (1、2、3、4 はビルディング ブロックで構築できます): コンボリューション モジュール + デコンボリューション モジュール + エンコーダー + デコーダー

2. コード

2.1 各モジュールの構成

2.1.1 コンボリューションモジュール

Convolution モジュールは、デフォルトの kernel_size=3、stride = 1、padding =1 に初期化します。つまり、特徴マップのサイズがそのまま出力されます。
次に、シーケンシャルを使用してパイプラインに処理します。

# 卷积模块
class ConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels,k_size=3,stride=1,pad=1) -> None:
        super().__init__()
        self.conv_bn_relu = nn.Sequential(
            nn.Conv2d(in_channels, out_channels,kernel_size=k_size,stride,padding=pad),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
            )
    
    def farward(self,x):
        x = self.conv_bn_relu(x)
        return x

2.1.2 デコンボリューションモジュール

デコンボリューションには 2 つのパディングが必要です。パディングはデコンボリューションが開始される位置で、output_padding はデコンボリューション後の画像の端を埋めます。

class DeconvBlock(nn.Module):
    def __init__(self, in_channels, out_channels,k_size=3,stride=2,padding=1,output_padding = 1) -> None:
        """
        反卷积需要有两个padding
        """
        super().__init__()
        #padding 是反卷积开始的位置, output_padding 将反卷积之后的图像的边缘部分进行填充
        self.deconv = nn.ConvTranspose2d(in_channels,out_channels,kernel_size=k_size,stride=stride,padding=padding,output_padding=output_padding)
        self.bn = nn.BatchNorm2d(out_channels)
    
    def farward(self,x, is_act=True):
        x = self.deconv(x)
        if is_act:
            x = torch.relu(self.bn(x))
        return x

2.1.3 エンコーダモジュール

多重化コンボリューション モジュールは、
ここに画像の説明を挿入
4 つの基本コンボリューション ブロック + 1 つのショートカット ブロックで構成されます。4 つのコンボリューション全体でズームが 2 倍になるため、ここで説明する必要があります。そのため、ショートカットもそれに応じて処理する必要があります。そうしないと合計が計算されません。 。

class EncodeBlock(nn.Module):
   def __init__(self, in_channels, out_channels) -> None:
       super().__init__()
       # 第一层需要对图像进行缩放
       self.conv1 = ConvBlock(in_channels,out_channels,stride=2)
       # 第2层不需要对图像进行缩放
       self.conv2 = ConvBlock(out_channels,out_channels)
       # 第三层,第四层原样输出
       self.conv3 = ConvBlock(out_channels,out_channels)
       self.conv4 = ConvBlock(out_channels,out_channels)
           
       self.short_cut =  ConvBlock(in_channels,out_channels,stride=2)
   def farward(self,x):
       out1 = self.conv1(x)
       out1 = self.conv2(out1)
       short_cut = self.short_cut(x)
       # 第一部分的输出和shortcut相加
       out2 = self.conv3(out1+short_cut)
       out2 = self.conv4(out2)
       return out2 + out1

2.2 コーディングネットワークの構造


ここに画像の説明を挿入
ブロックの構築を開始するには、このネットワーク構造図を確認する必要があります。


class Net(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        # 第一层
        self.input_conv = ConvBlock(3,64,stride=2,k_size=7,pad=3)
        # maxpool 原来的图像缩放2倍
        self.input_maxpool = nn.MaxPool2d(kernel_size=2)
        # 四个编码器模块,通道扩大一倍,size减小一倍
        self.encode1 = EncodeBlock(64,64)
        self.encode2 = EncodeBlock(64,128)
        self.encode3 = EncodeBlock(128,256)
        self.encode4 = EncodeBlock(256,512)
        # 四个解码模块,和encode是对应的,通道数减小,size扩大为原来的一倍
        self.decode4 = DeconvBlock(512,256)
        self.decode3 = DeconvBlock(256,128)
        self.decode2 = DeconvBlock(128,64)
        self.decode1 = DeconvBlock(64,64)
        # 输出部分,第一层走默认即可
        self.deconv_out1 = DeconvBlock(64,32)
        self.conv_out = ConvBlock(32,32)
        # stride 为2 可以不写, 一共就是2分类。kesize=2,因为论文给的是2x2的,2x2的适合 padding是不需要变化的,都是0 保证正好变为原来的2倍,因为stride正好是2
        self.deconv_out2 = DeconvBlock(32,2,k_size=2,padding=0,output_padding=0)
        
    def farward(self,x):
        # input 的两层
        x = self.input_conv(x)
        x = self.input_maxpool(x)
        # 后面的中间值要保留
        e1 = self.encode1(x)
        e2 = self.encode2(e1)
        e3 = self.encode3(e2)
        e4 = self.encode3(e3)
        # 到此为止,左边半拉,完成
        
        d4 = self.decode4(e4)
        d3 = self.decode3(d4+e3)
        d2 = self.decode2(d3+e2)
        d1 = self.decode2(d2+e1)
        f1 = self.deconv_out1(d1)
        f2 = self.conv_out(f1)
        f3 = self.deconv_out2(f2)
        return f3

初期化して構造を確認する

 Output exceeds the size limit. Open the full output data in a text editor
Net(
(input_conv): ConvBlock(
  (conv_bn_relu): Sequential(
    (0): Conv2d(3, 64, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3))
    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU(inplace=True)
  )
)
(input_maxpool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(encode1): EncodeBlock(
  (conv1): ConvBlock(
    (conv_bn_relu): Sequential(
      (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
  )
  (conv2): ConvBlock(
    (conv_bn_relu): Sequential(
      (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
  )
  (conv3): ConvBlock(
...
(deconv_out2): DeconvBlock(
  (deconv): ConvTranspose2d(32, 2, kernel_size=(2, 2), stride=(2, 2))
  (bn): BatchNorm2d(2, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)

2.3 損失関数とトレーニング

model = Net()
loss_fn = nn.CrossEntropyLoss()

そのトレーニングは unet トレーニングとほぼ同じですが、IOU インジケーターが追加されています。
IOU インデックス
テンソルとテンソルの除算には torch.true_divide(tensor1,tesor2) を使用します。

2.4 トレーニング

トレーニングアップ

Output exceeds the size limit. Open the full output data in a text editor
epoch:  0 loss:  0.072 accuracy: 0.806 IOU: 0

      test_loss:  0.071 test_accuracy: 0.81 test_iou: 0
epoch:  1 loss:  0.072 accuracy: 0.806 IOU: 0

      test_loss:  0.07 test_accuracy: 0.81 test_iou: 0
epoch:  2 loss:  0.071 accuracy: 0.807 IOU: 0

      test_loss:  0.07 test_accuracy: 0.809 test_iou: 0
epoch:  3 loss:  0.071 accuracy: 0.807 IOU: 0

      test_loss:  0.07 test_accuracy: 0.811 test_iou: 0
epoch:  4 loss:  0.071 accuracy: 0.807 IOU: 0

      test_loss:  0.071 test_accuracy: 0.81 test_iou: 0
epoch:  5 loss:  0.071 accuracy: 0.807 IOU: 0

      test_loss:  0.07 test_accuracy: 0.81 test_iou: 0
epoch:  6 loss:  0.071 accuracy: 0.808 IOU: 0

      test_loss:  0.07 test_accuracy: 0.81 test_iou: 0
epoch:  7 loss:  0.071 accuracy: 0.808 IOU: 0

      test_loss:  0.071 test_accuracy: 0.81 test_iou: 0
epoch:  8 loss:  0.071 accuracy: 0.809 IOU: 0
...
      test_loss:  0.07 test_accuracy: 0.81 test_iou: 0
epoch:  9 loss:  0.071 accuracy: 0.809 IOU: 0

      test_loss:  0.071 test_accuracy: 0.809 test_iou: 0

ここに画像の説明を挿入
データセットの概要

おすすめ

転載: blog.csdn.net/weixin_40293999/article/details/130496070