scatter.h 5.3 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Z
zchen0211 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

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 <cstring>
17
#include <string>
Z
zchen0211 已提交
18

Y
Yi Wang 已提交
19 20 21
#include "paddle/fluid/framework/ddim.h"
#include "paddle/fluid/framework/eigen.h"
#include "paddle/fluid/framework/tensor.h"
22
#include "paddle/fluid/operators/math/blas.h"
Y
Yi Wang 已提交
23
#include "paddle/fluid/platform/place.h"
24
#include "unordered_set"
Z
zchen0211 已提交
25 26 27 28 29 30 31

namespace paddle {
namespace operators {

using Tensor = framework::Tensor;

/**
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
  * Return the updated array pointer, use blas or eigen lib to optimize time
 * cost
 */
template <typename T, typename IndexT = int>
typename std::enable_if<std::is_floating_point<T>::value>::type
elementwise_inner_add(const framework::ExecutionContext& ctx,
                      const T* src_pointer, const T* dist_pointer,
                      T* result_dist_pointer, const framework::Tensor& src,
                      framework::Tensor* dist, const int& src_index,
                      const IndexT& dist_index, const int& slice_size,
                      const size_t& slice_bytes) {
  auto blas = math::GetBlas<platform::CPUDeviceContext, T>(ctx);

  blas.VADD(slice_size, src_pointer + src_index * slice_size,
            dist_pointer + dist_index * slice_size,
            result_dist_pointer + dist_index * slice_size);
}

template <typename T, typename IndexT = int>
typename std::enable_if<!std::is_floating_point<T>::value>::type
elementwise_inner_add(const framework::ExecutionContext& ctx,
                      const T* src_pointer, const T* dist_pointer,
                      T* result_dist_pointer, const framework::Tensor& src,
                      framework::Tensor* dist, const int& src_index,
                      const IndexT& dist_index, const int& slice_size,
                      const size_t& slice_bytes) {
  auto src_slice = src.Slice(src_index, src_index + 1);
  auto dist_slice = dist->Slice(dist_index, dist_index + 1);

  auto eigen_src = framework::EigenVector<T>::Flatten(src_slice);
  auto eigen_dist = framework::EigenVector<T>::Flatten(dist_slice);

  eigen_dist += eigen_src;
}
/**
 * Return an updated tensor from source tensor, scattered according to index:
Z
zchen0211 已提交
68
 * dst[i] = src[index[i]]
Z
zchen0211 已提交
69
 * input[src]: type-T source Tensor
70
 * input[index]: type-IndexT index Tensor (1-D)
Z
zchen0211 已提交
71 72
 * return: output tensor
 */
73
template <typename T, typename IndexT = int>
74 75
void ScatterAssign(const platform::DeviceContext& ctx, const Tensor& src,
                   const Tensor& index, Tensor* output) {
Z
zchen0211 已提交
76
  PADDLE_ENFORCE(platform::is_cpu_place(ctx.GetPlace()));
Z
zchen0211 已提交
77
  // check index of shape 1-D
Y
Yibing Liu 已提交
78 79
  PADDLE_ENFORCE(index.dims().size() == 1 ||
                 (index.dims().size() == 2 && index.dims()[1] == 1));
80
  int index_size = index.dims()[0];
Z
zchen0211 已提交
81

82
  auto src_dims = src.dims();
Z
zchen0211 已提交
83 84
  auto dst_dims = output->dims();

85
  const T* p_src = src.data<T>();
86
  const IndexT* p_index = index.data<IndexT>();
Z
zchen0211 已提交
87 88
  T* p_output = output->data<T>();

Z
zchen0211 已提交
89
  // check src shape and dst shape should match
Z
zchen0211 已提交
90
  for (int i = 1; i < src_dims.size(); i++)
Z
zchen0211 已提交
91 92 93 94
    PADDLE_ENFORCE(src_dims[i] == dst_dims[i]);

  // slice size
  size_t slice_size = 1;
Z
zchen0211 已提交
95
  for (int i = 1; i < src_dims.size(); ++i) slice_size *= src_dims[i];
Z
zchen0211 已提交
96

Z
1 api  
zchen0211 已提交
97 98 99
  const size_t slice_bytes = slice_size * sizeof(T);

  for (int i = 0; i < index_size; ++i) {
100
    IndexT index_ = p_index[i];
Z
1 api  
zchen0211 已提交
101 102
    memcpy(p_output + index_ * slice_size, p_src + i * slice_size, slice_bytes);
  }
Z
zchen0211 已提交
103 104
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
template <typename T, typename IndexT = int>
void ScatterAssignAdd(const framework::ExecutionContext& ctx, const Tensor& src,
                      const Tensor& index, Tensor* output) {
  PADDLE_ENFORCE(platform::is_cpu_place(ctx.device_context().GetPlace()));
  // check index of shape 1-D
  PADDLE_ENFORCE(index.dims().size() == 1 ||
                 (index.dims().size() == 2 && index.dims()[1] == 1));
  int index_size = index.dims()[0];

  auto src_dims = src.dims();
  auto dst_dims = output->dims();

  const T* p_src = src.data<T>();
  const IndexT* p_index = index.data<IndexT>();

  const T* p_output = output->data<T>();
  T* result_p_output = output->data<T>();

  // check src shape and dst shape should match
  for (int i = 1; i < src_dims.size(); i++)
    PADDLE_ENFORCE(src_dims[i] == dst_dims[i]);

  // slice size
  size_t slice_size = 1;
  for (int i = 1; i < src_dims.size(); ++i) slice_size *= src_dims[i];

  const size_t& slice_bytes = slice_size * sizeof(T);

  // if not in overwrite mode, need to init output data
  for (int i = 0; i < index_size; ++i) {
    const IndexT& index_ = p_index[i];
    memset(result_p_output + slice_size * index_, 0, slice_bytes);
  }

  for (int i = 0; i < index_size; ++i) {
    const IndexT& index_ = p_index[i];
    elementwise_inner_add<T, IndexT>(ctx, p_src, p_output, result_p_output, src,
                                     output, i, index_, slice_size,
                                     slice_bytes);
  }
}

Z
zchen0211 已提交
147 148
}  // namespace operators
}  // namespace paddle