Caffe2 - C++ API
A deep learning, cross platform ML framework
sinusoid_position_encoding_op.h
1 #ifndef CAFFE2_OPERATORS_SINUSOID_POSITION_ENCODING_OP_H_
2 #define CAFFE2_OPERATORS_SINUSOID_POSITION_ENCODING_OP_H_
3 
4 #ifdef _MSC_VER
5 #define _USE_MATH_DEFINES
6 #endif // _MSC_VER
7 #include <cmath>
8 
9 #include "caffe2/core/operator.h"
10 
11 #include "Eigen/Core"
12 #include "caffe2/utils/eigen_utils.h"
13 
14 namespace caffe2 {
15 
16 template <class Context>
17 class SinusoidPositionEncodingOp : public Operator<Context> {
18  public:
19  template <class... Args>
20  explicit SinusoidPositionEncodingOp(Args&&... args)
21  : Operator<Context>(std::forward<Args>(args)...),
22  embedding_size_(
23  this->template GetSingleArgument<int>("embedding_size", 100)),
24  alpha_(this->template GetSingleArgument<float>("alpha", 10000)),
25  amplitude_(this->template GetSingleArgument<float>("amplitude", 1)) {}
26  USE_OPERATOR_CONTEXT_FUNCTIONS;
27 
28  bool RunOnDevice() override {
30  this, this->template Input<Tensor>(0, CPU));
31  }
32 
33  template <typename Index>
34  bool DoRunWithType() {
35  auto& positions = Input(0);
36 
37  CAFFE_ENFORCE_EQ(positions.dim(), 2, "POSITIONS should be a 2-D tensor");
38 
39  auto shape = positions.sizes().vec();
40  shape.push_back(embedding_size_);
41  auto* output = Output(0, shape, at::dtype<float>());
42 
43  int M = shape[0];
44  int K = shape[1];
45  const Index* idxs = positions.template data<Index>();
46  float* out = output->template mutable_data<float>();
47 
48  float log_alpha = std::log(alpha_);
49  float max_alpha_pow =
50  ((float)embedding_size_ - 1.0f) / (float)embedding_size_;
51 
52  for (int i = 0; i < M; ++i) {
53  float pos = (float)idxs[i * K];
54 
55  // Compute the embedding for position i, example 0 first
56  float* row = &out[i * K * embedding_size_];
57  Eigen::Map<Eigen::VectorXf> row_map(row, embedding_size_, 1);
58  auto row_array = row_map.array();
59 
60  float log_pos = std::log(pos);
61  row_array.setLinSpaced(
62  embedding_size_, log_pos, log_pos - log_alpha * max_alpha_pow);
63  row_array = row_array.exp().eval();
64  // row_array[k] == pos / alpha^(k / embedding_size)
65 
66  // Phase shift so that alternating elements are cosines
67  for (int k = 1; k < embedding_size_; k += 2) {
68  row[k] += (float)M_PI_2;
69  }
70  row_array = amplitude_ * row_array.sin().eval();
71 
72  // Copy the embedding to position i in the other examples
73  for (int j = 1; j < K; ++j) {
74  int base = i * K * embedding_size_;
75  std::copy(
76  &out[base],
77  &out[base + embedding_size_],
78  &out[base + j * embedding_size_]);
79  }
80  }
81  return true;
82  }
83 
84  protected:
85  int embedding_size_;
86  float alpha_;
87  float amplitude_;
88 };
89 
90 } // namespace caffe2
91 
92 #endif // CAFFE2_OPERATORS_SINUSOID_POSITION_ENCODING_OP_H_
Definition: any.cpp:108
const Tensor & Input(int idx, DeviceType type=Context::GetDeviceType())
Retrieve a non-owning reference to the input at position &#39;idx&#39; for this operator. ...
Definition: operator.h:702
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13