blob: 3bcc896b590283ec800508cd57ca92e9bfd56ad0 [file] [log] [blame]
/************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "../src/model/operation/pooling.h"
#include "gtest/gtest.h"
using namespace singa;
#ifdef USE_MKLDNN
TEST(OperationPooling, Forward) {
const size_t batchsize = 2, c = 1, h = 3, w = 3;
const float x[batchsize * c * h * w] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f, 1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
Tensor in(Shape{batchsize, c, h, w});
in.CopyDataFromHostPtr(x, batchsize * c * h * w);
PoolingHandle pool_handle(in, {2, 2}, {1,1}, {0,0}, true);
Tensor out1 = CpuPoolingForward(pool_handle, in);
// Parameter "flag" does not influence pooling
const float *outptr1 = out1.data<float>();
// Input: 3*3; kernel: 2*2; stride: 1*1; no padding.
EXPECT_EQ(8u, out1.Size());
EXPECT_EQ(5.0f, outptr1[0]);
EXPECT_EQ(6.0f, outptr1[1]);
EXPECT_EQ(8.0f, outptr1[2]);
EXPECT_EQ(9.0f, outptr1[3]);
EXPECT_EQ(5.0f, outptr1[4]);
EXPECT_EQ(6.0f, outptr1[5]);
EXPECT_EQ(8.0f, outptr1[6]);
EXPECT_EQ(9.0f, outptr1[7]);
}
TEST(OperationPooling, ForwardAverage) {
const size_t batchsize = 2, c = 1, h = 3, w = 3;
const float x[batchsize * c * h * w] = {1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f,
1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f};
Tensor in(Shape{batchsize, c, h, w});
in.CopyDataFromHostPtr(x, batchsize * c * h * w);
PoolingHandle pool_handle(in, {2, 2}, {1,1}, {0,0}, false);
Tensor out1 = CpuPoolingForward(pool_handle, in);
// Parameter "flag" does not influence pooling
const float *outptr1 = out1.data<float>();
// Input: 3*3; kernel: 2*2; stride: 1*1; no padding.
EXPECT_EQ(8u, out1.Size());
EXPECT_EQ(3.0f, outptr1[0]);
EXPECT_EQ(4.0f, outptr1[1]);
EXPECT_EQ(6.0f, outptr1[2]);
EXPECT_EQ(7.0f, outptr1[3]);
EXPECT_EQ(3.0f, outptr1[4]);
EXPECT_EQ(4.0f, outptr1[5]);
EXPECT_EQ(6.0f, outptr1[6]);
EXPECT_EQ(7.0f, outptr1[7]);
}
TEST(OperationPooling, Backward) {
// src_data
const size_t batchsize = 2, c = 1, src_h = 3, src_w = 3;
const float x[batchsize * c * src_h * src_w] = {
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
Tensor in(Shape{batchsize, c, src_h, src_w});
in.CopyDataFromHostPtr(x, batchsize * c * src_h * src_w);
PoolingHandle pool_handle(in, {2, 2}, {1,1}, {0,0}, true);
Tensor out = CpuPoolingForward(pool_handle, in);
// grad - bwd
const size_t grad_h = 2, grad_w = 2;
const float dy[batchsize * c * grad_h * grad_w] = {0.1f, 0.2f, 0.3f, 0.4f,
0.1f, 0.2f, 0.3f, 0.4f};
Tensor grad(Shape{batchsize, c, grad_h, grad_w});
grad.CopyDataFromHostPtr(dy, batchsize * c * grad_h * grad_w);
Tensor in_grad = CpuPoolingBackward(pool_handle, grad, in, out);
const float *dx = in_grad.data<float>();
EXPECT_EQ(18u, in_grad.Size());
EXPECT_EQ(0.0f, dx[0]);
EXPECT_EQ(0.0f, dx[1]);
EXPECT_EQ(0.0f, dx[2]);
EXPECT_EQ(0.0f, dx[3]);
EXPECT_EQ(0.1f, dx[4]);
EXPECT_EQ(0.2f, dx[5]);
EXPECT_EQ(0.0f, dx[6]);
EXPECT_EQ(0.3f, dx[7]);
EXPECT_EQ(0.4f, dx[8]);
EXPECT_EQ(0.0f, dx[9]);
EXPECT_EQ(0.0f, dx[10]);
EXPECT_EQ(0.0f, dx[11]);
EXPECT_EQ(0.0f, dx[12]);
EXPECT_EQ(0.1f, dx[13]);
EXPECT_EQ(0.2f, dx[14]);
EXPECT_EQ(0.0f, dx[15]);
EXPECT_EQ(0.3f, dx[16]);
EXPECT_EQ(0.4f, dx[17]);
}
TEST(OperationPooling, BackwardAvg) {
// src_data
const size_t batchsize = 2, c = 1, src_h = 3, src_w = 3;
const float x[batchsize * c * src_h * src_w] = {
1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f,
1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f};
Tensor in(Shape{batchsize, c, src_h, src_w});
in.CopyDataFromHostPtr(x, batchsize * c * src_h * src_w);
PoolingHandle pool_handle(in, {2, 2}, {1,1}, {0,0}, false);
Tensor out = CpuPoolingForward(pool_handle, in);
// grad - bwd
const size_t grad_h = 2, grad_w = 2;
const float dy[batchsize * c * grad_h * grad_w] = {0.1f, 0.2f, 0.3f, 0.4f,
0.1f, 0.2f, 0.3f, 0.4f};
Tensor grad(Shape{batchsize, c, grad_h, grad_w});
grad.CopyDataFromHostPtr(dy, batchsize * c * grad_h * grad_w);
Tensor in_grad = CpuPoolingBackward(pool_handle, grad, in, out);
const float *dx = in_grad.data<float>();
EXPECT_EQ(18u, in_grad.Size());
EXPECT_NEAR(0.0250f, dx[0], 1e-5f);
EXPECT_NEAR(0.0750f, dx[1], 1e-5f);
EXPECT_NEAR(0.0500f, dx[2], 1e-5f);
EXPECT_NEAR(0.1000f, dx[3], 1e-5f);
EXPECT_NEAR(0.2500f, dx[4], 1e-5f);
EXPECT_NEAR(0.1500f, dx[5], 1e-5f);
EXPECT_NEAR(0.0750f, dx[6], 1e-5f);
EXPECT_NEAR(0.1750f, dx[7], 1e-5f);
EXPECT_NEAR(0.1000f, dx[8], 1e-5f);
EXPECT_NEAR(0.0250f, dx[9], 1e-5f);
EXPECT_NEAR(0.0750f, dx[10], 1e-5f);
EXPECT_NEAR(0.0500f, dx[11], 1e-5f);
EXPECT_NEAR(0.1000f, dx[12], 1e-5f);
EXPECT_NEAR(0.2500f, dx[13], 1e-5f);
EXPECT_NEAR(0.1500f, dx[14], 1e-5f);
EXPECT_NEAR(0.0750f, dx[15], 1e-5f);
EXPECT_NEAR(0.1750f, dx[16], 1e-5f);
EXPECT_NEAR(0.1000f, dx[17], 1e-5f);
}
#endif // USE_MKLDNN