当前位置: 首页 > news >正文

模型部署——融合BN和Conv层

今天我们将尝试了解如何使我们的模型在推理上更快一点。

使用 Batch Normalization 作为提高泛化能力的一种方式浪费了大量的网络。 但是在推理过程中,批量归一化被关闭,而是使用近似的每个通道均值和方差。 很酷的是,我们可以通过 1x1 卷积实现相同的行为。 更好的是将Batch Normalization 与前面的卷积合并。

Batch Normalization

假设 x x x 是要归一化的激活信号。 给定一组来自一个batch中不同样本的此类信号 x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1,x2,...,xn,归一化如下:

x ^ i = γ x i − μ σ 2 + ϵ + β = γ x i σ 2 + ϵ + β − γ μ σ 2 + ϵ \hat x_i = \gamma \frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon} }+\beta= \frac{\gamma x_i}{\sqrt{\sigma^2+\epsilon}} +\beta- \frac{\gamma \mu}{\sqrt{\sigma^2+\epsilon}} x^i=γσ2+ϵ xiμ+β=σ2+ϵ γxi+βσ2+ϵ γμ

这里 μ \mu μ σ 2 \sigma^2 σ2 为这个batch上计算得到的均值和方差(在B,H,W维度上计算,每个channel单独计算),而 ϵ \epsilon ϵ 是防止除零所设置的一个极小值, γ \gamma γ 是比例参数,而 β \beta β 是平移系数。在训练过程中, μ \mu μ σ \sigma σ 在当前batch上计算:

μ = 1 n ∑ x i σ 2 = 1 n ∑ ( x i − μ ) 2 \mu = \frac{1}{n} \sum x_i \\ \sigma^2=\frac{1}{n}\sum(x_i-\mu)^2 μ=n1xiσ2=n1(xiμ)2

参数 γ \gamma γ β \beta β 与网络的其他参数一起通过梯度下降缓慢学习。 在测试期间,通常不会在一个batch图像上运行网络。 因此,不能使用前面提到的 μ \mu μ σ \sigma σ 公式。 相反,我们使用他们在训练期间通过exponential moving average计算的估计值 μ ^ \hat \mu μ^ σ ^ 2 \hat \sigma^2 σ^2

如今,批量归一化主要用于卷积神经网络中。 在此设置中,输入特征图的每个通道 c c c 都有均值 μ c \mu_c μc 和方差估计 σ c 2 \sigma_c^2 σc2 、平移 β c \beta_c βc 和比例参数 γ c \gamma_c γc

融合方案

对于一个形状为 C × H × W C \times H \times W C×H×W的特征图 F F F,记归一化结果 F ^ \hat F F^,计算如下:

在这里插入图片描述

上式为 f ( x ) = W x + b f(x)=Wx+b f(x)=Wx+b的形式,可以看成 1 × 1 1 \times 1 1×1卷积,由于BN层常常在Conv层之后,可以将两操作合并。

融合BN卷积

  • w B N ∈ R C × C \mathbf w_{BN} \in \mathbb R^{C \times C} wBNRC×C b B N ∈ R C \mathbf b_{BN} \in \mathbb R^{C } bBNRCBN的参数
  • w c o n v ∈ R C × C p r e . k 2 \mathbf w_{conv} \in \mathbb R^{C \times C_{pre}.k^2} wconvRC×Cpre.k2 b c o n v ∈ R C \mathbf b_{conv} \in \mathbb R^C bconvRCConv层的参数
  • F p r e v F_{prev} Fprev是卷积的输入
  • C p r e v C_{prev} Cprev:输入层的通道数量
  • k k k:卷积核大小

F p r e v F_{prev} Fprev的每个 k × k k \times k k×k部分reshape为一个维度为 k 2 . C p r e v k^2.C_{prev} k2.Cprev 的向量 f i , j f_{i,j} fi,j,因此Conv层加BN层的操作为:

f ^ i , j = W B N . ( W c o n v . f i , j + b c o n v ) + b B N \hat {\mathbf f}_{i,j}=\mathbf W_{BN} . (\mathbf W_{conv}.\mathbf f_{i,j}+\mathbf b_{conv})+\mathbf b_{BN} f^i,j=WBN.(Wconv.fi,j+bconv)+bBN

因此,我们可以用具有以下参数的单个卷积层替换这两层:

  • 滤波器权重 W W W W = W B N . W c o n v \mathbf W=\mathbf W_{BN}. \mathbf W_{conv} W=WBN.Wconv
  • 偏置bias: b = W B N . b c o n v + b B N \mathbf b=\mathbf W_{BN}. \mathbf b_{conv}+ \mathbf b_{BN} b=WBN.bconv+bBN

pytorch实现:

nn.Conv2d参数:

  • 滤波器权重, W \mathbf W Wconv.weight
  • bias, b \mathbf b bconv.bias

nn.BatchNorm2d参数:

  • scaling, γ \gamma γbn.weight
    shift, β \beta βbn.bias
  • mean estimate, μ ^ \hat \mu μ^bn.running_mean
  • variance estimate, σ 2 \sigma^2 σ2bn.running_var
  • ϵ \epsilon ϵ(for numerical stability)::bn.eps

代码实现:


    import torch
    import torchvision
    
    def fuse(conv, bn):
    
        fused = torch.nn.Conv2d(
            conv.in_channels,
            conv.out_channels,
            kernel_size=conv.kernel_size,
            stride=conv.stride,
            padding=conv.padding,
            bias=True
        )
    
        # setting weights
        w_conv = conv.weight.clone().view(conv.out_channels, -1)
        w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps+bn.running_var)))
        fused.weight.copy_( torch.mm(w_bn, w_conv).view(fused.weight.size()) )
        
        # setting bias
        if conv.bias is not None:
            b_conv = conv.bias
        else:
            b_conv = torch.zeros( conv.weight.size(0) )
        b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(
                              torch.sqrt(bn.running_var + bn.eps)
                            )
        fused.bias.copy_( b_conv + b_bn )
    
        return fused
    
    # Testing
    # we need to turn off gradient calculation because we didn't write it
    torch.set_grad_enabled(False)
    x = torch.randn(16, 3, 256, 256)
    resnet18 = torchvision.models.resnet18(pretrained=True)
    # removing all learning variables, etc
    resnet18.eval()
    model = torch.nn.Sequential(
        resnet18.conv1,
        resnet18.bn1
    )
    f1 = model.forward(x)
    fused = fuse(model[0], model[1])
    f2 = fused.forward(x)
    d = (f1 - f2).mean().item()
    print("error:",d)

参考:https://learnml.today/speeding-up-model-with-fusing-batch-normalization-and-convolution-3

相关文章:

  • 美化你的Xfce桌面
  • 【.Net实用方法总结】 整理并总结System.IO中BufferedStream类及其方法介绍
  • Android移动应用开发之TextView实现阴影跑马灯文字效果
  • MySQL是怎样运行的:从根儿上理解MySQL | 查询优化器(二):基于规则的优化
  • 数据分享|WEKA用决策树、随机森林、支持向量机SVM、朴素贝叶斯、逻辑回归信贷违约预测报告
  • JavaSE学习----(八)常用类之Stirng类
  • 跨境电商自养号测评补单+广告结合打法,打造爆款产品
  • 01_中间件
  • 记录QUME上模拟ARM运行环境(内核 2.6.30)
  • JavaWeb开发之——MySQL数据模型(04)
  • c语言分层理解(c语言字符串+内存库函数)
  • Es6的promise和async
  • Java项目本地部署宝塔搭建实战java中小医院管理系统源码
  • java 低耦合观察者模式
  • 七、OCR-PaddlePaddle训练源码解析系列-文字识别
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 10个确保微服务与容器安全的最佳实践
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • 30秒的PHP代码片段(1)数组 - Array
  • canvas 五子棋游戏
  • CSS 提示工具(Tooltip)
  • JS题目及答案整理
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • SpiderData 2019年2月25日 DApp数据排行榜
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • 初探 Vue 生命周期和钩子函数
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 使用 Docker 部署 Spring Boot项目
  • 通过npm或yarn自动生成vue组件
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • elasticsearch-head插件安装
  • puppet连载22:define用法
  • 通过调用文摘列表API获取文摘
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • %check_box% in rails :coditions={:has_many , :through}
  • (1)SpringCloud 整合Python
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (3)(3.5) 遥测无线电区域条例
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转) Android中ViewStub组件使用
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)shell调试方法
  • .NET Framework与.NET Framework SDK有什么不同?
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .net的socket示例
  • .NET项目中存在多个web.config文件时的加载顺序
  • .NET与java的MVC模式(2):struts2核心工作流程与原理