mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2024-12-04 01:39:16 +08:00
8f7be2e72c
Signed-off-by: Stefan Weil <sw@weilnetz.de>
258 lines
9.7 KiB
C++
258 lines
9.7 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// File: networkscratch.h
|
|
// Description: Scratch space for Network layers that hides distinction
|
|
// between float/int implementations.
|
|
// Author: Ray Smith
|
|
// Created: Thu Jun 19 10:50:29 PST 2014
|
|
//
|
|
// (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"
|
|
#include "tprintf.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() {}
|
|
|
|
// 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_
|