Merge pull request #3753 from hedaoyuan/conv_op
	
		
	
				
					
				
			Add im2col functorAdaptive_data_structure_for_SwitchOrderLayer
						commit
						0140f3f9d0
					
				@ -1,8 +1,10 @@
 | 
				
			||||
 | 
				
			||||
if(WITH_GPU)
 | 
				
			||||
    nv_library(math_function SRCS math_function.cc math_function.cu DEPS cblas device_context)
 | 
				
			||||
    nv_library(math_function SRCS math_function.cc math_function.cu im2col.cc 
 | 
				
			||||
    im2col.cu DEPS cblas device_context)
 | 
				
			||||
else()
 | 
				
			||||
    cc_library(math_function SRCS math_function.cc DEPS cblas device_context)
 | 
				
			||||
    cc_library(math_function SRCS math_function.cc im2col.cc DEPS cblas device_context)
 | 
				
			||||
endif()
 | 
				
			||||
 | 
				
			||||
nv_test(math_function_test SRCS math_function_test.cc DEPS math_function tensor)
 | 
				
			||||
cc_test(im2col_test SRCS im2col_test.cc DEPS math_function tensor)
 | 
				
			||||
 | 
				
			||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								@ -0,0 +1,90 @@
 | 
				
			||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
 | 
				
			||||
 | 
				
			||||
Licensed 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. */
 | 
				
			||||
 | 
				
			||||
#pragma once
 | 
				
			||||
 | 
				
			||||
#include "paddle/framework/tensor.h"
 | 
				
			||||
#include "paddle/platform/device_context.h"
 | 
				
			||||
 | 
				
			||||
namespace paddle {
 | 
				
			||||
namespace operators {
 | 
				
			||||
namespace math {
 | 
				
			||||
 | 
				
			||||
/* The storage format of the coldata in the Im2ColFunctor and Col2ImFunctor. */
 | 
				
			||||
enum class ColFormat { kCFO = 0, kOCF = 1 };
 | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * \brief Converts the image data of three dimensions(CHW) into a colData of
 | 
				
			||||
 *        five dimensions in the Im2ColFunctor calculation,
 | 
				
			||||
 *        And in the Col2ImFunctor calculation, it is reversed.
 | 
				
			||||
 *
 | 
				
			||||
 * \param imData   Image data.
 | 
				
			||||
 * \param imShape  The shape of imData,
 | 
				
			||||
 *                 [input_channels, input_height, input_width].
 | 
				
			||||
 * \param colData  Column data.
 | 
				
			||||
 * \param colShape The shape of colData.
 | 
				
			||||
 *
 | 
				
			||||
 * If the template argument Format is kCFO, the shape of colData is:
 | 
				
			||||
 * [input_channels, filter_height, filter_width, output_height, output_width]
 | 
				
			||||
 * So, it is easy to reshape into a convolution matrix for convolution
 | 
				
			||||
 * calculation based on matrix multiplication.
 | 
				
			||||
 * The shape of convolution matrix is [height, width], where the height is equal
 | 
				
			||||
 * input_channels * filter_height * filter_width, and the width is equal
 | 
				
			||||
 * output_height * output_width.
 | 
				
			||||
 *
 | 
				
			||||
 * Reshape:
 | 
				
			||||
 *     shape of colData           shape of convolution matrix
 | 
				
			||||
 *     [input_channels,
 | 
				
			||||
 *      filter_height,
 | 
				
			||||
 *      filter_width,      ======>      [height, width]
 | 
				
			||||
 *      output_height,
 | 
				
			||||
 *      output_width]
 | 
				
			||||
 *
 | 
				
			||||
 * If the template argument Format is kOCF, the shape of colData is:
 | 
				
			||||
 * [output_height, output_width, input_channels, filter_height, filter_width]
 | 
				
			||||
 * So, it is easy to reshape into a sequence matrix for rnn calculation.
 | 
				
			||||
 * The shape of sequence matrix is [seq_length, step_size], where the seq_length
 | 
				
			||||
 * is equal output_height * output_width, and the step_size is equal
 | 
				
			||||
 * input_channels * filter_height * filter_width.
 | 
				
			||||
 *
 | 
				
			||||
 * Reshape:
 | 
				
			||||
 *     shape of colData             shape of sequence matrix
 | 
				
			||||
 *     [output_height,
 | 
				
			||||
 *      output_width,
 | 
				
			||||
 *      input_channels,    ======>    [seqLength, stepSize]
 | 
				
			||||
 *      filter_height,
 | 
				
			||||
 *      filter_width]
 | 
				
			||||
 *
 | 
				
			||||
 * \note The caller needs to ensure that imShape.inputChannels is equal to
 | 
				
			||||
 *       colShape.inputChannels.
 | 
				
			||||
 */
 | 
				
			||||
template <ColFormat Format, typename Place, typename T>
 | 
				
			||||
class Im2ColFunctor {
 | 
				
			||||
 public:
 | 
				
			||||
  void operator()(const framework::Tensor& im, framework::Tensor& col,
 | 
				
			||||
                  int stride_height, int stride_width, int padding_height,
 | 
				
			||||
                  int padding_width, platform::DeviceContext* context);
 | 
				
			||||
};
 | 
				
			||||
 | 
				
			||||
template <ColFormat Format, typename Place, typename T>
 | 
				
			||||
class Col2ImFunctor {
 | 
				
			||||
 public:
 | 
				
			||||
  void operator()(framework::Tensor& im, const framework::Tensor& col,
 | 
				
			||||
                  int stride_height, int stride_width, int padding_height,
 | 
				
			||||
                  int padding_width, platform::DeviceContext* context);
 | 
				
			||||
};
 | 
				
			||||
 | 
				
			||||
}  // namespace math
 | 
				
			||||
}  // namespace operators
 | 
				
			||||
}  // namespace paddle
 | 
				
			||||
@ -0,0 +1,118 @@
 | 
				
			||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
 | 
				
			||||
 | 
				
			||||
Licensed 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 "paddle/operators/math/im2col.h"
 | 
				
			||||
#include <gtest/gtest.h>
 | 
				
			||||
#include <iostream>
 | 
				
			||||
 | 
				
			||||
template <typename Place>
 | 
				
			||||
void testIm2col() {
 | 
				
			||||
  paddle::framework::Tensor input_tmp;
 | 
				
			||||
  paddle::framework::Tensor input;
 | 
				
			||||
  paddle::framework::Tensor output_cfo;
 | 
				
			||||
  paddle::framework::Tensor output_ocf;
 | 
				
			||||
  paddle::framework::Tensor output_tmp;
 | 
				
			||||
 | 
				
			||||
  /**
 | 
				
			||||
   * input = [0, 1, 2,
 | 
				
			||||
   *          3, 4, 5]
 | 
				
			||||
   *
 | 
				
			||||
   * output_cfo = [0, 1
 | 
				
			||||
   *               1, 2
 | 
				
			||||
   *               3, 4
 | 
				
			||||
   *               4, 5]
 | 
				
			||||
   *
 | 
				
			||||
   * output_ocf = [0, 1, 3, 4
 | 
				
			||||
   *               1, 2, 4, 5]
 | 
				
			||||
   */
 | 
				
			||||
  int input_height = 2;
 | 
				
			||||
  int input_width = 3;
 | 
				
			||||
  int filter_size = 2;
 | 
				
			||||
  int stride = 1;
 | 
				
			||||
  int padding = 0;
 | 
				
			||||
  int output_height = (input_height - filter_size + 2 * padding) / stride + 1;
 | 
				
			||||
  int output_width = (input_width - filter_size + 2 * padding) / stride + 1;
 | 
				
			||||
  float* input_ptr = input_tmp.mutable_data<float>(
 | 
				
			||||
      {1, input_height, input_width}, paddle::platform::CPUPlace());
 | 
				
			||||
  float arr[6] = {0, 1, 2, 3, 4, 5};
 | 
				
			||||
  memcpy(input_ptr, arr, 6 * sizeof(float));
 | 
				
			||||
 | 
				
			||||
  auto* place = new Place();
 | 
				
			||||
  if (paddle::platform::is_cpu_place(*place)) {
 | 
				
			||||
    input = input_tmp;
 | 
				
			||||
  } else {
 | 
				
			||||
    input.CopyFrom<float>(input_tmp, *place);
 | 
				
			||||
  }
 | 
				
			||||
  output_cfo.mutable_data<float>(
 | 
				
			||||
      {1, filter_size, filter_size, output_height, output_width}, *place);
 | 
				
			||||
  output_ocf.mutable_data<float>(
 | 
				
			||||
      {output_height, output_width, 1, filter_size, filter_size}, *place);
 | 
				
			||||
 | 
				
			||||
  paddle::operators::math::Im2ColFunctor<
 | 
				
			||||
      paddle::operators::math::ColFormat::kCFO, Place, float>
 | 
				
			||||
      im2col;
 | 
				
			||||
  paddle::operators::math::Im2ColFunctor<
 | 
				
			||||
      paddle::operators::math::ColFormat::kOCF, Place, float>
 | 
				
			||||
      im2col_ocf;
 | 
				
			||||
 | 
				
			||||
  paddle::platform::DeviceContext* context;
 | 
				
			||||
  if (paddle::platform::is_cpu_place(*place)) {
 | 
				
			||||
    context =
 | 
				
			||||
        new paddle::platform::CPUDeviceContext(paddle::platform::CPUPlace());
 | 
				
			||||
  } else {
 | 
				
			||||
    context =
 | 
				
			||||
        new paddle::platform::CUDADeviceContext(paddle::platform::GPUPlace());
 | 
				
			||||
  }
 | 
				
			||||
  im2col(input, output_cfo, stride, stride, padding, padding, context);
 | 
				
			||||
  im2col_ocf(input, output_ocf, stride, stride, padding, padding, context);
 | 
				
			||||
 | 
				
			||||
  float* out_cfo_ptr;
 | 
				
			||||
  if (paddle::platform::is_cpu_place(*place)) {
 | 
				
			||||
    out_cfo_ptr = output_cfo.data<float>();
 | 
				
			||||
  } else {
 | 
				
			||||
    output_tmp.CopyFrom<float>(output_cfo, paddle::platform::CPUPlace());
 | 
				
			||||
    out_cfo_ptr = output_tmp.data<float>();
 | 
				
			||||
  }
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[0], 0);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[1], 1);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[2], 1);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[3], 2);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[4], 3);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[5], 4);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[6], 4);
 | 
				
			||||
  EXPECT_EQ(out_cfo_ptr[7], 5);
 | 
				
			||||
 | 
				
			||||
  float* out_ocf_ptr;
 | 
				
			||||
  if (paddle::platform::is_cpu_place(*place)) {
 | 
				
			||||
    out_ocf_ptr = output_ocf.data<float>();
 | 
				
			||||
  } else {
 | 
				
			||||
    output_tmp.CopyFrom<float>(output_ocf, paddle::platform::CPUPlace());
 | 
				
			||||
    out_ocf_ptr = output_tmp.data<float>();
 | 
				
			||||
  }
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[0], 0);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[1], 1);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[2], 3);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[3], 4);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[4], 1);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[5], 2);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[6], 4);
 | 
				
			||||
  EXPECT_EQ(out_ocf_ptr[7], 5);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
TEST(math, im2col) {
 | 
				
			||||
  testIm2col<paddle::platform::CPUPlace>();
 | 
				
			||||
#ifndef PADDLE_ONLY_CPU
 | 
				
			||||
  testIm2col<paddle::platform::GPUPlace>();
 | 
				
			||||
#endif
 | 
				
			||||
}
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue