• 使用NNI对DLASeg剪枝的失败记录


    本文希望对CenterNet算法的Backbone暨DLASeg进行剪枝。

    剪枝试验涉及3个文件,分别为:

    DCN可变性卷积dcn_v2.py,因为DLASeg依赖DCN。

    1. #!/usr/bin/env python
    2. from __future__ import absolute_import
    3. from __future__ import print_function
    4. from __future__ import division
    5. import math
    6. import torch
    7. from torch import nn
    8. from torch.autograd import Function
    9. from torch.nn.modules.utils import _pair
    10. from torch.autograd.function import once_differentiable
    11. import _ext as _backend
    12. class _DCNv2(Function):
    13. @staticmethod
    14. def forward(ctx, input, offset, mask, weight, bias,
    15. stride, padding, dilation, deformable_groups):
    16. ctx.stride = _pair(stride)
    17. ctx.padding = _pair(padding)
    18. ctx.dilation = _pair(dilation)
    19. ctx.kernel_size = _pair(weight.shape[2:4])
    20. ctx.deformable_groups = deformable_groups
    21. output = _backend.dcn_v2_forward(input, weight, bias,
    22. offset, mask,
    23. ctx.kernel_size[0], ctx.kernel_size[1],
    24. ctx.stride[0], ctx.stride[1],
    25. ctx.padding[0], ctx.padding[1],
    26. ctx.dilation[0], ctx.dilation[1],
    27. ctx.deformable_groups)
    28. ctx.save_for_backward(input, offset, mask, weight, bias)
    29. return output
    30. @staticmethod
    31. @once_differentiable
    32. def backward(ctx, grad_output):
    33. input, offset, mask, weight, bias = ctx.saved_tensors
    34. grad_input, grad_offset, grad_mask, grad_weight, grad_bias = \
    35. _backend.dcn_v2_backward(input, weight,
    36. bias,
    37. offset, mask,
    38. grad_output,
    39. ctx.kernel_size[0], ctx.kernel_size[1],
    40. ctx.stride[0], ctx.stride[1],
    41. ctx.padding[0], ctx.padding[1],
    42. ctx.dilation[0], ctx.dilation[1],
    43. ctx.deformable_groups)
    44. return grad_input, grad_offset, grad_mask, grad_weight, grad_bias,\
    45. None, None, None, None,
    46. dcn_v2_conv = _DCNv2.apply
    47. class DCNv2(nn.Module):
    48. def __init__(self, in_channels, out_channels,
    49. kernel_size, stride, padding, dilation=1, deformable_groups=1):
    50. super(DCNv2, self).__init__()
    51. self.in_channels = in_channels
    52. self.out_channels = out_channels
    53. self.kernel_size = _pair(kernel_size)
    54. self.stride = _pair(stride)
    55. self.padding = _pair(padding)
    56. self.dilation = _pair(dilation)
    57. self.deformable_groups = deformable_groups
    58. self.weight = nn.Parameter(torch.Tensor(
    59. out_channels, in_channels, *self.kernel_size))
    60. self.bias = nn.Parameter(torch.Tensor(out_channels))
    61. self.reset_parameters()
    62. def reset_parameters(self):
    63. n = self.in_channels
    64. for k in self.kernel_size:
    65. n *= k
    66. stdv = 1. / math.sqrt(n)
    67. self.weight.data.uniform_(-stdv, stdv)
    68. self.bias.data.zero_()
    69. def forward(self, input, offset, mask):
    70. assert 2 * self.deformable_groups * self.kernel_size[0] * self.kernel_size[1] == \
    71. offset.shape[1]
    72. assert self.deformable_groups * self.kernel_size[0] * self.kernel_size[1] == \
    73. mask.shape[1]
    74. return dcn_v2_conv(input, offset, mask,
    75. self.weight,
    76. self.bias,
    77. self.stride,
    78. self.padding,
    79. self.dilation,
    80. self.deformable_groups)
    81. class DCN(DCNv2):
    82. def __init__(self, in_channels, out_channels,
    83. kernel_size, stride, padding,
    84. dilation=1, deformable_groups=1):
    85. super(DCN, self).__init__(in_channels, out_channels,
    86. kernel_size, stride, padding, dilation, deformable_groups)
    87. channels_ = self.deformable_groups * 3 * self.kernel_size[0] * self.kernel_size[1]
    88. self.conv_offset_mask = nn.Conv2d(self.in_channels,
    89. channels_,
    90. kernel_size=self.kernel_size,
    91. stride=self.stride,
    92. padding=self.padding,
    93. bias=True)
    94. self.init_offset()
    95. def init_offset(self):
    96. self.conv_offset_mask.weight.data.zero_()
    97. self.conv_offset_mask.bias.data.zero_()
    98. def forward(self, input):
    99. out = self.conv_offset_mask(input)
    100. o1, o2, mask = torch.chunk(out, 3, dim=1)
    101. offset = torch.cat((o1, o2), dim=1)
    102. mask = torch.sigmoid(mask)
    103. return dcn_v2_conv(input, offset, mask,
    104. self.weight, self.bias,
    105. self.stride,
    106. self.padding,
    107. self.dilation,
    108. self.deformable_groups)
    109. class _DCNv2Pooling(Function):
    110. @staticmethod
    111. def forward(ctx, input, rois, offset,
    112. spatial_scale,
    113. pooled_size,
    114. output_dim,
    115. no_trans,
    116. group_size=1,
    117. part_size=None,
    118. sample_per_part=4,
    119. trans_std=.0):
    120. ctx.spatial_scale = spatial_scale
    121. ctx.no_trans = int(no_trans)
    122. ctx.output_dim = output_dim
    123. ctx.group_size = group_size
    124. ctx.pooled_size = pooled_size
    125. ctx.part_size = pooled_size if part_size is None else part_size
    126. ctx.sample_per_part = sample_per_part
    127. ctx.trans_std = trans_std
    128. output, output_count = \
    129. _backend.dcn_v2_psroi_pooling_forward(input, rois, offset,
    130. ctx.no_trans, ctx.spatial_scale,
    131. ctx.output_dim, ctx.group_size,
    132. ctx.pooled_size, ctx.part_size,
    133. ctx.sample_per_part, ctx.trans_std)
    134. ctx.save_for_backward(input, rois, offset, output_count)
    135. return output
    136. @staticmethod
    137. @once_differentiable
    138. def backward(ctx, grad_output):
    139. input, rois, offset, output_count = ctx.saved_tensors
    140. grad_input, grad_offset = \
    141. _backend.dcn_v2_psroi_pooling_backward(grad_output,
    142. input,
    143. rois,
    144. offset,
    145. output_count,
    146. ctx.no_trans,
    147. ctx.spatial_scale,
    148. ctx.output_dim,
    149. ctx.group_size,
    150. ctx.pooled_size,
    151. ctx.part_size,
    152. ctx.sample_per_part,
    153. ctx.trans_std)
    154. return grad_input, None, grad_offset, \
    155. None, None, None, None, None, None, None, None
    156. dcn_v2_pooling = _DCNv2Pooling.apply
    157. class DCNv2Pooling(nn.Module):
    158. def __init__(self,
    159. spatial_scale,
    160. pooled_size,
    161. output_dim,
    162. no_trans,
    163. group_size=1,
    164. part_size=None,
    165. sample_per_part=4,
    166. trans_std=.0):
    167. super(DCNv2Pooling, self).__init__()
    168. self.spatial_scale = spatial_scale
    169. self.pooled_size = pooled_size
    170. self.output_dim = output_dim
    171. self.no_trans = no_trans
    172. self.group_size = group_size
    173. self.part_size = pooled_size if part_size is None else part_size
    174. self.sample_per_part = sample_per_part
    175. self.trans_std = trans_std
    176. def forward(self, input, rois, offset):
    177. assert input.shape[1] == self.output_dim
    178. if self.no_trans:
    179. offset = input.new()
    180. return dcn_v2_pooling(input, rois, offset,
    181. self.spatial_scale,
    182. self.pooled_size,
    183. self.output_dim,
    184. self.no_trans,
    185. self.group_size,
    186. self.part_size,
    187. self.sample_per_part,
    188. self.trans_std)
    189. class DCNPooling(DCNv2Pooling):
    190. def __init__(self,
    191. spatial_scale,
    192. pooled_size,
    193. output_dim,
    194. no_trans,
    195. group_size=1,
    196. part_size=None,
    197. sample_per_part=4,
    198. trans_std=.0,
    199. deform_fc_dim=1024):
    200. super(DCNPooling, self).__init__(spatial_scale,
    201. pooled_size,
    202. output_dim,
    203. no_trans,
    204. group_size,
    205. part_size,
    206. sample_per_part,
    207. trans_std)
    208. self.deform_fc_dim = deform_fc_dim
    209. if not no_trans:
    210. self.offset_mask_fc = nn.Sequential(
    211. nn.Linear(self.pooled_size * self.pooled_size *
    212. self.output_dim, self.deform_fc_dim),
    213. nn.ReLU(inplace=True),
    214. nn.Linear(self.deform_fc_dim, self.deform_fc_dim),
    215. nn.ReLU(inplace=True),
    216. nn.Linear(self.deform_fc_dim, self.pooled_size *
    217. self.pooled_size * 3)
    218. )
    219. self.offset_mask_fc[4].weight.data.zero_()
    220. self.offset_mask_fc[4].bias.data.zero_()
    221. def forward(self, input, rois):
    222. offset = input.new()
    223. if not self.no_trans:
    224. # do roi_align first
    225. n = rois.shape[0]
    226. roi = dcn_v2_pooling(input, rois, offset,
    227. self.spatial_scale,
    228. self.pooled_size,
    229. self.output_dim,
    230. True, # no trans
    231. self.group_size,
    232. self.part_size,
    233. self.sample_per_part,
    234. self.trans_std)
    235. # build mask and offset
    236. offset_mask = self.offset_mask_fc(roi.view(n, -1))
    237. offset_mask = offset_mask.view(
    238. n, 3, self.pooled_size, self.pooled_size)
    239. o1, o2, mask = torch.chunk(offset_mask, 3, dim=1)
    240. offset = torch.cat((o1, o2), dim=1)
    241. mask = torch.sigmoid(mask)
    242. # do pooling with offset and mask
    243. return dcn_v2_pooling(input, rois, offset,
    244. self.spatial_scale,
    245. self.pooled_size,
    246. self.output_dim,
    247. self.no_trans,
    248. self.group_size,
    249. self.part_size,
    250. self.sample_per_part,
    251. self.trans_std) * mask
    252. # only roi_align
    253. return dcn_v2_pooling(input, rois, offset,
    254. self.spatial_scale,
    255. self.pooled_size,
    256. self.output_dim,
    257. self.no_trans,
    258. self.group_size,
    259. self.part_size,
    260. self.sample_per_part,
    261. self.trans_std)

    pose_dla_dcn.py文件:

    1. from __future__ import absolute_import
    2. from __future__ import division
    3. from __future__ import print_function
    4. import os
    5. import math
    6. import logging
    7. import numpy as np
    8. from os.path import join
    9. import torch
    10. from torch import nn
    11. import torch.nn.functional as F
    12. import torch.utils.model_zoo as model_zoo
    13. from dcn_v2 import DCN
    14. BN_MOMENTUM = 0.1
    15. logger = logging.getLogger(__name__)
    16. def get_model_url(data='imagenet', name='dla34', hash='ba72cf86'):
    17. return join('http://dl.yf.io/dla/models', data, '{}-{}.pth'.format(name, hash))
    18. def conv3x3(in_planes, out_planes, stride=1):
    19. "3x3 convolution with padding"
    20. return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
    21. padding=1, bias=False)
    22. class BasicBlock(nn.Module):
    23. def __init__(self, inplanes, planes, stride=1, dilation=1):
    24. super(BasicBlock, self).__init__()
    25. self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3,
    26. stride=stride, padding=dilation,
    27. bias=False, dilation=dilation)
    28. self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
    29. self.relu = nn.ReLU(inplace=True)
    30. self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
    31. stride=1, padding=dilation,
    32. bias=False, dilation=dilation)
    33. self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
    34. self.stride = stride
    35. def forward(self, x, residual=None):
    36. if residual is None:
    37. residual = x
    38. out = self.conv1(x)
    39. out = self.bn1(out)
    40. out = self.relu(out)
    41. out = self.conv2(out)
    42. out = self.bn2(out)
    43. out += residual
    44. out = self.relu(out)
    45. return out
    46. class Bottleneck(nn.Module):
    47. expansion = 2
    48. def __init__(self, inplanes, planes, stride=1, dilation=1):
    49. super(Bottleneck, self).__init__()
    50. expansion = Bottleneck.expansion
    51. bottle_planes = planes // expansion
    52. self.conv1 = nn.Conv2d(inplanes, bottle_planes,
    53. kernel_size=1, bias=False)
    54. self.bn1 = nn.BatchNorm2d(bottle_planes, momentum=BN_MOMENTUM)
    55. self.conv2 = nn.Conv2d(bottle_planes, bottle_planes, kernel_size=3,
    56. stride=stride, padding=dilation,
    57. bias=False, dilation=dilation)
    58. self.bn2 = nn.BatchNorm2d(bottle_planes, momentum=BN_MOMENTUM)
    59. self.conv3 = nn.Conv2d(bottle_planes, planes,
    60. kernel_size=1, bias=False)
    61. self.bn3 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
    62. self.relu = nn.ReLU(inplace=True)
    63. self.stride = stride
    64. def forward(self, x, residual=None):
    65. if residual is None:
    66. residual = x
    67. out = self.conv1(x)
    68. out = self.bn1(out)
    69. out = self.relu(out)
    70. out = self.conv2(out)
    71. out = self.bn2(out)
    72. out = self.relu(out)
    73. out = self.conv3(out)
    74. out = self.bn3(out)
    75. out += residual
    76. out = self.relu(out)
    77. return out
    78. class BottleneckX(nn.Module):
    79. expansion = 2
    80. cardinality = 32
    81. def __init__(self, inplanes, planes, stride=1, dilation=1):
    82. super(BottleneckX, self).__init__()
    83. cardinality = BottleneckX.cardinality
    84. # dim = int(math.floor(planes * (BottleneckV5.expansion / 64.0)))
    85. # bottle_planes = dim * cardinality
    86. bottle_planes = planes * cardinality // 32
    87. self.conv1 = nn.Conv2d(inplanes, bottle_planes,
    88. kernel_size=1, bias=False)
    89. self.bn1 = nn.BatchNorm2d(bottle_planes, momentum=BN_MOMENTUM)
    90. self.conv2 = nn.Conv2d(bottle_planes, bottle_planes, kernel_size=3,
    91. stride=stride, padding=dilation, bias=False,
    92. dilation=dilation, groups=cardinality)
    93. self.bn2 = nn.BatchNorm2d(bottle_planes, momentum=BN_MOMENTUM)
    94. self.conv3 = nn.Conv2d(bottle_planes, planes,
    95. kernel_size=1, bias=False)
    96. self.bn3 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
    97. self.relu = nn.ReLU(inplace=True)
    98. self.stride = stride
    99. def forward(self, x, residual=None):
    100. if residual is None:
    101. residual = x
    102. out = self.conv1(x)
    103. out = self.bn1(out)
    104. out = self.relu(out)
    105. out = self.conv2(out)
    106. out = self.bn2(out)
    107. out = self.relu(out)
    108. out = self.conv3(out)
    109. out = self.bn3(out)
    110. out += residual
    111. out = self.relu(out)
    112. return out
    113. class Root(nn.Module):
    114. def __init__(self, in_channels, out_channels, kernel_size, residual):
    115. super(Root, self).__init__()
    116. self.conv = nn.Conv2d(
    117. in_channels, out_channels, 1,
    118. stride=1, bias=False, padding=(kernel_size - 1) // 2)
    119. self.bn = nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM)
    120. self.relu = nn.ReLU(inplace=True)
    121. self.residual = residual
    122. def forward(self, *x):
    123. children = x
    124. x = self.conv(torch.cat(x, 1))
    125. x = self.bn(x)
    126. if self.residual:
    127. x += children[0]
    128. x = self.relu(x)
    129. return x
    130. class Tree(nn.Module):
    131. def __init__(self, levels, block, in_channels, out_channels, stride=1,
    132. level_root=False, root_dim=0, root_kernel_size=1,
    133. dilation=1, root_residual=False):
    134. super(Tree, self).__init__()
    135. if root_dim == 0:
    136. root_dim = 2 * out_channels
    137. if level_root:
    138. root_dim += in_channels
    139. if levels == 1:
    140. self.tree1 = block(in_channels, out_channels, stride,
    141. dilation=dilation)
    142. self.tree2 = block(out_channels, out_channels, 1,
    143. dilation=dilation)
    144. else:
    145. self.tree1 = Tree(levels - 1, block, in_channels, out_channels,
    146. stride, root_dim=0,
    147. root_kernel_size=root_kernel_size,
    148. dilation=dilation, root_residual=root_residual)
    149. self.tree2 = Tree(levels - 1, block, out_channels, out_channels,
    150. root_dim=root_dim + out_channels,
    151. root_kernel_size=root_kernel_size,
    152. dilation=dilation, root_residual=root_residual)
    153. if levels == 1:
    154. self.root = Root(root_dim, out_channels, root_kernel_size,
    155. root_residual)
    156. self.level_root = level_root
    157. self.root_dim = root_dim
    158. self.downsample = None
    159. self.project = None
    160. self.levels = levels
    161. if stride > 1:
    162. self.downsample = nn.MaxPool2d(stride, stride=stride)
    163. if in_channels != out_channels:
    164. self.project = nn.Sequential(
    165. nn.Conv2d(in_channels, out_channels,
    166. kernel_size=1, stride=1, bias=False),
    167. nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM)
    168. )
    169. def forward(self, x, residual=None, children=None):
    170. children = [] if children is None else children
    171. bottom = self.downsample(x) if self.downsample else x
    172. residual = self.project(bottom) if self.project else bottom
    173. if self.level_root:
    174. children.append(bottom)
    175. x1 = self.tree1(x, residual)
    176. if self.levels == 1:
    177. x2 = self.tree2(x1)
    178. x = self.root(x2, x1, *children)
    179. else:
    180. children.append(x1)
    181. x = self.tree2(x1, children=children)
    182. return x
    183. class DLA(nn.Module):
    184. def __init__(self, levels, channels, num_classes=1000,
    185. block=BasicBlock, residual_root=False, linear_root=False):
    186. super(DLA, self).__init__()
    187. self.channels = channels
    188. self.num_classes = num_classes
    189. self.base_layer = nn.Sequential(
    190. nn.Conv2d(3, channels[0], kernel_size=7, stride=1,
    191. padding=3, bias=False),
    192. nn.BatchNorm2d(channels[0], momentum=BN_MOMENTUM),
    193. nn.ReLU(inplace=True))
    194. self.level0 = self._make_conv_level(
    195. channels[0], channels[0], levels[0])
    196. self.level1 = self._make_conv_level(
    197. channels[0], channels[1], levels[1], stride=2)
    198. self.level2 = Tree(levels[2], block, channels[1], channels[2], 2,
    199. level_root=False,
    200. root_residual=residual_root)
    201. self.level3 = Tree(levels[3], block, channels[2], channels[3], 2,
    202. level_root=True, root_residual=residual_root)
    203. self.level4 = Tree(levels[4], block, channels[3], channels[4], 2,
    204. level_root=True, root_residual=residual_root)
    205. self.level5 = Tree(levels[5], block, channels[4], channels[5], 2,
    206. level_root=True, root_residual=residual_root)
    207. # for m in self.modules():
    208. # if isinstance(m, nn.Conv2d):
    209. # n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
    210. # m.weight.data.normal_(0, math.sqrt(2. / n))
    211. # elif isinstance(m, nn.BatchNorm2d):
    212. # m.weight.data.fill_(1)
    213. # m.bias.data.zero_()
    214. def _make_level(self, block, inplanes, planes, blocks, stride=1):
    215. downsample = None
    216. if stride != 1 or inplanes != planes:
    217. downsample = nn.Sequential(
    218. nn.MaxPool2d(stride, stride=stride),
    219. nn.Conv2d(inplanes, planes,
    220. kernel_size=1, stride=1, bias=False),
    221. nn.BatchNorm2d(planes, momentum=BN_MOMENTUM),
    222. )
    223. layers = []
    224. layers.append(block(inplanes, planes, stride, downsample=downsample))
    225. for i in range(1, blocks):
    226. layers.append(block(inplanes, planes))
    227. return nn.Sequential(*layers)
    228. def _make_conv_level(self, inplanes, planes, convs, stride=1, dilation=1):
    229. modules = []
    230. for i in range(convs):
    231. modules.extend([
    232. nn.Conv2d(inplanes, planes, kernel_size=3,
    233. stride=stride if i == 0 else 1,
    234. padding=dilation, bias=False, dilation=dilation),
    235. nn.BatchNorm2d(planes, momentum=BN_MOMENTUM),
    236. nn.ReLU(inplace=True)])
    237. inplanes = planes
    238. return nn.Sequential(*modules)
    239. def forward(self, x):
    240. y = []
    241. x = self.base_layer(x)
    242. for i in range(6):
    243. x = getattr(self, 'level{}'.format(i))(x)
    244. y.append(x)
    245. return y
    246. def load_pretrained_model(self, data='imagenet', name='dla34', hash='ba72cf86'):
    247. # fc = self.fc
    248. if name.endswith('.pth'):
    249. model_weights = torch.load(data + name)
    250. else:
    251. model_url = get_model_url(data, name, hash)
    252. model_weights = model_zoo.load_url(model_url)
    253. num_classes = len(model_weights[list(model_weights.keys())[-1]])
    254. self.fc = nn.Conv2d(
    255. self.channels[-1], num_classes,
    256. kernel_size=1, stride=1, padding=0, bias=True)
    257. self.load_state_dict(model_weights)
    258. # self.fc = fc
    259. def dla34(pretrained=True, **kwargs): # DLA-34
    260. model = DLA([1, 1, 1, 2, 2, 1],
    261. [16, 32, 64, 128, 256, 512],
    262. block=BasicBlock, **kwargs)
    263. #if pretrained:
    264. # model.load_pretrained_model(data='imagenet', name='dla34', hash='ba72cf86')
    265. return model
    266. class Identity(nn.Module):
    267. def __init__(self):
    268. super(Identity, self).__init__()
    269. def forward(self, x):
    270. return x
    271. def fill_fc_weights(layers):
    272. for m in layers.modules():
    273. if isinstance(m, nn.Conv2d):
    274. if m.bias is not None:
    275. nn.init.constant_(m.bias, 0)
    276. def fill_up_weights(up):
    277. w = up.weight.data
    278. f = math.ceil(w.size(2) / 2)
    279. c = (2 * f - 1 - f % 2) / (2. * f)
    280. for i in range(w.size(2)):
    281. for j in range(w.size(3)):
    282. w[0, 0, i, j] = \
    283. (1 - math.fabs(i / f - c)) * (1 - math.fabs(j / f - c))
    284. for c in range(1, w.size(0)):
    285. w[c, 0, :, :] = w[0, 0, :, :]
    286. class DeformConv(nn.Module):
    287. def __init__(self, chi, cho):
    288. super(DeformConv, self).__init__()
    289. self.actf = nn.Sequential(
    290. nn.BatchNorm2d(cho, momentum=BN_MOMENTUM),
    291. nn.ReLU(inplace=True)
    292. )
    293. self.conv = DCN(chi, cho, kernel_size=(3,3), stride=1, padding=1, dilation=1, deformable_groups=1)
    294. def forward(self, x):
    295. x = self.conv(x)
    296. x = self.actf(x)
    297. return x
    298. class IDAUp(nn.Module):
    299. def __init__(self, o, channels, up_f):
    300. super(IDAUp, self).__init__()
    301. for i in range(1, len(channels)):
    302. c = channels[i]
    303. f = int(up_f[i])
    304. proj = DeformConv(c, o)
    305. node = DeformConv(o, o)
    306. up = nn.ConvTranspose2d(o, o, f * 2, stride=f,
    307. padding=f // 2, output_padding=0,
    308. groups=o, bias=False)
    309. fill_up_weights(up)
    310. setattr(self, 'proj_' + str(i), proj)
    311. setattr(self, 'up_' + str(i), up)
    312. setattr(self, 'node_' + str(i), node)
    313. def forward(self, layers, startp, endp):
    314. for i in range(startp + 1, endp):
    315. upsample = getattr(self, 'up_' + str(i - startp))
    316. project = getattr(self, 'proj_' + str(i - startp))
    317. layers[i] = upsample(project(layers[i]))
    318. node = getattr(self, 'node_' + str(i - startp))
    319. layers[i] = node(layers[i] + layers[i - 1])
    320. class DLAUp(nn.Module):
    321. def __init__(self, startp, channels, scales, in_channels=None):
    322. super(DLAUp, self).__init__()
    323. self.startp = startp
    324. if in_channels is None:
    325. in_channels = channels
    326. self.channels = channels
    327. channels = list(channels)
    328. scales = np.array(scales, dtype=int)
    329. for i in range(len(channels) - 1):
    330. j = -i - 2
    331. setattr(self, 'ida_{}'.format(i),
    332. IDAUp(channels[j], in_channels[j:],
    333. scales[j:] // scales[j]))
    334. scales[j + 1:] = scales[j]
    335. in_channels[j + 1:] = [channels[j] for _ in channels[j + 1:]]
    336. def forward(self, layers):
    337. out = [layers[-1]] # start with 32
    338. for i in range(len(layers) - self.startp - 1):
    339. ida = getattr(self, 'ida_{}'.format(i))
    340. ida(layers, len(layers) -i - 2, len(layers))
    341. out.insert(0, layers[-1])
    342. return out
    343. class Interpolate(nn.Module):
    344. def __init__(self, scale, mode):
    345. super(Interpolate, self).__init__()
    346. self.scale = scale
    347. self.mode = mode
    348. def forward(self, x):
    349. x = F.interpolate(x, scale_factor=self.scale, mode=self.mode, align_corners=False)
    350. return x
    351. class DLASeg(nn.Module):
    352. def __init__(self, base_name, heads, pretrained, down_ratio, final_kernel,
    353. last_level, head_conv, out_channel=0):
    354. super(DLASeg, self).__init__()
    355. assert down_ratio in [2, 4, 8, 16]
    356. self.first_level = int(np.log2(down_ratio))
    357. self.last_level = last_level
    358. self.base = globals()[base_name](pretrained=pretrained)
    359. channels = self.base.channels
    360. scales = [2 ** i for i in range(len(channels[self.first_level:]))]
    361. self.dla_up = DLAUp(self.first_level, channels[self.first_level:], scales)
    362. if out_channel == 0:
    363. out_channel = channels[self.first_level]
    364. self.ida_up = IDAUp(out_channel, channels[self.first_level:self.last_level],
    365. [2 ** i for i in range(self.last_level - self.first_level)])
    366. self.heads = heads
    367. for head in self.heads:
    368. classes = self.heads[head]
    369. if head_conv > 0:
    370. fc = nn.Sequential(
    371. nn.Conv2d(channels[self.first_level], head_conv,
    372. kernel_size=3, padding=1, bias=True),
    373. nn.ReLU(inplace=True),
    374. nn.Conv2d(head_conv, classes,
    375. kernel_size=final_kernel, stride=1,
    376. padding=final_kernel // 2, bias=True))
    377. if 'hm' in head:
    378. fc[-1].bias.data.fill_(-2.19)
    379. else:
    380. fill_fc_weights(fc)
    381. else:
    382. fc = nn.Conv2d(channels[self.first_level], classes,
    383. kernel_size=final_kernel, stride=1,
    384. padding=final_kernel // 2, bias=True)
    385. if 'hm' in head:
    386. fc.bias.data.fill_(-2.19)
    387. else:
    388. fill_fc_weights(fc)
    389. self.__setattr__(head, fc)
    390. def forward(self, x):
    391. x = self.base(x)
    392. x = self.dla_up(x)
    393. y = []
    394. for i in range(self.last_level - self.first_level):
    395. y.append(x[i].clone())
    396. self.ida_up(y, 0, len(y))
    397. z = {}
    398. for head in self.heads:
    399. z[head] = self.__getattr__(head)(y[-1])
    400. # return [z] xiehao
    401. return z
    402. def get_pose_net(num_layers, heads, head_conv=256, down_ratio=4):
    403. model = DLASeg('dla{}'.format(num_layers), heads,
    404. pretrained=True,
    405. down_ratio=down_ratio,
    406. final_kernel=1,
    407. last_level=5,
    408. head_conv=head_conv)
    409. return model

    测试剪枝主流程的centerNet_prune文件

    1. from nni.compression.pytorch.pruning import L1NormPruner
    2. from nni.compression.pytorch.speedup import ModelSpeedup
    3. import pose_dla_dcn
    4. import torch
    5. num_layers = 34
    6. heads = {'hm': 2, 'wh': 2, 'reg': 2}
    7. config_list = [{
    8. 'sparsity': 0.5,
    9. 'op_types': ['Conv2d']
    10. }]
    11. model = pose_dla_dcn.get_pose_net(num_layers, heads)
    12. torch.save(model.state_dict(), "baseline.pth")
    13. # model.cuda()
    14. # model(torch.rand(1, 3, 512, 512).cuda()) # 512严格要求
    15. print("--------------raw model--------------")
    16. print(model)
    17. pruner = L1NormPruner(model, config_list, mode='dependency_aware', dummy_input=torch.rand(1, 3, 512, 512))
    18. print("--------------pruned model--------------")
    19. print(model)
    20. # compress the model and generate the masks
    21. _, masks = pruner.compress()
    22. # show the masks sparsity
    23. for name, mask in masks.items():
    24. print(name, ' sparsity: ', '{:.2f}'.format(mask['weight'].sum() / mask['weight'].numel()))
    25. # need to unwarp the model, if the model is wrawpped before speedup
    26. pruner._unwrap_model()
    27. # speedup the model
    28. model.eval()
    29. ModelSpeedup(model, dummy_input=torch.rand(1, 3, 512, 512), masks_file=masks).speedup_model()
    30. print("--------------after sppedup--------------")
    31. print(model)
    32. torch.save(model, "model_pruner.pth")

    最后一个文件有一个注意点,就是dummy_input输入一定是[batch, 3, 512, 512]的形式,否则卷积池化后残差连接会有问题,会出现[batch, 128, 3, 3] 和[batch, 128, 2, 2]相加的情况。

    执行后报错,出错信息为:

    self.output = self.module(*dummy_input)
      File "D:\programs\python37\lib\site-packages\torch\nn\modules\module.py", line 727, in _call_impl
        result = self.forward(*input, **kwargs)
    TypeError: forward() missing 1 required positional argument: 'input'

    1. [2022-11-18 19:15:08] start to speedup the model
    2. D:\programs\python37\lib\site-packages\nni\compression\pytorch\utils\mask_conflict.py:124: UserWarning: This overload of nonzero is deprecated:
    3. nonzero()
    4. Consider using one of the following signatures instead:
    5. nonzero(*, bool as_tuple) (Triggered internally at ..\torch\csrc\utils\python_arg_parser.cpp:882.)
    6. all_ones = (w_mask.flatten(1).sum(-1) == count).nonzero().squeeze(1).tolist()
    7. both dim0 and dim1 masks found.
    8. [2022-11-18 19:18:01] infer module masks...
    9. [2022-11-18 19:18:01] Update mask for base.base_layer.0
    10. [2022-11-18 19:18:03] Update mask for dla_up.ida_0.proj_1.actf.0
    11. Traceback (most recent call last):
    12. File "D:/workspace/newczalgo/CenterNet_3DCar_Slimming/src/centernet_prune/centernet_prune.py", line 34, in
    13. ModelSpeedup(model, torch.rand(1, 3, 512, 512), masks).speedup_model()
    14. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 536, in speedup_model
    15. self.infer_modules_masks()
    16. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 371, in infer_modules_masks
    17. self.update_direct_sparsity(curnode)
    18. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 240, in update_direct_sparsity
    19. state_dict=copy.deepcopy(module.state_dict()), batch_dim=self.batch_dim)
    20. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\infer_mask.py", line 80, in __init__
    21. self.output = self.module(*dummy_input)
    22. File "D:\programs\python37\lib\site-packages\torch\nn\modules\module.py", line 727, in _call_impl
    23. result = self.forward(*input, **kwargs)
    24. TypeError: forward() missing 1 required positional argument: 'input'
    25. Process finished with exit code 1

    nni的github上有对应的issue:

    Meet a dropout missing argument problem when speed up the model and update mask for my own model · Issue #4297 · microsoft/nni · GitHub

     主要是DCN的输出为empy,导致dummy_input的list为空的。

    尝试方法一:

    网上说把有问题的层信息加入config_list的exclude中,比如:

    1. config_list = [{
    2. 'sparsity': 0.5,
    3. 'op_types': ['Conv2d']
    4. },
    5. {'exclude': True, 'op_names': ['conv_offset_mask']}
    6. ]

     op_names换成:

    dla_up.ida_0.proj_1.actf.0 或 dla_up.ida_0.proj_1.conv.conv_offset_mask或dla_up等都失败,报错信息还是一样的。

    尝试方法二:

    在compress中当dumpy_input为空时直接return,如下所示:

    此时又会出现新的bug:

    1. [2022-11-18 21:43:10] Update mask for dla_up.ida_2.aten::add.233
    2. Traceback (most recent call last):
    3. File "D:/workspace/newczalgo/CenterNet_3DCar_Slimming/src/centernet_prune/centernet_prune.py", line 38, in
    4. ModelSpeedup(model, dummy_input=torch.rand(1, 3, 512, 512), masks_file=masks).speedup_model()
    5. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 539, in speedup_model
    6. self.infer_modules_masks()
    7. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 374, in infer_modules_masks
    8. self.update_direct_sparsity(curnode)
    9. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\compressor.py", line 235, in update_direct_sparsity
    10. func, dummy_input, in_masks, in_constants=in_constants, batch_dim=self.batch_dim)
    11. File "D:\programs\python37\lib\site-packages\nni\compression\pytorch\speedup\infer_mask.py", line 80, in __init__
    12. self.output = self.module(*dummy_input)
    13. TypeError: add() received an invalid combination of arguments - got (Tensor), but expected (Tensor input, Tensor other, *, Number alpha, Tensor out)

    结论:DLASeg使用NNI进行剪枝挑战失败!!

  • 相关阅读:
    前端ps基本操作
    滚动播报、el-scrollbar
    C语言解决约瑟夫环问题
    R语言ggplot2和gganimate包可视化动态动画气泡图(Animated Bubble chart):使用gganimate包创建可视化gif动图
    flink源码分析 - 获取调用位置信息
    vscode中注释多行bash脚本
    远程控制 Linux 系统的软件下载
    gdb-dashboard的简单使用
    到底是选择极米还是选择当贝?画质看当贝,音质看极米 在意画质和使用体验的选当贝
    Vscode连接远程服务器(一套配置成功)
  • 原文地址:https://blog.csdn.net/benben044/article/details/127931805