Caffe2 - C++ API
A deep learning, cross platform ML framework
iter_op.h
1 #ifndef CAFFE2_SGD_ITER_OP_H_
2 #define CAFFE2_SGD_ITER_OP_H_
3 
4 #include <limits>
5 #include <mutex>
6 
7 #include "caffe2/core/blob_serialization.h"
8 #include "caffe2/core/context.h"
9 #include "caffe2/core/operator.h"
10 #include "caffe2/core/stats.h"
11 
12 namespace caffe2 {
13 
14 inline void IncrementIter(TensorCPU* output) {
15  CAFFE_ENFORCE_EQ(
16  output->numel(),
17  1,
18  "The output of IterOp exists, but not of the right size.");
19  int64_t* iter = output->template mutable_data<int64_t>();
20  CAFFE_ENFORCE(*iter >= 0, "Previous iteration number is negative.");
21  CAFFE_ENFORCE(
22  *iter < std::numeric_limits<int64_t>::max(), "Overflow will happen!");
23  (*iter)++;
24 }
25 
26 // IterOp runs an iteration counter. I cannot think of a case where we would
27 // need to access the iter variable on device, so this will always produce a
28 // tensor on the CPU side. If the blob already exists and is a tensor<int64_t>
29 // object, we will simply increment it (this emulates the case when we want to
30 // resume training). Otherwise we will have the iter starting with 0.
31 template <class Context>
32 class IterOp final : public Operator<Context> {
33  public:
34  USE_OPERATOR_CONTEXT_FUNCTIONS;
35 
36  IterOp(const OperatorDef& operator_def, Workspace* ws)
37  : Operator<Context>(operator_def, ws) {}
38 
39  bool RunOnDevice() override {
40  if (InputSize() == 0) {
41  LOG(INFO) << "[Input size is zero]";
42  if (!OperatorBase::OutputIsTensorType(0, CPU)) {
43  // This is the first run; set the iter to start with 0.
44  LOG(ERROR) << "You are using an old definition of IterOp that will "
45  "be deprecated soon. More specifically, IterOp now "
46  "requires an explicit in-place input and output.";
47 
48  VLOG(1) << "Initializing iter counter.";
49  auto* output = OperatorBase::OutputTensor(
50  0, {1}, at::dtype<int64_t>().device(CPU));
51  output->template mutable_data<int64_t>()[0] = 0;
52  }
53  }
54  IncrementIter(OperatorBase::Output<Tensor>(0, CPU));
55  return true;
56  }
57 };
58 
59 template <class Context>
60 class AtomicIterOp final : public Operator<Context> {
61  public:
62  USE_OPERATOR_CONTEXT_FUNCTIONS;
63 
64  AtomicIterOp(const OperatorDef& operator_def, Workspace* ws)
65  : Operator<Context>(operator_def, ws),
66  stats_(std::string("atomic_iter/stats/") + operator_def.input(1)) {}
67 
68  bool RunOnDevice() override {
69  auto& mutex = OperatorBase::Input<std::unique_ptr<std::mutex>>(0);
70  std::lock_guard<std::mutex> lg(*mutex);
71  IncrementIter(OperatorBase::Output<Tensor>(0, CPU));
72  CAFFE_EVENT(stats_, num_iter);
73  return true;
74  }
75 
76  private:
77  struct AtomicIterOpStats {
78  CAFFE_STAT_CTOR(AtomicIterOpStats);
79  CAFFE_EXPORTED_STAT(num_iter);
80  } stats_;
81 };
82 
84  public:
90  void Serialize(
91  const void* pointer,
92  TypeMeta typeMeta,
93  const string& name,
94  BlobSerializerBase::SerializationAcceptor acceptor) override;
95 };
96 
98  public:
99  void Deserialize(const BlobProto& proto, Blob* blob) override;
100 };
101 
102 } // namespace caffe2
103 
104 #endif // CAFFE2_SGD_ITER_OP_H_
Blob is a general container that hosts a typed pointer.
Definition: blob.h:24
BlobDeserializerBase is an abstract class that deserializes a blob from a BlobProto or a TensorProto...
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:47
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13
TypeMeta is a thin class that allows us to store the type of a container such as a blob...
Definition: typeid.h:324
BlobSerializerBase is an abstract class that serializes a blob to a string.