blob: 64713bbc62ac3d4f3fd031a792bf9b26ce7a05c6 [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/layer/concat.h"
#include "gtest/gtest.h"
using singa::Shape;
TEST(Concat, Setup) {
Shape s1{2u, 3u};
Shape s2{1u, 3u};
singa::LayerConf conf;
conf.set_type("singa_concat");
conf.mutable_concat_conf()->set_axis(0);
singa::Concat layer;
layer.Setup({{3u}, {3u}}, conf);
auto s = layer.GetOutputSampleShape();
EXPECT_EQ(s[0], 3u);
}
void ForwardConcatRowTest(std::shared_ptr<singa::Device> dev) {
size_t a = 2u, b = 1u, c = 3u;
singa::Tensor t1({a, c}, dev);
singa::Tensor t2({b, c}, dev);
singa::LayerConf conf;
conf.set_type("singa_concat");
conf.mutable_concat_conf()->set_axis(0);
singa::Concat layer;
layer.Setup({{c}, {c}}, conf);
layer.ToDevice(dev);
t1.SetValue(1.0f);
t2.SetValue(2.0f);
auto out = layer.Forward(singa::kTrain, {t1, t2});
EXPECT_EQ(out.size(), 1u);
out[0].ToHost();
const float* outptr = out[0].data<float>();
for (size_t i = 0; i < a; i++) {
for (size_t j = 0; j < c; j++) EXPECT_FLOAT_EQ(outptr[i * c + j], 1.0f);
}
for (size_t i = a; i < a + b; i++) {
for (size_t j = 0; j < c; j++) EXPECT_FLOAT_EQ(outptr[i * c + j], 2.0f);
}
}
void ForwardConcatColumnTest(std::shared_ptr<singa::Device> dev) {
size_t a = 2u, b = 1u, c = 3u;
singa::Tensor t1({c, a}, dev);
singa::Tensor t2({c, b}, dev);
singa::LayerConf conf;
conf.set_type("singa_concat");
conf.mutable_concat_conf()->set_axis(1);
singa::Concat layer;
layer.Setup({{a}, {b}}, conf);
layer.ToDevice(dev);
t1.SetValue(1.0f);
t2.SetValue(2.0f);
auto out = layer.Forward(singa::kTrain, {t1, t2});
EXPECT_EQ(out.size(), 1u);
out[0].ToHost();
const float* outptr = out[0].data<float>();
for (size_t i = 0; i < c; i++) {
for (size_t j = 0; j < a; j++)
EXPECT_FLOAT_EQ(outptr[i * (a + b) + j], 1.0f);
}
for (size_t i = 0; i < c; i++) {
for (size_t j = a; j < a + b; j++)
EXPECT_FLOAT_EQ(outptr[i * (a + b) + j], 2.0f);
}
}
TEST(Concat, ForwardConcatRowCpp) {
ForwardConcatRowTest(singa::defaultDevice);
}
TEST(Concat, ForwardConcatColumnCpp) {
ForwardConcatColumnTest(singa::defaultDevice);
}
#ifdef USE_CUDA
TEST(Concat, ForwardConcatRowCuda) {
ForwardConcatRowTest(std::make_shared<singa::CudaGPU>());
}
TEST(Concat, ForwardConcatColumnCuda) {
ForwardConcatColumnTest(std::make_shared<singa::CudaGPU>());
}
#endif // USE_CUDA
void BackwardConcatRowTest(std::shared_ptr<singa::Device> dev) {
size_t a = 2u, b = 1u, c = 3u;
singa::LayerConf conf;
conf.set_type("singa_concat");
conf.mutable_concat_conf()->set_axis(0);
singa::Concat layer;
layer.Setup({{c}, {c}}, conf);
layer.ToDevice(dev);
singa::Tensor t1({a, c}, dev);
singa::Tensor t2({b, c}, dev);
t1.SetValue(1.0f);
t2.SetValue(2.0f);
layer.Forward(singa::kTrain, {t1, t2});
singa::Tensor t({a + b, c}, dev);
singa::Uniform(-1.f, 1.f, &t);
auto out = layer.Backward(singa::kTrain, {t});
auto grads = out.first;
EXPECT_EQ(grads.size(), 2u);
t.ToHost();
const float* tptr = t.data<float>();
grads[0].ToHost();
const float* outa = grads[0].data<float>();
for (size_t i = 0; i < a; i++)
for (size_t j = 0; j < c; j++)
EXPECT_FLOAT_EQ(outa[i * c + j], tptr[i * c + j]);
grads[1].ToHost();
const float* outb = grads[1].data<float>();
for (size_t i = 0; i < b; i++)
for (size_t j = 0; j < c; j++)
EXPECT_FLOAT_EQ(outb[i * c + j], tptr[(i + a) * c + j]);
}
void BackwardConcatColumnTest(std::shared_ptr<singa::Device> dev) {
size_t a = 2u, b = 1u, c = 3u;
singa::LayerConf conf;
conf.set_type("singa_concat");
conf.mutable_concat_conf()->set_axis(1);
singa::Concat layer;
layer.Setup({{a}, {b}}, conf);
layer.ToDevice(dev);
singa::Tensor t1({c, a}, dev);
singa::Tensor t2({c, b}, dev);
t1.SetValue(1.0f);
t2.SetValue(2.0f);
layer.Forward(singa::kTrain, {t1, t2});
singa::Tensor t({c, a + b}, dev);
singa::Uniform(-1.f, 1.f, &t);
auto out = layer.Backward(singa::kTrain, {t});
auto grads = out.first;
EXPECT_EQ(grads.size(), 2u);
t.ToHost();
const float* tptr = t.data<float>();
grads[0].ToHost();
const float* outa = grads[0].data<float>();
for (size_t i = 0; i < c; i++)
for (size_t j = 0; j < a; j++)
EXPECT_FLOAT_EQ(outa[i * a + j], tptr[i * (a + b) + j]);
grads[1].ToHost();
const float* outb = grads[1].data<float>();
for (size_t i = 0; i < c; i++)
for (size_t j = 0; j < b; j++)
EXPECT_FLOAT_EQ(outb[i * b + j], tptr[i * (a + b) + a + j]);
}
TEST(Concat, BackwardConcatRowCpp) {
BackwardConcatRowTest(singa::defaultDevice);
}
TEST(Concat, BackwardConcatColumn) {
BackwardConcatColumnTest(singa::defaultDevice);
}
#ifdef USE_CUDA
TEST(Concat, BackwardConcatRowCuda) {
BackwardConcatRowTest(std::make_shared<singa::CudaGPU>());
}
TEST(Concat, BackwardConcatColumnCuda) {
BackwardConcatColumnTest(std::make_shared<singa::CudaGPU>());
}
#endif // USE_CUDA