| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- ///////////////////////////////////////////////////////////////////////
- // File: networkscratch.h
- // Description: Scratch space for Network layers that hides distinction
- // between float/int implementations.
- // Author: Ray Smith
- //
- // (C) Copyright 2014, Google Inc.
- // 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.
- ///////////////////////////////////////////////////////////////////////
- #ifndef TESSERACT_LSTM_NETWORKSCRATCH_H_
- #define TESSERACT_LSTM_NETWORKSCRATCH_H_
- #include "genericvector.h"
- #include "matrix.h"
- #include "networkio.h"
- #include "svutil.h"
- namespace tesseract {
- // Generic scratch space for network layers. Provides NetworkIO that can store
- // a complete set (over time) of intermediates, and GenericVector<float>
- // scratch space that auto-frees after use. The aim here is to provide a set
- // of temporary buffers to network layers that can be reused between layers
- // and don't have to be reallocated on each call.
- class NetworkScratch {
- public:
- NetworkScratch() : int_mode_(false) {}
- ~NetworkScratch() = default;
- // Sets the network representation. If the representation is integer, then
- // default (integer) NetworkIOs are separated from the always-float variety.
- // This saves memory by having separate int-specific and float-specific
- // stacks. If the network representation is float, then all NetworkIOs go
- // to the float stack.
- void set_int_mode(bool int_mode) {
- int_mode_ = int_mode;
- }
- // Class that acts like a NetworkIO (by having an implicit cast operator),
- // yet actually holds a pointer to NetworkIOs in the source NetworkScratch,
- // and knows how to unstack the borrowed pointers on destruction.
- class IO {
- public:
- // The NetworkIO should be sized after construction.
- IO(const NetworkIO& src, NetworkScratch* scratch)
- : int_mode_(scratch->int_mode_ && src.int_mode()),
- scratch_space_(scratch) {
- network_io_ = int_mode_ ? scratch_space_->int_stack_.Borrow()
- : scratch_space_->float_stack_.Borrow();
- }
- // Default constructor for arrays. Use one of the Resize functions
- // below to initialize and size.
- IO() : int_mode_(false), network_io_(nullptr), scratch_space_(nullptr) {}
- ~IO() {
- if (scratch_space_ == nullptr) {
- ASSERT_HOST(network_io_ == nullptr);
- } else if (int_mode_) {
- scratch_space_->int_stack_.Return(network_io_);
- } else {
- scratch_space_->float_stack_.Return(network_io_);
- }
- }
- // Resizes the array (and stride), avoiding realloc if possible, to the
- // size from various size specs:
- // Same time size, given number of features.
- void Resize(const NetworkIO& src, int num_features,
- NetworkScratch* scratch) {
- if (scratch_space_ == nullptr) {
- int_mode_ = scratch->int_mode_ && src.int_mode();
- scratch_space_ = scratch;
- network_io_ = int_mode_ ? scratch_space_->int_stack_.Borrow()
- : scratch_space_->float_stack_.Borrow();
- }
- network_io_->Resize(src, num_features);
- }
- // Resizes to a specific size as a temp buffer. No batches, no y-dim.
- void Resize2d(bool int_mode, int width, int num_features,
- NetworkScratch* scratch) {
- if (scratch_space_ == nullptr) {
- int_mode_ = scratch->int_mode_ && int_mode;
- scratch_space_ = scratch;
- network_io_ = int_mode_ ? scratch_space_->int_stack_.Borrow()
- : scratch_space_->float_stack_.Borrow();
- }
- network_io_->Resize2d(int_mode, width, num_features);
- }
- // Resize forcing a float representation with the width of src and the given
- // number of features.
- void ResizeFloat(const NetworkIO& src, int num_features,
- NetworkScratch* scratch) {
- if (scratch_space_ == nullptr) {
- int_mode_ = false;
- scratch_space_ = scratch;
- network_io_ = scratch_space_->float_stack_.Borrow();
- }
- network_io_->ResizeFloat(src, num_features);
- }
- // Returns a ref to a NetworkIO that enables *this to be treated as if
- // it were just a NetworkIO*.
- NetworkIO& operator*() {
- return *network_io_;
- }
- NetworkIO* operator->() {
- return network_io_;
- }
- operator NetworkIO*() {
- return network_io_;
- }
- private:
- // True if this is from the always-float stack, otherwise the default stack.
- bool int_mode_;
- // The NetworkIO that we have borrowed from the scratch_space_.
- NetworkIO* network_io_;
- // The source scratch_space_. Borrowed pointer, used to free the
- // NetworkIO. Don't delete!
- NetworkScratch* scratch_space_;
- }; // class IO.
- // Class that acts like a fixed array of float, yet actually uses space
- // from a GenericVector<float> in the source NetworkScratch, and knows how
- // to unstack the borrowed vector on destruction.
- class FloatVec {
- public:
- // The array will have size elements in it, uninitialized.
- FloatVec(int size, NetworkScratch* scratch)
- : vec_(nullptr), scratch_space_(scratch) {
- Init(size, scratch);
- }
- // Default constructor is for arrays. Use Init to setup.
- FloatVec() : vec_(nullptr), data_(nullptr), scratch_space_(nullptr) {}
- ~FloatVec() {
- if (scratch_space_ != nullptr) scratch_space_->vec_stack_.Return(vec_);
- }
- void Init(int size, NetworkScratch* scratch) {
- if (scratch_space_ != nullptr && vec_ != nullptr)
- scratch_space_->vec_stack_.Return(vec_);
- scratch_space_ = scratch;
- vec_ = scratch_space_->vec_stack_.Borrow();
- vec_->resize_no_init(size);
- data_ = &(*vec_)[0];
- }
- // Use the cast operator instead of operator[] so the FloatVec can be used
- // as a double* argument to a function call.
- operator double*() const { return data_; }
- double* get() { return data_; }
- private:
- // Vector borrowed from the scratch space. Use Return to free it.
- GenericVector<double>* vec_;
- // Short-cut pointer to the underlying array.
- double* data_;
- // The source scratch_space_. Borrowed pointer, used to free the
- // vector. Don't delete!
- NetworkScratch* scratch_space_;
- }; // class FloatVec
- // Class that acts like a 2-D array of double, yet actually uses space
- // from the source NetworkScratch, and knows how to unstack the borrowed
- // array on destruction.
- class GradientStore {
- public:
- // Default constructor is for arrays. Use Init to setup.
- GradientStore() : array_(nullptr), scratch_space_(nullptr) {}
- ~GradientStore() {
- if (scratch_space_ != nullptr) scratch_space_->array_stack_.Return(array_);
- }
- void Init(int size1, int size2, NetworkScratch* scratch) {
- if (scratch_space_ != nullptr && array_ != nullptr)
- scratch_space_->array_stack_.Return(array_);
- scratch_space_ = scratch;
- array_ = scratch_space_->array_stack_.Borrow();
- array_->Resize(size1, size2, 0.0);
- }
- // Accessors to get to the underlying TransposedArray.
- TransposedArray* get() const { return array_; }
- const TransposedArray& operator*() const { return *array_; }
- private:
- // Array borrowed from the scratch space. Use Return to free it.
- TransposedArray* array_;
- // The source scratch_space_. Borrowed pointer, used to free the
- // vector. Don't delete!
- NetworkScratch* scratch_space_;
- }; // class GradientStore
- // Class that does the work of holding a stack of objects, a stack pointer
- // and a vector of in-use flags, so objects can be returned out of order.
- // It is safe to attempt to Borrow/Return in multiple threads.
- template<typename T> class Stack {
- public:
- Stack() : stack_top_(0) {
- }
- // Lends out the next free item, creating one if none available, sets
- // the used flags and increments the stack top.
- T* Borrow() {
- SVAutoLock lock(&mutex_);
- if (stack_top_ == stack_.size()) {
- stack_.push_back(new T);
- flags_.push_back(false);
- }
- flags_[stack_top_] = true;
- return stack_[stack_top_++];
- }
- // Takes back the given item, and marks it free. Item does not have to be
- // the most recently lent out, but free slots don't get re-used until the
- // blocking item is returned. The assumption is that there will only be
- // small, temporary variations from true stack use. (Determined by the order
- // of destructors within a local scope.)
- void Return(T* item) {
- SVAutoLock lock(&mutex_);
- // Linear search will do.
- int index = stack_top_ - 1;
- while (index >= 0 && stack_[index] != item) --index;
- if (index >= 0) flags_[index] = false;
- while (stack_top_ > 0 && !flags_[stack_top_ - 1]) --stack_top_;
- }
- private:
- PointerVector<T> stack_;
- GenericVector<bool> flags_;
- int stack_top_;
- SVMutex mutex_;
- }; // class Stack.
- private:
- // If true, the network weights are int8_t, if false, float.
- bool int_mode_;
- // Stacks of NetworkIO and GenericVector<float>. Once allocated, they are not
- // deleted until the NetworkScratch is deleted.
- Stack<NetworkIO> int_stack_;
- Stack<NetworkIO> float_stack_;
- Stack<GenericVector<double> > vec_stack_;
- Stack<TransposedArray> array_stack_;
- };
- } // namespace tesseract.
- #endif // TESSERACT_LSTM_NETWORKSCRATCH_H_
|