深度学习模型权重转换(pytorch转mindspore)

以img_backbone(Resnet50为例)

1 先拿到pytorch版的参数

./tools/dist_train.sh ./projects/configs/bevformer/bevformer_tiny.py

在bevformer.py文件__init__之后打断点,通过self.img_backbone.state_dict()得到入参数--

是一个<class 'collections.OrderedDict'>这种格式的数据;

self.img_backbone.state_dict().keys(),可以得到全部的参数

写入一个文件里面得到pytorchKey.txt

2 拿到mindspore版的参数

在resnet.py这个文件里面

import warnings

from mindspore import nn


class ResLayer(nn.SequentialCell):
    """ResLayer to build ResNet style backbone.

    Args:
        block (nn.Module): block used to build ResLayer.
        inplanes (int): inplanes of block.
        planes (int): planes of block.
        num_blocks (int): number of blocks.
        stride (int): stride of the first block. Default: 1
        avg_down (bool): Use AvgPool instead of stride conv when
            downsampling in the bottleneck. Default: False
        conv_cfg (dict): dictionary to construct and config conv layer.
            Default: None
        norm_cfg (dict): dictionary to construct and config norm layer.
            Default: dict(type='BN')
        downsample_first (bool): Downsample at the first block or last block.
            False for Hourglass, True for ResNet. Default: True
    """

    def __init__(self,
                 block,
                 inplanes,
                 planes,
                 num_blocks,
                 stride=1,
                 avg_down=False,
                 conv_cfg=None,
                 norm_cfg=dict(type='BN'),
                 downsample_first=True,
                 **kwargs):
        self.block = block

        downsample = None
        if stride != 1 or inplanes != planes * block.expansion:
            downsample = []
            conv_stride = stride
            if avg_down:
                conv_stride = 1
                downsample.append(
                    nn.AvgPool2d(
                        kernel_size=stride,
                        stride=stride,
                        ceil_mode=True,
                        count_include_pad=False))
            downsample.extend([
                nn.Conv2d(
                    in_channels=inplanes,
                    out_channels=planes * block.expansion,
                    kernel_size=1,
                    stride=conv_stride,
                    has_bias=False),
                nn.BatchNorm2d(num_features=planes * block.expansion)
            ])
            downsample = nn.SequentialCell(*downsample)

        layers = []
        if downsample_first:
            layers.append(
                block(
                    inplanes=inplanes,
                    planes=planes,
                    stride=stride,
                    downsample=downsample,
                    conv_cfg=conv_cfg,
                    norm_cfg=norm_cfg,
                    **kwargs))
            inplanes = planes * block.expansion
            for _ in range(1, num_blocks):
                layers.append(
                    block(
                        inplanes=inplanes,
                        planes=planes,
                        stride=1,
                        conv_cfg=conv_cfg,
                        norm_cfg=norm_cfg,
                        **kwargs))

        else:  # downsample_first=False is for HourglassModule
            for _ in range(num_blocks - 1):
                layers.append(
                    block(
                        inplanes=inplanes,
                        planes=inplanes,
                        stride=1,
                        conv_cfg=conv_cfg,
                        norm_cfg=norm_cfg,
                        **kwargs))
            layers.append(
                block(
                    inplanes=inplanes,
                    planes=planes,
                    stride=stride,
                    downsample=downsample,
                    conv_cfg=conv_cfg,
                    norm_cfg=norm_cfg,
                    **kwargs))
        super(ResLayer, self).__init__(*layers)


class Bottleneck(nn.Cell):
    expansion = 4

    def __init__(self,
                 inplanes,
                 planes,
                 stride=1,
                 dilation=1,
                 downsample=None,
                 style='pytorch',
                 with_cp=False,
                 conv_cfg=None,
                 norm_cfg=dict(type='BN'),
                 dcn=None,
                 plugins=None,
                 init_cfg=None):
        """Bottleneck block for ResNet.

        If style is "pytorch", the stride-two layer is the 3x3 conv layer, if
        it is "caffe", the stride-two layer is the first 1x1 conv layer.
        """
        super(Bottleneck, self).__init__()
        assert style in ['pytorch', 'caffe']
        assert dcn is None or isinstance(dcn, dict)
        assert plugins is None or isinstance(plugins, list)
        if plugins is not None:
            allowed_position = ['after_conv1', 'after_conv2', 'after_conv3']
            assert all(p['position'] in allowed_position for p in plugins)

        self.inplanes = inplanes
        self.planes = planes
        self.stride = stride
        self.dilation = dilation
        self.style = style
        self.with_cp = with_cp
        self.conv_cfg = conv_cfg
        self.norm_cfg = norm_cfg
        self.dcn = dcn
        self.with_dcn = dcn is not None
        self.plugins = plugins
        self.with_plugins = plugins is not None

        if self.with_plugins:
            # collect plugins for conv1/conv2/conv3
            pass

        if self.style == 'pytorch':
            self.conv1_stride = 1
            self.conv2_stride = stride
        else:
            self.conv1_stride = stride
            self.conv2_stride = 1
        if norm_cfg['type'] == 'BN':
            self.norm1 = nn.BatchNorm2d(num_features=planes)
            self.norm2 = nn.BatchNorm2d(num_features=planes)
            self.norm3 = nn.BatchNorm2d(num_features=planes * self.expansion)

        self.conv1 = nn.Conv2d(
            in_channels=inplanes,
            out_channels=planes,
            kernel_size=1,
            stride=self.conv1_stride,
            has_bias=False)
        fallback_on_stride = False
        if self.with_dcn:
            pass
        if not self.with_dcn or fallback_on_stride:
            self.conv2 = nn.Conv2d(
                in_channels=planes,
                out_channels=planes,
                kernel_size=3,
                stride=self.conv2_stride,
                padding=dilation,
                dilation=dilation,
                has_bias=False,
                pad_mode='pad')
        else:
            pass

        self.conv3 = nn.Conv2d(
            in_channels=planes,
            out_channels=planes * self.expansion,
            kernel_size=1,
            has_bias=False)

        self.relu = nn.ReLU()
        self.downsample = downsample

    def construct(self, x):
        """Forward function."""
        identity = x
        out = self.conv1(x)
        out = self.norm1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.norm2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.norm3(out)

        if self.downsample is not None:
            identity = self.downsample(x)

        out += identity

        out = self.relu(out)

        return out


class ResNet(nn.Cell):
    """ResNet backbone.

    Args:
        depth (int): Depth of resnet, from {18, 34, 50, 101, 152}.
        stem_channels (int | None): Number of stem channels. If not specified,
            it will be the same as `base_channels`. Default: None.
        base_channels (int): Number of base channels of res layer. Default: 64.
        in_channels (int): Number of input image channels. Default: 3.
        num_stages (int): Resnet stages. Default: 4.
        strides (Sequence[int]): Strides of the first block of each stage.
        dilations (Sequence[int]): Dilation of each stage.
        out_indices (Sequence[int]): Output from which stages.
        style (str): `pytorch` or `caffe`. If set to "pytorch", the stride-two
            layer is the 3x3 conv layer, otherwise the stride-two layer is
            the first 1x1 conv layer.
        deep_stem (bool): Replace 7x7 conv in input stem with 3 3x3 conv
        avg_down (bool): Use AvgPool instead of stride conv when
            downsampling in the bottleneck.
        frozen_stages (int): Stages to be frozen (stop grad and set eval mode).
            -1 means not freezing any parameters.
        norm_cfg (dict): Dictionary to construct and config norm layer.
        norm_eval (bool): Whether to set norm layers to eval mode, namely,
            freeze running stats (mean and var). Note: Effect on Batch Norm
            and its variants only.
        plugins (list[dict]): List of plugins for stages, each dict contains:

            - cfg (dict, required): Cfg dict to build plugin.
            - position (str, required): Position inside block to insert
              plugin, options are 'after_conv1', 'after_conv2', 'after_conv3'.
            - stages (tuple[bool], optional): Stages to apply plugin, length
              should be same as 'num_stages'.
        with_cp (bool): Use checkpoint or not. Using checkpoint will save some
            memory while slowing down the training speed.
        zero_init_residual (bool): Whether to use zero init for last norm layer
            in resblocks to let them behave as identity.
        pretrained (str, optional): model pretrained path. Default: None
        init_cfg (dict or list[dict], optional): Initialization config dict.
            Default: None
    """

    arch_settings = {
        50: (Bottleneck, (3, 4, 6, 3)),
        101: (Bottleneck, (3, 4, 23, 3)),
        152: (Bottleneck, (3, 8, 36, 3))
    }

    def __init__(self,
                 depth,
                 in_channels=3,
                 stem_channels=None,
                 base_channels=64,
                 num_stages=4,
                 strides=(1, 2, 2, 2),
                 dilations=(1, 1, 1, 1),
                 out_indices=(0, 1, 2, 3),
                 style='pytorch',
                 deep_stem=False,
                 avg_down=False,
                 frozen_stages=-1,
                 conv_cfg=None,
                 norm_cfg=dict(type='BN'),
                 norm_eval=True,
                 dcn=None,
                 stage_with_dcn=(False, False, False, False),
                 plugins=None,
                 with_cp=False,
                 zero_init_residual=True,
                 pretrained=None,
                 init_cfg=None):
        super(ResNet, self).__init__()
        self.zero_init_residual = zero_init_residual
        if depth not in self.arch_settings:
            raise KeyError(f'invalid depth {depth} for resnet')

        block_init_cfg = None
        assert not (init_cfg and pretrained), \
            'init_cfg and pretrained cannot be setting at the same time'
        if isinstance(pretrained, str):
            warnings.warn('DeprecationWarning: pretrained is deprecated, '
                          'please use "init_cfg" instead')
            self.init_cfg = dict(type='Pretrained', checkpoint=pretrained)
        elif pretrained is None:
            if init_cfg is None:
                self.init_cfg = [
                    dict(type='Kaiming', layer='Conv2d'),
                    dict(
                        type='Constant',
                        val=1,
                        layer=['_BatchNorm', 'GroupNorm'])
                ]
                block = self.arch_settings[depth][0]
                if self.zero_init_residual:
                    if block is Bottleneck:
                        block_init_cfg = dict(
                            type='Constant',
                            val=0,
                            override=dict(name='norm3'))
        else:
            raise TypeError('pretrained must be a str or None')

        self.depth = depth
        if stem_channels is None:
            stem_channels = base_channels
        self.stem_channels = stem_channels
        self.base_channels = base_channels
        self.num_stages = num_stages
        assert num_stages >= 1 and num_stages <= 4
        self.strides = strides
        self.dilations = dilations
        assert len(strides) == len(dilations) == num_stages
        self.out_indices = out_indices
        assert max(out_indices) < num_stages
        self.style = style
        self.deep_stem = deep_stem
        self.avg_down = avg_down
        self.frozen_stages = frozen_stages
        self.conv_cfg = conv_cfg
        self.norm_cfg = norm_cfg
        self.with_cp = with_cp
        self.norm_eval = norm_eval
        self.dcn = dcn
        self.stage_with_dcn = stage_with_dcn
        if dcn is not None:
            assert len(stage_with_dcn) == num_stages
        self.plugins = plugins
        self.block, stage_blocks = self.arch_settings[depth]
        self.stage_blocks = stage_blocks[:num_stages]
        self.inplanes = stem_channels

        self._make_stem_layer(in_channels, stem_channels)

        self.res_layers = []
        for i, num_blocks in enumerate(self.stage_blocks):
            stride = strides[i]
            dilation = dilations[i]
            dcn = self.dcn if self.stage_with_dcn[i] else None
            if plugins is None:
                stage_plugins = None
            planes = base_channels * 2 ** i
            res_layer = self.make_res_layer(
                block=self.block,
                inplanes=self.inplanes,
                planes=planes,
                num_blocks=num_blocks,
                stride=stride,
                dilation=dilation,
                style=self.style,
                avg_down=self.avg_down,
                with_cp=with_cp,
                conv_cfg=conv_cfg,
                norm_cfg=norm_cfg,
                dcn=dcn,
                plugins=stage_plugins,
                init_cfg=block_init_cfg)
            self.inplanes = planes * self.block.expansion
            layer_name = f'layer{i + 1}'
            setattr(self, layer_name, res_layer)
            self.res_layers.append(layer_name)

        self._freeze_stages()  #TODO

        self.feat_dim = self.block.expansion * base_channels * 2 ** (
                len(self.stage_blocks) - 1)

    def make_res_layer(self, **kwargs):
        """Pack all blocks in a stage into a ``ResLayer``."""
        return ResLayer(**kwargs)

    def _make_stem_layer(self, in_channels, stem_channels):
        if self.deep_stem:
            self.stem = nn.SequentialCell(
                nn.Conv2d(
                    in_channels=in_channels,
                    out_channels=stem_channels // 2,
                    kernel_size=3,
                    stride=2,
                    padding=1,
                    has_bias=False,
                    pad_mode='pad'),
                nn.BatchNorm2d(num_features=stem_channels // 2),
                nn.ReLU(),
                nn.Conv2d(
                    in_channels=stem_channels // 2,
                    out_channels=stem_channels // 2,
                    kernel_size=3,
                    stride=1,
                    padding=1,
                    has_bias=False,
                    pad_mode='pad'),
                nn.BatchNorm2d(num_features=stem_channels // 2),
                nn.ReLU(),
                nn.Conv2d(
                    in_channels=stem_channels // 2,
                    out_channels=stem_channels,
                    kernel_size=3,
                    stride=1,
                    padding=1,
                    has_bias=False,
                    pad_mode='pad'),
                nn.BatchNorm2d(num_features=stem_channels),
                nn.ReLU())
        else:
            self.conv1 = nn.Conv2d(
                in_channels=in_channels,
                out_channels=stem_channels,
                kernel_size=7,
                stride=2,
                padding=3,
                has_bias=False,
                pad_mode='pad')
            self.norm1 = nn.BatchNorm2d(stem_channels)
            self.relu = nn.ReLU()
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, pad_mode='pad')

    def _freeze_stages(self):
        if self.frozen_stages >= 0:
            if self.deep_stem:
                self.stem.set_train(False)
                for param in self.stem.trainable_params():
                    param.requires_grad = False
            else:
                self.norm1.set_train(False)
                for m in [self.conv1, self.norm1]:
                    for param in m.trainable_params():
                        param.requires_grad = False

        for i in range(1, self.frozen_stages + 1):
            m = getattr(self, f'layer{i}')
            m.set_train(False)
            for param in m.trainable_params():
                param.requires_grad = False

    def construct(self, x, mode=True):
        """Forward function."""
        self.train(mode)
        if self.deep_stem:
            x = self.stem(x)
        else:
            x = self.conv1(x)
            x = self.norm1(x)
            x = self.relu(x)
        x = self.maxpool(x)
        outs = []
        for i, layer_name in enumerate(self.res_layers):
            res_layer = getattr(self, layer_name)
            x = res_layer(x)
            if i in self.out_indices:
                outs.append(x)
        return tuple(outs)

    def train(self, mode=True):
        """Convert the model into training mode while keep normalization layer
        freezed."""
        super(ResNet, self).set_train(mode)
        self._freeze_stages()
        if mode and self.norm_eval:
            for name, module in self.name_cells().items():
                # trick: eval have effect on BatchNorm only
                if isinstance(module, nn.BatchNorm2d):
                    module.set_train(False)




param_list = []
net = ResNet(depth=50,
        num_stages=4,
        out_indices=(3,),
        frozen_stages=0,
        norm_cfg=dict(type='BN', requires_grad=False),
        norm_eval=True,
        style='pytorch')

for x in net.get_parameters():
    param_list.append(x.name)
print(param_list)
print(len(param_list))


for i in range(len(param_list)):
    with open("./mindsporeKey.txt", 'a') as file:
        file.write(param_list[i])
        file.write("\n")

直接运行一下,重点是net.get_parameters()这个方法可以直接拿到参数

然后写入mindposreKey.txt

3 用beyond compare对比这两个文件,然后根据规律写一个脚本

import json

# 读取第一个文本文件并将内容存储为列表
with open('pytorchKeyBEV.txt', 'r') as file2:
    file1_lines = file2.read().splitlines()


# 读取第二个文本文件并将内容存储为列表
with open('mindsporeKey.txt', 'r') as file1:
    file2_lines = file1.read().splitlines()


# 初始化一个字典来存储映射关系
mapping = {}

for i in range(len(file1_lines)):
    temp = file1_lines[i]
    if  ".downsample.0" in file1_lines[i] or ("conv" in file1_lines[i]):
        mapping[file1_lines[i]] = temp
        continue
    if "bn" in file1_lines[i]:
        temp = temp.replace("bn", "norm")
    if "weight" in file1_lines[i]:
        temp = temp.replace("weight", "gamma")
    if "bias" in file1_lines[i]:
        temp = temp.replace("bias", "beta")
    if "running_mean" in file1_lines[i]:
        temp = temp.replace("running_mean", "moving_mean")
    if "running_var" in file1_lines[i]:
        temp = temp.replace("running_var", "moving_variance")
    mapping[file1_lines[i]] = temp
    if temp not in file2_lines:
        print(temp)
        print("wrong")

with open('mapping.json', 'w') as json_file:
    json.dump(mapping, json_file, indent=4)


print("Mapping saved to 'mapping.json'")

4 根据得到到mapping.json文件生成mindspore需要的ckpt文件;

核心:先载入一个pytorch的模型,用mindspore的key和pytorch的value

# convert pytorch model to mindspore
import json
import os

from torchvision.models import resnet50


import mindspore as ms



# load param_map json
with open("mapping.json", "r") as json_file:
    param_name_map = json.load(json_file)

net = resnet50(pretrained=True)

params_dict = net.state_dict()
# conversion
ms_params = []
for name, value in params_dict.items():
    each_param = dict()
    if name not in param_name_map:
        continue
    each_param["name"] = param_name_map[name]
    each_param["data"] = ms.Tensor(value.numpy())
    ms_params.append(each_param)

ms.save_checkpoint(ms_params, "resnet50_ms.ckpt")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值