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

177 lines
7.1 KiB
Python
Raw Normal View History

2025-05-06 11:18:48 +08:00
#!/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_pv.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)