惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
J
Java Code Geeks
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
美团技术团队
L
LangChain Blog
WordPress大学
WordPress大学
A
About on SuperTechFans
Martin Fowler
Martin Fowler
月光博客
月光博客
Y
Y Combinator Blog
U
Unit 42
D
Docker
Recent Announcements
Recent Announcements
Hugging Face - Blog
Hugging Face - Blog
B
Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
G
Google Developers Blog
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

博客园 - Dsp Tian

MMDiT 骨干网络详解 DiT (Diffusion Transformer) 骨干网络详解 Flow Matching 原理与 MNIST 条件生成实践 Claude Code 自动推送测试 ssh端口转发 【Python】使用uv虚拟环境 解决ModuleNotFoundError: No module named 'pkg_resources' 配置Nginx反向代理 【Python】大模型工具调用 Claude Code配置Qwen3-Coder OpenCode + Oh My OpenCode配置Qwen3-Coder 【Python】vllm部署调用Qwen3-VL make指定安装目录 解决colcon编译卡死 【Python】调用C++ 深度学习(Grad-CAM) 深度学习(CVAE) 深度学习(DBBNet重参数化) 深度学习(视觉注意力SeNet/CbmaNet/SkNet/EcaNet) 深度学习(RepVGG重参数化) 深度学习(修改onnx文件batchsize) 【Python】生成git仓库贡献热力图 深度学习(onnx量化) 深度学习(pytorch量化) cmake构建后执行命令
深度学习(ACNet重参数化)
Dsp Tian · 2025-08-30 · via 博客园 - Dsp Tian
import torch
import torch.nn as nn

class AcNetBlock(nn.Module):
    def __init__(self, channels, deploy):
        super(AcNetBlock, self).__init__()

        self.deploy = deploy
        self.channels = channels

        self.conv3x3 = nn.Conv2d(channels, channels, kernel_size=3, stride=1, padding=1, bias=True)
        self.bn3x3 = nn.BatchNorm2d(channels)

        self.conv3x1 = nn.Conv2d(channels, channels, kernel_size=(3,1), stride=1, padding=(1,0), bias=True)
        self.bn3x1 = nn.BatchNorm2d(channels)

        self.conv1x3 = nn.Conv2d(channels, channels, kernel_size=(1,3), stride=1, padding=(0,1), bias=True)
        self.bn1x3 = nn.BatchNorm2d(channels)

        if deploy == False:
            self.conv3x3.weight.data = torch.randn(channels, channels, 3, 3)
            self.conv3x3.bias.data = torch.randn(channels)
            self.bn3x3.weight.data = torch.randn(channels)
            self.bn3x3.bias.data = torch.randn(channels)

            self.conv3x1.weight.data = torch.randn(channels, channels, 3, 1)
            self.conv3x1.bias.data = torch.randn(channels)
            self.bn3x1.weight.data = torch.randn(channels)
            self.bn3x1.bias.data = torch.randn(channels)

            self.conv1x3.weight.data = torch.randn(channels, channels, 1, 3)
            self.conv1x3.bias.data = torch.randn(channels)
            self.bn1x3.weight.data = torch.randn(channels)
            self.bn1x3.bias.data = torch.randn(channels)

        # Fusion conv
        self.fusion_conv = nn.Conv2d(channels, channels, kernel_size=3, stride=1, padding=1, bias=True)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        if self.deploy == False:
            x1 = self.conv3x3(x)
            x1 = self.bn3x3(x1)

            x2 = self.conv3x1(x)
            x2 = self.bn3x1(x2)

            x3 = self.conv1x3(x)
            x3 = self.bn1x3(x3)

            x = x1 + x2 + x3
        else:
            x = self.fusion_conv(x)

        return self.relu(x)
    
    def reparam3x3(self):
        conv_w = self.conv3x3.weight
        conv_b = self.conv3x3.bias

        bn_w = self.bn3x3.weight
        bn_b = self.bn3x3.bias 

        bn_w = bn_w.div(torch.sqrt(self.bn3x3.eps + self.bn3x3.running_var))

        fusion_w = torch.mm(torch.diag(bn_w), conv_w.view(self.channels, -1)).view(self.channels,self.channels,3,3)
        fusion_b = bn_w * (conv_b - self.bn3x3.running_mean) + bn_b

        print(fusion_w.shape,fusion_b.shape)
        return fusion_w, fusion_b

    def reparam3x1(self):
        conv_w = self.conv3x1.weight
        conv_b = self.conv3x1.bias

        bn_w = self.bn3x1.weight
        bn_b = self.bn3x1.bias 

        bn_w = bn_w.div(torch.sqrt(self.bn3x1.eps + self.bn3x1.running_var))

        fusion_w = torch.mm(torch.diag(bn_w), conv_w.view(self.channels, -1)).view(self.channels,self.channels,3,1)
        w = torch.zeros(self.channels, self.channels, 3, 3)
        w[:,:,:,1] = fusion_w.squeeze(3)

        fusion_b = bn_w * (conv_b - self.bn3x1.running_mean) + bn_b

        print(w.shape,fusion_b.shape)
        return w, fusion_b

    def reparam1x3(self):
        conv_w = self.conv1x3.weight
        conv_b = self.conv1x3.bias

        bn_w = self.bn1x3.weight
        bn_b = self.bn1x3.bias 

        bn_w = bn_w.div(torch.sqrt(self.bn1x3.eps + self.bn1x3.running_var))

        fusion_w = torch.mm(torch.diag(bn_w), conv_w.view(self.channels, -1)).view(self.channels,self.channels,1,3)
        w = torch.zeros(self.channels, self.channels, 3, 3)
        w[:,:,1,:] = fusion_w.squeeze(2)

        fusion_b = bn_w * (conv_b - self.bn1x3.running_mean) + bn_b

        print(w.shape,fusion_b.shape)
        return w, fusion_b

    def reparam(self):
        w_3x3, b_3x3 = self.reparam3x3()
        w_3x1, b_3x1 = self.reparam3x1()
        w_1x3, b_1x3 = self.reparam1x3()

        self.fusion_conv.weight.data = (w_3x3 + w_3x1 + w_1x3).clone()
        self.fusion_conv.bias.data = (b_3x3 +b_3x1 + b_1x3).clone()   
    

x = torch.randn(1, 20, 224, 224)  

net1 = AcNetBlock(20, False)
torch.save(net1.state_dict(), "acnet.pth")
net1.eval()   
y1 = net1(x)

net2 = AcNetBlock(20, True)
net2.load_state_dict(torch.load("acnet.pth"))
net2.reparam()  
net2.eval()   
y2 = net2(x)

print(y1.shape,y2.shape)
print(torch.allclose(y1, y2, atol=1e-4))

torch.onnx.export(net1, x, "acnet.onnx", input_names=['input'], output_names=['output'])
torch.onnx.export(net2, x, "acnet_deploy.onnx", input_names=['input'], output_names=['output'])