QUANTRIUM GUIDES
Improving PPOCR Recognition Time in Python
Utilizing multiprocessing and Colab GPU for PPOCR recognition
Introduction
Over the last few months, I have been writing some articles on Optical Character Recognition (OCR) using Python. But, one of the challenges faced even today with OCR in Python is the recognition time taken by some OCR models. We can find some of the OCR models (such as easyOCR, docTROCR, etc.) performing very fast when implemented with a Graphical Processing Unit (GPU).
If you had gone through my article on integrating multiple OCR models (which can be found here), you would have noticed recognition models such as PPOCR, pytesseract, etc., which perform recognition coordinate-wise. A major drawback with these recognition models is that, since they recognize the text coordinate-wise, their recognition time is much higher than recognition models like easyOCR, which takes the list of all coordinates and images at a time to perform recognition.
Also, if you try performing recognition using PPOCR using a Google Colab GPU directly, you may observe that the GPU is not consumed at all by the recognition model and a warning pops out in some time stating that the GPU is not consumed. Also, GPU availability in such platforms is very limited. However, there is a procedure to perform PPOCR recognition by consuming the Colab GPU, which I have explained in the upcoming sections. PPOCR documentation can be found here.
I have also explained how PPOCR recognition can be done using multiprocessing, which is a basic solution with which one can start and try improving the process even further.
We will test the recognition using all the methods with the following image (in fact, I used the same image in my docTROCR article. The article can be found in this link):-
Implementing PPOCR recognition with ordinary CPU
For comparison purposes, we will first check and record the time taken by ordinary CPU for PPOCR recognition.
The following installations should be made:
!pip install "paddleocr>=2.0.1"
!pip install paddlepaddleAfter the above installations, the following imports and definitions should be made:
from paddleocr import PaddleOCR
ocr = PaddleOCR(lang='en')To obtain the detection coordinates, I have explained the complete procedure in the articles whose links I have shared above. Now using the text_coordinates, we will perform PPOCR recognition:
import cv2
import time
img_path = <> #define your image path here
start = time.time()
for coord in text_coordinates:
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]
if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
im2 =cv2.imread(img_path)
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
end = time.time()
print(f"Time taken with ordinary CPU: {end-start} sec")The following output was obtained in my case:
Time taken with ordinary CPU: 11.89705514907837 secPPOCR recognition with multiprocessing
The installations for this are the same as the previous one. The following additional imports need to be made:
from multiprocessing import Pool
from functools import partial
pool = Pool(processes=8)More about multiprocessing can be understood from its documentation which can be found here.
Get Bhargav Sridhar’s stories in your inbox
Join Medium for free to get updates from this writer.
Now, we will implement the recognition in a slightly different way:
def perform_ocr_recognition(coord, im2):
text = ""
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]
if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
return {str(coord): text[0][0]}
img = cv2.imread(img_path)
start = time.time()
text_output = pool.map(partial(perform_ocr_recognition, im2=img),
text_coordinates
)
end = time.time()
print(f"Time taken with multiprocessing: {end-start} sec")The partial module is used to fix an argument throughout the process (especially in a loop). In our case, the image array would remain the same for the entire recognition process. That is why I declare it as a fixed argument and loop through the text coordinates outside the partial method.
The map function is used to automatically append the output of each iteration to a list. You can obtain the coordinate and text as dictionary objects and this can be checked by printing out the text_output variable.
The following output was obtained in my case (and it will vary for different users and systems):-
Time taken with multiprocessing: 7.432933568954468 secPPOCR recognition with Colab GPU
The following installations have to be made:-
!pip install "paddleocr>=2.0.1"
!pip install paddlepaddle
!python -m pip install paddlepaddle-gpu #or python3The paddlepaddle-gpu can be used to implement PPOCR by utilizing GPU (especially when you have GPU-CUDA set up in your platform). More information on installing this on your system can be found in the paddlepaddle documentation.
The imports and implementation are the same as that of ordinary CPU:-
from paddleocr import PaddleOCR
import cv2
import time
ocr = PaddleOCR(lang='en')
img_path = <> #define your image path here
start = time.time()
for coord in text_coordinates:
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]
if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
im2 =cv2.imread(img_path)
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
end = time.time()
print(f"Time taken with GPU: {end-start} sec")The following output was obtained in my case:-
Time taken with GPU: 0.5593817234039307 secNow let us try to understand the observations in the final section.
Observations and Conclusion
From the above experiments, the following observations are quite clear:-
- Ordinary CPU has taken more time when compared to the other methods. This is due to the iteration of each coordinate and a single process is utilized to recognize all coordinates in order;
- With multiprocessing, PPOCR recognition has executed faster than that of ordinary CPU, even though the time taken is still on the higher side. This is because multiple coordinates are recognized parallelly with the help of multiple processes utilized at the same time. But when testing with a large dataset, multiprocessing could save a lot of time than ordinary CPU execution;
- As expected, recognition with GPU was the quickest, but implementation was a bit different when compared to the other OCR tools;
Thus, I hope I have given you an idea of improving the PPOCR recognition process. In most cases, GPU availability would be low and hence multiprocessing may serve as a good starting point to increase PPOCR recognition speed. However with a GPU availability, one could install the paddlepaddle-gpu which serves specifically for the PPOCR model and optimize the time as shown in the previous sections. I would be more than willing to acknowledge questions and clarifications related to the topic which can be posted through the comments. Hope you have found this article useful. Thanks!










