tesseract  4.00.00dev
tesseract::WeightMatrix Class Reference

#include <weightmatrix.h>

Public Member Functions

 WeightMatrix ()
 
int InitWeightsFloat (int no, int ni, bool use_adam, float weight_range, TRand *randomizer)
 
int RemapOutputs (const std::vector< int > &code_map)
 
void ConvertToInt ()
 
int RoundInputs (int size) const
 
bool is_int_mode () const
 
int NumOutputs () const
 
const double * GetWeights (int index) const
 
double GetDW (int i, int j) const
 
void InitBackward ()
 
bool Serialize (bool training, TFile *fp) const
 
bool DeSerialize (bool training, TFile *fp)
 
bool DeSerializeOld (bool training, TFile *fp)
 
void MatrixDotVector (const double *u, double *v) const
 
void MatrixDotVector (const inT8 *u, double *v) const
 
void MultiplyAccumulate (const double *v, double *inout)
 
void VectorDotMatrix (const double *u, double *v) const
 
void SumOuterTransposed (const TransposedArray &u, const TransposedArray &v, bool parallel)
 
void Update (double learning_rate, double momentum, double adam_beta, int num_samples)
 
void AddDeltas (const WeightMatrix &other)
 
void CountAlternators (const WeightMatrix &other, double *same, double *changed) const
 
void Debug2D (const char *msg)
 

Static Public Member Functions

static double DotProduct (const double *u, const double *v, int n)
 
static void FloatToDouble (const GENERIC_2D_ARRAY< float > &wf, GENERIC_2D_ARRAY< double > *wd)
 

Detailed Description

Definition at line 65 of file weightmatrix.h.

Constructor & Destructor Documentation

◆ WeightMatrix()

tesseract::WeightMatrix::WeightMatrix ( )
inline

Definition at line 67 of file weightmatrix.h.

67 : int_mode_(false), use_adam_(false) {}

Member Function Documentation

◆ AddDeltas()

void tesseract::WeightMatrix::AddDeltas ( const WeightMatrix other)

Definition at line 300 of file weightmatrix.cpp.

300  {
301  ASSERT_HOST(dw_.dim1() == other.dw_.dim1());
302  ASSERT_HOST(dw_.dim2() == other.dw_.dim2());
303  dw_ += other.dw_;
304 }
int dim2() const
Definition: matrix.h:206
#define ASSERT_HOST(x)
Definition: errcode.h:84
int dim1() const
Definition: matrix.h:205

◆ ConvertToInt()

void tesseract::WeightMatrix::ConvertToInt ( )

Definition at line 94 of file weightmatrix.cpp.

94  {
95  wi_.ResizeNoInit(wf_.dim1(), wf_.dim2());
96  scales_.init_to_size(wi_.dim1(), 0.0);
97  int dim2 = wi_.dim2();
98  for (int t = 0; t < wi_.dim1(); ++t) {
99  double* f_line = wf_[t];
100  inT8* i_line = wi_[t];
101  double max_abs = 0.0;
102  for (int f = 0; f < dim2; ++f) {
103  double abs_val = fabs(f_line[f]);
104  if (abs_val > max_abs) max_abs = abs_val;
105  }
106  double scale = max_abs / MAX_INT8;
107  scales_[t] = scale;
108  if (scale == 0.0) scale = 1.0;
109  for (int f = 0; f < dim2; ++f) {
110  i_line[f] = IntCastRounded(f_line[f] / scale);
111  }
112  }
113  wf_.Resize(1, 1, 0.0);
114  int_mode_ = true;
115  multiplier_.reset(IntSimdMatrix::GetFastestMultiplier());
116  if (multiplier_ != nullptr) multiplier_->Init(wi_);
117 }
#define MAX_INT8
Definition: host.h:60
void ResizeNoInit(int size1, int size2, int pad=0)
Definition: matrix.h:88
void Resize(int size1, int size2, const T &empty)
Definition: matrix.h:102
int dim2() const
Definition: matrix.h:206
int8_t inT8
Definition: host.h:34
int IntCastRounded(double x)
Definition: helpers.h:179
void init_to_size(int size, T t)
static IntSimdMatrix * GetFastestMultiplier()
int dim1() const
Definition: matrix.h:205

◆ CountAlternators()

void tesseract::WeightMatrix::CountAlternators ( const WeightMatrix other,
double *  same,
double *  changed 
) const

Definition at line 309 of file weightmatrix.cpp.

310  {
311  int num_outputs = updates_.dim1();
312  int num_inputs = updates_.dim2();
313  ASSERT_HOST(num_outputs == other.updates_.dim1());
314  ASSERT_HOST(num_inputs == other.updates_.dim2());
315  for (int i = 0; i < num_outputs; ++i) {
316  const double* this_i = updates_[i];
317  const double* other_i = other.updates_[i];
318  for (int j = 0; j < num_inputs; ++j) {
319  double product = this_i[j] * other_i[j];
320  if (product < 0.0)
321  *changed -= product;
322  else
323  *same += product;
324  }
325  }
326 }
int dim2() const
Definition: matrix.h:206
#define ASSERT_HOST(x)
Definition: errcode.h:84
int dim1() const
Definition: matrix.h:205

◆ Debug2D()

void tesseract::WeightMatrix::Debug2D ( const char *  msg)

Definition at line 340 of file weightmatrix.cpp.

340  {
341  STATS histogram(0, kHistogramBuckets);
342  if (int_mode_) {
343  for (int i = 0; i < wi_.dim1(); ++i) {
344  for (int j = 0; j < wi_.dim2(); ++j) {
345  HistogramWeight(wi_[i][j] * scales_[i], &histogram);
346  }
347  }
348  } else {
349  for (int i = 0; i < wf_.dim1(); ++i) {
350  for (int j = 0; j < wf_.dim2(); ++j) {
351  HistogramWeight(wf_[i][j], &histogram);
352  }
353  }
354  }
355  tprintf("%s\n", msg);
356  histogram.print();
357 }
#define tprintf(...)
Definition: tprintf.h:31
int dim2() const
Definition: matrix.h:206
const int kHistogramBuckets
Definition: statistc.h:33
int dim1() const
Definition: matrix.h:205

◆ DeSerialize()

bool tesseract::WeightMatrix::DeSerialize ( bool  training,
TFile fp 
)

Definition at line 159 of file weightmatrix.cpp.

159  {
160  uinT8 mode = 0;
161  if (fp->FRead(&mode, sizeof(mode), 1) != 1) return false;
162  int_mode_ = (mode & kInt8Flag) != 0;
163  use_adam_ = (mode & kAdamFlag) != 0;
164  if ((mode & kDoubleFlag) == 0) return DeSerializeOld(training, fp);
165  if (int_mode_) {
166  if (!wi_.DeSerialize(fp)) return false;
167  if (!scales_.DeSerialize(fp)) return false;
168  multiplier_.reset(IntSimdMatrix::GetFastestMultiplier());
169  if (multiplier_ != nullptr) multiplier_->Init(wi_);
170  } else {
171  if (!wf_.DeSerialize(fp)) return false;
172  if (training) {
173  InitBackward();
174  if (!updates_.DeSerialize(fp)) return false;
175  if (use_adam_ && !dw_sq_sum_.DeSerialize(fp)) return false;
176  }
177  }
178  return true;
179 }
const int kDoubleFlag
const int kInt8Flag
uint8_t uinT8
Definition: host.h:35
bool DeSerialize(bool swap, FILE *fp)
Definition: matrix.h:159
const int kAdamFlag
bool DeSerialize(bool swap, FILE *fp)
CMD_EVENTS mode
Definition: pgedit.cpp:116
static IntSimdMatrix * GetFastestMultiplier()
bool DeSerializeOld(bool training, TFile *fp)

◆ DeSerializeOld()

bool tesseract::WeightMatrix::DeSerializeOld ( bool  training,
TFile fp 
)

Definition at line 183 of file weightmatrix.cpp.

183  {
184  GENERIC_2D_ARRAY<float> float_array;
185  if (int_mode_) {
186  if (!wi_.DeSerialize(fp)) return false;
187  GenericVector<float> old_scales;
188  if (!old_scales.DeSerialize(fp)) return false;
189  scales_.resize_no_init(old_scales.size());
190  for (int i = 0; i < old_scales.size(); ++i) scales_[i] = old_scales[i];
191  } else {
192  if (!float_array.DeSerialize(fp)) return false;
193  FloatToDouble(float_array, &wf_);
194  }
195  if (training) {
196  InitBackward();
197  if (!float_array.DeSerialize(fp)) return false;
198  FloatToDouble(float_array, &updates_);
199  // Errs was only used in int training, which is now dead.
200  if (!float_array.DeSerialize(fp)) return false;
201  }
202  return true;
203 }
void resize_no_init(int size)
Definition: genericvector.h:66
int size() const
Definition: genericvector.h:72
static void FloatToDouble(const GENERIC_2D_ARRAY< float > &wf, GENERIC_2D_ARRAY< double > *wd)
bool DeSerialize(bool swap, FILE *fp)
Definition: matrix.h:159
bool DeSerialize(bool swap, FILE *fp)

◆ DotProduct()

double tesseract::WeightMatrix::DotProduct ( const double *  u,
const double *  v,
int  n 
)
static

Definition at line 361 of file weightmatrix.cpp.

361  {
362  // Note: because the order of addition is different among the 3 DotProduct
363  // functions, the results can (and do) vary slightly (although they agree
364  // to within about 4e-15). This produces different results when running
365  // training, despite all random inputs being precisely equal.
366  // To get consistent results, use just one of these DotProduct functions.
367  // On a test multi-layer network, serial is 57% slower than sse, and avx
368  // is about 8% faster than sse. This suggests that the time is memory
369  // bandwidth constrained and could benefit from holding the reused vector
370  // in AVX registers.
371  if (SIMDDetect::IsAVXAvailable()) return DotProductAVX(u, v, n);
372  if (SIMDDetect::IsSSEAvailable()) return DotProductSSE(u, v, n);
373  double total = 0.0;
374  for (int k = 0; k < n; ++k) total += u[k] * v[k];
375  return total;
376 }
static bool IsSSEAvailable()
Definition: simddetect.h:38
double DotProductSSE(const double *u, const double *v, int n)
double DotProductAVX(const double *u, const double *v, int n)
static bool IsAVXAvailable()
Definition: simddetect.h:26

◆ FloatToDouble()

void tesseract::WeightMatrix::FloatToDouble ( const GENERIC_2D_ARRAY< float > &  wf,
GENERIC_2D_ARRAY< double > *  wd 
)
static

Definition at line 381 of file weightmatrix.cpp.

382  {
383  int dim1 = wf.dim1();
384  int dim2 = wf.dim2();
385  wd->ResizeNoInit(dim1, dim2);
386  for (int i = 0; i < dim1; ++i) {
387  const float* wfi = wf[i];
388  double* wdi = (*wd)[i];
389  for (int j = 0; j < dim2; ++j) wdi[j] = static_cast<double>(wfi[j]);
390  }
391 }
void ResizeNoInit(int size1, int size2, int pad=0)
Definition: matrix.h:88
int dim2() const
Definition: matrix.h:206
int dim1() const
Definition: matrix.h:205

◆ GetDW()

double tesseract::WeightMatrix::GetDW ( int  i,
int  j 
) const
inline

Definition at line 105 of file weightmatrix.h.

105 { return dw_(i, j); }

◆ GetWeights()

const double* tesseract::WeightMatrix::GetWeights ( int  index) const
inline

Definition at line 103 of file weightmatrix.h.

103 { return wf_[index]; }

◆ InitBackward()

void tesseract::WeightMatrix::InitBackward ( )

Definition at line 121 of file weightmatrix.cpp.

121  {
122  int no = int_mode_ ? wi_.dim1() : wf_.dim1();
123  int ni = int_mode_ ? wi_.dim2() : wf_.dim2();
124  dw_.Resize(no, ni, 0.0);
125  updates_.Resize(no, ni, 0.0);
126  wf_t_.Transpose(wf_);
127  if (use_adam_) dw_sq_sum_.Resize(no, ni, 0.0);
128 }
void Resize(int size1, int size2, const T &empty)
Definition: matrix.h:102
void Transpose(const GENERIC_2D_ARRAY< double > &input)
int dim2() const
Definition: matrix.h:206
int dim1() const
Definition: matrix.h:205

◆ InitWeightsFloat()

int tesseract::WeightMatrix::InitWeightsFloat ( int  no,
int  ni,
bool  use_adam,
float  weight_range,
TRand randomizer 
)

Definition at line 45 of file weightmatrix.cpp.

46  {
47  int_mode_ = false;
48  wf_.Resize(no, ni, 0.0);
49  if (randomizer != NULL) {
50  for (int i = 0; i < no; ++i) {
51  for (int j = 0; j < ni; ++j) {
52  wf_[i][j] = randomizer->SignedRand(weight_range);
53  }
54  }
55  }
56  use_adam_ = use_adam;
57  InitBackward();
58  return ni * no;
59 }
void Resize(int size1, int size2, const T &empty)
Definition: matrix.h:102

◆ is_int_mode()

bool tesseract::WeightMatrix::is_int_mode ( ) const
inline

Definition at line 98 of file weightmatrix.h.

98  {
99  return int_mode_;
100  }

◆ MatrixDotVector() [1/2]

void tesseract::WeightMatrix::MatrixDotVector ( const double *  u,
double *  v 
) const

Definition at line 210 of file weightmatrix.cpp.

210  {
211  ASSERT_HOST(!int_mode_);
212  MatrixDotVectorInternal(wf_, true, false, u, v);
213 }
#define ASSERT_HOST(x)
Definition: errcode.h:84

◆ MatrixDotVector() [2/2]

void tesseract::WeightMatrix::MatrixDotVector ( const inT8 u,
double *  v 
) const

Definition at line 215 of file weightmatrix.cpp.

215  {
216  ASSERT_HOST(int_mode_);
217  ASSERT_HOST(multiplier_ != nullptr);
218  multiplier_->MatrixDotVector(wi_, scales_, u, v);
219 }
#define ASSERT_HOST(x)
Definition: errcode.h:84

◆ MultiplyAccumulate()

void tesseract::WeightMatrix::MultiplyAccumulate ( const double *  v,
double *  inout 
)

Definition at line 223 of file weightmatrix.cpp.

223  {
224  ASSERT_HOST(!int_mode_);
225  ASSERT_HOST(wf_.dim1() == 1);
226  int n = wf_.dim2();
227  const double* u = wf_[0];
228  for (int i = 0; i < n; ++i) {
229  inout[i] += u[i] * v[i];
230  }
231 }
int dim2() const
Definition: matrix.h:206
#define ASSERT_HOST(x)
Definition: errcode.h:84
int dim1() const
Definition: matrix.h:205

◆ NumOutputs()

int tesseract::WeightMatrix::NumOutputs ( ) const
inline

Definition at line 101 of file weightmatrix.h.

101 { return int_mode_ ? wi_.dim1() : wf_.dim1(); }
int dim1() const
Definition: matrix.h:205

◆ RemapOutputs()

int tesseract::WeightMatrix::RemapOutputs ( const std::vector< int > &  code_map)

Definition at line 66 of file weightmatrix.cpp.

66  {
67  GENERIC_2D_ARRAY<double> old_wf(wf_);
68  int old_no = wf_.dim1();
69  int new_no = code_map.size();
70  int ni = wf_.dim2();
71  std::vector<double> means(ni, 0.0);
72  for (int c = 0; c < old_no; ++c) {
73  const double* weights = wf_[c];
74  for (int i = 0; i < ni; ++i) means[i] += weights[i];
75  }
76  for (double& mean : means) mean /= old_no;
77  wf_.ResizeNoInit(new_no, ni);
78  InitBackward();
79  for (int dest = 0; dest < new_no; ++dest) {
80  int src = code_map[dest];
81  const double* src_data = src >= 0 ? old_wf[src] : means.data();
82  memcpy(wf_[dest], src_data, ni * sizeof(*src_data));
83  }
84  return ni * new_no;
85 }
void ResizeNoInit(int size1, int size2, int pad=0)
Definition: matrix.h:88
int dim2() const
Definition: matrix.h:206
int dim1() const
Definition: matrix.h:205

◆ RoundInputs()

int tesseract::WeightMatrix::RoundInputs ( int  size) const
inline

Definition at line 92 of file weightmatrix.h.

92  {
93  if (multiplier_ == nullptr) return size;
94  return multiplier_->RoundInputs(size);
95  }

◆ Serialize()

bool tesseract::WeightMatrix::Serialize ( bool  training,
TFile fp 
) const

Definition at line 140 of file weightmatrix.cpp.

140  {
141  // For backward compatibility, add kDoubleFlag to mode to indicate the doubles
142  // format, without errs, so we can detect and read old format weight matrices.
143  uinT8 mode =
144  (int_mode_ ? kInt8Flag : 0) | (use_adam_ ? kAdamFlag : 0) | kDoubleFlag;
145  if (fp->FWrite(&mode, sizeof(mode), 1) != 1) return false;
146  if (int_mode_) {
147  if (!wi_.Serialize(fp)) return false;
148  if (!scales_.Serialize(fp)) return false;
149  } else {
150  if (!wf_.Serialize(fp)) return false;
151  if (training && !updates_.Serialize(fp)) return false;
152  if (training && use_adam_ && !dw_sq_sum_.Serialize(fp)) return false;
153  }
154  return true;
155 }
const int kDoubleFlag
bool Serialize(FILE *fp) const
Definition: matrix.h:141
const int kInt8Flag
uint8_t uinT8
Definition: host.h:35
bool Serialize(FILE *fp) const
const int kAdamFlag
CMD_EVENTS mode
Definition: pgedit.cpp:116

◆ SumOuterTransposed()

void tesseract::WeightMatrix::SumOuterTransposed ( const TransposedArray u,
const TransposedArray v,
bool  parallel 
)

Definition at line 247 of file weightmatrix.cpp.

249  {
250  ASSERT_HOST(!int_mode_);
251  int num_outputs = dw_.dim1();
252  ASSERT_HOST(u.dim1() == num_outputs);
253  ASSERT_HOST(u.dim2() == v.dim2());
254  int num_inputs = dw_.dim2() - 1;
255  int num_samples = u.dim2();
256  // v is missing the last element in dim1.
257  ASSERT_HOST(v.dim1() == num_inputs);
258 #ifdef _OPENMP
259 #pragma omp parallel for num_threads(4) if (in_parallel)
260 #endif
261  for (int i = 0; i < num_outputs; ++i) {
262  double* dwi = dw_[i];
263  const double* ui = u[i];
264  for (int j = 0; j < num_inputs; ++j) {
265  dwi[j] = DotProduct(ui, v[j], num_samples);
266  }
267  // The last element of v is missing, presumed 1.0f.
268  double total = 0.0;
269  for (int k = 0; k < num_samples; ++k) total += ui[k];
270  dwi[num_inputs] = total;
271  }
272 }
static double DotProduct(const double *u, const double *v, int n)
int dim2() const
Definition: matrix.h:206
#define ASSERT_HOST(x)
Definition: errcode.h:84
int dim1() const
Definition: matrix.h:205

◆ Update()

void tesseract::WeightMatrix::Update ( double  learning_rate,
double  momentum,
double  adam_beta,
int  num_samples 
)

Definition at line 277 of file weightmatrix.cpp.

278  {
279  ASSERT_HOST(!int_mode_);
280  if (use_adam_ && num_samples > 0 && num_samples < kAdamCorrectionIterations) {
281  learning_rate *= sqrt(1.0 - pow(adam_beta, num_samples));
282  learning_rate /= 1.0 - pow(momentum, num_samples);
283  }
284  if (use_adam_ && num_samples > 0 && momentum > 0.0) {
285  dw_sq_sum_.SumSquares(dw_, adam_beta);
286  dw_ *= learning_rate * (1.0 - momentum);
287  updates_ *= momentum;
288  updates_ += dw_;
289  wf_.AdamUpdate(updates_, dw_sq_sum_, learning_rate * kAdamEpsilon);
290  } else {
291  dw_ *= learning_rate;
292  updates_ += dw_;
293  if (momentum > 0.0) wf_ += updates_;
294  if (momentum >= 0.0) updates_ *= momentum;
295  }
296  wf_t_.Transpose(wf_);
297 }
void AdamUpdate(const GENERIC_2D_ARRAY< T > &sum, const GENERIC_2D_ARRAY< T > &sqsum, T epsilon)
Definition: matrix.h:378
void SumSquares(const GENERIC_2D_ARRAY< T > &src, T decay_factor)
Definition: matrix.h:367
void Transpose(const GENERIC_2D_ARRAY< double > &input)
const double kAdamEpsilon
#define ASSERT_HOST(x)
Definition: errcode.h:84
const int kAdamCorrectionIterations

◆ VectorDotMatrix()

void tesseract::WeightMatrix::VectorDotMatrix ( const double *  u,
double *  v 
) const

Definition at line 237 of file weightmatrix.cpp.

237  {
238  ASSERT_HOST(!int_mode_);
239  MatrixDotVectorInternal(wf_t_, false, true, u, v);
240 }
#define ASSERT_HOST(x)
Definition: errcode.h:84

The documentation for this class was generated from the following files: