Philipp Allgeuer
commited on
Commit
·
7ad5fd3
1
Parent(s):
f0f9d74
Revamp app structure
Browse files- app.py +82 -49
- app_novic.py +35 -0
- novic +1 -1
- requirements.txt +6 -0
app.py
CHANGED
|
@@ -4,70 +4,103 @@
|
|
| 4 |
# Imports
|
| 5 |
import os
|
| 6 |
import glob
|
| 7 |
-
import random
|
| 8 |
-
import pathlib
|
| 9 |
-
import subprocess
|
| 10 |
from typing import Optional
|
| 11 |
import PIL.Image
|
| 12 |
import gradio as gr
|
|
|
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
|
| 22 |
# Sample images
|
| 23 |
IMAGE_EXTS = ('jpg', 'jpeg', 'png', 'webp')
|
| 24 |
SAMPLE_IMAGES = sorted(image_path for image_ext in IMAGE_EXTS for image_path in glob.glob(os.path.join('sample_images', f'*.{image_ext}')))
|
| 25 |
|
| 26 |
-
# Classify image
|
| 27 |
-
def classify_image(image: Optional[PIL.Image.Image]) -> dict[str, float]:
|
| 28 |
-
|
| 29 |
-
if image is None:
|
| 30 |
return {}
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
probs = [random.random() for _ in labels]
|
| 34 |
-
prob_sum = sum(probs)
|
| 35 |
-
return {label: prob / prob_sum for label, prob in zip(labels, probs)}
|
| 36 |
|
| 37 |
# Gradio UI
|
| 38 |
-
|
| 39 |
-
fn=classify_image,
|
| 40 |
-
inputs=gr.Image(
|
| 41 |
-
height=400,
|
| 42 |
-
image_mode='RGB',
|
| 43 |
-
type='pil',
|
| 44 |
-
label='Input image',
|
| 45 |
-
show_label=True,
|
| 46 |
-
interactive=True,
|
| 47 |
-
show_fullscreen_button=True,
|
| 48 |
-
),
|
| 49 |
-
outputs=gr.Label(
|
| 50 |
-
num_top_classes=3,
|
| 51 |
-
label='Predicted label',
|
| 52 |
-
show_label=True,
|
| 53 |
-
show_heading=True,
|
| 54 |
-
),
|
| 55 |
-
examples=SAMPLE_IMAGES,
|
| 56 |
-
examples_per_page=20,
|
| 57 |
-
live=True,
|
| 58 |
-
title="🖼️ NOVIC: Unconstrained Open Vocabulary Image Classification",
|
| 59 |
-
description="*Select* an image from the examples shown below **OR** *Upload* an image file from your computer **OR** *Capture* an image using an attached camera **OR** *Copy-paste* an image from your clipboard. The label predictions on the right will update automatically!",
|
| 60 |
-
article=None,
|
| 61 |
theme=None,
|
| 62 |
-
flagging_mode='never',
|
| 63 |
analytics_enabled=True,
|
| 64 |
-
|
| 65 |
-
allow_duplication=False,
|
| 66 |
-
clear_btn=gr.Button(value='Clear', variant='secondary'),
|
| 67 |
-
show_progress='full',
|
| 68 |
fill_width=False,
|
| 69 |
-
|
| 70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
# Run demo
|
| 73 |
if __name__ == '__main__':
|
|
|
|
| 4 |
# Imports
|
| 5 |
import os
|
| 6 |
import glob
|
|
|
|
|
|
|
|
|
|
| 7 |
from typing import Optional
|
| 8 |
import PIL.Image
|
| 9 |
import gradio as gr
|
| 10 |
+
import app_novic
|
| 11 |
|
| 12 |
+
# Model checkpoints
|
| 13 |
+
MODEL_CHECKPOINTS = {
|
| 14 |
+
'NOVIC SigLIP B/16 FT2': os.path.join('ovod_20240610_105233', 'ovod_chunk0899_20240612_005748.train'),
|
| 15 |
+
'NOVIC SigLIP SO/14 FT2': os.path.join('ovod_20240626_001447', 'ovod_chunk0899_20240627_112729.train'),
|
| 16 |
+
'NOVIC DFN-5B H/14-378 FT2': os.path.join('ovod_20240620_162925', 'ovod_chunk0899_20240621_202727.train'),
|
| 17 |
+
'NOVIC DFN-5B H/14-378 FT0': os.path.join('ovod_20240628_142131', 'ovod_chunk0433_20240630_235415.train'),
|
| 18 |
+
}
|
| 19 |
|
| 20 |
# Sample images
|
| 21 |
IMAGE_EXTS = ('jpg', 'jpeg', 'png', 'webp')
|
| 22 |
SAMPLE_IMAGES = sorted(image_path for image_ext in IMAGE_EXTS for image_path in glob.glob(os.path.join('sample_images', f'*.{image_ext}')))
|
| 23 |
|
| 24 |
+
# Classify an image
|
| 25 |
+
def classify_image(image: Optional[PIL.Image.Image], model: Optional[str]) -> dict[str, float]:
|
| 26 |
+
if image is None or model is None:
|
|
|
|
| 27 |
return {}
|
| 28 |
+
checkpoint = os.path.join('checkpoints', MODEL_CHECKPOINTS[model])
|
| 29 |
+
return app_novic.classify_image(image=image, checkpoint=checkpoint)
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
# Gradio UI
|
| 32 |
+
with gr.Blocks(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
theme=None,
|
|
|
|
| 34 |
analytics_enabled=True,
|
| 35 |
+
title="🖼️ NOVIC Demo",
|
|
|
|
|
|
|
|
|
|
| 36 |
fill_width=False,
|
| 37 |
+
) as demo:
|
| 38 |
+
|
| 39 |
+
gr.HTML("<h1 style='text-align: center; margin-bottom: 1rem'>🖼️ NOVIC: Unconstrained Open Vocabulary Image Classification</h1><div style='text-align: center'><i>Select</i> an example image below <b>OR</b> <i>Upload</i> an image file <b>OR</b> <i>Capture</i> a camera image <b>OR</b> <i>Copy-paste</i> an image from your clipboard ⇒ The label predictions on the right will update automatically!<br>Note that CPU inference is naturally <i>much</i> slower than GPU inference.</div>")
|
| 40 |
+
|
| 41 |
+
with gr.Row(equal_height=True):
|
| 42 |
+
|
| 43 |
+
with gr.Column(scale=1):
|
| 44 |
+
input_model = gr.Dropdown(
|
| 45 |
+
choices=list(MODEL_CHECKPOINTS),
|
| 46 |
+
value='NOVIC DFN-5B H/14-378 FT0',
|
| 47 |
+
type='value',
|
| 48 |
+
multiselect=False,
|
| 49 |
+
allow_custom_value=False,
|
| 50 |
+
filterable=False,
|
| 51 |
+
label='NOVIC model',
|
| 52 |
+
show_label=True,
|
| 53 |
+
interactive=True,
|
| 54 |
+
)
|
| 55 |
+
input_image = gr.Image(
|
| 56 |
+
height=400,
|
| 57 |
+
image_mode='RGB',
|
| 58 |
+
type='pil',
|
| 59 |
+
label='Input image',
|
| 60 |
+
show_label=True,
|
| 61 |
+
interactive=True,
|
| 62 |
+
show_fullscreen_button=True,
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
with gr.Column(scale=1):
|
| 66 |
+
output_label = gr.Label(
|
| 67 |
+
num_top_classes=3,
|
| 68 |
+
label='Predicted label',
|
| 69 |
+
show_label=True,
|
| 70 |
+
scale=1,
|
| 71 |
+
show_heading=True,
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
with gr.Row(equal_height=True):
|
| 75 |
+
gr.ClearButton(
|
| 76 |
+
components=[input_image],
|
| 77 |
+
value='Clear input image',
|
| 78 |
+
variant='secondary',
|
| 79 |
+
size='lg',
|
| 80 |
+
scale=1,
|
| 81 |
+
)
|
| 82 |
+
gr.DeepLinkButton(
|
| 83 |
+
variant='secondary',
|
| 84 |
+
size='lg',
|
| 85 |
+
scale=1,
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
gr.Examples(
|
| 89 |
+
examples=SAMPLE_IMAGES,
|
| 90 |
+
inputs=input_image,
|
| 91 |
+
cache_examples=False,
|
| 92 |
+
examples_per_page=100,
|
| 93 |
+
label='Example images',
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
gr.on(
|
| 97 |
+
triggers=[input_image.change, input_model.change],
|
| 98 |
+
fn=classify_image,
|
| 99 |
+
inputs=[input_image, input_model], # noqa
|
| 100 |
+
outputs=output_label,
|
| 101 |
+
api_name='classify',
|
| 102 |
+
show_progress='full',
|
| 103 |
+
)
|
| 104 |
|
| 105 |
# Run demo
|
| 106 |
if __name__ == '__main__':
|
app_novic.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# NOVIC interface
|
| 2 |
+
|
| 3 |
+
# Imports
|
| 4 |
+
import sys
|
| 5 |
+
import random # TODO: TEMP
|
| 6 |
+
import pathlib
|
| 7 |
+
import subprocess
|
| 8 |
+
import PIL.Image
|
| 9 |
+
# TODO: Then start coding infer.py (ANY additional import has to be clarified with novic_spaces/requirements.txt (pip install -r requirements.txt) and novic/requirements-infer.txt
|
| 10 |
+
|
| 11 |
+
# Ensure access to NOVIC code
|
| 12 |
+
REPO_ROOT = pathlib.Path(__file__).parent.resolve()
|
| 13 |
+
NOVIC_DIR = REPO_ROOT / 'novic'
|
| 14 |
+
NOVIC_TEST = NOVIC_DIR / '__init__.py'
|
| 15 |
+
if not NOVIC_TEST.exists():
|
| 16 |
+
print("Initialising git submodules as NOVIC code was not found yet...")
|
| 17 |
+
subprocess.run(['git', 'submodule', 'update', '--init', '--recursive'], cwd=REPO_ROOT, check=True)
|
| 18 |
+
if not NOVIC_TEST.exists():
|
| 19 |
+
raise RuntimeError("Failed to find NOVIC code")
|
| 20 |
+
if str(NOVIC_DIR) not in sys.path:
|
| 21 |
+
sys.path.insert(0, str(NOVIC_DIR))
|
| 22 |
+
|
| 23 |
+
# NOVIC imports
|
| 24 |
+
import infer # TODO: TEMP
|
| 25 |
+
print(infer) # TODO: TEMP
|
| 26 |
+
|
| 27 |
+
# Classify an image
|
| 28 |
+
def classify_image(image: PIL.Image.Image, checkpoint: str) -> dict[str, float]:
|
| 29 |
+
# TODO: TEMP
|
| 30 |
+
print(image, checkpoint)
|
| 31 |
+
labels = ('thing', 'item', 'stuff', 'object', 'entity')
|
| 32 |
+
probs = [random.random() for _ in labels]
|
| 33 |
+
prob_sum = sum(probs)
|
| 34 |
+
return {label: prob / prob_sum for label, prob in zip(labels, probs)}
|
| 35 |
+
# EOF
|
novic
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
Subproject commit
|
|
|
|
| 1 |
+
Subproject commit 553f618ae2cbea281ff2926a526e1cfa23e20086
|
requirements.txt
CHANGED
|
@@ -1 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
pillow
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# python>=3.10
|
| 2 |
+
numpy
|
| 3 |
+
open_clip_torch==2.23
|
| 4 |
pillow
|
| 5 |
+
torch
|
| 6 |
+
tqdm
|
| 7 |
+
unidecode
|