Repository: tesseract-ocr/tesseract
File: src/training/unicharset/lstmtester.cpp (C++)

Code before:
    const ImageData *trainingdata = test_data_.GetPageBySerial(eval_iteration);
    trainer.SetIteration(++eval_iteration);
    NetworkIO fwd_outputs, targets;
    Trainability result = trainer.PrepareForBackward(trainingdata, &fwd_outputs, &targets);
    if (result != UNENCODABLE) {
      char_error += trainer.NewSingleError(tesseract::ET_CHAR_ERROR);
      word_error += trainer.NewSingleError(tesseract::ET_WORD_RECERR);
      ++error_count;
      if (verbosity > 1 || (verbosity > 0 && result != PERFECT)) {
        tprintf("Truth:%s\n", trainingdata->transcription().c_str());
        std::vector<int> ocr_labels;
        std::vector<int> xcoords;
        trainer.LabelsFromOutputs(fwd_outputs, &ocr_labels, &xcoords);
        std::string ocr_text = trainer.DecodeLabels(ocr_labels);
        tprintf("OCR  :%s\n", ocr_text.c_str());
        if (verbosity > 2 || (verbosity > 1 && result != PERFECT)) {
          tprintf("Line Char error rate=%f, Word error rate=%f\n\n",
                  trainer.NewSingleError(tesseract::ET_CHAR_ERROR),
                  trainer.NewSingleError(tesseract::ET_WORD_RECERR));
        }
      }
    }
  }
  char_error *= 100.0 / total_pages_;
  word_error *= 100.0 / total_pages_;
  std::string result;
  result += "At iteration " + std::to_string(iteration);
  result += ", stage " + std::to_string(training_stage);
  result += ", BCER eval=" + std::to_string(char_error);
  result += ", BWER eval=" + std::to_string(word_error);
  return result;
}

// Helper thread function for RunEvalAsync.
// LockIfNotRunning must have returned true before calling ThreadFunc, and
// it will call UnlockRunning to release the lock after RunEvalSync completes.
void LSTMTester::ThreadFunc() {
  test_result_ =
      RunEvalSync(test_iteration_, test_training_errors_, test_model_mgr_, test_training_stage_,
                  /*verbosity*/ 0);
  UnlockRunning();
}

// Returns true if there is currently nothing running, and takes the lock
// if there is nothing running.
bool LSTMTester::LockIfNotRunning() {
  std::lock_guard<std::mutex> lock(running_mutex_);
  if (async_running_) {
    return false;
  }
  async_running_ = true;

Review comment (suggestion):
There's one more: one line 109 (`Line Char error rate` → `Line BCER`) – cannot use GH suggestions.

Code after:
    const ImageData *trainingdata = test_data_.GetPageBySerial(eval_iteration);
    trainer.SetIteration(++eval_iteration);
    NetworkIO fwd_outputs, targets;
    Trainability result = trainer.PrepareForBackward(trainingdata, &fwd_outputs, &targets);
    if (result != UNENCODABLE) {
      char_error += trainer.NewSingleError(tesseract::ET_CHAR_ERROR);
      word_error += trainer.NewSingleError(tesseract::ET_WORD_RECERR);
      ++error_count;
      if (verbosity > 1 || (verbosity > 0 && result != PERFECT)) {
        tprintf("Truth:%s\n", trainingdata->transcription().c_str());
        std::vector<int> ocr_labels;
        std::vector<int> xcoords;
        trainer.LabelsFromOutputs(fwd_outputs, &ocr_labels, &xcoords);
        std::string ocr_text = trainer.DecodeLabels(ocr_labels);
        tprintf("OCR  :%s\n", ocr_text.c_str());
        if (verbosity > 2 || (verbosity > 1 && result != PERFECT)) {
          tprintf("Line BCER=%f, BWER=%f\n\n",
                  trainer.NewSingleError(tesseract::ET_CHAR_ERROR),
                  trainer.NewSingleError(tesseract::ET_WORD_RECERR));
        }
      }
    }
  }
  char_error *= 100.0 / total_pages_;
  word_error *= 100.0 / total_pages_;
  std::string result;
  result += "At iteration " + std::to_string(iteration);
  result += ", stage " + std::to_string(training_stage);
  result += ", BCER eval=" + std::to_string(char_error);
  result += ", BWER eval=" + std::to_string(word_error);
  return result;
}

// Helper thread function for RunEvalAsync.
// LockIfNotRunning must have returned true before calling ThreadFunc, and
// it will call UnlockRunning to release the lock after RunEvalSync completes.
void LSTMTester::ThreadFunc() {
  test_result_ =
      RunEvalSync(test_iteration_, test_training_errors_, test_model_mgr_, test_training_stage_,
                  /*verbosity*/ 0);
  UnlockRunning();
}

// Returns true if there is currently nothing running, and takes the lock
// if there is nothing running.
bool LSTMTester::LockIfNotRunning() {
  std::lock_guard<std::mutex> lock(running_mutex_);
  if (async_running_) {
    return false;
  }
  async_running_ = true;