ResNet50卷积神经网络输出数据形参分析-笔记

news2024/11/24 10:24:40

ResNet50卷积神经网络输出数据形参分析-笔记

ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块
50=49个卷积(3+4+6+3)*3+1和一个全连接层
分析结果为:
输入数据形状:[10, 3, 224, 224]
最后输出结果:linear_0 [10, 1] [2048, 1] [1]

在这里插入图片描述
ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块
第1模块:7X7(64) 一个卷积
第2模块:3X3(64) 三个残差块=9个卷积
第3模块:3X3(128) 四个残差块=12个卷积
第4模块:3X3(256) 六个残差块=18个卷积
第5模块:3X3(512) 三个残差块=9个卷积
最后一个全连接层
在这里插入图片描述

分析详细过程如下所示:

PS E:\project\python> & D:/ProgramData/Anaconda3/python.exe e:/project/python/PM/ResNet_PM_test.py
layers= 50
W0804 20:41:04.044713 18388 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 6.1, Driver API Version: 12.2, Runtime API Version: 10.2
W0804 20:41:04.053730 18388 gpu_resources.cc:91] device: 0, cuDNN Version: 7.6.
block= 0 depth[block]= 3    Cout=256 
bottleneck[ 256 64 False
bottleneck[ 256 64 True
bottleneck[ 256 64 True
create bnb 3
block= 1 depth[block]= 4   Cout=512 
bottleneck[ 512 128 False
bottleneck[ 512 128 True
bottleneck[ 512 128 True
bottleneck[ 512 128 True
create bnb 4
block= 2 depth[block]= 6   Cout=1024 
bottleneck[ 1024 256 False
bottleneck[ 1024 256 True
bottleneck[ 1024 256 True
bottleneck[ 1024 256 True
bottleneck[ 1024 256 True
bottleneck[ 1024 256 True
create bnb 6
block= 3 depth[block]= 3   Cout=2048
bottleneck[ 2048 512 False
bottleneck[ 2048 512 True
bottleneck[ 2048 512 True
create bnb 3
[10, 3, 224, 224]
conv2d_0 [10, 64, 112, 112] [64, 3, 7, 7] [ 64 ]
D:\ProgramData\Anaconda3\lib\site-packages\paddle\nn\layer\norm.py:712: UserWarning: When training, we now always track global mean and variance.
  warnings.warn(
conv_bn_layer_0 [10, 64, 112, 112]
maxpool2d: [10, 64, 56, 56]
======start bottleneckBlock:
#第二个模块 Cout=256  包括三个残差块bottleneckBlock
-----print bottleneckBlock: 0
conv2d_1 [10, 64, 56, 56] [64, 64, 1, 1] [ 64 ]
conv2d_2 [10, 64, 56, 56] [64, 64, 3, 3] [ 64 ]
conv2d_3 [10, 256, 56, 56] [256, 64, 1, 1] [ 256 ]
conv2d_4 [10, 256, 56, 56] [256, 64, 1, 1] [ 256 ]
end block: [10, 256, 56, 56]
-----print bottleneckBlock: 1
conv2d_5 [10, 64, 56, 56] [64, 256, 1, 1] [ 64 ]
conv2d_6 [10, 64, 56, 56] [64, 64, 3, 3] [ 64 ]
conv2d_7 [10, 256, 56, 56] [256, 64, 1, 1] [ 256 ]
end block: [10, 256, 56, 56]
-----print bottleneckBlock: 2
conv2d_8 [10, 64, 56, 56] [64, 256, 1, 1] [ 64 ]
conv2d_9 [10, 64, 56, 56] [64, 64, 3, 3] [ 64 ]
conv2d_10 [10, 256, 56, 56] [256, 64, 1, 1] [ 256 ]
end block: [10, 256, 56, 56]
#第三个模块 Cout=512  包括四个残差块bottleneckBlock
-----print bottleneckBlock: 3
conv2d_11 [10, 128, 56, 56] [128, 256, 1, 1] [ 128 ]
conv2d_12 [10, 128, 28, 28] [128, 128, 3, 3] [ 128 ]
conv2d_13 [10, 512, 28, 28] [512, 128, 1, 1] [ 512 ]
conv2d_14 [10, 512, 28, 28] [512, 256, 1, 1] [ 512 ]
end block: [10, 512, 28, 28]
-----print bottleneckBlock: 4
conv2d_15 [10, 128, 28, 28] [128, 512, 1, 1] [ 128 ]
conv2d_16 [10, 128, 28, 28] [128, 128, 3, 3] [ 128 ]
conv2d_17 [10, 512, 28, 28] [512, 128, 1, 1] [ 512 ]
end block: [10, 512, 28, 28]
-----print bottleneckBlock: 5
conv2d_18 [10, 128, 28, 28] [128, 512, 1, 1] [ 128 ]
conv2d_19 [10, 128, 28, 28] [128, 128, 3, 3] [ 128 ]
conv2d_20 [10, 512, 28, 28] [512, 128, 1, 1] [ 512 ]
end block: [10, 512, 28, 28]
-----print bottleneckBlock: 6
conv2d_21 [10, 128, 28, 28] [128, 512, 1, 1] [ 128 ]
conv2d_22 [10, 128, 28, 28] [128, 128, 3, 3] [ 128 ]
conv2d_23 [10, 512, 28, 28] [512, 128, 1, 1] [ 512 ]
end block: [10, 512, 28, 28]
#第四个模块 Cout=1024  包括六个残差块bottleneckBlock
-----print bottleneckBlock: 7
conv2d_24 [10, 256, 28, 28] [256, 512, 1, 1] [ 256 ]
conv2d_25 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_26 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
conv2d_27 [10, 1024, 14, 14] [1024, 512, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
-----print bottleneckBlock: 8
conv2d_28 [10, 256, 14, 14] [256, 1024, 1, 1] [ 256 ]
conv2d_29 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_30 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
-----print bottleneckBlock: 9
conv2d_31 [10, 256, 14, 14] [256, 1024, 1, 1] [ 256 ]
conv2d_32 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_33 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
-----print bottleneckBlock: 10
conv2d_34 [10, 256, 14, 14] [256, 1024, 1, 1] [ 256 ]
conv2d_35 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_36 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
-----print bottleneckBlock: 11
conv2d_37 [10, 256, 14, 14] [256, 1024, 1, 1] [ 256 ]
conv2d_38 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_39 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
-----print bottleneckBlock: 12
conv2d_40 [10, 256, 14, 14] [256, 1024, 1, 1] [ 256 ]
conv2d_41 [10, 256, 14, 14] [256, 256, 3, 3] [ 256 ]
conv2d_42 [10, 1024, 14, 14] [1024, 256, 1, 1] [ 1024 ]
end block: [10, 1024, 14, 14]
#第五个模块 Cout=2048  包括三个残差块bottleneckBlock
-----print bottleneckBlock: 13
conv2d_43 [10, 512, 14, 14] [512, 1024, 1, 1] [ 512 ]
conv2d_44 [10, 512, 7, 7] [512, 512, 3, 3] [ 512 ]
conv2d_45 [10, 2048, 7, 7] [2048, 512, 1, 1] [ 2048 ]
conv2d_46 [10, 2048, 7, 7] [2048, 1024, 1, 1] [ 2048 ]
end block: [10, 2048, 7, 7]
-----print bottleneckBlock: 14
conv2d_47 [10, 512, 7, 7] [512, 2048, 1, 1] [ 512 ]
conv2d_48 [10, 512, 7, 7] [512, 512, 3, 3] [ 512 ]
conv2d_49 [10, 2048, 7, 7] [2048, 512, 1, 1] [ 2048 ]
end block: [10, 2048, 7, 7]
-----print bottleneckBlock: 15
conv2d_50 [10, 512, 7, 7] [512, 2048, 1, 1] [ 512 ]
conv2d_51 [10, 512, 7, 7] [512, 512, 3, 3] [ 512 ]
conv2d_52 [10, 2048, 7, 7] [2048, 512, 1, 1] [ 2048 ]
end block: [10, 2048, 7, 7]
======end bottleneckBlock:
adaptive_avg_pool2d_0 [10, 2048, 1, 1]
y.shape= [10, 2048]
linear_0 [10, 1] [2048, 1] [1]
PS E:\project\python> 

分析测试代码如下所示:

# -*- coding:utf-8 -*-

# ResNet模型代码
import numpy as np
import paddle
import paddle.nn as nn
import paddle.nn.functional as F

def printItem(item,x):
      # item是CNN类中的一个子层
      # 查看经过子层之后的输出数据形状
      try:
          x = item(x)
      except:
          x = paddle.reshape(x, [x.shape[0], -1])
          x = item(x)  
      #print(len(item.parameters()))         
      if len(item.parameters())==1:       
          print(item.full_name(), x.shape,item.parameters()[0].shape,'[',item.parameters()[0].shape[0],']') 
          #print(item)
      elif len(item.parameters())==2:
          # 查看卷积和全连接层的数据和参数的形状,
          # 其中item.parameters()[0]是权重参数w,item.parameters()[1]是偏置参数b
          print(item.full_name(), x.shape, item.parameters()[0].shape, item.parameters()[1].shape)
      else:
          # 池化层没有参数
          print(item.full_name(), x.shape) 
      return x;      

# ResNet中使用了BatchNorm层,在卷积层的后面加上BatchNorm以提升数值稳定性
# 定义卷积批归一化块  (包括一个卷积)
class ConvBNLayer(paddle.nn.Layer):
    def __init__(self,
                 num_channels,
                 num_filters,
                 filter_size,
                 stride=1,
                 groups=1,
                 act=None):
       
        """
        num_channels, 卷积层的输入通道数
        num_filters, 卷积层的输出通道数
        stride, 卷积层的步幅
        groups, 分组卷积的组数,默认groups=1不使用分组卷积
        """
        super(ConvBNLayer, self).__init__()

        # 创建卷积层
        self._conv = nn.Conv2D(
            in_channels=num_channels,
            out_channels=num_filters,
            kernel_size=filter_size,
            stride=stride,
            padding=(filter_size - 1) // 2,
            groups=groups,
            bias_attr=False)

        # 创建BatchNorm层
        self._batch_norm = paddle.nn.BatchNorm2D(num_filters)
        
        self.act = act

    def forward_old(self, inputs):
        y = self._conv(inputs)
        y = self._batch_norm(y)
        if self.act == 'leaky':
            y = F.leaky_relu(x=y, negative_slope=0.1)
        elif self.act == 'relu':
            y = F.relu(x=y)
        return y

    def forward(self, inputs):
        y=printItem(self._conv,inputs)
        #print('[',num_filters,num_channels,filter_size,filter_size)
        y = self._batch_norm(y)
        if self.act == 'leaky':
            y = F.leaky_relu(x=y, negative_slope=0.1)
        elif self.act == 'relu':
            y = F.relu(x=y)
        return y

# 定义残差块  (包括三个卷积)   16*3=48
# 每个残差块会对输入图片做三次卷积,然后跟输入图片进行短接
# 如果残差块中第三次卷积输出特征图的形状与输入不一致,则对输入图片做1x1卷积,将其输出形状调整成一致
class BottleneckBlock(paddle.nn.Layer):
    def __init__(self,
                 num_channels,
                 num_filters,
                 stride,
                 shortcut=True):
        super(BottleneckBlock, self).__init__()
        # 创建第一个卷积层 1x1
        self.conv0 = ConvBNLayer(
            num_channels=num_channels,
            num_filters=num_filters,
            filter_size=1,
            act='relu')
        # 创建第二个卷积层 3x3
        self.conv1 = ConvBNLayer(
            num_channels=num_filters,
            num_filters=num_filters,
            filter_size=3,
            stride=stride,
            act='relu')
        # 创建第三个卷积 1x1,但输出通道数乘以4
        self.conv2 = ConvBNLayer(
            num_channels=num_filters,
            num_filters=num_filters * 4,
            filter_size=1,
            act=None)

        # 如果conv2的输出跟此残差块的输入数据形状一致,则shortcut=True
        # 否则shortcut = False,添加1个1x1的卷积作用在输入数据上,使其形状变成跟conv2一致
        if not shortcut:
            self.short = ConvBNLayer(
                num_channels=num_channels,
                num_filters=num_filters * 4,
                filter_size=1,
                stride=stride)

        self.shortcut = shortcut

        self._num_channels_out = num_filters * 4

    def forward_old(self, inputs):
        y = self.conv0(inputs)
        conv1 = self.conv1(y)
        conv2 = self.conv2(conv1)

        # 如果shortcut=True,直接将inputs跟conv2的输出相加
        # 否则需要对inputs进行一次卷积,将形状调整成跟conv2输出一致
        if self.shortcut:
            short = inputs
        else:
            short = self.short(inputs)

        y = paddle.add(x=short, y=conv2)
        y = F.relu(y)
        return y

    def forward(self, inputs): 
        y = self.conv0(inputs)
        #print('>>>>ConvBMLayer0.shape=',y.shape,self.conv0)
        conv1 = self.conv1(y)
        #print('>>>>ConvBMLayer1.shape=',conv1.shape)
        conv2 = self.conv2(conv1)
        #print('>>>>ConvBMLayer2.shape=',conv2.shape)

        # 如果shortcut=True,直接将inputs跟conv2的输出相加
        # 否则需要对inputs进行一次卷积,将形状调整成跟conv2输出一致
        if self.shortcut:
            short = inputs
        else:
            short = self.short(inputs)

        y = paddle.add(x=short, y=conv2)
        y = F.relu(y)
        return y   

# 定义ResNet模型
class ResNet(paddle.nn.Layer):
    def __init__(self, layers=50, class_dim=1):
        print('layers=',layers)
        """
        
        layers, 网络层数,可以是50, 101或者152
        class_dim,分类标签的类别数
        """
        super(ResNet, self).__init__()
        self.layers = layers
        supported_layers = [50, 101, 152]
        assert layers in supported_layers, \
            "supported layers are {} but input layer is {}".format(supported_layers, layers)

        if layers == 50:
            #ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块
            depth = [3, 4, 6, 3]
        elif layers == 101:
            #ResNet101包含多个模块,其中第2到第5个模块分别包含3、4、23、3个残差块
            depth = [3, 4, 23, 3]
        elif layers == 152:
            #ResNet152包含多个模块,其中第2到第5个模块分别包含3、8、36、3个残差块
            depth = [3, 8, 36, 3]
        
        # 残差块中使用到的卷积的输出通道数
        num_filters = [64, 128, 256, 512]

        # ResNet的第一个模块,包含1个7x7卷积,后面跟着1个最大池化层
        self.conv = ConvBNLayer(
            num_channels=3,
            num_filters=64,
            filter_size=7,
            stride=2,
            act='relu')
        self.pool2d_max = nn.MaxPool2D(
            kernel_size=3,
            stride=2,
            padding=1)

        # ResNet的第二到第五个模块c2、c3、c4、c5
        self.bottleneck_block_list = []
        num_channels = 64
        for block in range(len(depth)):     #4(0,1,2,3)
            shortcut = False
            print('block=',block,'depth[block]=',depth[block])
            k=0
            for i in range(depth[block]):   #depth = [3, 4, 6, 3]
                k+=1
                # c3、c4、c5将会在第一个残差块使用stride=2;其余所有残差块stride=1
                bottleneck_block = self.add_sublayer(
                    'bb_%d_%d' % (block, i),
                    BottleneckBlock(
                        num_channels=num_channels,
                        num_filters=num_filters[block],
                        stride=2 if i == 0 and block != 0 else 1, 
                        shortcut=shortcut))
                num_channels = bottleneck_block._num_channels_out
                self.bottleneck_block_list.append(bottleneck_block)
                print('bottleneck[',num_channels,num_filters[block],shortcut)
                shortcut = True;               
            print('create bnb',k)

        # 在c5的输出特征图上使用全局池化
        self.pool2d_avg = paddle.nn.AdaptiveAvgPool2D(output_size=1)

        # stdv用来作为全连接层随机初始化参数的方差
        import math
        stdv = 1.0 / math.sqrt(2048 * 1.0)
        
        # 创建全连接层,输出大小为类别数目,经过残差网络的卷积和全局池化后,
        # 卷积特征的维度是[B,2048,1,1],故最后一层全连接的输入维度是2048
        self.out = nn.Linear(in_features=2048, out_features=class_dim,
                      weight_attr=paddle.ParamAttr(
                          initializer=paddle.nn.initializer.Uniform(-stdv, stdv)))

    def forward(self, inputs):
        y = self.conv(inputs)
        y = self.pool2d_max(y)
        for bottleneck_block in self.bottleneck_block_list:
            y = bottleneck_block(y)
        y = self.pool2d_avg(y)
        y = paddle.reshape(y, [y.shape[0], -1])
        y = self.out(y)
        return y

    def printStruct(self,inputs):
        y=paddle.to_tensor(inputs)
        print(y.shape)
        y=printItem(self.conv,y)
        y = self.pool2d_max(y)
        print("maxpool2d:",y.shape)
        print('======start bottleneckBlock:')
        i=0        
        for bottleneck_block in self.bottleneck_block_list:            
            print('-----print bottleneckBlock:',i)
            y = bottleneck_block(y)
            print('end block:',y.shape)
            i+=1                       
        print('======end bottleneckBlock:')
        y=printItem(self.pool2d_avg,y)
        y = paddle.reshape(y, [y.shape[0], -1])
        print('y.shape=',y.shape)        
        y=printItem(self.out,y)
        return y
            
# 创建模型
model = ResNet()
# 定义优化器
opt = paddle.optimizer.Momentum(learning_rate=0.001, momentum=0.9, parameters=model.parameters(), weight_decay=0.001)
# 启动训练过程
import PM
#PM.train_pm(model, opt)
#

# 输入数据形状是 [N, 3, H, W]
# 这里用np.random创建一个随机数组作为输入数据
x = np.random.randn(*[10,3,224,224])
x = x.astype('float32')
# 创建CNN类的实例,指定模型名称和分类的类别数目
#model = VGG(1)
#
model.printStruct(x)
#

训练源代码如下所示:

# -*- coding:utf-8 -*-

# ResNet模型代码
import numpy as np
import paddle
import paddle.nn as nn
import paddle.nn.functional as F

# ResNet中使用了BatchNorm层,在卷积层的后面加上BatchNorm以提升数值稳定性
# 定义卷积批归一化块  (包括一个卷积)
class ConvBNLayer(paddle.nn.Layer):
    def __init__(self,
                 num_channels,
                 num_filters,
                 filter_size,
                 stride=1,
                 groups=1,
                 act=None):
       
        """
        num_channels, 卷积层的输入通道数
        num_filters, 卷积层的输出通道数
        stride, 卷积层的步幅
        groups, 分组卷积的组数,默认groups=1不使用分组卷积
        """
        super(ConvBNLayer, self).__init__()

        # 创建卷积层
        self._conv = nn.Conv2D(
            in_channels=num_channels,
            out_channels=num_filters,
            kernel_size=filter_size,
            stride=stride,
            padding=(filter_size - 1) // 2,
            groups=groups,
            bias_attr=False)

        # 创建BatchNorm层
        self._batch_norm = paddle.nn.BatchNorm2D(num_filters)
        
        self.act = act

    def forward(self, inputs):
        y = self._conv(inputs)
        y = self._batch_norm(y)
        if self.act == 'leaky':
            y = F.leaky_relu(x=y, negative_slope=0.1)
        elif self.act == 'relu':
            y = F.relu(x=y)
        return y

# 定义残差块  (包括三个卷积)
# 每个残差块会对输入图片做三次卷积,然后跟输入图片进行短接
# 如果残差块中第三次卷积输出特征图的形状与输入不一致,则对输入图片做1x1卷积,将其输出形状调整成一致
class BottleneckBlock(paddle.nn.Layer):
    def __init__(self,
                 num_channels,
                 num_filters,
                 stride,
                 shortcut=True):
        super(BottleneckBlock, self).__init__()
        # 创建第一个卷积层 1x1
        self.conv0 = ConvBNLayer(
            num_channels=num_channels,
            num_filters=num_filters,
            filter_size=1,
            act='relu')
        # 创建第二个卷积层 3x3
        self.conv1 = ConvBNLayer(
            num_channels=num_filters,
            num_filters=num_filters,
            filter_size=3,
            stride=stride,
            act='relu')
        # 创建第三个卷积 1x1,但输出通道数乘以4
        self.conv2 = ConvBNLayer(
            num_channels=num_filters,
            num_filters=num_filters * 4,
            filter_size=1,
            act=None)

        # 如果conv2的输出跟此残差块的输入数据形状一致,则shortcut=True
        # 否则shortcut = False,添加1个1x1的卷积作用在输入数据上,使其形状变成跟conv2一致
        if not shortcut:
            self.short = ConvBNLayer(
                num_channels=num_channels,
                num_filters=num_filters * 4,
                filter_size=1,
                stride=stride)

        self.shortcut = shortcut

        self._num_channels_out = num_filters * 4

    def forward(self, inputs):
        y = self.conv0(inputs)
        conv1 = self.conv1(y)
        conv2 = self.conv2(conv1)

        # 如果shortcut=True,直接将inputs跟conv2的输出相加
        # 否则需要对inputs进行一次卷积,将形状调整成跟conv2输出一致
        if self.shortcut:
            short = inputs
        else:
            short = self.short(inputs)

        y = paddle.add(x=short, y=conv2)
        y = F.relu(y)
        return y

# 定义ResNet模型
class ResNet(paddle.nn.Layer):
    def __init__(self, layers=50, class_dim=1):
        """
        
        layers, 网络层数,可以是50, 101或者152
        class_dim,分类标签的类别数
        """
        super(ResNet, self).__init__()
        self.layers = layers
        supported_layers = [50, 101, 152]
        assert layers in supported_layers, \
            "supported layers are {} but input layer is {}".format(supported_layers, layers)

        if layers == 50:
            #ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块
            depth = [3, 4, 6, 3]
        elif layers == 101:
            #ResNet101包含多个模块,其中第2到第5个模块分别包含3、4、23、3个残差块
            depth = [3, 4, 23, 3]
        elif layers == 152:
            #ResNet152包含多个模块,其中第2到第5个模块分别包含3、8、36、3个残差块
            depth = [3, 8, 36, 3]
        
        # 残差块中使用到的卷积的输出通道数
        num_filters = [64, 128, 256, 512]

        # ResNet的第一个模块,包含1个7x7卷积,后面跟着1个最大池化层
        self.conv = ConvBNLayer(
            num_channels=3,
            num_filters=64,
            filter_size=7,
            stride=2,
            act='relu')
        self.pool2d_max = nn.MaxPool2D(
            kernel_size=3,
            stride=2,
            padding=1)

        # ResNet的第二到第五个模块c2、c3、c4、c5
        self.bottleneck_block_list = []
        num_channels = 64
        for block in range(len(depth)):
            shortcut = False
            for i in range(depth[block]):
                # c3、c4、c5将会在第一个残差块使用stride=2;其余所有残差块stride=1
                bottleneck_block = self.add_sublayer(
                    'bb_%d_%d' % (block, i),
                    BottleneckBlock(
                        num_channels=num_channels,
                        num_filters=num_filters[block],
                        stride=2 if i == 0 and block != 0 else 1, 
                        shortcut=shortcut))
                num_channels = bottleneck_block._num_channels_out
                self.bottleneck_block_list.append(bottleneck_block)
                shortcut = True

        # 在c5的输出特征图上使用全局池化
        self.pool2d_avg = paddle.nn.AdaptiveAvgPool2D(output_size=1)

        # stdv用来作为全连接层随机初始化参数的方差
        import math
        stdv = 1.0 / math.sqrt(2048 * 1.0)
        
        # 创建全连接层,输出大小为类别数目,经过残差网络的卷积和全局池化后,
        # 卷积特征的维度是[B,2048,1,1],故最后一层全连接的输入维度是2048
        self.out = nn.Linear(in_features=2048, out_features=class_dim,
                      weight_attr=paddle.ParamAttr(
                          initializer=paddle.nn.initializer.Uniform(-stdv, stdv)))

    def forward(self, inputs):
        y = self.conv(inputs)
        y = self.pool2d_max(y)
        for bottleneck_block in self.bottleneck_block_list:
            y = bottleneck_block(y)
        y = self.pool2d_avg(y)
        y = paddle.reshape(y, [y.shape[0], -1])
        y = self.out(y)
        return y
# 创建模型
model = ResNet()   #=ResNet(50)   =ResNet(101)   =ResNet(152)
# 定义优化器
opt = paddle.optimizer.Momentum(learning_rate=0.001, momentum=0.9, parameters=model.parameters(), weight_decay=0.001)
# 启动训练过程
import PM
PM.train_pm(model, opt)
#

训练结果:

D:\ProgramData\Anaconda3\lib\site-packages\paddle\nn\layer\norm.py:712: UserWarning: When training, we now always track global mean and variance.
  warnings.warn(
epoch: 0, batch_id: 0, loss is: 0.7711
epoch: 0, batch_id: 20, loss is: 0.6860
[validation] accuracy/loss: 0.7700/0.4910
epoch: 1, batch_id: 0, loss is: 0.7769
epoch: 1, batch_id: 20, loss is: 0.6261
[validation] accuracy/loss: 0.8475/0.3368
epoch: 2, batch_id: 0, loss is: 0.4543
epoch: 2, batch_id: 20, loss is: 0.3392
[validation] accuracy/loss: 0.8950/0.2690
epoch: 3, batch_id: 0, loss is: 1.1716
epoch: 3, batch_id: 20, loss is: 0.0736
[validation] accuracy/loss: 0.8975/0.2387
epoch: 4, batch_id: 0, loss is: 0.0909
epoch: 4, batch_id: 20, loss is: 0.1900
[validation] accuracy/loss: 0.9375/0.2098
PS E:\project\python> 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/846766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Verilog求log10和log2近似

Verilog求log10和log2近似 Verilog求10对数近似方法,整数部分用位置index代替,小数部分用查找表实现 参考: Verilog写一个对数计算模块Log2(x) FPGA实现对数log2和10*log10

【C++】function包装器

function包装器的使用 function包装器的使用格式 function<返回类型(参数)> #include<iostream> #include<functional> using namespace std;class test { public:static void func1(int a,int b){cout << a b << endl;}void func2(int a, int …

机器学习、深度学习项目开发业务数据场景梳理汇总记录

本文的主要作用是对历史项目开发过程中接触到的业务数据进行整体的汇总梳理&#xff0c;文章会随着项目的开发推进不断更新。 一、MSTAR雷达影像数据 MSTAR&#xff08;Moving and Stationary Target Acquisition and Recognition&#xff09;雷达影像数据集是一种常用的合成…

PowerDesigner数据库设计工具使用笔记

简单记录下这个数据库设计工具的使用&#xff0c;在开发中设计数据库过程用得上&#xff0c;好记性不如烂笔头Q 显示窗口 工具类View >ToolBox 即可 选择数据库SQL语句类型是MySQL还是Orale以及版本 顶部栏中的Database 选中 第一个选项 change current DBMS 更改SQL…

HTML+CSS 改进前端简易响应式登录界面

day5 改进上次的项目 HTMLCSS前端 动态响应用户登录界面_一只名叫Me的猫的博客-CSDN博客 emmet自动创建html模板 在vscode中&#xff0c;空白html文件打入一个感叹号&#xff0c;可以自动创建html模板&#xff0c;避免手搓&#xff08;悲&#xff09;。 上次就是因为手搓导致漏…

基于vant的密码输入框,数字键盘,及金额输入

<template><div><el-button click"showPopup">余额支付</el-button><!--以下是密码输入--><van-popup v-model"passshow"closeableclose-icon-position"top-left"position"bottom":style"{ hei…

情感书单素材库大全,好的文案试试做成视频吧

当我们沉浸在热爱的小说或故事中时&#xff0c;我们会被情感所吸引&#xff0c;感受到其中所包含的情感&#xff0c;这些情感会在我们的内心深处留下印记。情感书单素材库是一个非常棒的资源&#xff0c;可以帮助我们发现那些让我们心动的故事和情感&#xff0c;从而创作出有意…

真实分享!赴日IT培训 在日本做程序员真的不加班?

如果有人告诉你完全没有加班那是不太可能的&#xff0c;但是日本的IT行业加班确实不严重&#xff0c;大家可以看一下厚生劳动省&#xff0c;你可以理解为中国的社会保障部这样一个作用&#xff0c;但是是做事风格不太一样的社会保障部&#xff0c;给大家放张IT产业加班图&#…

正运动亮相2023半导体设备材料与核心部件展示会,助力半导体产业高速高精应用

■展会名称&#xff1a; 第11届&#xff08;2023&#xff09;半导体设备材料与核心部件展示会 ■展会日期 2023年8月9日-11日 ■展馆地点 无锡太湖国际博览中心A6馆 ■展位号 A6-A361 正运动技术&#xff0c;作为国内领先的运动控制企业&#xff0c;将于2023年8月9日参加…

炼油厂运营商遭黑客入侵,全球范围内大规模宕机

据最新报道&#xff0c;以色列最大的炼油厂运营商BAZAN Group的网站遭遇黑客入侵&#xff0c;导致该网站在全球出现大范围宕机。在上周末&#xff0c;该集团全球各地的炼油厂网站均无法访问&#xff0c;显示"请求超时"和"被公司的服务器拒绝"等字样。黑客组…

排序第二课【选择排序】直接选择排序 与 堆排序

目录 1. 排序的概念&#xff1a; 2.选择排序的基本思想 3.直接选择排序 4.堆排序 1. 排序的概念&#xff1a; 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xf…

RISC-V架构的演变

随着苹果基于ARM的硅和新的RISC-V CPU的推出&#xff0c;对于CPU开发来说&#xff0c;这是一个令人兴奋的时刻&#xff0c;尽管开发人员的旅程目前对后者来说有点坎坷。 我最喜欢的理论是&#xff0c;没有发生是孤独的&#xff0c;而只是重复了以前发生过的事情&#xff0c;也…

手写springboot

前言 首先确定springboot在spring基础上主要做了哪些改动&#xff1a;内嵌tomcatspi技术动态加载 一、基本实现 1. 建一个工程目录结构如下&#xff1a; springboot: 源码实现逻辑 user : 业务系统2.springboot工程项目构建 1. pom依赖如下 <dependencies>…

vue基于java的高校就业管理系统的设计和实现f0c2k

相比于传统的高校就业管理方式&#xff0c;智能化的管理方式可以大幅提高学生的就业率&#xff0c;实现了高校就业管理的标准化、制度化、程序化的管理&#xff0c;有效地防止了高校就业的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、准确地查询和…

生命科学组织使用 OpenText ETX 随时随地为医疗保健和生命科学人员提供相关信息

生命科学组织使用 OpenText ETX 随时随地为医疗保健和生命科学人员提供相关信息 引领生命科学远程工作的IT新高度 生命科学组织一直承受着改进工作流程、降低成本和比以往更快地交付产品的压力。 使用远程访问和集中式 IT 基础架构&#xff0c;企业可以在加快上市时间方面取得…

opencv基础45-图像金字塔01-高斯金字塔cv2.pyrDown()

什么是图像金字塔&#xff1f; 图像金字塔&#xff08;Image> Pyramid&#xff09;是一种用于多尺度图像处理和分析的技术&#xff0c;它通过构建一系列不同分辨率的图像&#xff0c;从而使得图像可以在不同尺度下进行处理和分析。图像金字塔在计算机视觉、图像处理和计算机…

就地程控站控制柜与斗轮机之间无线通讯

一、应用背景 马钢的前身是成立于1953年的马鞍山铁厂&#xff0c;2019年马钢集团正式成为中国宝武控股子公司。马钢产品以建筑用型线材为主&#xff0c;满足重型工业厂房、轻钢结构、高层建筑、桥梁结构、工业管道等构件的加工需要。目前马钢在岗员工4.8万人&#xff0c;具备了…

三菱PLC与变频器通讯-ModbusRTU协议

Modbus是Modicon公司为其PLC与主机之间的通讯而发明的串行通讯协议。其物理层采用RS232、485等异步串行标准。由于其开放性而被大量的PLC及RTU厂家采用。Modbus通讯方式采用主从方式的查询&#xff0d;相应机制&#xff0c;只有主站发出查询时&#xff0c;从站才能给出响应&…

【快应用】list组件属性的运用指导

【关键词】 list、瀑布流、刷新、页面布局 【问题背景】 1、 页面部分内容需要瀑布流格式展示&#xff0c;在使用lsit列表组件设置columns进行多列渲染时&#xff0c;此时在里面加入刷新动画时&#xff0c;动画只占了list组件的一列&#xff0c;并没有完全占据一行宽度&…

Node.js新手在哪儿找小项目练手?

前言 可以参考一下下面的nodejs相关的项目&#xff0c;希望对你的学习有所帮助&#xff0c;废话少说&#xff0c;让我们直接进入正题>> 1、 NodeBB Star: 13.3k 一个基于Node.js的现代化社区论坛软件&#xff0c;具有快速、可扩展、易于使用和灵活的特点。它支持多种数…