1 ///////////////////////////////////////////////////////////////////////
2 // File:        convolve.cpp
3 // Description: Convolutional layer that stacks the inputs over its rectangle
4 //              and pulls in random data to fill out-of-input inputs.
5 //              Output is therefore same size as its input, but deeper.
6 // Author:      Ray Smith
7 //
8 // (C) Copyright 2014, Google Inc.
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 ///////////////////////////////////////////////////////////////////////
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config_auto.h"
22 #endif
23 
24 #include "convolve.h"
25 
26 #include "networkscratch.h"
27 #include "serialis.h"
28 
29 namespace tesseract {
30 
Convolve(const std::string & name,int ni,int half_x,int half_y)31 Convolve::Convolve(const std::string &name, int ni, int half_x, int half_y)
32     : Network(NT_CONVOLVE, name, ni, ni * (2 * half_x + 1) * (2 * half_y + 1))
33     , half_x_(half_x)
34     , half_y_(half_y) {}
35 
36 // Writes to the given file. Returns false in case of error.
Serialize(TFile * fp) const37 bool Convolve::Serialize(TFile *fp) const {
38   return Network::Serialize(fp) && fp->Serialize(&half_x_) && fp->Serialize(&half_y_);
39 }
40 
41 // Reads from the given file. Returns false in case of error.
DeSerialize(TFile * fp)42 bool Convolve::DeSerialize(TFile *fp) {
43   if (!fp->DeSerialize(&half_x_)) {
44     return false;
45   }
46   if (!fp->DeSerialize(&half_y_)) {
47     return false;
48   }
49   no_ = ni_ * (2 * half_x_ + 1) * (2 * half_y_ + 1);
50   return true;
51 }
52 
53 // Runs forward propagation of activations on the input line.
54 // See NetworkCpp for a detailed discussion of the arguments.
Forward(bool debug,const NetworkIO & input,const TransposedArray * input_transpose,NetworkScratch * scratch,NetworkIO * output)55 void Convolve::Forward(bool debug, const NetworkIO &input, const TransposedArray *input_transpose,
56                        NetworkScratch *scratch, NetworkIO *output) {
57   output->Resize(input, no_);
58   int y_scale = 2 * half_y_ + 1;
59   StrideMap::Index dest_index(output->stride_map());
60   do {
61     // Stack x_scale groups of y_scale * ni_ inputs together.
62     int t = dest_index.t();
63     int out_ix = 0;
64     for (int x = -half_x_; x <= half_x_; ++x, out_ix += y_scale * ni_) {
65       StrideMap::Index x_index(dest_index);
66       if (!x_index.AddOffset(x, FD_WIDTH)) {
67         // This x is outside the image.
68         output->Randomize(t, out_ix, y_scale * ni_, randomizer_);
69       } else {
70         int out_iy = out_ix;
71         for (int y = -half_y_; y <= half_y_; ++y, out_iy += ni_) {
72           StrideMap::Index y_index(x_index);
73           if (!y_index.AddOffset(y, FD_HEIGHT)) {
74             // This y is outside the image.
75             output->Randomize(t, out_iy, ni_, randomizer_);
76           } else {
77             output->CopyTimeStepGeneral(t, out_iy, ni_, input, y_index.t(), 0);
78           }
79         }
80       }
81     }
82   } while (dest_index.Increment());
83 #ifndef GRAPHICS_DISABLED
84   if (debug) {
85     DisplayForward(*output);
86   }
87 #endif
88 }
89 
90 // Runs backward propagation of errors on the deltas line.
91 // See NetworkCpp for a detailed discussion of the arguments.
Backward(bool debug,const NetworkIO & fwd_deltas,NetworkScratch * scratch,NetworkIO * back_deltas)92 bool Convolve::Backward(bool debug, const NetworkIO &fwd_deltas, NetworkScratch *scratch,
93                         NetworkIO *back_deltas) {
94   back_deltas->Resize(fwd_deltas, ni_);
95   NetworkScratch::IO delta_sum;
96   delta_sum.ResizeFloat(fwd_deltas, ni_, scratch);
97   delta_sum->Zero();
98   int y_scale = 2 * half_y_ + 1;
99   StrideMap::Index src_index(fwd_deltas.stride_map());
100   do {
101     // Stack x_scale groups of y_scale * ni_ inputs together.
102     int t = src_index.t();
103     int out_ix = 0;
104     for (int x = -half_x_; x <= half_x_; ++x, out_ix += y_scale * ni_) {
105       StrideMap::Index x_index(src_index);
106       if (x_index.AddOffset(x, FD_WIDTH)) {
107         int out_iy = out_ix;
108         for (int y = -half_y_; y <= half_y_; ++y, out_iy += ni_) {
109           StrideMap::Index y_index(x_index);
110           if (y_index.AddOffset(y, FD_HEIGHT)) {
111             fwd_deltas.AddTimeStepPart(t, out_iy, ni_, delta_sum->f(y_index.t()));
112           }
113         }
114       }
115     }
116   } while (src_index.Increment());
117   back_deltas->CopyAll(*delta_sum);
118   return true;
119 }
120 
121 } // namespace tesseract.
122