VSCODE调试控制台的使用——以pytorch下神经网络的加载模型前向传播为例

前言

最近在做模型的量化与量化后模型在arm平台上的迁移工作,为了保证量化后的模型在python下与在arm下运行的一致性(相同输入下,不同环境下的输出完全一致),需要对python下模型前向传播的每个操作的激活值、权重、输入的量化参数(scale与zero_point)、权重的量化参数(scale与zero_point)都能查看,在这个查看的过程中,发现VSCODE帮了大忙,因此记录一下VSCODE调试控制台的使用,便于自己与他人后续参考使用。

查看加载模型的参数

我在保存模型时,仅保存了模型的参数信息,而非整个模型的结构信息:

torch.save(model_object.state_dict(), 'params.pth')  

加载模型的参数信息,则需:

state_dict = model_object.load_state_dict(torch.load('params.pth')) 

state_dict为OrderedDict类型,加载后,在左侧的变量栏可以看到state_dict包含的一些key, value
在这里插入图片描述

对于模型比较大的,在左侧栏可能看不全state_dict包含的所有key,value,可以通过遍历查看state_dict中的key值

for k,v in stat_dict.items():
        # if `v` is `torch.Tensor`, then save it into dict: 
        print(k)

查看或修改state_dict中的值

这里以查看并修改模型中某一层的激活scale值、权重scale值为例
查看并修改激活scale的值
在调试控制台,可以通过state_dict的key值对其进行查看,并修改其中的值
在这里插入图片描述
查看修改权重scale的值
在这里插入图片描述
通过stat_dict['stage3.1.branch2.0.weight']可以查看到stage3.1.branch2.0的权重是一个Tensor,这里是量化后的模型,可以看到tensor中还有scale, zero_point等属性,但是直接使用stat_dict['stage3.1.branch2.0.weight'].scale是无法查看到scale的值的,也就无法通过这种方式对其进行修改。查看与修改应使用stat_dict['stage3.1.branch2.0.weight'].q_per_channel_scales(),如下图:
在这里插入图片描述

对模型的前向传播进行跟踪

现在的网络大都不是简单的只有conv,fc这样的平直的结构,二是有一些其他的基本单元,如,Resnet的残差块,MobileNet中的瓶颈层等等。这种基本单元的构成会使得调试的时候,深入查看某个基本单元的某一层的值有点麻烦。以shufflenetv2的基本单元InvertedResidual为例。branch1为空,或depthwise conv + pointwise conv,branch2为pointwise conv + depthwise conv + pointwise conv。

class InvertedResidual(nn.Module):
    def __init__(self, inp, oup, stride):
        super(InvertedResidual, self).__init__()

        if not (1 <= stride <= 3):
            raise ValueError('illegal stride value')
        self.stride = stride

        branch_features = oup // 2
        assert (self.stride != 1) or (inp == branch_features << 1)

        if self.stride > 1:
            self.branch1 = nn.Sequential(
                self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1),
                nn.BatchNorm2d(inp),
                nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(branch_features),
                nn.ReLU(inplace=True),
            )
        else:
            self.branch1 = nn.Sequential()

        self.branch2 = nn.Sequential(
            nn.Conv2d(inp if (self.stride > 1) else branch_features,
                      branch_features, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True),
            self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),
            nn.BatchNorm2d(branch_features),
            nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True),
        )

    @staticmethod
    def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):
        return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)

    def forward(self, x):
        if self.stride == 1:
            x1, x2 = x.chunk(2, dim=1)
            out = torch.cat((x1, self.branch2(x2)), dim=1)
        else:
            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)  # 可在此处加断点

        out = channel_shuffle(out, 2)

        return out

查看基本单元中某一层权重的值

调试时,在前向传播里添加断点,在InvertedResidual中branch1,branch2是作为一个整体前向传播的,如果想要具体查看内部某一层的执行情况,可以在调试控制台中实现。
在这里插入图片描述
上图是branch1和branch2的结构,这里量化的时候CONV与BN进行了融合,因此CONV变成了QuantizedConv2d,BN变为了Identity()。如果想要查看branch1.0.weight则可以在调试控制台中使用self.branch1[0].state_dict()['weight']进行查看
在这里插入图片描述
使用self.branch1[0].state_dict()['weight'].int_repr()可以查看该层量化后的权重值
在这里插入图片描述

查看基本单元中某一层前向传播的值

以branch2.4的输出为例,可以通过以下代码得到brach2.4的输出
在这里插入图片描述
进一步,可以通过以下代码查看该层量化后的值
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值