#define EIGEN_USE_THREADS #include #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/register_types.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_shape.h" #include "tensorflow/core/framework/types.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/shape_inference.h" #include "tensorflow/core/framework/common_shape_fns.h" using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; void Downsample(const GPUDevice& d, typename TTypes::ConstTensor images, typename TTypes::Tensor output); class DownsampleOp : public OpKernel { public: explicit DownsampleOp(OpKernelConstruction* c) : OpKernel(c) { OP_REQUIRES_OK(c, c->GetAttr("scale", &scale)); } void Compute(OpKernelContext* context) override { const Tensor& input = context->input(0); typename TTypes::ConstTensor input_data = input.tensor(); OP_REQUIRES(context, input_data.dimension(1) % scale == 0 && input_data.dimension(2) % scale == 0, errors::InvalidArgument("Input height and width must be divisible by scale")); const int batch = input_data.dimension(0); const int height = input_data.dimension(1) / scale; const int width = input_data.dimension(2) / scale; const int channels = input_data.dimension(3); auto output_shape = TensorShape({batch, height, width, channels}); Tensor* output = NULL; OP_REQUIRES_OK(context, context->allocate_output(0, output_shape, &output)); typename TTypes::Tensor output_data = output->tensor(); Downsample(context->eigen_device(), input_data, output_data); } private: int scale; }; using shape_inference::DimensionHandle; using shape_inference::ShapeHandle; REGISTER_OP("Downsample") .Input("images: float") .Attr("scale: int = 2") .Output("out_images: float") .SetShapeFn([](shape_inference::InferenceContext* c) { ShapeHandle in = c->input(0); int scale; DimensionHandle batch = c->Dim(in, 0); DimensionHandle channels = c->Dim(in, 3); DimensionHandle height; DimensionHandle width; c->GetAttr("scale", &scale); c->Divide(c->Dim(in, 1), scale, true, &height); c->Divide(c->Dim(in, 2), scale, true, &width); c->set_output(0, c->MakeShape({batch, height, width, channels})); return Status::OK(); }); #if GOOGLE_CUDA REGISTER_KERNEL_BUILDER(Name("Downsample").Device(DEVICE_GPU), DownsampleOp); #endif // GOOGLE_CUDA