AdaptiveAvgPool2D 不支持 onnx 导出,自定义一个类代替 AdaptiveAvgPool2D

AdaptiveAvgPool2D 不支持 onnx 导出,导出过程会告诉你,onnx不支持那个动态操作巴拉巴拉

我用的是 pp_liteseg 导出为 onnx 模型,都一样,paddle和Torch的 Adaptive Pool2D 都是动态的,onnx暂时都不支持,我根据下述公式,将 AdaptiveAvgPool2D 改了,可以用onnx导出了,但是需要指定一下原图的大小,和输出图的大小

h s t a r t = f l o o r ( i ∗ H i n / H o u t ) h e n d = c e i l ( ( i + 1 ) ∗ H i n / H o u t ) w s t a r t = f l o o r ( j ∗ W i n / W o u t ) w e n d = c e i l ( ( j + 1 ) ∗ W i n / W o u t ) O u t p u t ( i , j ) = ∑ I n p u t [ h s t a r t : h e n d , w s t a r t : w e n d ] ( h e n d − h s t a r t ) ∗ ( w e n d − w s t a r t ) \begin{aligned} hstart &= floor(i * H_{in} / H_{out})\\ hend &= ceil((i + 1) * H_{in} / H_{out})\\ wstart &= floor(j * W_{in} / W_{out}) \\ wend &= ceil((j + 1) * W_{in} / W_{out}) \\ Output(i ,j) &= \frac{\sum Input[hstart:hend, wstart:wend]}{(hend - hstart) * (wend - wstart)} \end{aligned} hstarthendwstartwendOutput(i,j)=floor(iHin/Hout)=ceil((i+1)Hin/Hout)=floor(jWin/Wout)=ceil((j+1)Win/Wout)=(hendhstart)(wendwstart)Input[hstart:hend,wstart:wend]
参考自:
AdaptiveAvgPool2D

class CostomAdaptiveAvgPool2D(nn.Layer):
    
    def __init__(self, output_size, input_size):
        
        super(CostomAdaptiveAvgPool2D, self).__init__()
        
        self.output_size = output_size
        self.input_size  = input_size
        
    def forward(self, x):
        
        H_in,  W_in  = self.input_size
        H_out, W_out = [self.output_size, self.output_size] \
                       if isinstance(self.output_size, int) \
                       else self.output_size
        
        out_i = []
        for i in range(H_out):
            out_j = []
            for j in range(W_out):
                
                hs = int(np.floor(i * H_in / H_out))
                he = int(np.ceil((i+1) * H_in / H_out))
                
                ws = int(np.floor(j * W_in / W_out))
                we = int(np.ceil((j+1) * W_in / W_out))
                
                # print(hs, he, ws, we)
                kernel_size = [he-hs, we-ws]
                
                out = F.avg_pool2d(x[:, :, hs:he, ws:we], kernel_size) 
                out_j.append(out)
                
            out_j = paddle.concat(out_j, -1)
            out_i.append(out_j)
            
        out_i = paddle.concat(out_i, -2)
        return out_i

用 CostomAdaptiveAvgPool2D 调换 AdaptiveAvgPool2D, 并且指定原图和输出图的大小即可

在这里插入图片描述

[14,14] 就是输入图的大小,我这个pp_liteseg 输入shape是 224 × 224 224\times 224 224×224,所以上一层的shape是

[-1, 512, 14, 14]

然后一次过三个AdaptiveAvgPool2D 变成

[-1, 512,  1,   1]
[-1, 512,  2,   2]
[-1, 512,  4,   4]

然后 paddle2onnx 导出即可

paddle2onnx --model_dir . \
            --model_filename model.pdmodel \
            --params_filename model.pdiparams \
            --opset_version 11 \
            --save_file output.onnx

最后测试一下:

import paddle
import numpy as np
import paddle.nn as nn
import paddle.nn.functional as F

class CostomAdaptiveAvgPool2D(nn.Layer):
    
    def __init__(self, output_size, input_size):
        
        super(CostomAdaptiveAvgPool2D, self).__init__()
        
        self.output_size = output_size
        self.input_size  = input_size
        
    def forward(self, x):
        
        H_in,  W_in  = self.input_size
        H_out, W_out = [self.output_size, self.output_size] \
                       if isinstance(self.output_size, int) \
                       else self.output_size
        
        out_i = []
        for i in range(H_out):
            out_j = []
            for j in range(W_out):
                
                hs = int(np.floor(i * H_in / H_out))
                he = int(np.ceil((i+1) * H_in / H_out))
                
                ws = int(np.floor(j * W_in / W_out))
                we = int(np.ceil((j+1) * W_in / W_out))
                
                # print(hs, he, ws, we)
                kernel_size = [he-hs, we-ws]
                
                out = F.avg_pool2d(x[:, :, hs:he, ws:we], kernel_size) 
                out_j.append(out)
                
            out_j = paddle.concat(out_j, -1)
            out_i.append(out_j)
            
        out_i = paddle.concat(out_i, -2)
        return out_i

# 输入
input_data = np.random.rand(1, 3, 128, 128)
x = paddle.to_tensor(input_data)


adaptive_avg_pool = paddle.nn.AdaptiveAvgPool2D(output_size=1)
pool_out = adaptive_avg_pool(x = x)
costom_avg_pool = CostomAdaptiveAvgPool2D(output_size=(1, 1), input_size=(128, 128))
costom_pool_out = costom_avg_pool(x = x)
>>> costom_pool_out
Tensor(shape=[1, 3, 1, 1], dtype=float64, place=Place(gpu:0), stop_gradient=True,
       [[[[0.49809119]],

         [[0.49674173]],

         [[0.50111742]]]])

>>> pool_out
Tensor(shape=[1, 3, 1, 1], dtype=float64, place=Place(gpu:0), stop_gradient=True,
       [[[[0.49809119]],

         [[0.49674173]],

         [[0.50111742]]]])
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值