-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Implement dropout #4554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
stweil
wants to merge
14
commits into
tesseract-ocr:main
Choose a base branch
from
stweil:dropout
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Implement dropout #4554
Changes from 12 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
934f0fb
Add new network layer for dropout
stweil 0cfa2d5
dropout (w.i.p.)
stweil 0f766d9
dropout
stweil 3e8b1a1
Update dropout code (still unfinished)
stweil aad5646
Update dropout code (still unfinished)
stweil a9e3904
Update dropout code (still unfinished)
stweil 41af4f8
Update dropout code
stweil 172d6a5
Update dropout code (created with help from qwen3-coder)
stweil fec422f
Fix range check for dropout rate
stweil cac70b2
Update dummy dropout code
stweil bf0a596
lstm: Implement Dropout layer Forward and Backward passes
stweil 0fc02f3
lstm: Add dimension parameter for Dropout layer
stweil 90bff03
Add float variant of helper function UnsignedRand
stweil 1aaae51
Use unsigned dimension for dropout
stweil File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| /////////////////////////////////////////////////////////////////////// | ||
| // File: dropout.cpp | ||
| // Description: Dropout layer. | ||
| // Author: Stefan Weil | ||
| // | ||
| // 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. | ||
| /////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #ifdef HAVE_CONFIG_H | ||
| # include "config_auto.h" | ||
| #endif | ||
|
|
||
| #include "dropout.h" | ||
| #include "networkscratch.h" | ||
| #include "serialis.h" | ||
| #include "tesserrstream.h" // for tesserr | ||
|
|
||
| namespace tesseract { | ||
|
|
||
| Dropout::Dropout(const std::string &name, int ni, float dropout_rate, int dropout_dim) | ||
| : Network(NT_DROPOUT, name, ni, ni), | ||
| dropout_mask_(), | ||
| dropout_rate_(dropout_rate), | ||
| dropout_dim_(dropout_dim) { | ||
| if (dropout_rate_ < 0 || dropout_rate_ >= 1) { | ||
| throw std::invalid_argument("Invalid dropout rate. Must be in [0, 1)."); | ||
| } | ||
| if (dropout_dim_ < 0 || dropout_dim_ > 2) { | ||
| throw std::invalid_argument("Invalid dropout dim. Must be 0, 1 or 2."); | ||
| } | ||
| } | ||
|
|
||
| void Dropout::DebugWeights() { | ||
| tesserr << "Dropout layer '" << name_ << "': rate=" << dropout_rate_ << '\n'; | ||
| } | ||
|
|
||
| // Writes to the given file. Returns false in case of error. | ||
| bool Dropout::Serialize(TFile *fp) const { | ||
| // dropout_mask_ is runtime data and is not serialized. | ||
| return Network::Serialize(fp) && | ||
| fp->Serialize(&dropout_rate_) && | ||
| fp->Serialize(&dropout_dim_); | ||
| } | ||
|
|
||
| // Reads from the given file. Returns false in case of error. | ||
| bool Dropout::DeSerialize(TFile *fp) { | ||
| if (!fp->DeSerialize(&dropout_rate_)) { | ||
| return false; | ||
| } | ||
| if (!fp->DeSerialize(&dropout_dim_)) { | ||
| return false; | ||
| } | ||
| no_ = ni_; | ||
| return true; | ||
| } | ||
|
|
||
| // Runs forward propagation of activations on the input line. | ||
| // See Network for a detailed discussion of the arguments. | ||
| void Dropout::Forward(bool debug, const NetworkIO &input, | ||
| const TransposedArray *input_transpose, | ||
| NetworkScratch *scratch, NetworkIO *output) { | ||
| // Output has the same shape as input (ni_ == no_). | ||
| output->Resize(input, no_); | ||
|
|
||
| int width = input.Width(); | ||
| int num_features = input.NumFeatures(); | ||
|
|
||
| if (IsTraining() && dropout_rate_ > 0.0f) { | ||
| // Inverted dropout: scale retained activations by 1/keep_prob so that | ||
| // inference can pass the network output through unchanged. | ||
| float keep_prob = 1.0f - dropout_rate_; | ||
| float scale = 1.0f / keep_prob; | ||
|
|
||
| if (dropout_dim_ == 2) { | ||
| // Feature dropout: one mask value per feature, shared across all timesteps. | ||
| dropout_mask_.resize(num_features); | ||
| for (int i = 0; i < num_features; ++i) { | ||
| float r = static_cast<float>(randomizer_->UnsignedRand(1.0)); | ||
| dropout_mask_[i] = (r < keep_prob) ? 1 : 0; | ||
| } | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = input.f(t); | ||
| float *out = output->f(t); | ||
| for (int i = 0; i < num_features; ++i) | ||
| out[i] = dropout_mask_[i] ? in[i] * scale : 0.0f; | ||
| } | ||
| } else if (dropout_dim_ == 1) { | ||
| // Temporal dropout: one mask value per timestep, shared across all features. | ||
| dropout_mask_.resize(width); | ||
| for (int t = 0; t < width; ++t) { | ||
| float r = static_cast<float>(randomizer_->UnsignedRand(1.0)); | ||
| dropout_mask_[t] = (r < keep_prob) ? 1 : 0; | ||
| } | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = input.f(t); | ||
| float *out = output->f(t); | ||
| if (dropout_mask_[t]) { | ||
| for (int i = 0; i < num_features; ++i) out[i] = in[i] * scale; | ||
| } else { | ||
| memset(out, 0, sizeof(float) * num_features); | ||
| } | ||
| } | ||
| } else { | ||
| // Element-wise dropout (dim=0, default). | ||
| dropout_mask_.resize(width * num_features); | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = input.f(t); | ||
| float *out = output->f(t); | ||
| char *mask = dropout_mask_.data() + t * num_features; | ||
| for (int i = 0; i < num_features; ++i) { | ||
| // UnsignedRand(1.0) returns a value in [0, 1]. | ||
| float r = static_cast<float>(randomizer_->UnsignedRand(1.0)); | ||
| mask[i] = (r < keep_prob) ? 1 : 0; | ||
| out[i] = mask[i] ? in[i] * scale : 0.0f; | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| // Inference mode (or dropout_rate_ == 0): pass input through unchanged. | ||
| output->CopyAll(input); | ||
| } | ||
|
|
||
| #ifndef GRAPHICS_DISABLED | ||
| if (debug) { | ||
| DisplayForward(*output); | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| // Runs backward propagation of errors on the deltas line. | ||
| // See Network for a detailed discussion of the arguments. | ||
| bool Dropout::Backward(bool debug, const NetworkIO &fwd_deltas, | ||
| NetworkScratch *scratch, NetworkIO *back_deltas) { | ||
| back_deltas->Resize(fwd_deltas, ni_); | ||
|
|
||
| int width = fwd_deltas.Width(); | ||
| int num_features = fwd_deltas.NumFeatures(); | ||
|
|
||
| if (IsTraining() && dropout_rate_ > 0.0f) { | ||
| float scale = 1.0f / (1.0f - dropout_rate_); | ||
|
|
||
| if (dropout_dim_ == 2) { | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = fwd_deltas.f(t); | ||
| float *out = back_deltas->f(t); | ||
| for (int i = 0; i < num_features; ++i) | ||
| out[i] = dropout_mask_[i] ? in[i] * scale : 0.0f; | ||
| } | ||
| } else if (dropout_dim_ == 1) { | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = fwd_deltas.f(t); | ||
| float *out = back_deltas->f(t); | ||
| if (dropout_mask_[t]) { | ||
| for (int i = 0; i < num_features; ++i) out[i] = in[i] * scale; | ||
| } else { | ||
| memset(out, 0, sizeof(float) * num_features); | ||
| } | ||
| } | ||
| } else { | ||
| for (int t = 0; t < width; ++t) { | ||
| const float *in = fwd_deltas.f(t); | ||
| float *out = back_deltas->f(t); | ||
| const char *mask = dropout_mask_.data() + t * num_features; | ||
| for (int i = 0; i < num_features; ++i) | ||
| out[i] = mask[i] ? in[i] * scale : 0.0f; | ||
| } | ||
| } | ||
| } else { | ||
| // Inference mode: pass gradients through unchanged. | ||
| back_deltas->CopyAll(fwd_deltas); | ||
| } | ||
|
|
||
| #ifndef GRAPHICS_DISABLED | ||
| if (debug) { | ||
| DisplayBackward(*back_deltas); | ||
| } | ||
| #endif | ||
| return needs_to_backprop_; | ||
| } | ||
|
|
||
| } // namespace tesseract. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /////////////////////////////////////////////////////////////////////// | ||
| // File: dropout.h | ||
| // Description: Standard Dropout layer. | ||
| // Author: Stefan Weil | ||
| // | ||
| // 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_DROPOUT_H_ | ||
| #define TESSERACT_LSTM_DROPOUT_H_ | ||
|
|
||
| #include "network.h" | ||
|
|
||
| namespace tesseract { | ||
|
|
||
| // Dropout. | ||
| class Dropout : public Network { | ||
| public: | ||
| TESS_API | ||
| Dropout(const std::string &name, int ni, float dropout_rate, int dropout_dim = 0); | ||
| ~Dropout() override = default; | ||
|
|
||
| // Accessors. | ||
| std::string spec() const override { | ||
| std::string s = "Do" + std::to_string(dropout_rate_); | ||
| if (dropout_dim_ != 0) | ||
| s += "," + std::to_string(dropout_dim_); | ||
| return s; | ||
| } | ||
|
|
||
| // Writes to the given file. Returns false in case of error. | ||
| bool Serialize(TFile *fp) const override; | ||
| // Reads from the given file. Returns false in case of error. | ||
| bool DeSerialize(TFile *fp) override; | ||
|
|
||
| // Runs forward propagation of activations on the input line. | ||
| // See Network for a detailed discussion of the arguments. | ||
| void Forward(bool debug, const NetworkIO &input, const TransposedArray *input_transpose, | ||
| NetworkScratch *scratch, NetworkIO *output) override; | ||
|
|
||
| // Runs backward propagation of errors on the deltas line. | ||
| // See Network for a detailed discussion of the arguments. | ||
| bool Backward(bool debug, const NetworkIO &fwd_deltas, NetworkScratch *scratch, | ||
| NetworkIO *back_deltas) override; | ||
|
|
||
| private: | ||
| void DebugWeights() override; | ||
|
|
||
| std::vector<char> dropout_mask_; | ||
| float dropout_rate_; | ||
| int dropout_dim_; // 0=elementwise, 1=temporal, 2=feature/channel | ||
| }; | ||
|
|
||
| } // namespace tesseract. | ||
|
|
||
| #endif // TESSERACT_LSTM_DROPOUT_H_ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.