ai-station-code/wudingpv/taihuyuan_roof/compared_experiment/pspnet/model/pspnet.py

181 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@project:
@File : pspnet
@Author : qiqq
@create_time : 2022/11/4 22:37
"""
import torch
import torch.nn.functional as F
from torch import nn
from taihuyuan_roof.compared_experiment.pspnet.model.resnet import resnet50,resnet101
class Resnet(nn.Module):
def __init__(self, dilate_scale=8):
super(Resnet, self).__init__()
from functools import partial
model = resnet50()
# model = resnet101()
# --------------------------------------------------------------------------------------------#
# 根据下采样因子修改卷积的步长与膨胀系数
# 当downsample_factor=16的时候我们最终获得两个特征层shape分别是30,30,1024和30,30,2048
# --------------------------------------------------------------------------------------------#
if dilate_scale == 8:
model.layer3.apply(partial(self._nostride_dilate, dilate=2))
model.layer4.apply(partial(self._nostride_dilate, dilate=4))
elif dilate_scale == 16:
model.layer4.apply(partial(self._nostride_dilate, dilate=2))
self.conv1 = model.conv1[0]
self.bn1 = model.conv1[1]
self.relu1 = model.conv1[2]
self.conv2 = model.conv1[3]
self.bn2 = model.conv1[4]
self.relu2 = model.conv1[5]
self.conv3 = model.conv1[6]
self.bn3 = model.bn1
self.relu3 = model.relu
self.maxpool = model.maxpool
self.layer1 = model.layer1
self.layer2 = model.layer2
self.layer3 = model.layer3
self.layer4 = model.layer4
def _nostride_dilate(self, m, dilate):
classname = m.__class__.__name__
if classname.find('Conv') != -1:
if m.stride == (2, 2):
m.stride = (1, 1)
if m.kernel_size == (3, 3):
m.dilation = (dilate // 2, dilate // 2)
m.padding = (dilate // 2, dilate // 2)
else:
if m.kernel_size == (3, 3):
m.dilation = (dilate, dilate)
m.padding = (dilate, dilate)
def forward(self, x):
x = self.relu1(self.bn1(self.conv1(x)))
x = self.relu2(self.bn2(self.conv2(x)))
x = self.relu3(self.bn3(self.conv3(x)))
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x_aux = self.layer3(x)
x = self.layer4(x_aux)
return x_aux, x
class _PSPModule(nn.Module):
def __init__(self, in_channels, pool_sizes, norm_layer):
super(_PSPModule, self).__init__()
out_channels = in_channels // len(pool_sizes)
# -----------------------------------------------------#
# 分区域进行平均池化
# 30, 30, 320 + 30, 30, 80 + 30, 30, 80 + 30, 30, 80 + 30, 30, 80 = 30, 30, 640
# -----------------------------------------------------#
self.stages = nn.ModuleList(
[self._make_stages(in_channels, out_channels, pool_size, norm_layer) for pool_size in pool_sizes])
# 30, 30, 640 -> 30, 30, 80
self.bottleneck = nn.Sequential(
nn.Conv2d(in_channels + (out_channels * len(pool_sizes)), out_channels, kernel_size=3, padding=1,
bias=False),
norm_layer(out_channels),
nn.ReLU(inplace=True),
nn.Dropout2d(0.1)
)
def _make_stages(self, in_channels, out_channels, bin_sz, norm_layer):
prior = nn.AdaptiveAvgPool2d(output_size=bin_sz)
conv = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False)
bn = norm_layer(out_channels)
relu = nn.ReLU(inplace=True)
return nn.Sequential(prior, conv, bn, relu)
def forward(self, features):#以512*512 降采样16倍 到这里是32*32*2048
h, w = features.size()[2], features.size()[3]
pyramids = [features] #这个地方这样写就成了5个分支了 我觉得应该还是[]
pyramids.extend(
[F.interpolate(stage(features), size=(h, w), mode='bilinear', align_corners=True) for stage in self.stages])
output = self.bottleneck(torch.cat(pyramids, dim=1)) #4096降维到 512
return output
class PSPNet(nn.Module):
def __init__(self, num_classes, downsample_factor, backbone="resnet50", aux_branch=False):
super(PSPNet, self).__init__()
norm_layer = nn.BatchNorm2d
if backbone == "resnet50":
self.backbone = Resnet(downsample_factor)
aux_channel = 1024
out_channel = 2048
# --------------------------------------------------------------#
# PSP模块分区域进行池化
# 分别分割成1x1的区域2x2的区域3x3的区域6x6的区域
# 30,30,320 -> 30,30,80 -> 30,30,21
# --------------------------------------------------------------#
self.master_branch = nn.Sequential(
_PSPModule(out_channel, pool_sizes=[1, 2, 3, 6], norm_layer=norm_layer),
nn.Conv2d(out_channel // 4, num_classes, kernel_size=1)
)
self.aux_branch = aux_branch
if self.aux_branch:
# ---------------------------------------------------#
# 利用特征获得预测结果
# 30, 30, 96 -> 30, 30, 40 -> 30, 30, 21
# ---------------------------------------------------#
self.auxiliary_branch = nn.Sequential(
nn.Conv2d(aux_channel, out_channel // 8, kernel_size=3, padding=1, bias=False),
norm_layer(out_channel // 8),
nn.ReLU(inplace=True),
nn.Dropout2d(0.1),
nn.Conv2d(out_channel // 8, num_classes, kernel_size=1)
)
self.initialize_weights(self.master_branch)
def forward(self, x):
input_size = (x.size()[2], x.size()[3])
x_aux, x = self.backbone(x)
output = self.master_branch(x)
output = F.interpolate(output, size=input_size, mode='bilinear', align_corners=True)
if self.aux_branch:
output_aux = self.auxiliary_branch(x_aux)
output_aux = F.interpolate(output_aux, size=input_size, mode='bilinear', align_corners=True)
return output_aux, output
else:
return output
def initialize_weights(self, *models):
for model in models:
for m in model.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight.data, nonlinearity='relu')
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1.)
m.bias.data.fill_(1e-4)
elif isinstance(m, nn.Linear):
m.weight.data.normal_(0.0, 0.0001)
m.bias.data.zero_()
if __name__ == '__main__':
inpuu =torch.rand(2,3,512,512)
model =PSPNet(num_classes=3,downsample_factor=8,)
# model.eval()
out =model(inpuu)
print(out.shape)