Spaces:
Runtime error
Runtime error
Andrey
commited on
Commit
•
2c16c94
1
Parent(s):
ec55dcd
Add "about" page and more descriptions in readme. Change default thre… (#12)
Browse files* Add "about" page and more descriptions in readme. Change default threshold to 0.8.
* Update variable name for deepsource.
- .flake8 +1 -1
- .github/README.md +2 -1
- README.md +1 -1
- pages/about.py +22 -0
- src/utils.py +16 -5
- st_app.py +12 -1
.flake8
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
[flake8]
|
2 |
-
ignore = I001,I002,I004,I005,I101,I201,C101,C403,C901,F401,F403,S001,D100,D101,D102,D103,D104,D105,D106,D107,D200,D210,D205,D400,T001,W504,D202,E203,W503,B006,T002,T100,P103,C408,F841
|
3 |
max-line-length = 120
|
4 |
exclude = outputs/*
|
5 |
max-complexity = 10
|
|
|
1 |
[flake8]
|
2 |
+
ignore = I001,I002,I004,I005,I101,I201,C101,C403,C901,F401,F403,S001,D100,D101,D102,D103,D104,D105,D106,D107,D200,D210,D205,D400,T001,W504,D202,E203,E501,W503,B006,T002,T100,P103,C408,F841
|
3 |
max-line-length = 120
|
4 |
exclude = outputs/*
|
5 |
max-complexity = 10
|
.github/README.md
CHANGED
@@ -1 +1,2 @@
|
|
1 |
-
|
|
|
|
1 |
+
![visitors](https://visitor-badge.glitch.me/badge?page_id=wissamantoun.arabicnlpapp)
|
2 |
+
[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/Erlemar/digit-draw-detect/?ref=repository-badge )
|
README.md
CHANGED
@@ -10,4 +10,4 @@ app_file: st_app.py
|
|
10 |
pinned: false
|
11 |
license: mit
|
12 |
---
|
13 |
-
|
|
|
10 |
pinned: false
|
11 |
license: mit
|
12 |
---
|
13 |
+
![visitors](https://visitor-badge.glitch.me/badge?page_id=wissamantoun.arabicnlpapp)
|
pages/about.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
text = """
|
4 |
+
## A brief history of the project.
|
5 |
+
The first idea of the project was conceived in the summer of 2017. I completed cs231n course and wanted to put my skills to the test. So I studied Flask and many other tools from scratch and made an [app](https://github.com/Erlemar/digit-draw-recognize) for recognizing handwritten digits. It had two models - a simple feed-forward neural net written in NumPy and a CNN written in Tensorflow. One fun feature of this app was online learning: the model continuously improved its predictions based on new inputs (though this did sometimes lead to incorrect predictions).
|
6 |
+
|
7 |
+
In 2019 I decided to update the [project](https://github.com/Erlemar/digit-draw-predict): I trained the new neural net in PyTorch and used cv2 to detect separate digits (people often drew multiple digits). More than that, the model had 11 classes - I made a separate class for "junk", as people often drew things for fun: animals, objects, or words.
|
8 |
+
|
9 |
+
The first two versions were deployed on Heroku's free plan, but in 2022 these plans were discontinued. I didn't want my project to die because of nostalgia, so I developed a new version and deployed it differently. The current version has an object detection model (yolo3 written from scratch) and 12 classes (digits, junk, and **censored**)
|
10 |
+
. If you want to know what does **censored** means, just try to draw something 😉
|
11 |
+
|
12 |
+
Initially, I considered deploying the app on Streamlit Cloud, but its computational limits were too low, so now the model is live on HuggingFace Spaces.
|
13 |
+
|
14 |
+
### Links with additional information:
|
15 |
+
|
16 |
+
* [Project page on my personal website](https://andlukyane.com/project/drawn-digits-prediction)
|
17 |
+
* [A dataset with the digits and bounding boxes on Kaggle](https://www.kaggle.com/datasets/artgor/handwritten-digits-and-bounding-boxes)
|
18 |
+
* [Training code](https://github.com/Erlemar/pytorch_tempest_pet_)
|
19 |
+
|
20 |
+
"""
|
21 |
+
|
22 |
+
st.markdown(text, unsafe_allow_html=True)
|
src/utils.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import datetime
|
2 |
import json
|
|
|
3 |
import uuid
|
4 |
from typing import List
|
5 |
|
@@ -9,12 +10,22 @@ import matplotlib.patches as patches
|
|
9 |
import matplotlib.pyplot as plt
|
10 |
import numpy.typing as npt
|
11 |
import streamlit as st
|
|
|
12 |
|
13 |
AWS_ACCESS_KEY_ID = ''
|
14 |
AWS_SECRET_ACCESS_KEY = ''
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
client = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
|
20 |
|
@@ -84,8 +95,8 @@ def save_image(image: npt.ArrayLike, pred: List[List]) -> str:
|
|
84 |
fig.savefig(f'{file_name}.png')
|
85 |
|
86 |
# dump bboxes in a local file
|
87 |
-
with open(f'{file_name}.json', 'w') as
|
88 |
-
json.dump({f'{file_name}.png': pred},
|
89 |
|
90 |
# upload the image and the bboxes to s3.
|
91 |
save_object_to_s3(f'{file_name}.png', f'images/{file_name}.png')
|
|
|
1 |
import datetime
|
2 |
import json
|
3 |
+
import os
|
4 |
import uuid
|
5 |
from typing import List
|
6 |
|
|
|
10 |
import matplotlib.pyplot as plt
|
11 |
import numpy.typing as npt
|
12 |
import streamlit as st
|
13 |
+
import tomli
|
14 |
|
15 |
AWS_ACCESS_KEY_ID = ''
|
16 |
AWS_SECRET_ACCESS_KEY = ''
|
17 |
+
try:
|
18 |
+
if st.secrets is not None:
|
19 |
+
AWS_ACCESS_KEY_ID = st.secrets['AWS_ACCESS_KEY_ID']
|
20 |
+
AWS_SECRET_ACCESS_KEY = st.secrets['AWS_SECRET_ACCESS_KEY']
|
21 |
+
except BaseException:
|
22 |
+
pass
|
23 |
+
|
24 |
+
if os.path.exists('config.toml'):
|
25 |
+
with open('config.toml', 'rb') as f:
|
26 |
+
config = tomli.load(f)
|
27 |
+
AWS_ACCESS_KEY_ID = config['AWS_ACCESS_KEY_ID']
|
28 |
+
AWS_SECRET_ACCESS_KEY = config['AWS_SECRET_ACCESS_KEY']
|
29 |
|
30 |
client = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
|
31 |
|
|
|
95 |
fig.savefig(f'{file_name}.png')
|
96 |
|
97 |
# dump bboxes in a local file
|
98 |
+
with open(f'{file_name}.json', 'w') as j_f:
|
99 |
+
json.dump({f'{file_name}.png': pred}, j_f)
|
100 |
|
101 |
# upload the image and the bboxes to s3.
|
102 |
save_object_to_s3(f'{file_name}.png', f'images/{file_name}.png')
|
st_app.py
CHANGED
@@ -8,6 +8,7 @@ from streamlit_drawable_canvas import st_canvas
|
|
8 |
from src.ml_utils import predict, get_model, transforms
|
9 |
from src.utils import plot_img_with_rects, save_image
|
10 |
|
|
|
11 |
logging.info('Starting')
|
12 |
|
13 |
col1, col2 = st.columns(2)
|
@@ -38,9 +39,19 @@ with col2:
|
|
38 |
logging.info('prediction done')
|
39 |
|
40 |
file_name = save_image(image.permute(1, 2, 0).numpy(), pred)
|
41 |
-
threshold = st.slider('Bbox probability slider', min_value=0.0, max_value=1.0, value=0.
|
42 |
|
43 |
fig = plot_img_with_rects(image.permute(1, 2, 0).numpy(), pred, threshold, coef=192)
|
44 |
fig.savefig(f'{file_name}_temp.png')
|
45 |
image = Image.open(f'{file_name}_temp.png')
|
46 |
st.image(image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
from src.ml_utils import predict, get_model, transforms
|
9 |
from src.utils import plot_img_with_rects, save_image
|
10 |
|
11 |
+
st.title('Handwritten digit detector')
|
12 |
logging.info('Starting')
|
13 |
|
14 |
col1, col2 = st.columns(2)
|
|
|
39 |
logging.info('prediction done')
|
40 |
|
41 |
file_name = save_image(image.permute(1, 2, 0).numpy(), pred)
|
42 |
+
threshold = st.slider('Bbox probability slider', min_value=0.0, max_value=1.0, value=0.8)
|
43 |
|
44 |
fig = plot_img_with_rects(image.permute(1, 2, 0).numpy(), pred, threshold, coef=192)
|
45 |
fig.savefig(f'{file_name}_temp.png')
|
46 |
image = Image.open(f'{file_name}_temp.png')
|
47 |
st.image(image)
|
48 |
+
|
49 |
+
text = """
|
50 |
+
This is a small app for handwritten digit recognition and recognition developed for fun. It uses a handwritten YOLOv3 model trained from scratch.
|
51 |
+
You can draw a digit (or whatever you want) and the model will try to understand what is it.
|
52 |
+
You can use the slider above to show bounding boxes with a probability higher than the threshold.
|
53 |
+
If you want to know how the app works in more detail, you are welcome to read "About" page.
|
54 |
+
Enjoy! :)
|
55 |
+
"""
|
56 |
+
|
57 |
+
st.markdown(text, unsafe_allow_html=True)
|