Pytorch AdaptivePooing操作转Pooling操作

多数的前向推理框架不支持AdaptivePooing操作,此时需要将AdaptivePooing操作转换为普通的Pooling操作。AdaptivePooling与Max/AvgPooling相互转换提供了一种转换方法,但我在Pytorch1.6中的测试结果是错误的。通过查看Pytorch源码(pytorch-master\aten\src\ATen\native\AdaptiveAveragePooling.cpp)我找出了正确的转换方式。

  inline int start_index(int a, int b, int c) {
return (int)std::floor((float)(a * c) / b);
} inline int end_index(int a, int b, int c) {
return (int)std::ceil((float)((a + 1) * c) / b);
} template <typename scalar_t>
static void adaptive_avg_pool2d_single_out_frame(
scalar_t *input_p,
scalar_t *output_p,
int64_t sizeD,
int64_t isizeH,
int64_t isizeW,
int64_t osizeH,
int64_t osizeW,
int64_t istrideD,
int64_t istrideH,
int64_t istrideW)
{
at::parallel_for(0, sizeD, 0, [&](int64_t start, int64_t end) {
for (auto d = start; d < end; d++)
{
/* loop over output */
int64_t oh, ow;
for(oh = 0; oh < osizeH; oh++)
{
int istartH = start_index(oh, osizeH, isizeH);
int iendH = end_index(oh, osizeH, isizeH);
int kH = iendH - istartH; for(ow = 0; ow < osizeW; ow++)
{
int istartW = start_index(ow, osizeW, isizeW);
int iendW = end_index(ow, osizeW, isizeW);
int kW = iendW - istartW; /* local pointers */
scalar_t *ip = input_p + d*istrideD + istartH*istrideH + istartW*istrideW;
scalar_t *op = output_p + d*osizeH*osizeW + oh*osizeW + ow; /* compute local average: */
scalar_t sum = 0;
int ih, iw;
for(ih = 0; ih < kH; ih++)
{
for(iw = 0; iw < kW; iw++)
{
scalar_t val = *(ip + ih*istrideH + iw*istrideW);
sum += val;
}
} /* set output to local average */
*op = sum / kW / kH;
}
}
}
});
}

上述代码段中isizeH,isizeW分别表示输入张量的宽高osizeH,osizeW则表示输出宽高。关注第二个for循环for(oh = 0; oh < osizeH; oh++){.....}中的内容。假设输入的宽高均为223isizeH = isizeW = 223,输出的宽高均为7osizeH = osizeW = 224,然后简单分析一下oh=0,1,2时的情况:

  • oh=0, istartH = 0, iendH = ceil(223/7)=32, kH = 32
  • oh=1, istartH = floor(223/7) = 31, iendH = ceil(223*2/7)=64, kH = 33
  • oh=2, istartH = floor(223*2/7) = 63, iendH = ceil(223*3/7)=96, kH = 33

这里的kH就是kernel_size的大小. oh=0时的kernel_size比其他情况要小,所以需要在输入上添加padding,让oh=0时的kernel_size与其他情况相同。添加的padding大小为1,等价于让istartH从-1开始,即kH = 32-(-1) = 33. 下一个需要获取的参数是stride,stride = istartH[oh=i]-istartH[oh=i-1], 在上述例子中即为32。按照上述的例子分析输入宽高为224的情况可以发现padding=0,所以padding也是一个需要转换的参数。下面给出3个参数的转换公式:

  • stride = ceil(input_size / output_size)
  • kernel_size = ceil(2 * input_size / output_size) - floor(input_size / output_size)
  • padding = ceil(input_size / output_size) - floor(input_size / output_size)

在上述的代码中最后部分,可以看见均值使用*op = sum / kW / kH计算得到的。这表明在边缘部分计算均值没有考虑padding,所以对应的AvgPool中的count_include_pad应该设为False。下面贴出我的测试代码:

def test(size):
import numpy as np
import torch x = torch.randn(1,1,size,size) input_size = np.array(x.shape[2:])
output_size = np.array([7,7]) # stride = ceil(input_size / output_size)
# kernel_size = ceil(2 * input_size / output_size) - floor(input_size / output_size)
# padding = ceil(input_size / output_size) - floor(input_size / output_size) stride = numpy.ceil(input_size / output_size).astype(int)
kernel_size = (numpy.ceil(2 * input_size / output_size) - numpy.floor(input_size / output_size)).astype(int)
padding = (numpy.ceil(input_size / output_size) - numpy.floor(input_size / output_size)).astype(int)
print(stride)
print(kernel_size)
print(padding)
avg1 = nn.AdaptiveAvgPool2d(list(output_size))
avg2 = nn.AvgPool2d(kernel_size=kernel_size.tolist(), stride=stride.tolist(), padding=padding.tolist(), ceil_mode=False, count_include_pad=False)
max1 = nn.AdaptiveMaxPool2d(list(output_size))
max2 = nn.MaxPool2d(kernel_size=kernel_size.tolist(), stride=stride.tolist(), padding=padding.tolist(), ceil_mode=False ) avg1_out = avg1(x)
avg2_out = avg2(x)
max1_out = max1(x)
max2_out = max2(x)
print(avg1_out-avg2_out)
print(max1_out-max2_out)
print(torch.__version__)
  • inH = inW=224时的输出

  • inH = inW=223时的输出

Pytorch AdaptivePooing操作转Pooling操作的更多相关文章

  1. python基础操作以及hdfs操作

    目录 前言 基础操作 hdfs操作 总结 一.前言        作为一个全栈工程师,必须要熟练掌握各种语言...HelloWorld.最近就被"逼着"走向了python开发之路, ...

  2. [WCF编程]10.操作:单向操作

    一.单向操作概述 WCF提供了单向操作,一旦客户端调用,WCF会生成一个请求,但没有相关的应答信息返回给客户端.所以,单向操作是不能有返回值,服务抛出的任何异常都不会传递给客户端. 理想情况下,一旦客 ...

  3. Linq查询操作之聚合操作(count,max,min,sum,average,aggregate,longcount)

    在Linq中有一些这样的操作,根据集合计算某一单一值,比如集合的最大值,最小值,平均值等等.Linq中包含7种操作,这7种操作被称作聚合操作. 1.Count操作,计算序列中元素的个数,或者计算满足一 ...

  4. Linq查询操作之排序操作

    在Linq中排序操作可以按照一个或多个关键字对序列进行排序.其中第一个排序关键字为主要关键字,第二个排序关键字为次要关键字.Linq排序操作共包含以下5个基本的操作. 1.OrderBy操作,根据排序 ...

  5. Linq查询操作之投影操作

    投影操作,乍一看不知道在说啥.那么什么是投影操作呢?其实就是Select操作,名字起的怪怪的.和Linq查询表达式中的select操作是一样的.它能够选择数据源中的元素,并指定元素的表现形式.投影操作 ...

  6. Laravel框架数据库CURD操作、连贯操作

    这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 $users = DB::t ...

  7. Laravel框架数据库CURD操作、连贯操作总结

    这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 复制代码代码如下: $use ...

  8. IOS文件操作的两种方式:NSFileManager操作和流操作

    1.常见的NSFileManager文件方法 -(NSData *)contentsAtPath:path //从一个文件读取数据 -(BOOL)createFileAtPath: path cont ...

  9. ThinkPHP - 前置操作+后置操作

    前置操作和后置操作   系统会检测当前操作(不仅仅是index操作,其他操作一样可以使用)是否具有前置和后置操作,如果存在就会按照顺序执行,前置和后置操作的方法名是在要执行的方法前面加 _before ...

随机推荐

  1. 【刷题-LeetCode】150 Evaluate Reverse Polish Notation

    Evaluate Reverse Polish Notation Evaluate the value of an arithmetic expression in Reverse Polish No ...

  2. 【代码分享】用redis+lua实现多个集合取交集并过滤,类似于: select key from set2 where key in (select key from set1) and value>=xxx

    redis中的zset结构可以看成一个个包含数值的集合,或者认为是一个关系数据库中用列存储方式存储的一列. 需求 假设我有这样一个数据筛选需求,用SQL表示为: select key from set ...

  3. Redis作缓存

    缓存策略三要素:缓存命中率   缓存更新策略  最大缓存容量.衡量一个缓存方案的好坏标准是:缓存命中率.缓存命中率越高,缓存方法设计的越好. 三者之间的关系为:当缓存到达最大的缓存容量时,会触发缓存更 ...

  4. 一文读懂HarmonyOS服务卡片怎么换肤

    作者:zhenyu,华为软件开发工程师 关注HarmonyOS的小伙伴肯定对服务卡片已经很熟悉了.服务卡片(也简称为"卡片")是FA(FeatureAbility,元服务)的一种界 ...

  5. POSIX之消息队列

    my_semqueue_send.c: #include<stdio.h> #include<errno.h> #include<mqueue.h> #includ ...

  6. listen()和accept()

    1.listen()队列剖析 作用:监听端口,TCP连接中的服务器端角色 调用格式:int listen(int sockfd, int backlog); 第一个参数:创建的sockfd, 好好理解 ...

  7. python中grpc配置asyncio使用

    python中grpc配置asyncio使用 安装grpclib pip3 install grpclib protoc编译.proto文件,生成源码文件 python -m grpc_tools.p ...

  8. Web开发底层是Servlet

    SpringMVC:是基于spring的一个框架,实际上就是spring的一个模块,专门是做web开发. 可以理解成servlet是一个升级 web开发底层是servlet,框架是在servlet基础 ...

  9. SpringBoot+Minio搭建不再爆肝秃头的分布式文件服务器

    前言 1).有人一定会问,为什么不用FastDFS?众所周知,FastDFS的原生安装非常复杂,有过安装经验的人大体都明白,虽然可以利用别人做好的docker直接安装,但真正使用过程中也可能出现许多莫 ...

  10. Java动态绑定和静态绑定-多态

    一.问题 Java方法调用过程中,Jvm是如何知道调用的是哪个类的方法?Jvm又是如何处理?   二.概念 a.当子类和父类(接口和实现类)存在同一个方法时,子类重写父类(接口)方法时,程序在运行时调 ...