Spaces:
Paused
Paused
Jinglong Xiong
commited on
Commit
Β·
15369ca
0
Parent(s):
first commit
Browse files- .gitignore +177 -0
- data/descriptions.csv +166 -0
- data/eval.csv +166 -0
- data/gen_descriptions.py +245 -0
- data/gen_vqa.py +136 -0
- improved-aesthetic-predictor/F5WsLD0XoAAviiV (1).jpeg +0 -0
- improved-aesthetic-predictor/LICENSE +201 -0
- improved-aesthetic-predictor/README.md +13 -0
- improved-aesthetic-predictor/prepare-data-for-training.py +76 -0
- improved-aesthetic-predictor/simple_inference.py +122 -0
- improved-aesthetic-predictor/train_predictor.py +178 -0
- improved-aesthetic-predictor/visulaize_100k_from_LAION400M.py +175 -0
- kaggle_evaluation/__init__.py +25 -0
- kaggle_evaluation/core/__init__.py +5 -0
- kaggle_evaluation/core/base_gateway.py +229 -0
- kaggle_evaluation/core/generated/__init__.py +5 -0
- kaggle_evaluation/core/generated/kaggle_evaluation_pb2.py +44 -0
- kaggle_evaluation/core/generated/kaggle_evaluation_pb2_grpc.py +66 -0
- kaggle_evaluation/core/kaggle_evaluation.proto +66 -0
- kaggle_evaluation/core/relay.py +343 -0
- kaggle_evaluation/core/templates.py +114 -0
- kaggle_evaluation/svg.py +56 -0
- kaggle_evaluation/svg_constraints.py +311 -0
- kaggle_evaluation/svg_gateway.py +63 -0
- kaggle_evaluation/svg_gateway.py~ +61 -0
- kaggle_evaluation/test.csv +1 -0
- metric.py +558 -0
- requirements.txt +23 -0
- starter.ipynb +259 -0
.gitignore
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.parquet
|
2 |
+
*.pth
|
3 |
+
|
4 |
+
# Byte-compiled / optimized / DLL files
|
5 |
+
__pycache__/
|
6 |
+
*.py[cod]
|
7 |
+
*$py.class
|
8 |
+
|
9 |
+
# C extensions
|
10 |
+
*.so
|
11 |
+
|
12 |
+
# Distribution / packaging
|
13 |
+
.Python
|
14 |
+
build/
|
15 |
+
develop-eggs/
|
16 |
+
dist/
|
17 |
+
downloads/
|
18 |
+
eggs/
|
19 |
+
.eggs/
|
20 |
+
lib/
|
21 |
+
lib64/
|
22 |
+
parts/
|
23 |
+
sdist/
|
24 |
+
var/
|
25 |
+
wheels/
|
26 |
+
share/python-wheels/
|
27 |
+
*.egg-info/
|
28 |
+
.installed.cfg
|
29 |
+
*.egg
|
30 |
+
MANIFEST
|
31 |
+
|
32 |
+
# PyInstaller
|
33 |
+
# Usually these files are written by a python script from a template
|
34 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
35 |
+
*.manifest
|
36 |
+
*.spec
|
37 |
+
|
38 |
+
# Installer logs
|
39 |
+
pip-log.txt
|
40 |
+
pip-delete-this-directory.txt
|
41 |
+
|
42 |
+
# Unit test / coverage reports
|
43 |
+
htmlcov/
|
44 |
+
.tox/
|
45 |
+
.nox/
|
46 |
+
.coverage
|
47 |
+
.coverage.*
|
48 |
+
.cache
|
49 |
+
nosetests.xml
|
50 |
+
coverage.xml
|
51 |
+
*.cover
|
52 |
+
*.py,cover
|
53 |
+
.hypothesis/
|
54 |
+
.pytest_cache/
|
55 |
+
cover/
|
56 |
+
|
57 |
+
# Translations
|
58 |
+
*.mo
|
59 |
+
*.pot
|
60 |
+
|
61 |
+
# Django stuff:
|
62 |
+
*.log
|
63 |
+
local_settings.py
|
64 |
+
db.sqlite3
|
65 |
+
db.sqlite3-journal
|
66 |
+
|
67 |
+
# Flask stuff:
|
68 |
+
instance/
|
69 |
+
.webassets-cache
|
70 |
+
|
71 |
+
# Scrapy stuff:
|
72 |
+
.scrapy
|
73 |
+
|
74 |
+
# Sphinx documentation
|
75 |
+
docs/_build/
|
76 |
+
|
77 |
+
# PyBuilder
|
78 |
+
.pybuilder/
|
79 |
+
target/
|
80 |
+
|
81 |
+
# Jupyter Notebook
|
82 |
+
.ipynb_checkpoints
|
83 |
+
|
84 |
+
# IPython
|
85 |
+
profile_default/
|
86 |
+
ipython_config.py
|
87 |
+
|
88 |
+
# pyenv
|
89 |
+
# For a library or package, you might want to ignore these files since the code is
|
90 |
+
# intended to run in multiple environments; otherwise, check them in:
|
91 |
+
# .python-version
|
92 |
+
|
93 |
+
# pipenv
|
94 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
95 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
96 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
97 |
+
# install all needed dependencies.
|
98 |
+
#Pipfile.lock
|
99 |
+
|
100 |
+
# UV
|
101 |
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
102 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
103 |
+
# commonly ignored for libraries.
|
104 |
+
#uv.lock
|
105 |
+
|
106 |
+
# poetry
|
107 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
108 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
109 |
+
# commonly ignored for libraries.
|
110 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
111 |
+
#poetry.lock
|
112 |
+
|
113 |
+
# pdm
|
114 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
115 |
+
#pdm.lock
|
116 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
117 |
+
# in version control.
|
118 |
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
119 |
+
.pdm.toml
|
120 |
+
.pdm-python
|
121 |
+
.pdm-build/
|
122 |
+
|
123 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
124 |
+
__pypackages__/
|
125 |
+
|
126 |
+
# Celery stuff
|
127 |
+
celerybeat-schedule
|
128 |
+
celerybeat.pid
|
129 |
+
|
130 |
+
# SageMath parsed files
|
131 |
+
*.sage.py
|
132 |
+
|
133 |
+
# Environments
|
134 |
+
.env
|
135 |
+
.venv
|
136 |
+
env/
|
137 |
+
venv/
|
138 |
+
ENV/
|
139 |
+
env.bak/
|
140 |
+
venv.bak/
|
141 |
+
|
142 |
+
# Spyder project settings
|
143 |
+
.spyderproject
|
144 |
+
.spyproject
|
145 |
+
|
146 |
+
# Rope project settings
|
147 |
+
.ropeproject
|
148 |
+
|
149 |
+
# mkdocs documentation
|
150 |
+
/site
|
151 |
+
|
152 |
+
# mypy
|
153 |
+
.mypy_cache/
|
154 |
+
.dmypy.json
|
155 |
+
dmypy.json
|
156 |
+
|
157 |
+
# Pyre type checker
|
158 |
+
.pyre/
|
159 |
+
|
160 |
+
# pytype static type analyzer
|
161 |
+
.pytype/
|
162 |
+
|
163 |
+
# Cython debug symbols
|
164 |
+
cython_debug/
|
165 |
+
|
166 |
+
# PyCharm
|
167 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
168 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
169 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
170 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
171 |
+
#.idea/
|
172 |
+
|
173 |
+
# Ruff stuff:
|
174 |
+
.ruff_cache/
|
175 |
+
|
176 |
+
# PyPI configuration file
|
177 |
+
.pypirc
|
data/descriptions.csv
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
id,description,category
|
2 |
+
0,a purple forest at dusk,landscape
|
3 |
+
1,gray wool coat with a faux fur collar,fashion
|
4 |
+
2,a lighthouse overlooking the ocean,landscape
|
5 |
+
3,burgundy corduroy pants with patch pockets and silver buttons,fashion
|
6 |
+
4,orange corduroy overalls,fashion
|
7 |
+
5,a purple silk scarf with tassel trim,fashion
|
8 |
+
6,a green lagoon under a cloudy sky,landscape
|
9 |
+
7,crimson rectangles forming a chaotic grid,abstract
|
10 |
+
8,purple pyramids spiraling around a bronze cone,abstract
|
11 |
+
9,magenta trapezoids layered on a transluscent silver sheet,abstract
|
12 |
+
10,a snowy plain,landscape
|
13 |
+
11,black and white checkered pants,fashion
|
14 |
+
12,a starlit night over snow-covered peaks,landscape
|
15 |
+
13,khaki triangles and azure crescents,abstract
|
16 |
+
14,a maroon dodecahedron interwoven with teal threads,abstract
|
17 |
+
14,a peaceful meadow under a bright blue sky,landscapes
|
18 |
+
15,a bright coral beach at midday,landscapes
|
19 |
+
16,a misty morning over a tranquil fjord,landscapes
|
20 |
+
17,an arctic tundra blanketed in snow,landscapes
|
21 |
+
18,rolling hills covered in wildflowers,landscapes
|
22 |
+
19,a peaceful hillside dotted with grazing animals,landscapes
|
23 |
+
20,a tranquil lake surrounded by mountains,landscapes
|
24 |
+
21,a rocky outcrop with panoramic views,landscapes
|
25 |
+
22,a tranquil beach with soft white sands,landscapes
|
26 |
+
23,a hidden waterfall cascading into a serene pool,landscapes
|
27 |
+
24,a serene bay with anchored sailboats,landscapes
|
28 |
+
25,a peaceful orchard in full bloom,landscapes
|
29 |
+
26,a shimmering ice field reflecting the sun,landscapes
|
30 |
+
27,a calm river reflecting the changing leaves,landscapes
|
31 |
+
28,a vibrant autumn forest ablaze with colors,landscapes
|
32 |
+
29,a tranquil forest path lined with ferns,landscapes
|
33 |
+
30,a lush jungle vibrant with life,landscapes
|
34 |
+
31,a sunlit plateau with sprawling grasslands,landscapes
|
35 |
+
32,a quiet pond with lily pads and frogs,landscapes
|
36 |
+
33,an endless field of sunflowers reaching for the sky,landscapes
|
37 |
+
34,a craggy shoreline kissed by foamy waves,landscapes
|
38 |
+
35,a vibrant city skyline at twilight,landscapes
|
39 |
+
36,a grassy hilltop with sweeping views,landscapes
|
40 |
+
37,"a narrow canyon with steep, colorful walls",landscapes
|
41 |
+
38,a secluded glen with singing streams,landscapes
|
42 |
+
39,a winding path through golden autumn leaves,landscapes
|
43 |
+
40,a deserted island surrounded by turquoise waters,landscapes
|
44 |
+
41,a rocky plateau under a blanket of stars,landscapes
|
45 |
+
42,a golden desert at sunset,landscapes
|
46 |
+
43,a sunlit glade filled with chirping birds,landscapes
|
47 |
+
44,a vibrant coral reef beneath crystal waters,landscapes
|
48 |
+
45,a striking basalt cliff alongside a river,landscapes
|
49 |
+
46,a verdant valley framed by majestic peaks,landscapes
|
50 |
+
47,a remote mountain lake surrounded by pines,landscapes
|
51 |
+
48,a quaint village nestled in rolling hills,landscapes
|
52 |
+
49,an ancient forest bathed in moonlight,landscapes
|
53 |
+
50,a colorful wildflower meadow in full bloom,landscapes
|
54 |
+
51,a sun-drenched vineyard on a gentle slope,landscapes
|
55 |
+
52,a lush garden bursting with colors,landscapes
|
56 |
+
53,a windswept dune under a vast sky,landscapes
|
57 |
+
54,a misty valley at dawn,landscapes
|
58 |
+
55,a rocky cliff overlooking a shimmering sea,landscapes
|
59 |
+
56,a rugged coastline with crashing waves,landscapes
|
60 |
+
57,a colorful canyon painted by natureβs brush,landscapes
|
61 |
+
58,a misty mountain range shrouded in clouds,landscapes
|
62 |
+
59,an expansive savanna dotted with acacia trees,landscapes
|
63 |
+
60,a secluded cove with clear blue waters,landscapes
|
64 |
+
61,a foggy marsh with tall grasses swaying,landscapes
|
65 |
+
62,a serene river winding through lush greenery,landscapes
|
66 |
+
63,a dramatic volcanic landscape with black sands,landscapes
|
67 |
+
64,a dance of teal waves and coral stripes in motion,abstract
|
68 |
+
65,intermingled shades of peach and plum creating warmth,abstract
|
69 |
+
66,a burst of burnt orange triangles against pale blue,abstract
|
70 |
+
67,bright cyan squares floating in a sea of dark gray,abstract
|
71 |
+
68,a chaotic arrangement of yellow and purple lines,abstract
|
72 |
+
69,"bold, vibrant colors colliding in rhythmic patterns",abstract
|
73 |
+
70,sapphire spirals intertwining with silver rectangles,abstract
|
74 |
+
71,layers of olive and gold squares forming depth,abstract
|
75 |
+
72,crimson and cobalt circles spiraling inward,abstract
|
76 |
+
73,layered translucent shapes in shades of teal and jade,abstract
|
77 |
+
74,sharp angles of black and white creating an illusion,abstract
|
78 |
+
75,a cascade of fuchsia polygons on a cream backdrop,abstract
|
79 |
+
76,golden circles overlapping with deep blue squares,abstract
|
80 |
+
77,yellow triangles punctuated by black dots on white,abstract
|
81 |
+
78,geometric clouds of gray juxtaposed with fiery reds,abstract
|
82 |
+
79,a patchwork of deep reds and bright yellows,abstract
|
83 |
+
80,a mosaic of lavender hexagons on a charcoal background,abstract
|
84 |
+
81,woven threads of silver and burgundy forming landscapes,abstract
|
85 |
+
82,turquoise lines radiating from a central ruby star,abstract
|
86 |
+
83,a lattice of mauve and chartreuse intersecting forms,abstract
|
87 |
+
84,chaotic lines of dark green tracing a golden background,abstract
|
88 |
+
85,emerald diamonds scattered across a warm orange canvas,abstract
|
89 |
+
86,diagonal lines of plum and mint creating tension,abstract
|
90 |
+
87,bold black squares anchored by splashes of turquoise,abstract
|
91 |
+
88,a whirl of soft lavender and sharp black angles,abstract
|
92 |
+
89,soft pink spirals weaving through a canvas of cream,abstract
|
93 |
+
90,a balanced composition of red circles and blue lines,abstract
|
94 |
+
91,pulsating layers of orange and purple creating depth,abstract
|
95 |
+
92,whispering curves of lavender on a deep black canvas,abstract
|
96 |
+
93,a field of intersecting lines in soft earth tones,abstract
|
97 |
+
94,a cluster of copper diamonds floating on deep azure,abstract
|
98 |
+
95,a dynamic interplay of orange and teal shapes,abstract
|
99 |
+
96,gentle curves of olive green and burnt sienna,abstract
|
100 |
+
97,a field of gray circles encircled by vibrant yellows,abstract
|
101 |
+
98,violet waves flowing through a grid of muted greens,abstract
|
102 |
+
99,textured green rectangles layered over a soft beige,abstract
|
103 |
+
100,intersecting teal and amber shapes on a stark white,abstract
|
104 |
+
101,a swirl of pastel circles against a dark indigo field,abstract
|
105 |
+
102,a burst of bright colors scattered across gentle curves,abstract
|
106 |
+
103,jagged navy triangles contrasting against a light canvas,abstract
|
107 |
+
104,golden rays emerging from a central violet orb,abstract
|
108 |
+
105,cyan and magenta triangles creating visual tension,abstract
|
109 |
+
106,pastel arcs dancing across a canvas of dark navy,abstract
|
110 |
+
107,layered rectangles in shades of rose and steel gray,abstract
|
111 |
+
108,a rhythmic pattern of orange and white stripes,abstract
|
112 |
+
109,fractured shapes of green and gold evoking movement,abstract
|
113 |
+
110,interlocking beige ovals on a vibrant cerulean base,abstract
|
114 |
+
111,abstract black and white circles creating visual harmony,abstract
|
115 |
+
112,crimson arcs and navy triangles creating dynamic tension,abstract
|
116 |
+
113,overlapping shapes in muted tones of green and brown,abstract
|
117 |
+
114,two-tone canvas slip-ons in navy and white,fashion
|
118 |
+
115,soft ankle socks in pastel colors with a ribbed top,fashion
|
119 |
+
116,luxe velvet dress in deep emerald with a wrap design,fashion
|
120 |
+
117,soft merino wool pullover in muted lavender,fashion
|
121 |
+
118,high-waisted shorts in a lightweight chambray fabric,fashion
|
122 |
+
119,classic trench coat in beige with a tie belt,fashion
|
123 |
+
120,soft fleece hoodie in light gray with a kangaroo pocket,fashion
|
124 |
+
121,graphic tee in soft cotton with a vintage design,fashion
|
125 |
+
122,satin camisole in blush pink with delicate lace trim,fashion
|
126 |
+
123,plaid wool skirt with a high waist and pleats,fashion
|
127 |
+
124,chevron knit blanket scarf in shades of gray,fashion
|
128 |
+
125,classic white button-up shirt with a tailored fit,fashion
|
129 |
+
126,cotton twill chinos in olive green with a slim fit,fashion
|
130 |
+
127,floral print wrap dress with flutter sleeves,fashion
|
131 |
+
128,denim overalls with a relaxed fit and side buttons,fashion
|
132 |
+
129,chunky heeled sandals in tan leather with ankle strap,fashion
|
133 |
+
130,sleek pencil skirt in faux leather with a back slit,fashion
|
134 |
+
131,fitted turtleneck in soft cotton in rich burgundy,fashion
|
135 |
+
132,knitted cardigan in soft beige with patch pockets,fashion
|
136 |
+
133,sleek black leather ankle boots with a pointed toe,fashion
|
137 |
+
134,canvas sneakers in bright yellow with white soles,fashion
|
138 |
+
135,elegant silk blouse featuring ruffled cuffs,fashion
|
139 |
+
136,cropped bomber jacket in olive green with ribbed cuffs,fashion
|
140 |
+
137,vibrant floral maxi dress with a cinched waist,fashion
|
141 |
+
138,soft flannel shirt in checkered red and black,fashion
|
142 |
+
139,chunky knit scarf in cream with fringed edges,fashion
|
143 |
+
140,tailored trousers in classic black with a straight cut,fashion
|
144 |
+
141,lightweight denim jacket with frayed hem and pockets,fashion
|
145 |
+
142,leather crossbody bag with an adjustable strap,fashion
|
146 |
+
143,striped linen shirt with rolled-up sleeves,fashion
|
147 |
+
144,flowy midi skirt with a watercolor print,fashion
|
148 |
+
145,soft jersey t-shirt in pastel pink with a crew neck,fashion
|
149 |
+
146,ribbed knit beanie in charcoal gray,fashion
|
150 |
+
147,soft cashmere sweater in a rich navy blue,fashion
|
151 |
+
148,vintage-inspired high-waisted jeans in dark wash,fashion
|
152 |
+
149,cotton sundress in bright yellow with a flared skirt,fashion
|
153 |
+
150,distressed denim jacket with a faded finish,fashion
|
154 |
+
151,lightweight parka in navy with a hood and drawstrings,fashion
|
155 |
+
152,pleated satin trousers in metallic gold,fashion
|
156 |
+
153,distressed boyfriend jeans with a relaxed silhouette,fashion
|
157 |
+
154,wool beanie in forest green with a cuffed edge,fashion
|
158 |
+
155,mesh-paneled leggings for active wear,fashion
|
159 |
+
156,canvas tote bag with a bold graphic print,fashion
|
160 |
+
157,long-sleeve wrap top in crisp white with a tie detail,fashion
|
161 |
+
158,midi dress in a bold animal print with a flowy hem,fashion
|
162 |
+
159,tailored shorts in crisp white with a hidden zipper,fashion
|
163 |
+
160,fitted blazer in a rich burgundy hue,fashion
|
164 |
+
161,quilted puffer vest in bright red with zip pockets,fashion
|
165 |
+
162,polka dot silk scarf in navy with white spots,fashion
|
166 |
+
163,sheer kimono in floral chiffon with wide sleeves,fashion
|
data/eval.csv
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
id,question,choices,answer
|
2 |
+
0,"[""What color are the trees in the forest?"", ""What time of day is depicted in the image?"", ""Are there any visible animals in the forest?"", ""What is the sky's color like in the image?"", ""Is there a path or trail visible in the forest?""]","[[""green"", ""purple"", ""brown"", ""yellow""], [""morning"", ""afternoon"", ""dusk"", ""midnight""], [""yes"", ""no""], [""blue"", ""purple"", ""orange"", ""gray""], [""yes"", ""no""]]","[""purple"", ""dusk"", ""no"", ""purple"", ""no""]"
|
3 |
+
1,"[""What color is the coat?"", ""What type of collar does the coat have?"", ""Is the coat long-sleeved or short-sleeved?"", ""What material is the coat made of?""]","[[""gray"", ""black"", ""brown"", ""blue""], [""faux fur"", ""cotton"", ""leather"", ""silk""], [""long-sleeved"", ""short-sleeved"", ""sleeveless""], [""wool"", ""denim"", ""polyester"", ""nylon""]]","[""gray"", ""faux fur"", ""long-sleeved"", ""wool""]"
|
4 |
+
2,"[""What color is the lighthouse?"", ""Are there any waves in the ocean?"", ""Is there a sun or moon in the sky?"", ""What is the primary color of the ocean?"", ""Does the lighthouse have a light at the top?""]","[[""red"", ""blue"", ""green"", ""white""], [""yes"", ""no""], [""sun"", ""moon"", ""none""], [""blue"", ""green"", ""brown"", ""gray""], [""yes"", ""no""]]","[""red"", ""yes"", ""sun"", ""blue"", ""yes""]"
|
5 |
+
3,"[""What color are the pants?"", ""What type of fabric are the pants made of?"", ""How many pockets do the pants have?"", ""What color are the buttons on the pants?""]","[[""red"", ""burgundy"", ""blue"", ""black""], [""denim"", ""corduroy"", ""cotton"", ""wool""], [""1"", ""2"", ""3"", ""4""], [""gold"", ""silver"", ""black"", ""white""]]","[""burgundy"", ""corduroy"", ""2"", ""silver""]"
|
6 |
+
4,"[""What color are the overalls?"", ""What texture is depicted on the overalls?"", ""Are there any straps visible on the overalls?"", ""What type of clothing is represented in the image?""]","[[""blue"", ""orange"", ""green"", ""red""], [""smooth"", ""corduroy"", ""denim"", ""silk""], [""yes"", ""no""], [""shirt"", ""pants"", ""overalls"", ""jacket""]]","[""orange"", ""corduroy"", ""yes"", ""overalls""]"
|
7 |
+
5,"[""What is the main color of the scarf?"", ""Does the scarf have any decorative trim?"", ""What material is the scarf made of?"", ""What kind of embellishments are present on the scarf?"", ""Is the scarf depicted as being tied or loose?""]","[[""red"", ""purple"", ""blue"", ""green""], [""yes"", ""no""], [""cotton"", ""silk"", ""wool"", ""linen""], [""beads"", ""tassels"", ""fringe"", ""embroidery""], [""tied"", ""loose""]]","[""purple"", ""yes"", ""silk"", ""tassels"", ""loose""]"
|
8 |
+
6,"[""What color is the lagoon?"", ""Are there clouds in the sky?"", ""What is the predominant color of the sky?"", ""Is there any land visible around the lagoon?""]","[[""blue"", ""green"", ""yellow"", ""red""], [""yes"", ""no""], [""gray"", ""blue"", ""white"", ""black""], [""yes"", ""no""]]","[""green"", ""yes"", ""gray"", ""no""]"
|
9 |
+
7,"[""What color are the rectangles in the image?"", ""Are the rectangles arranged in a uniform grid?"", ""What is the overall visual theme of the rectangles?"", ""Do the rectangles vary in size?""]","[[""blue"", ""crimson"", ""green"", ""yellow""], [""yes"", ""no""], [""chaotic"", ""structured"", ""minimalist"", ""symmetrical""], [""yes"", ""no""]]","[""crimson"", ""no"", ""chaotic"", ""yes""]"
|
10 |
+
8,"[""What color are the pyramids in the image?"", ""What is the shape of the main element at the center?"", ""How are the pyramids arranged around the cone?"", ""What material does the cone appear to be?""]","[[""red"", ""purple"", ""blue"", ""green""], [""sphere"", ""cube"", ""cone"", ""pyramid""], [""spiraling"", ""stacked"", ""scattered"", ""aligned""], [""gold"", ""silver"", ""bronze"", ""copper""]]","[""purple"", ""cone"", ""spiraling"", ""bronze""]"
|
11 |
+
9,"[""What color are the trapezoids?"", ""What is the texture of the sheet behind the trapezoids?"", ""How many trapezoids are layered on the sheet?"", ""What can be inferred about the visibility of the trapezoids?"", ""What geometric shape is featured in the image?""]","[[""red"", ""magenta"", ""blue"", ""green""], [""opaque"", ""glossy"", ""translucent"", ""matte""], [""one"", ""two"", ""three"", ""multiple""], [""they are fully visible"", ""they are partially hidden"", ""they are not visible""], [""circle"", ""square"", ""trapezoid"", ""triangle""]]","[""magenta"", ""translucent"", ""multiple"", ""they are partially hidden"", ""trapezoid""]"
|
12 |
+
10,"[""What is the predominant color of the plain?"", ""Are there any trees visible in the image?"", ""What type of weather is depicted in the image?"", ""Is there a sun or moon in the sky?""]","[[""white"", ""green"", ""brown"", ""blue""], [""yes"", ""no""], [""snowy"", ""sunny"", ""rainy"", ""cloudy""], [""sun"", ""moon"", ""none"", ""both""]]","[""white"", ""no"", ""snowy"", ""none""]"
|
13 |
+
11,"[""What color are the pants?"", ""What pattern is visible on the pants?"", ""Are the pants striped or checkered?"", ""Is there any color other than black and white in the pants?""]","[[""black"", ""white"", ""gray"", ""red""], [""solid"", ""polka dot"", ""checkered"", ""floral""], [""striped"", ""checkered"", ""plaid"", ""solid""], [""yes"", ""no""]]","[""black"", ""checkered"", ""checkered"", ""no""]"
|
14 |
+
12,"[""What kind of peaks are depicted in the image?"", ""What is the color of the sky in the image?"", ""Are there any stars visible in the image?"", ""What season does the image represent?""]","[[""rocky"", ""snow-covered"", ""forest-covered"", ""flat""], [""blue"", ""black"", ""gray"", ""orange""], [""yes"", ""no""], [""spring"", ""summer"", ""autumn"", ""winter""]]","[""snow-covered"", ""black"", ""yes"", ""winter""]"
|
15 |
+
13,"[""What color are the triangles?"", ""What shape do the azure elements resemble?"", ""How many different colors are used in the image?"", ""Which color is associated with the triangles?"", ""Are the crescents depicted in a solid color?""]","[[""green"", ""khaki"", ""blue"", ""red""], [""squares"", ""crescents"", ""rectangles"", ""triangles""], [""one"", ""two"", ""three"", ""four""], [""khaki"", ""azure"", ""yellow"", ""purple""], [""yes"", ""no"", ""partially"", ""unknown""]]","[""khaki"", ""crescents"", ""two"", ""khaki"", ""no""]"
|
16 |
+
14,"[""What color is the dodecahedron?"", ""What color are the threads interwoven with the dodecahedron?"", ""How many faces does the dodecahedron have?"", ""What is the primary geometric shape depicted in the image?""]","[[""red"", ""maroon"", ""blue"", ""green""], [""teal"", ""yellow"", ""pink"", ""black""], [""6"", ""12"", ""20"", ""8""], [""cube"", ""tetrahedron"", ""dodecahedron"", ""octahedron""]]","[""maroon"", ""teal"", ""12"", ""dodecahedron""]"
|
17 |
+
14,"[""What color is the sky in the image?"", ""What type of vegetation is predominant in the meadow?"", ""Are there any clouds in the sky?"", ""Is there any water present in the meadow?"", ""What is the overall mood conveyed by the image?""]","[[""blue"", ""gray"", ""white"", ""green""], [""grass"", ""desert"", ""trees"", ""flowers""], [""yes"", ""no""], [""yes"", ""no""], [""peaceful"", ""chaotic"", ""gloomy"", ""dark""]]","[""blue"", ""grass"", ""no"", ""no"", ""peaceful""]"
|
18 |
+
15,"[""What color is the beach in the image?"", ""What time of day is depicted in the image?"", ""Are there any palm trees on the beach?"", ""What is the condition of the sky in the image?""]","[[""bright coral"", ""dark brown"", ""sand yellow"", ""deep blue""], [""morning"", ""midday"", ""evening"", ""night""], [""yes"", ""no""], [""clear"", ""cloudy"", ""stormy"", ""sunset""]]","[""bright coral"", ""midday"", ""yes"", ""clear""]"
|
19 |
+
16,"[""What is the predominant weather condition depicted in the image?"", ""What color is the water of the fjord?"", ""Are there any mountains or cliffs visible in the background?"", ""Is there any visible wildlife in the image?"", ""What type of sky is depicted in the image?""]","[[""clear"", ""misty"", ""rainy"", ""snowy""], [""blue"", ""gray"", ""green"", ""brown""], [""yes"", ""no""], [""yes"", ""no""], [""sunny"", ""cloudy"", ""misty"", ""stormy""]]","[""misty"", ""gray"", ""yes"", ""no"", ""misty""]"
|
20 |
+
17,"[""What is the predominant color of the landscape?"", ""Are there any trees visible in the image?"", ""What type of animal might be present in the tundra?"", ""Is the sky clear or cloudy?""]","[[""blue"", ""green"", ""white"", ""brown""], [""yes"", ""no""], [""penguin"", ""caribou"", ""lion"", ""elephant""], [""clear"", ""cloudy"", ""sunset"", ""stormy""]]","[""white"", ""no"", ""caribou"", ""cloudy""]"
|
21 |
+
18,"[""What color are the wildflowers?"", ""Are the hills smooth or rugged?"", ""What is the overall mood of the landscape?"", ""Is there a body of water visible in the image?"", ""What season does the landscape depict?""]","[[""red"", ""yellow"", ""blue"", ""mixed""], [""smooth"", ""rugged""], [""serene"", ""stormy"", ""chaotic"", ""desolate""], [""yes"", ""no""], [""spring"", ""summer"", ""autumn"", ""winter""]]","[""mixed"", ""smooth"", ""serene"", ""no"", ""spring""]"
|
22 |
+
19,"[""What type of landscape is depicted in the image?"", ""What color are the grazing animals primarily?"", ""Are there any trees on the hillside?"", ""Is there a body of water visible in the image?"", ""What is the overall mood conveyed by the image?""]","[[""mountainous"", ""hillside"", ""flatland"", ""desert""], [""black"", ""brown"", ""white"", ""multicolored""], [""yes"", ""no""], [""yes"", ""no""], [""peaceful"", ""chaotic"", ""somber"", ""dynamic""]]","[""hillside"", ""brown"", ""yes"", ""no"", ""peaceful""]"
|
23 |
+
20,"[""What color is the water in the lake?"", ""What type of terrain is surrounding the lake?"", ""Are there any trees visible near the lake?""]","[[""blue"", ""green"", ""brown"", ""red""], [""mountains"", ""plains"", ""desert"", ""hills""], [""yes"", ""no""]]","[""blue"", ""mountains"", ""no""]"
|
24 |
+
21,"[""What type of terrain is depicted in the image?"", ""Are there any trees visible in the image?"", ""Does the image show any bodies of water?"", ""What is the predominant color of the rocky outcrop?"", ""Can you see a horizon line in the image?""]","[[""flat"", ""rocky"", ""sandy"", ""mountainous""], [""yes"", ""no""], [""yes"", ""no""], [""gray"", ""green"", ""blue"", ""brown""], [""yes"", ""no""]]","[""rocky"", ""no"", ""no"", ""gray"", ""yes""]"
|
25 |
+
22,"[""What color is the sand on the beach?"", ""Are there any palm trees in the image?"", ""What is the texture of the sand depicted in the image?"", ""Is there water visible in the image?"", ""Are there any people on the beach?""]","[[""white"", ""yellow"", ""black"", ""gray""], [""yes"", ""no""], [""rough"", ""soft"", ""rocky"", ""sandy""], [""yes"", ""no""], [""yes"", ""no""]]","[""white"", ""no"", ""soft"", ""yes"", ""no""]"
|
26 |
+
23,"[""What is the primary feature of the image?"", ""What color is the water in the pool?"", ""Is the waterfall visible in the image?"", ""What kind of atmosphere does the pool convey?""]","[[""waterfall"", ""mountain"", ""forest"", ""sky""], [""blue"", ""green"", ""clear"", ""brown""], [""yes"", ""no""], [""serene"", ""chaotic"", ""dark"", ""bright""]]","[""waterfall"", ""clear"", ""no"", ""serene""]"
|
27 |
+
24,"[""How many sailboats are anchored in the bay?"", ""What color are the sailboats?"", ""Is there a visible shoreline in the image?"", ""What is the overall mood conveyed by the image?"", ""Are there any clouds in the sky?""]","[[""1-2"", ""3-4"", ""5-6"", ""More than 6""], [""Red"", ""Blue"", ""White"", ""Green""], [""Yes"", ""No""], [""Serene"", ""Chaotic"", ""Sad"", ""Dramatic""], [""Yes"", ""No""]]","[""3-4"", ""White"", ""Yes"", ""Serene"", ""Yes""]"
|
28 |
+
25,"[""What color are the blossoms in the orchard?"", ""Are there any trees in the orchard?"", ""Is there a path visible in the orchard?"", ""What type of landscape is depicted in the image?""]","[[""pink"", ""blue"", ""yellow"", ""green""], [""yes"", ""no""], [""yes"", ""no""], [""mountainous"", ""urban"", ""rural"", ""desert""]]","[""pink"", ""yes"", ""yes"", ""rural""]"
|
29 |
+
26,"[""What color predominates the ice field?"", ""What feature is likely seen in the sky?"", ""What effect is visible on the surface of the ice?"", ""What time of day does the scene suggest?""]","[[""blue"", ""green"", ""brown"", ""gray""], [""clouds"", ""stars"", ""sun"", ""moon""], [""shimmering"", ""matte"", ""dull"", ""rough""], [""morning"", ""noon"", ""evening"", ""night""]]","[""blue"", ""sun"", ""shimmering"", ""noon""]"
|
30 |
+
27,"[""What color are the leaves reflecting in the river?"", ""Is the river depicted as calm or turbulent?"", ""What kind of texture might the water surface have?"", ""Are there any animals present in the image?""]","[[""red"", ""blue"", ""green"", ""yellow""], [""calm"", ""turbulent""], [""smooth"", ""rough"", ""bumpy"", ""choppy""], [""yes"", ""no""]]","[""red"", ""calm"", ""smooth"", ""no""]"
|
31 |
+
28,"[""What predominant colors can be seen in the forest?"", ""Are there any animals visible in the image?"", ""What type of trees are primarily depicted in the forest?"", ""Is there a clear sky visible in the image?""]","[[""red, orange, yellow"", ""blue, green, purple"", ""black, white, gray""], [""yes"", ""no""], [""evergreen"", ""deciduous"", ""cacti"", ""palm""], [""yes"", ""no""]]","[""red, orange, yellow"", ""no"", ""deciduous"", ""no""]"
|
32 |
+
29,"[""What type of vegetation lines the path?"", ""Is the path straight or winding?"", ""What is the overall mood of the image?"", ""Are there any animals visible in the image?""]","[[""flowers"", ""ferns"", ""trees"", ""grass""], [""straight"", ""winding""], [""tranquil"", ""chaotic"", ""gloomy"", ""bright""], [""yes"", ""no""]]","[""ferns"", ""winding"", ""tranquil"", ""no""]"
|
33 |
+
30,"[""What types of plants are predominantly visible in the jungle image?"", ""Are there any animals depicted in the jungle scene?"", ""What color are the leaves in the jungle?"", ""Is there any water element present in the image?"", ""What is the overall mood conveyed by the jungle scene?""]","[[""tropical ferns and palm trees"", ""desert cacti"", ""deciduous trees"", ""coniferous trees""], [""yes, monkeys and birds"", ""no animals"", ""only insects"", ""only reptiles""], [""deep green"", ""brown"", ""yellow"", ""grey""], [""yes, a river"", ""no water"", ""only puddles"", ""a waterfall""], [""tranquil and peaceful"", ""dark and ominous"", ""chaotic and stormy"", ""bright and lively""]]","[""tropical ferns and palm trees"", ""yes, monkeys and birds"", ""deep green"", ""yes, a river"", ""bright and lively""]"
|
34 |
+
31,"[""What is the primary color of the grasslands?"", ""Are there any clouds in the sky?"", ""Is there a river or stream visible in the image?"", ""What time of day does the lighting suggest?"", ""Is there any wildlife depicted in the image?""]","[[""green"", ""brown"", ""yellow"", ""blue""], [""yes"", ""no""], [""yes"", ""no""], [""morning"", ""noon"", ""evening"", ""night""], [""yes"", ""no""]]","[""green"", ""no"", ""no"", ""noon"", ""no""]"
|
35 |
+
32,"[""What color are the lily pads in the pond?"", ""How many frogs are visible in the image?"", ""What is the primary feature of the pond?"", ""Are there any flowers present on the lily pads?""]","[[""green"", ""blue"", ""yellow"", ""red""], [""one"", ""two"", ""three"", ""four""], [""lily pads"", ""fish"", ""turtles"", ""rocks""], [""yes"", ""no""]]","[""green"", ""two"", ""lily pads"", ""no""]"
|
36 |
+
33,"[""What color are the sunflower petals?"", ""Are there any clouds in the sky?"", ""What is the predominant color of the field?"", ""How tall do the sunflowers appear to be?""]","[[""yellow"", ""red"", ""blue"", ""green""], [""yes"", ""no""], [""green"", ""brown"", ""yellow"", ""purple""], [""short"", ""medium"", ""tall"", ""dwarf""]]","[""yellow"", ""no"", ""green"", ""tall""]"
|
37 |
+
34,"[""What type of shoreline is depicted in the image?"", ""Are there visible waves in the image?"", ""What color might the waves be?"", ""What texture is likely seen on the shoreline?"", ""Is there any foliage or vegetation present in the image?""]","[[""sandy"", ""craggy"", ""smooth"", ""rocky""], [""yes"", ""no""], [""blue"", ""green"", ""white"", ""brown""], [""smooth"", ""craggy"", ""flat"", ""sandy""], [""yes"", ""no""]]","[""craggy"", ""yes"", ""white"", ""craggy"", ""no""]"
|
38 |
+
35,"[""What is the predominant color of the sky in the image?"", ""Are there any clouds visible in the skyline?"", ""What type of building is most prominently featured in the skyline?"", ""Is there any light coming from the buildings?"", ""What time of day is depicted in the image?""]","[[""blue"", ""purple"", ""orange"", ""pink""], [""yes"", ""no""], [""skyscrapers"", ""houses"", ""trees"", ""bridges""], [""yes"", ""no""], [""morning"", ""afternoon"", ""twilight"", ""night""]]","[""purple"", ""no"", ""skyscrapers"", ""yes"", ""twilight""]"
|
39 |
+
36,"[""What color primarily represents the grassy hilltop?"", ""Are there any trees visible in the image?"", ""What is the weather condition depicted in the image?"", ""What type of view is visible from the hilltop?""]","[[""green"", ""brown"", ""yellow"", ""blue""], [""yes"", ""no""], [""sunny"", ""cloudy"", ""rainy"", ""snowy""], [""mountains"", ""cityscape"", ""ocean"", ""forest""]]","[""green"", ""yes"", ""sunny"", ""mountains""]"
|
40 |
+
37,"[""What colors are primarily visible on the canyon walls?"", ""How steep are the walls of the canyon?"", ""Is there any vegetation present in the canyon?"", ""What is the width of the canyon?"", ""Does the canyon have a visible sky above it?""]","[[""red and orange"", ""blue and green"", ""grey and brown"", ""black and white""], [""gently sloped"", ""moderately steep"", ""vertical"", ""overhanging""], [""yes"", ""no""], [""very narrow"", ""moderately wide"", ""very wide"", ""not specified""], [""yes"", ""no""]]","[""red and orange"", ""vertical"", ""no"", ""very narrow"", ""yes""]"
|
41 |
+
38,"[""What type of vegetation is primarily depicted in the glen?"", ""Is there a visible stream in the image?"", ""What is the overall color scheme of the image?"", ""Are there any animals present in the glen?"", ""What is the general mood conveyed by the image?""]","[[""tall trees"", ""cacti"", ""desert shrubs"", ""tropical plants""], [""yes"", ""no""], [""bright and vibrant"", ""dark and moody"", ""monochrome"", ""pastel""], [""birds"", ""deer"", ""no animals"", ""fish""], [""peaceful"", ""chaotic"", ""tense"", ""mysterious""]]","[""tall trees"", ""yes"", ""bright and vibrant"", ""birds"", ""peaceful""]"
|
42 |
+
39,"[""What color are the leaves depicted in the image?"", ""What is the primary shape of the path in the image?"", ""Are there any animals visible in the image?"", ""What season is represented by the leaves in the image?"", ""Is the path straight or winding?""]","[[""red"", ""golden"", ""green"", ""brown""], [""straight"", ""winding"", ""zigzag"", ""curved""], [""yes"", ""no"", ""only silhouettes"", ""not sure""], [""spring"", ""summer"", ""autumn"", ""winter""], [""straight"", ""winding"", ""circular"", ""none""]]","[""golden"", ""winding"", ""no"", ""autumn"", ""winding""]"
|
43 |
+
40,"[""What color are the waters surrounding the island?"", ""What type of landform is depicted on the island?"", ""Is there any vegetation visible on the island?"", ""What is the overall atmosphere of the image?""]","[[""blue"", ""turquoise"", ""green"", ""clear""], [""mountain"", ""deserted island"", ""cliff"", ""peninsula""], [""yes"", ""no""], [""crowded"", ""deserted"", ""urban"", ""industrial""]]","[""turquoise"", ""deserted island"", ""yes"", ""deserted""]"
|
44 |
+
41,"[""What type of terrain is depicted in the image?"", ""How is the sky depicted in the image?"", ""Are there any trees visible in the image?"", ""What kind of celestial bodies are present in the sky?""]","[[""sandy beach"", ""rocky plateau"", ""forest"", ""mountain range""], [""clear blue"", ""cloudy"", ""blanket of stars"", ""sunset""], [""yes"", ""no""], [""planets"", ""stars"", ""moons"", ""comets""]]","[""rocky plateau"", ""blanket of stars"", ""no"", ""stars""]"
|
45 |
+
42,"[""What color dominates the sky in the image?"", ""What is the predominant color of the desert sand?"", ""Are there any plants visible in the image?"", ""What time of day is depicted in the image?""]","[[""blue"", ""golden"", ""gray"", ""pink""], [""golden"", ""green"", ""brown"", ""white""], [""yes"", ""no""], [""morning"", ""noon"", ""sunset"", ""midnight""]]","[""golden"", ""golden"", ""no"", ""sunset""]"
|
46 |
+
43,"[""What type of trees are depicted in the glade?"", ""Are there birds visible in the image?"", ""What is the predominant color of the sunlight in the glade?"", ""Is there any water depicted in the scene?""]","[[""oaks"", ""pines"", ""maples"", ""willows""], [""yes"", ""no""], [""yellow"", ""blue"", ""green"", ""red""], [""yes"", ""no""]]","[""oaks"", ""yes"", ""yellow"", ""no""]"
|
47 |
+
44,"[""What color predominates the coral in the image?"", ""What is the clarity of the water above the coral reef?"", ""What type of sea life is likely present in the reef?"", ""What is the general atmosphere of the scene?""]","[[""red"", ""blue"", ""green"", ""yellow""], [""crystal clear"", ""murky"", ""cloudy"", ""dark""], [""fish"", ""crabs"", ""seaweed"", ""all of the above""], [""tranquil"", ""stormy"", ""chaotic"", ""dull""]]","[""red"", ""crystal clear"", ""all of the above"", ""tranquil""]"
|
48 |
+
45,"[""What color dominates the cliff in the image?"", ""Is there a river visible in the image?"", ""What is the texture of the cliff surface?"", ""What is the overall mood conveyed by the image?""]","[[""black"", ""white"", ""blue"", ""green""], [""yes"", ""no""], [""smooth"", ""bumpy"", ""sandy"", ""wet""], [""calm"", ""dramatic"", ""cheerful"", ""sad""]]","[""black"", ""yes"", ""bumpy"", ""dramatic""]"
|
49 |
+
46,"[""What color predominantly represents the valley?"", ""What type of terrain is visible in the foreground?"", ""How are the peaks depicted in relation to the valley?"", ""What is the overall atmosphere of the image?""]","[[""green"", ""brown"", ""blue"", ""yellow""], [""flat"", ""rocky"", ""hilly"", ""sandy""], [""tall and imposing"", ""small and gentle"", ""flat"", ""invisible""], [""stormy"", ""serene"", ""chaotic"", ""urban""]]","[""green"", ""hilly"", ""tall and imposing"", ""serene""]"
|
50 |
+
47,"[""What is the predominant color of the lake?"", ""What type of trees surround the lake?"", ""Is there any visible wildlife near the lake?"", ""What is the terrain around the lake like?"", ""What is the weather condition depicted in the image?""]","[[""blue"", ""green"", ""brown"", ""gray""], [""oak"", ""pines"", ""maple"", ""birch""], [""yes"", ""no""], [""rocky"", ""flat"", ""hilly"", ""sandy""], [""sunny"", ""rainy"", ""foggy"", ""snowy""]]","[""blue"", ""pines"", ""no"", ""rocky"", ""sunny""]"
|
51 |
+
48,"[""What type of landscape is depicted in the image?"", ""Are there any houses visible in the village?"", ""What color are the hills in the background?"", ""What type of vegetation is present in the village?""]","[[""mountains"", ""rolling hills"", ""flat plains"", ""desert""], [""yes"", ""no""], [""green"", ""brown"", ""yellow"", ""gray""], [""trees"", ""cacti"", ""palm trees"", ""bushes""]]","[""rolling hills"", ""yes"", ""green"", ""trees""]"
|
52 |
+
49,"[""What is the primary light source in the image?"", ""What type of trees are predominantly depicted in the forest?"", ""Is there any visible wildlife in the image?"", ""What is the overall color tone of the forest scene?""]","[[""moonlight"", ""sunlight"", ""firelight"", ""torchlight""], [""pines"", ""oaks"", ""willows"", ""maples""], [""yes"", ""no""], [""warm hues"", ""cool hues"", ""black and white"", ""bright colors""]]","[""moonlight"", ""pines"", ""no"", ""cool hues""]"
|
53 |
+
50,"[""What colors are predominantly visible in the wildflower meadow?"", ""Are there any trees in the background of the meadow?"", ""What type of flowers can be seen in the meadow?"", ""Is there a clear blue sky above the meadow?"", ""What is the overall mood conveyed by the image?""]","[[""red, yellow, blue, green"", ""black and white"", ""monochrome"", ""pastel colors""], [""yes"", ""no""], [""roses"", ""daisies"", ""sunflowers"", ""all of the above""], [""yes"", ""no""], [""cheerful"", ""gloomy"", ""neutral"", ""tense""]]","[""red, yellow, blue, green"", ""no"", ""all of the above"", ""yes"", ""cheerful""]"
|
54 |
+
51,"[""What type of landscape is depicted in the image?"", ""Are there rows of plants visible in the vineyard?"", ""What is the predominant weather condition suggested by the description?"", ""Is there a sun present in the image?"", ""What color might the grapes in the vineyard be?""]","[[""mountainous"", ""flat"", ""gentle slope"", ""hilly""], [""yes"", ""no""], [""rainy"", ""sunny"", ""stormy"", ""foggy""], [""yes"", ""no""], [""green"", ""red"", ""purple"", ""all of the above""]]","[""gentle slope"", ""yes"", ""sunny"", ""yes"", ""all of the above""]"
|
55 |
+
52,"[""What type of flowers are prominently featured in the garden?"", ""Are there any trees visible in the garden?"", ""What color dominates the flowers in the garden?"", ""Is there any visible pathway in the garden?"", ""What type of foliage can be observed in the garden?""]","[[""roses"", ""daisies"", ""tulips"", ""sunflowers""], [""yes"", ""no""], [""yellow"", ""blue"", ""pink"", ""white""], [""yes"", ""no""], [""ferns"", ""cacti"", ""pines"", ""bamboo""]]","[""tulips"", ""yes"", ""pink"", ""yes"", ""ferns""]"
|
56 |
+
53,"[""What is the primary feature of the landscape?"", ""How does the sky appear in the image?"", ""What texture is likely present on the dune?"", ""What colors might dominate the scene?""]","[[""a windswept dune"", ""a forest"", ""a mountain"", ""a lake""], [""clear and blue"", ""stormy and dark"", ""sunset hues"", ""cloudy""], [""smooth and soft"", ""rocky and rough"", ""wet and muddy"", ""frozen and hard""], [""sandy beige and yellow"", ""green and brown"", ""blue and grey"", ""purple and pink""]]","[""a windswept dune"", ""clear and blue"", ""smooth and soft"", ""sandy beige and yellow""]"
|
57 |
+
54,"[""What color dominates the sky in the image?"", ""Are there any trees visible in the valley?"", ""What is the predominant weather condition depicted?"", ""Is there a river or stream in the valley?"", ""What time of day is represented in the image?""]","[[""blue"", ""orange"", ""gray"", ""purple""], [""yes"", ""no""], [""clear"", ""foggy"", ""rainy"", ""snowy""], [""yes"", ""no""], [""dawn"", ""noon"", ""dusk"", ""midnight""]]","[""orange"", ""yes"", ""foggy"", ""no"", ""dawn""]"
|
58 |
+
55,"[""What color is the sea in the image?"", ""What type of terrain is depicted in the image?"", ""Are there any clouds in the sky?"", ""What is the texture of the cliff?"", ""Is there any vegetation on the cliff?""]","[[""blue"", ""green"", ""gray"", ""brown""], [""rocky"", ""sandy"", ""flat"", ""hilly""], [""yes"", ""no""], [""smooth"", ""rough"", ""wet"", ""dry""], [""yes"", ""no""]]","[""blue"", ""rocky"", ""no"", ""rough"", ""no""]"
|
59 |
+
56,"[""What type of terrain is depicted in the image?"", ""Are there any visible waves in the image?"", ""What colors are predominantly used to represent the sea?"", ""Is there any vegetation shown along the coastline?""]","[[""sandy beach"", ""rugged coastline"", ""flat plain"", ""mountainous region""], [""yes"", ""no""], [""blue and white"", ""green and yellow"", ""brown and gray"", ""red and orange""], [""yes"", ""no""]]","[""rugged coastline"", ""yes"", ""blue and white"", ""no""]"
|
60 |
+
57,"[""What colors dominate the canyon's landscape?"", ""Are there any water features visible in the canyon?"", ""What type of vegetation can be seen in the canyon?"", ""Is there a sky visible in the image?"", ""What geological features are prominent in the canyon?""]","[[""red and orange"", ""blue and green"", ""black and white"", ""purple and yellow""], [""yes"", ""no""], [""cacti"", ""pine trees"", ""flowers"", ""none""], [""yes"", ""no""], [""sharp cliffs"", ""flat plains"", ""rolling hills"", ""deep valleys""]]","[""red and orange"", ""no"", ""cacti"", ""yes"", ""sharp cliffs""]"
|
61 |
+
58,"[""What color dominates the mountain range?"", ""Are there visible clouds in the image?"", ""How many peaks are visible in the mountain range?"", ""Is the atmosphere in the image bright and clear?""]","[[""green"", ""blue"", ""gray"", ""brown""], [""yes"", ""no""], [""one"", ""two"", ""three"", ""four""], [""yes"", ""no""]]","[""gray"", ""yes"", ""three"", ""no""]"
|
62 |
+
59,"[""What type of trees are prominently featured in the image?"", ""What is the primary color of the grass in the savanna?"", ""How many acacia trees are visible in the image?"", ""Is there a clear sky visible in the image?""]","[[""palm trees"", ""acacia trees"", ""oak trees"", ""birch trees""], [""green"", ""brown"", ""yellow"", ""blue""], [""none"", ""one"", ""several"", ""too many to count""], [""yes"", ""no""]]","[""acacia trees"", ""yellow"", ""several"", ""yes""]"
|
63 |
+
60,"[""What color are the waters in the cove?"", ""Is there any vegetation visible in the image?"", ""What type of landform is surrounding the cove?"", ""Are there any boats in the water?"", ""What is the general atmosphere of the cove?""]","[[""green"", ""blue"", ""brown"", ""clear""], [""yes"", ""no""], [""mountains"", ""flat land"", ""cliffs"", ""sand dunes""], [""yes"", ""no""], [""busy"", ""secluded"", ""industrial"", ""urban""]]","[""blue"", ""yes"", ""cliffs"", ""no"", ""secluded""]"
|
64 |
+
61,"[""What is the predominant atmosphere in the image?"", ""What color are the grasses likely to be?"", ""Is there any visible water in the marsh?"", ""How are the grasses depicted in the image?""]","[[""sunny"", ""foggy"", ""clear"", ""stormy""], [""green"", ""brown"", ""yellow"", ""blue""], [""yes"", ""no""], [""swaying gently"", ""standing still"", ""bent over"", ""dried up""]]","[""foggy"", ""green"", ""yes"", ""swaying gently""]"
|
65 |
+
62,"[""What color is the river in the image?"", ""What type of vegetation surrounds the river?"", ""Is there any wildlife depicted near the river?"", ""What is the overall mood or tone of the image?""]","[[""blue"", ""green"", ""brown"", ""red""], [""tall grass"", ""desert shrubs"", ""lush trees"", ""cacti""], [""birds"", ""fish"", ""deer"", ""none""], [""serene"", ""chaotic"", ""dramatic"", ""gloomy""]]","[""blue"", ""lush trees"", ""none"", ""serene""]"
|
66 |
+
63,"[""What color dominates the sands in the landscape?"", ""What type of geological feature is prominently visible in the image?"", ""Are there any vegetation or plants depicted in the scene?"", ""What is the overall atmosphere of the landscape?""]","[[""black"", ""white"", ""brown"", ""yellow""], [""volcanoes"", ""mountains"", ""rivers"", ""lakes""], [""yes"", ""no""], [""calm"", ""dramatic"", ""peaceful"", ""chaotic""]]","[""black"", ""volcanoes"", ""no"", ""dramatic""]"
|
67 |
+
64,"[""What is the primary color of the waves in the image?"", ""What pattern do the stripes in the image create?"", ""How would you describe the movement of the elements in the image?"", ""Which color is dominant in the stripes?""]","[[""teal"", ""coral"", ""blue"", ""green""], [""horizontal"", ""vertical"", ""diagonal"", ""spiral""], [""static"", ""dynamic"", ""still"", ""fixed""], [""teal"", ""coral"", ""yellow"", ""purple""]]","[""teal"", ""horizontal"", ""dynamic"", ""coral""]"
|
68 |
+
65,"[""What predominant colors are present in the image?"", ""Is there a gradient effect in the image?"", ""What is the overall tone of the image?"", ""Are there any geometric shapes defined in the image?""]","[[""peach and plum"", ""blue and green"", ""red and yellow"", ""black and white""], [""yes"", ""no""], [""warm"", ""cool"", ""neutral"", ""dark""], [""yes"", ""no"", ""only lines"", ""only textures""]]","[""peach and plum"", ""yes"", ""warm"", ""no""]"
|
69 |
+
66,"[""What color are the triangles in the image?"", ""What is the background color of the image?"", ""Are there any circles present in the image?"", ""What shape predominantly features in the image?"", ""How would you describe the arrangement of the triangles?""]","[[""burnt orange"", ""pale blue"", ""green"", ""yellow""], [""burnt orange"", ""pale blue"", ""black"", ""white""], [""yes"", ""no""], [""square"", ""triangle"", ""rectangle"", ""oval""], [""randomly scattered"", ""neatly aligned"", ""overlapping"", ""in a circular pattern""]]","[""burnt orange"", ""pale blue"", ""no"", ""triangle"", ""randomly scattered""]"
|
70 |
+
67,"[""What color are the squares in the image?"", ""What is the background color of the image?"", ""How would you describe the arrangement of the squares?"", ""Are there any circles in the image?"", ""What geometric shape is primarily featured in the image?""]","[[""bright cyan"", ""dark gray"", ""bright red"", ""light blue""], [""dark gray"", ""bright cyan"", ""white"", ""black""], [""floating"", ""stacked"", ""aligned"", ""overlapping""], [""yes"", ""no""], [""square"", ""circle"", ""triangle"", ""rectangle""]]","[""bright cyan"", ""dark gray"", ""floating"", ""no"", ""square""]"
|
71 |
+
68,"[""What colors are predominantly used in the image?"", ""Are the lines predominantly straight, curved, or both?"", ""Is there a pattern to the arrangement of the lines?"", ""Do the lines overlap each other?""]","[[""red and blue"", ""yellow and purple"", ""green and orange""], [""straight"", ""curved"", ""both"", ""neither""], [""yes"", ""no""], [""yes"", ""no""]]","[""yellow and purple"", ""both"", ""no"", ""yes""]"
|
72 |
+
69,"[""Are there contrasting colors present in the image?"", ""What type of patterns can be observed in the image?"", ""Is there a dominant color that stands out in the composition?"", ""Do the shapes in the image appear to be geometric or organic?"", ""Is there a sense of depth created by overlapping colors?""]","[[""yes"", ""no""], [""stripes"", ""polka dots"", ""swirls"", ""rhythmic patterns""], [""yes"", ""no""], [""geometric"", ""organic"", ""both"", ""neither""], [""yes"", ""no""]]","[""yes"", ""rhythmic patterns"", ""yes"", ""both"", ""yes""]"
|
73 |
+
70,"[""What color are the spirals in the image?"", ""What geometric shape is intertwined with the spirals?"", ""What color are the rectangles in the image?"", ""Are the spirals solid or outlined?"", ""How many different shapes are present in the image?""]","[[""blue"", ""green"", ""red"", ""purple""], [""circle"", ""rectangle"", ""triangle"", ""oval""], [""gold"", ""silver"", ""black"", ""white""], [""solid"", ""outlined"", ""dashed"", ""none""], [""one"", ""two"", ""three"", ""four""]]","[""blue"", ""rectangle"", ""silver"", ""solid"", ""two""]"
|
74 |
+
71,"[""What colors are predominantly used in the squares?"", ""Are the squares arranged in a uniform or varying pattern?"", ""What is the overall effect of the layers of squares?"", ""Do the squares overlap to create a sense of depth?"", ""Is there any other shape present in the image?""]","[[""blue and red"", ""olive and gold"", ""black and white"", ""purple and orange""], [""uniform pattern"", ""varying pattern"", ""circular pattern"", ""diagonal pattern""], [""flat appearance"", ""sense of depth"", ""chaotic look"", ""minimalist design""], [""yes"", ""no""], [""yes"", ""no""]]","[""olive and gold"", ""varying pattern"", ""sense of depth"", ""yes"", ""no""]"
|
75 |
+
72,"[""What colors are predominantly used in the circles?"", ""Are the circles arranged in a linear fashion?"", ""Do the circles get larger or smaller as they spiral inward?"", ""How many distinct colors are present in the circles?""]","[[""red and blue"", ""crimson and cobalt"", ""green and yellow"", ""black and white""], [""yes"", ""no""], [""larger"", ""smaller""], [""one"", ""two"", ""three"", ""four""]]","[""crimson and cobalt"", ""no"", ""smaller"", ""two""]"
|
76 |
+
73,"[""What color is predominantly featured in the shapes?"", ""Are the shapes solid or translucent?"", ""How many different shades are present in the image?"", ""What effect do the layered shapes create?"", ""Is there any use of gradients in the image?""]","[[""red"", ""teal"", ""blue"", ""purple""], [""solid"", ""translucent"", ""opaque"", ""transparent""], [""1"", ""2"", ""3"", ""4""], [""depth"", ""flatness"", ""chaos"", ""simplicity""], [""yes"", ""no""]]","[""teal"", ""translucent"", ""2"", ""depth"", ""yes""]"
|
77 |
+
74,"[""What color dominates the sharp angles in the image?"", ""Are there any curved shapes present in the image?"", ""What kind of illusion does the arrangement of black and white create?"", ""How many distinct colors are used in the image?"", ""What geometric shapes are primarily featured in the image?""]","[[""black"", ""white"", ""gray"", ""red""], [""yes"", ""no""], [""depth illusion"", ""motion illusion"", ""color illusion"", ""text illusion""], [""one"", ""two"", ""three"", ""four""], [""triangles"", ""circles"", ""squares"", ""ovals""]]","[""black"", ""no"", ""depth illusion"", ""two"", ""triangles""]"
|
78 |
+
75,"[""What color are the polygons in the image?"", ""What is the background color of the image?"", ""How are the polygons arranged in the image?"", ""What type of shapes are present in the image?""]","[[""red"", ""fuchsia"", ""blue"", ""green""], [""white"", ""cream"", ""pink"", ""yellow""], [""scattered"", ""stacked"", ""in a line"", ""cascading""], [""circles"", ""polygons"", ""lines"", ""squares""]]","[""fuchsia"", ""cream"", ""cascading"", ""polygons""]"
|
79 |
+
76,"[""What color are the circles in the image?"", ""What color are the squares in the image?"", ""Do the circles overlap with the squares?"", ""What is the predominant shape in the image?"", ""Are there any triangles present in the image?""]","[[""gold"", ""blue"", ""red"", ""green""], [""gold"", ""blue"", ""yellow"", ""purple""], [""yes"", ""no""], [""circle"", ""square"", ""triangle"", ""rectangle""], [""yes"", ""no""]]","[""gold"", ""blue"", ""yes"", ""circle"", ""no""]"
|
80 |
+
77,"[""What color are the triangles in the image?"", ""What color are the dots in the image?"", ""What is the background color of the image?"", ""How many distinct colors are present in the image?"", ""What shape is primarily featured in the image?""]","[[""red"", ""yellow"", ""blue"", ""green""], [""black"", ""white"", ""yellow"", ""red""], [""black"", ""gray"", ""white"", ""yellow""], [""two"", ""three"", ""four"", ""five""], [""circle"", ""square"", ""triangle"", ""rectangle""]]","[""yellow"", ""black"", ""white"", ""two"", ""triangle""]"
|
81 |
+
78,"[""What color dominates the clouds in the image?"", ""What type of red is present in the image?"", ""Are the clouds depicted in a geometric style?"", ""Is there a contrast between colors in the image?"", ""What is the overall mood conveyed by the juxtaposition of colors?""]","[[""gray"", ""white"", ""blue"", ""black""], [""fiery red"", ""dark red"", ""pale red"", ""muted red""], [""yes"", ""no""], [""yes"", ""no""], [""calm"", ""chaotic"", ""neutral"", ""sad""]]","[""gray"", ""fiery red"", ""yes"", ""yes"", ""chaotic""]"
|
82 |
+
79,"[""What is the dominant color in the patchwork?"", ""Are there any bright yellow sections in the image?"", ""What type of pattern is depicted in the image?"", ""Is there a mix of deep reds and bright yellows present?""]","[[""deep red"", ""bright yellow"", ""blue"", ""green""], [""yes"", ""no""], [""stripes"", ""polka dots"", ""patchwork"", ""solid""], [""yes"", ""no""]]","[""deep red"", ""yes"", ""patchwork"", ""yes""]"
|
83 |
+
80,"[""What color are the hexagons in the image?"", ""What is the background color of the image?"", ""How many sides does each hexagon have?"", ""Are the hexagons arranged in a regular pattern?"", ""Do the hexagons have a glossy or matte finish?""]","[[""lavender"", ""charcoal"", ""blue"", ""green""], [""charcoal"", ""lavender"", ""white"", ""black""], [""4"", ""5"", ""6"", ""8""], [""yes"", ""no"", ""randomly"", ""diagonally""], [""glossy"", ""matte"", ""transparent"", ""metallic""]]","[""lavender"", ""charcoal"", ""6"", ""yes"", ""matte""]"
|
84 |
+
81,"[""What color predominantly represents the threads in the image?"", ""Are there any natural elements depicted in the landscape?"", ""Do the threads appear to create a sense of depth in the landscape?"", ""What is the secondary color used alongside silver in the weaving?"", ""Is the overall mood of the image warm or cool?""]","[[""silver"", ""gold"", ""blue"", ""green""], [""yes"", ""no""], [""yes"", ""no""], [""burgundy"", ""black"", ""white"", ""yellow""], [""warm"", ""cool""]]","[""silver"", ""yes"", ""yes"", ""burgundy"", ""cool""]"
|
85 |
+
82,"[""What color are the lines radiating from the star?"", ""What shape does the central star resemble?"", ""How many lines are radiating from the central star?"", ""What is the main color of the star in the center?""]","[[""red"", ""turquoise"", ""blue"", ""green""], [""circle"", ""star"", ""square"", ""triangle""], [""2"", ""5"", ""10"", ""8""], [""ruby"", ""sapphire"", ""emerald"", ""diamond""]]","[""turquoise"", ""star"", ""10"", ""ruby""]"
|
86 |
+
83,"[""What primary colors are present in the lattice design?"", ""What type of shapes are primarily used in the image?"", ""How are the mauve and chartreuse forms arranged in relation to each other?"", ""Are the intersecting forms transparent or solid?"", ""Is there a predominant background color in the image?""]","[[""red and blue"", ""mauve and chartreuse"", ""green and yellow"", ""black and white""], [""circles"", ""squares"", ""triangles"", ""irregular forms""], [""overlapping"", ""side by side"", ""stacked"", ""randomly dispersed""], [""transparent"", ""solid"", ""gradient"", ""textured""], [""white"", ""black"", ""none"", ""mauve""]]","[""mauve and chartreuse"", ""irregular forms"", ""overlapping"", ""solid"", ""none""]"
|
87 |
+
84,"[""What is the predominant color of the background?"", ""What color are the chaotic lines?"", ""How would you describe the pattern created by the lines?"", ""Is the background solid or textured?"", ""Are the lines straight or curved?""]","[[""red"", ""blue"", ""gold"", ""green""], [""dark green"", ""light green"", ""brown"", ""black""], [""orderly"", ""chaotic"", ""geometric"", ""symmetrical""], [""solid"", ""textured"", ""patterned"", ""transparent""], [""straight"", ""curved"", ""zigzag"", ""intertwined""]]","[""gold"", ""dark green"", ""chaotic"", ""solid"", ""curved""]"
|
88 |
+
85,"[""What color are the diamonds in the image?"", ""What is the background color of the canvas?"", ""Are the diamonds evenly distributed across the canvas?"", ""Which of the following shapes is present in the image?"", ""What is the overall theme of the image?""]","[[""red"", ""emerald"", ""blue"", ""yellow""], [""green"", ""blue"", ""warm orange"", ""purple""], [""yes"", ""no""], [""circle"", ""square"", ""diamond"", ""triangle""], [""cool colors"", ""warm colors"", ""monochrome"", ""pastel""]]","[""emerald"", ""warm orange"", ""no"", ""diamond"", ""warm colors""]"
|
89 |
+
86,"[""What colors are predominantly used in the image?"", ""What direction do the lines in the image primarily run?"", ""What type of line is featured in the image?""]","[[""red and blue"", ""plum and mint"", ""yellow and green"", ""black and white""], [""horizontal"", ""vertical"", ""diagonal"", ""circular""], [""dashed"", ""solid"", ""curved"", ""zigzag""]]","[""plum and mint"", ""diagonal"", ""solid""]"
|
90 |
+
87,"[""What color are the squares in the image?"", ""What color is used for the splashes in the image?"", ""How many bold black squares are present?"", ""What shape do the splashes take in the image?""]","[[""red"", ""blue"", ""black"", ""green""], [""turquoise"", ""yellow"", ""pink"", ""orange""], [""1"", ""2"", ""3"", ""4""], [""circle"", ""splash"", ""square"", ""triangle""]]","[""black"", ""turquoise"", ""3"", ""splash""]"
|
91 |
+
88,"[""What predominant color is featured in the image?"", ""Are there any curved shapes present in the image?"", ""What type of angles are represented in the image?"", ""Is there a gradient effect in the lavender color?"", ""How does the black elements contrast with the lavender?""]","[[""lavender"", ""red"", ""blue"", ""green""], [""yes"", ""no""], [""sharp"", ""rounded"", ""obtuse"", ""right""], [""yes"", ""no""], [""high contrast"", ""low contrast"", ""no contrast"", ""monochromatic""]]","[""lavender"", ""yes"", ""sharp"", ""yes"", ""high contrast""]"
|
92 |
+
89,"[""What color are the spirals in the image?"", ""What is the background color of the canvas?"", ""Do the spirals have a soft or sharp appearance?"", ""Are the spirals uniform in size or varied?"", ""Is there any other color present besides soft pink and cream?""]","[[""soft pink"", ""bright red"", ""dark blue"", ""yellow""], [""cream"", ""white"", ""light gray"", ""beige""], [""soft"", ""sharp"", ""jagged"", ""angular""], [""uniform"", ""varied"", ""none"", ""overlapping""], [""yes"", ""no""]]","[""soft pink"", ""cream"", ""soft"", ""varied"", ""no""]"
|
93 |
+
90,"[""What color are the circles in the image?"", ""What type of lines are present in the image?"", ""Is there more than one red circle in the composition?"", ""Are the lines in the image curved or straight?""]","[[""red"", ""blue"", ""green"", ""yellow""], [""dotted"", ""solid"", ""wavy"", ""broken""], [""yes"", ""no""], [""curved"", ""straight""]]","[""red"", ""solid"", ""yes"", ""straight""]"
|
94 |
+
91,"[""What colors are primarily used in the image?"", ""Are there visible layers in the design?"", ""Does the image contain any gradients?"", ""Is there a sense of movement in the image?"", ""What is the overall mood conveyed by the colors?""]","[[""red and blue"", ""orange and purple"", ""yellow and green"", ""black and white""], [""yes"", ""no""], [""yes"", ""no""], [""yes"", ""no""], [""calm"", ""energetic"", ""dark"", ""sad""]]","[""orange and purple"", ""yes"", ""yes"", ""yes"", ""energetic""]"
|
95 |
+
92,"[""What color are the curves in the image?"", ""What is the background color of the canvas?"", ""Are the curves sharp or smooth?"", ""Is there any text included in the image?"", ""What vibe do the curves convey?""]","[[""red"", ""blue"", ""lavender"", ""green""], [""white"", ""black"", ""blue"", ""purple""], [""sharp"", ""jagged"", ""smooth"", ""angular""], [""yes"", ""no""], [""aggressive"", ""serene"", ""chaotic"", ""industrial""]]","[""lavender"", ""black"", ""smooth"", ""no"", ""serene""]"
|
96 |
+
93,"[""What color palette is predominantly used in the image?"", ""Are the lines in the image thick or thin?"", ""Is there a geometric shape that stands out prominently?"", ""What is the overall mood conveyed by the color tones?"", ""Are the lines arranged in a random pattern or a structured grid?""]","[[""vibrant colors"", ""soft earth tones"", ""monochrome"", ""bright primary colors""], [""thick"", ""thin"", ""varying thickness"", ""none""], [""circle"", ""square"", ""lines"", ""triangle""], [""calm"", ""chaotic"", ""energetic"", ""sad""], [""random pattern"", ""structured grid"", ""circular pattern"", ""diagonal lines""]]","[""soft earth tones"", ""thin"", ""lines"", ""calm"", ""structured grid""]"
|
97 |
+
94,"[""What color are the diamonds in the image?"", ""What is the background color of the image?"", ""How many diamonds are clustered in the image?"", ""What shape do the diamonds resemble?"", ""Are the diamonds solid or transparent?""]","[[""copper"", ""silver"", ""gold"", ""bronze""], [""deep azure"", ""light blue"", ""green"", ""black""], [""one"", ""three"", ""five"", ""seven""], [""circle"", ""square"", ""diamond"", ""triangle""], [""solid"", ""transparent"", ""striped"", ""dotted""]]","[""copper"", ""deep azure"", ""three"", ""diamond"", ""solid""]"
|
98 |
+
95,"[""What primary color is predominantly featured in the shapes?"", ""Are there any circular shapes present in the image?"", ""Is there a contrast between the colors used in the image?"", ""What geometric shape is predominantly used alongside orange?"", ""Are the shapes overlapping in the image?""]","[[""orange"", ""blue"", ""green"", ""purple""], [""yes"", ""no""], [""yes"", ""no""], [""triangle"", ""rectangle"", ""circle"", ""hexagon""], [""yes"", ""no""]]","[""orange"", ""yes"", ""yes"", ""rectangle"", ""yes""]"
|
99 |
+
96,"[""What colors predominantly appear in the image?"", ""Do the curves in the image appear sharp or gentle?"", ""Is there a dominant color among the olive green and burnt sienna?"", ""Are the curves in the image horizontal, vertical, or flowing?""]","[[""olive green and burnt sienna"", ""blue and yellow"", ""red and white"", ""black and grey""], [""sharp"", ""gentle"", ""jagged"", ""straight""], [""olive green"", ""burnt sienna"", ""both equally"", ""none""], [""horizontal"", ""vertical"", ""flowing"", ""zigzag""]]","[""olive green and burnt sienna"", ""gentle"", ""both equally"", ""flowing""]"
|
100 |
+
97,"[""What color are the circles in the field?"", ""What color encircles the gray circles?"", ""What is the overall shape of the main elements in the image?"", ""Is there a background color in the image?""]","[[""gray"", ""yellow"", ""blue"", ""green""], [""yellow"", ""red"", ""blue"", ""purple""], [""square"", ""circle"", ""triangle"", ""rectangle""], [""yes"", ""no""]]","[""gray"", ""yellow"", ""circle"", ""yes""]"
|
101 |
+
98,"[""What color are the waves in the image?"", ""What is the predominant color of the grid?"", ""How would you describe the overall mood of the image?"", ""Are there any sharp angles in the wave design?"", ""What pattern is the grid made of?""]","[[""blue"", ""violet"", ""green"", ""yellow""], [""bright green"", ""muted green"", ""dark green"", ""neon green""], [""calm and serene"", ""chaotic"", ""dark and gloomy"", ""energetic""], [""yes"", ""no""], [""stripes"", ""dots"", ""squares"", ""random shapes""]]","[""violet"", ""muted green"", ""calm and serene"", ""no"", ""squares""]"
|
102 |
+
99,"[""What is the primary color of the background?"", ""What texture do the rectangles have?"", ""How many green rectangles are layered over the beige background?"", ""What color are the rectangles?"", ""What is the overall tone of the image?""]","[[""green"", ""beige"", ""blue"", ""yellow""], [""smooth"", ""textured"", ""glossy"", ""transparent""], [""one"", ""two"", ""three"", ""multiple""], [""green"", ""red"", ""blue"", ""yellow""], [""vibrant"", ""soft"", ""dark"", ""neon""]]","[""beige"", ""textured"", ""multiple"", ""green"", ""soft""]"
|
103 |
+
100,"[""What color are the intersecting shapes?"", ""What is the background color of the image?"", ""Are the shapes solid or outlined?"", ""How many colors are used in the shapes?"", ""Are the shapes geometric or organic in form?""]","[[""teal and amber"", ""red and blue"", ""green and yellow"", ""purple and orange""], [""white"", ""black"", ""grey"", ""blue""], [""solid"", ""outlined"", ""gradient"", ""transparent""], [""two"", ""three"", ""four"", ""one""], [""geometric"", ""organic"", ""abstract"", ""figurative""]]","[""teal and amber"", ""white"", ""solid"", ""two"", ""geometric""]"
|
104 |
+
101,"[""What color is the background of the image?"", ""Are the circles in the image vibrant or pastel?"", ""What is the overall color scheme of the circles?"", ""Is the background color light or dark?""]","[[""light blue"", ""dark indigo"", ""white"", ""yellow""], [""vibrant"", ""pastel"", ""neon"", ""dark""], [""monochrome"", ""pastel"", ""dark"", ""bright""], [""light"", ""dark""]]","[""dark indigo"", ""pastel"", ""pastel"", ""dark""]"
|
105 |
+
102,"[""What type of colors are predominantly featured in the image?"", ""Are there any straight lines present in the design?"", ""What overall shape do the curves create in the image?"", ""Do the colors appear to be bright or muted?"", ""Is there a gradient effect in the color distribution?""]","[[""bright"", ""muted""], [""yes"", ""no""], [""geometric"", ""organic"", ""abstract""], [""bright"", ""dark""], [""yes"", ""no""]]","[""bright"", ""no"", ""organic"", ""bright"", ""yes""]"
|
106 |
+
103,"[""What color are the triangles in the image?"", ""What background color contrasts with the triangles?"", ""What shape do the prominent elements of the image resemble?"", ""How would you describe the edges of the triangles?""]","[[""red"", ""navy"", ""green"", ""yellow""], [""dark gray"", ""white"", ""light canvas"", ""black""], [""circle"", ""square"", ""triangle"", ""rectangle""], [""smooth"", ""curved"", ""jagged"", ""rounded""]]","[""navy"", ""light canvas"", ""triangle"", ""jagged""]"
|
107 |
+
104,"[""What color is the central orb?"", ""What direction do the rays emerge from?"", ""What color are the rays?"", ""Is the orb larger than the rays?"", ""Are there any other shapes present besides the orb and rays?""]","[[""red"", ""blue"", ""violet"", ""green""], [""upward"", ""downward"", ""outward"", ""inward""], [""gold"", ""silver"", ""black"", ""white""], [""yes"", ""no""], [""yes"", ""no""]]","[""violet"", ""outward"", ""gold"", ""yes"", ""no""]"
|
108 |
+
105,"[""What colors are the triangles in the image?"", ""Are the triangles overlapping?"", ""What is the overall visual effect created by the triangles?"", ""How many distinct colors are used in the triangles?""]","[[""cyan and magenta"", ""red and blue"", ""green and yellow"", ""black and white""], [""yes"", ""no""], [""harmony"", ""visual tension"", ""chaos"", ""balance""], [""one"", ""two"", ""three"", ""four""]]","[""cyan and magenta"", ""yes"", ""visual tension"", ""two""]"
|
109 |
+
106,"[""What color is the background of the image?"", ""What is the general shape of the elements in the image?"", ""Are the arcs primarily in bright, bold colors or softer tones?"", ""How do the arcs appear to be arranged on the canvas?"", ""What is the overall mood conveyed by the color scheme?""]","[[""black"", ""dark navy"", ""light blue"", ""white""], [""lines"", ""squares"", ""arcs"", ""dots""], [""bright and bold"", ""pastel and soft"", ""dark and muted"", ""neutral""], [""randomly scattered"", ""uniformly spaced"", ""layered"", ""overlapping""], [""energetic"", ""somber"", ""playful"", ""neutral""]]","[""dark navy"", ""arcs"", ""pastel and soft"", ""randomly scattered"", ""playful""]"
|
110 |
+
107,"[""What colors are predominantly used in the rectangles?"", ""Are the rectangles layered on top of each other?"", ""What geometric shape is primarily featured in the image?"", ""Is there any gradient effect used in the rectangles?"", ""Are there any circles included in the design?""]","[[""rose and steel gray"", ""blue and yellow"", ""green and black""], [""yes"", ""no""], [""rectangle"", ""circle"", ""triangle"", ""oval""], [""yes"", ""no""], [""yes"", ""no""]]","[""rose and steel gray"", ""yes"", ""rectangle"", ""no"", ""no""]"
|
111 |
+
108,"[""What colors are present in the stripes?"", ""Are the stripes arranged vertically or horizontally?"", ""Is there any other pattern besides stripes in the image?"", ""How many distinct colors are used in the pattern?""]","[[""orange and white"", ""red and white"", ""blue and yellow"", ""green and pink""], [""vertically"", ""horizontally"", ""diagonally"", ""randomly""], [""yes"", ""no""], [""one"", ""two"", ""three"", ""four""]]","[""orange and white"", ""horizontally"", ""no"", ""two""]"
|
112 |
+
109,"[""What colors are predominantly used in the image?"", ""Do the shapes in the image appear to be smooth or fractured?"", ""Is there a sense of movement conveyed by the arrangement of the shapes?"", ""Are the shapes primarily angular or rounded?"", ""What is the overall mood evoked by the colors and shapes?""]","[[""red and blue"", ""green and gold"", ""black and white"", ""purple and orange""], [""smooth"", ""fractured"", ""rounded"", ""flat""], [""yes"", ""no""], [""angular"", ""rounded"", ""circular"", ""elliptical""], [""calm"", ""chaotic"", ""energetic"", ""somber""]]","[""green and gold"", ""fractured"", ""yes"", ""angular"", ""energetic""]"
|
113 |
+
110,"[""What color is the background of the image?"", ""What is the color of the ovals?"", ""How are the ovals arranged in the image?"", ""What shape are the interlocking elements in the image?""]","[[""red"", ""cerulean"", ""beige"", ""green""], [""blue"", ""beige"", ""white"", ""black""], [""stacked"", ""interlocking"", ""scattered"", ""overlapping""], [""squares"", ""triangles"", ""ovals"", ""rectangles""]]","[""cerulean"", ""beige"", ""interlocking"", ""ovals""]"
|
114 |
+
111,"[""What colors are predominantly used in the image?"", ""Are there overlapping circles in the design?"", ""Is there a specific pattern formed by the circles?"", ""What is the overall tone of the image?""]","[[""red and blue"", ""black and white"", ""green and yellow"", ""purple and orange""], [""yes"", ""no""], [""geometric"", ""random"", ""spiral"", ""linear""], [""chaotic"", ""calm"", ""bright"", ""dark""]]","[""black and white"", ""yes"", ""geometric"", ""calm""]"
|
115 |
+
112,"[""What color are the arcs in the image?"", ""What geometric shape is prominently featured in the image?"", ""What color are the triangles in the image?"", ""Do the arcs and triangles create a sense of movement?"", ""Are the arcs and triangles overlapping in the design?""]","[[""crimson"", ""navy"", ""gold"", ""green""], [""circle"", ""triangle"", ""rectangle"", ""oval""], [""crimson"", ""navy"", ""yellow"", ""black""], [""yes"", ""no""], [""yes"", ""no""]]","[""crimson"", ""triangle"", ""navy"", ""yes"", ""yes""]"
|
116 |
+
113,"[""What is the predominant color scheme of the shapes?"", ""Are the shapes primarily geometric or organic?"", ""Do the shapes overlap each other?"", ""What tones are used in the image?"", ""Is there a bright color present in the image?""]","[[""Muted tones of green and brown"", ""Bright colors"", ""Black and white"", ""Vibrant colors""], [""Geometric"", ""Organic"", ""Mixed"", ""Abstract""], [""Yes"", ""No""], [""Warm tones"", ""Cool tones"", ""Muted tones"", ""Neon colors""], [""Yes"", ""No""]]","[""Muted tones of green and brown"", ""Mixed"", ""Yes"", ""Muted tones"", ""No""]"
|
117 |
+
114,"[""What colors are visible on the slip-ons?"", ""Are there any patterns on the canvas slip-ons?"", ""What type of footwear is depicted in the image?"", ""What is the predominant color of the slip-ons?""]","[[""navy and white"", ""red and blue"", ""green and yellow"", ""black and white""], [""yes"", ""no""], [""sandals"", ""boots"", ""slip-ons"", ""loafers""], [""navy"", ""white"", ""gray"", ""black""]]","[""navy and white"", ""no"", ""slip-ons"", ""navy""]"
|
118 |
+
115,"[""What colors are the ankle socks in the image?"", ""What type of top do the socks have?"", ""Are the socks designed for a specific season?"", ""What pattern, if any, is present on the socks?""]","[[""bright colors"", ""pastel colors"", ""dark colors"", ""neon colors""], [""ribbed top"", ""smooth top"", ""frilled top"", ""flat top""], [""summer"", ""winter"", ""year-round"", ""fall""], [""striped"", ""polka dots"", ""solid color"", ""floral""]]","[""pastel colors"", ""ribbed top"", ""year-round"", ""solid color""]"
|
119 |
+
116,"[""What color is the dress?"", ""What type of fabric is the dress made of?"", ""What design feature does the dress have?"", ""Is the dress long or short?"", ""Does the dress have sleeves?""]","[[""red"", ""deep emerald"", ""blue"", ""black""], [""cotton"", ""silk"", ""velvet"", ""denim""], [""wrap design"", ""A-line"", ""fit and flare"", ""ball gown""], [""long"", ""short"", ""knee-length"", ""mid-calf""], [""yes"", ""no""]]","[""deep emerald"", ""velvet"", ""wrap design"", ""long"", ""no""]"
|
120 |
+
117,"[""What color is the pullover?"", ""What material is the pullover made of?"", ""What style of clothing does the image depict?"", ""Is the pullover textured or smooth?"", ""What is the overall tone of the pullover's color?""]","[[""red"", ""muted lavender"", ""blue"", ""green""], [""cotton"", ""silk"", ""merino wool"", ""polyester""], [""jacket"", ""pullover"", ""shirt"", ""dress""], [""textured"", ""smooth"", ""ruffled"", ""embroidered""], [""bright"", ""muted"", ""dark"", ""vibrant""]]","[""muted lavender"", ""merino wool"", ""pullover"", ""smooth"", ""muted""]"
|
121 |
+
118,"[""What color is the fabric of the shorts?"", ""What style of shorts is depicted?"", ""What type of fabric are the shorts made from?"", ""Do the shorts have a high waist design?"", ""Are the shorts depicted as tight-fitting or loose?""]","[[""blue"", ""red"", ""green"", ""yellow""], [""high-waisted"", ""low-rise"", ""cargo"", ""bermuda""], [""denim"", ""chambray"", ""cotton"", ""linen""], [""yes"", ""no""], [""tight-fitting"", ""loose"", ""skinny"", ""capri""]]","[""blue"", ""high-waisted"", ""chambray"", ""yes"", ""loose""]"
|
122 |
+
119,"[""What color is the trench coat?"", ""Does the trench coat have a tie belt?"", ""What type of collar does the trench coat have?"", ""Are there any buttons visible on the trench coat?"", ""Is the trench coat long-sleeved or short-sleeved?""]","[[""beige"", ""black"", ""blue"", ""red""], [""yes"", ""no""], [""notched"", ""mandarin"", ""shawl"", ""collarless""], [""yes"", ""no""], [""long-sleeved"", ""short-sleeved"", ""sleeveless""]]","[""beige"", ""yes"", ""notched"", ""yes"", ""long-sleeved""]"
|
123 |
+
120,"[""What color is the hoodie?"", ""Does the hoodie have a kangaroo pocket?"", ""What type of material is the hoodie made from?"", ""Is the hoodie designed for adults or children?"", ""What style does the hoodie depict?""]","[[""light gray"", ""dark gray"", ""black"", ""white""], [""yes"", ""no""], [""cotton"", ""fleece"", ""denim"", ""polyester""], [""adults"", ""children"", ""both"", ""neither""], [""hooded"", ""crew neck"", ""v-neck"", ""turtleneck""]]","[""light gray"", ""yes"", ""fleece"", ""adults"", ""hooded""]"
|
124 |
+
121,"[""What type of fabric is the graphic tee made of?"", ""What style of design is featured on the tee?"", ""Is the graphic design on the tee modern or vintage?"", ""What color scheme is predominantly used in the graphic design?"", ""Does the tee have a fitted or relaxed fit?""]","[[""cotton"", ""polyester"", ""wool"", ""linen""], [""abstract"", ""vintage"", ""minimalist"", ""futuristic""], [""modern"", ""vintage""], [""bright"", ""pastel"", ""monochrome"", ""earth tones""], [""fitted"", ""relaxed"", ""oversized"", ""crop""]]","[""cotton"", ""vintage"", ""vintage"", ""earth tones"", ""relaxed""]"
|
125 |
+
122,"[""What color is the camisole?"", ""What type of fabric is the camisole likely made of?"", ""What decorative feature is present on the camisole?"", ""Is the camisole designed to be fitted or loose?""]","[[""blush pink"", ""white"", ""black"", ""blue""], [""cotton"", ""satin"", ""denim"", ""wool""], [""lace trim"", ""ruffles"", ""buttons"", ""pockets""], [""fitted"", ""loose"", ""baggy"", ""oversized""]]","[""blush pink"", ""satin"", ""lace trim"", ""fitted""]"
|
126 |
+
123,"[""What pattern is visible on the skirt?"", ""Does the skirt have pleats?"", ""What is the waist style of the skirt?"", ""What type of fabric is the skirt made of?"", ""Is the skirt long or short?""]","[[""solid"", ""striped"", ""plaid"", ""polka dot""], [""yes"", ""no""], [""high waist"", ""low waist"", ""mid-rise"", ""none""], [""cotton"", ""silk"", ""wool"", ""denim""], [""long"", ""short"", ""knee-length"", ""mini""]]","[""plaid"", ""yes"", ""high waist"", ""wool"", ""knee-length""]"
|
127 |
+
124,"[""What pattern is featured on the scarf?"", ""What color scheme is used in the scarf?"", ""Is the texture of the scarf smooth or knit?"", ""What type of scarf is depicted in the image?""]","[[""stripes"", ""polka dots"", ""chevron"", ""floral""], [""bright colors"", ""shades of gray"", ""pastel colors"", ""primary colors""], [""smooth"", ""knit"", ""silky"", ""rough""], [""blanket scarf"", ""infinity scarf"", ""bandana"", ""wrap scarf""]]","[""chevron"", ""shades of gray"", ""knit"", ""blanket scarf""]"
|
128 |
+
125,"[""What color is the shirt?"", ""Does the shirt have a collar?"", ""What type of fit does the shirt have?"", ""Are there any patterns on the shirt?"", ""What is the style of the shirt's sleeves?""]","[[""white"", ""blue"", ""black"", ""gray""], [""yes"", ""no""], [""tailored"", ""loose"", ""oversized"", ""fitted""], [""yes"", ""no""], [""short sleeves"", ""long sleeves"", ""sleeveless"", ""three-quarter sleeves""]]","[""white"", ""yes"", ""tailored"", ""no"", ""long sleeves""]"
|
129 |
+
126,"[""What color are the chinos?"", ""What type of fit do the chinos have?"", ""What material are the chinos made from?"", ""What style are the chinos designed to represent?""]","[[""red"", ""olive green"", ""blue"", ""black""], [""loose fit"", ""slim fit"", ""regular fit"", ""baggy fit""], [""denim"", ""cotton twill"", ""polyester"", ""linen""], [""formal"", ""casual"", ""athletic"", ""business""]]","[""olive green"", ""slim fit"", ""cotton twill"", ""casual""]"
|
130 |
+
127,"[""What type of sleeves does the dress have?"", ""What pattern is featured on the dress?"", ""What is the overall color scheme of the floral print?"", ""Is the dress designed to be long or short?"", ""Does the dress have a fitted or loose silhouette?""]","[[""cap sleeves"", ""flutter sleeves"", ""long sleeves"", ""no sleeves""], [""striped"", ""polka dot"", ""floral"", ""checkered""], [""monochrome"", ""pastel"", ""bright multicolor"", ""dark colors""], [""long"", ""short"", ""knee-length"", ""floor-length""], [""fitted"", ""loose"", ""tailored"", ""bodycon""]]","[""flutter sleeves"", ""floral"", ""bright multicolor"", ""knee-length"", ""loose""]"
|
131 |
+
128,"[""What color are the overalls?"", ""What type of fit do the overalls have?"", ""Where are the buttons located on the overalls?"", ""What is the primary material of the overalls?""]","[[""blue"", ""black"", ""green"", ""red""], [""tight"", ""relaxed"", ""loose"", ""fitted""], [""front"", ""sides"", ""back"", ""none""], [""denim"", ""cotton"", ""polyester"", ""wool""]]","[""blue"", ""relaxed"", ""sides"", ""denim""]"
|
132 |
+
129,"[""What color are the sandals?"", ""Do the sandals have an ankle strap?"", ""What type of heel do the sandals have?"", ""What material are the sandals made of?""]","[[""red"", ""tan"", ""black"", ""white""], [""yes"", ""no""], [""chunky"", ""stiletto"", ""flat"", ""wedge""], [""leather"", ""canvas"", ""rubber"", ""synthetic""]]","[""tan"", ""yes"", ""chunky"", ""leather""]"
|
133 |
+
130,"[""What color is the pencil skirt?"", ""Does the skirt have a back slit?"", ""What material is the skirt made of?"", ""What is the style of the skirt?""]","[[""black"", ""blue"", ""red"", ""green""], [""yes"", ""no""], [""denim"", ""cotton"", ""faux leather"", ""silk""], [""A-line"", ""pencil"", ""pleated"", ""maxi""]]","[""black"", ""yes"", ""faux leather"", ""pencil""]"
|
134 |
+
131,"[""What color is the turtleneck?"", ""What type of fabric is the turtleneck made of?"", ""What style of collar does the turtleneck have?"", ""Is the turtleneck fitted or loose?"", ""What is the overall tone of the turtleneck?""]","[[""black"", ""burgundy"", ""blue"", ""green""], [""wool"", ""cotton"", ""silk"", ""polyester""], [""crew neck"", ""v-neck"", ""turtleneck"", ""collarless""], [""fitted"", ""loose"", ""oversized"", ""baggy""], [""light"", ""neutral"", ""rich"", ""pastel""]]","[""burgundy"", ""cotton"", ""turtleneck"", ""fitted"", ""rich""]"
|
135 |
+
132,"[""What color is the cardigan?"", ""What type of pockets does the cardigan have?"", ""Is the cardigan made of a soft material?"", ""What is the style of the cardigan?""]","[[""beige"", ""black"", ""red"", ""blue""], [""patch pockets"", ""zippered pockets"", ""no pockets"", ""side pockets""], [""yes"", ""no""], [""hooded"", ""cropped"", ""long-sleeve"", ""sleeveless""]]","[""beige"", ""patch pockets"", ""yes"", ""long-sleeve""]"
|
136 |
+
133,"[""What color are the ankle boots?"", ""What type of toe do the boots have?"", ""What material are the boots made of?"", ""How high are the boots on the ankle?""]","[[""black"", ""brown"", ""red"", ""white""], [""rounded"", ""pointed"", ""square"", ""flat""], [""leather"", ""canvas"", ""suede"", ""rubber""], [""low"", ""mid"", ""high"", ""very high""]]","[""black"", ""pointed"", ""leather"", ""mid""]"
|
137 |
+
134,"[""What color are the sneakers?"", ""What color are the soles of the sneakers?"", ""Do the sneakers have laces?"", ""What type of shoe is depicted in the image?"", ""Are the sneakers high-top or low-top?""]","[[""red"", ""yellow"", ""blue"", ""green""], [""black"", ""white"", ""brown"", ""gray""], [""yes"", ""no""], [""sandals"", ""boots"", ""sneakers"", ""loafers""], [""high-top"", ""low-top""]]","[""yellow"", ""white"", ""yes"", ""sneakers"", ""low-top""]"
|
138 |
+
135,"[""What color is the blouse?"", ""Are there ruffled cuffs on the blouse?"", ""Is the blouse made of a shiny fabric?"", ""What type of neckline does the blouse have?"", ""Are there any patterns on the blouse?""]","[[""red"", ""blue"", ""black"", ""silk""], [""yes"", ""no""], [""yes"", ""no""], [""v-neck"", ""round"", ""collared"", ""off-shoulder""], [""floral"", ""striped"", ""solid"", ""polka dot""]]","[""silk"", ""yes"", ""yes"", ""v-neck"", ""solid""]"
|
139 |
+
136,"[""What color is the bomber jacket?"", ""Does the jacket have ribbed cuffs?"", ""Is the jacket cropped in length?"", ""What type of jacket is depicted in the image?""]","[[""olive green"", ""black"", ""brown"", ""blue""], [""yes"", ""no""], [""yes"", ""no""], [""bomber jacket"", ""denim jacket"", ""parka"", ""trench coat""]]","[""olive green"", ""yes"", ""yes"", ""bomber jacket""]"
|
140 |
+
137,"[""What type of pattern is featured on the dress?"", ""What is the waist style of the dress?"", ""What length is the dress?"", ""What color scheme is predominant in the floral pattern?""]","[[""striped"", ""floral"", ""polka dot"", ""geometric""], [""cinched"", ""high-waisted"", ""low-rise"", ""empire""], [""mini"", ""knee-length"", ""maxi"", ""crop""], [""pastel"", ""monochrome"", ""vibrant"", ""dark""]]","[""floral"", ""cinched"", ""maxi"", ""vibrant""]"
|
141 |
+
138,"[""What color dominates the checkered pattern?"", ""Does the shirt have long sleeves?"", ""Is the fabric texture smooth or soft?"", ""Are there any buttons visible on the shirt?"", ""What type of collar does the shirt have?""]","[[""red"", ""blue"", ""green"", ""yellow""], [""yes"", ""no""], [""smooth"", ""soft""], [""yes"", ""no""], [""pointed"", ""rounded"", ""no collar"", ""high""]]","[""red"", ""yes"", ""soft"", ""yes"", ""pointed""]"
|
142 |
+
139,"[""What color is the scarf?"", ""Does the scarf have fringed edges?"", ""What texture does the scarf appear to have?"", ""Is the scarf in a solid color or patterned?"", ""What is the overall style of the scarf?""]","[[""cream"", ""red"", ""blue"", ""green""], [""yes"", ""no""], [""smooth"", ""chunky"", ""silky"", ""thin""], [""solid color"", ""striped"", ""polka dot"", ""floral""], [""formal"", ""casual"", ""sporty"", ""elegant""]]","[""cream"", ""yes"", ""chunky"", ""solid color"", ""casual""]"
|
143 |
+
140,"[""What color are the trousers?"", ""What type of cut do the trousers have?"", ""Are the trousers fitted or straight cut?"", ""Is there any visible pattern on the trousers?""]","[[""black"", ""blue"", ""grey"", ""white""], [""tapered"", ""straight"", ""bootcut"", ""flared""], [""fitted"", ""straight"", ""baggy"", ""skinny""], [""yes"", ""no""]]","[""black"", ""straight"", ""straight"", ""no""]"
|
144 |
+
141,"[""What color is the denim jacket?"", ""Does the jacket have any pockets?"", ""What type of hem does the jacket have?"", ""Is the denim jacket styled for a casual look?""]","[[""light blue"", ""dark blue"", ""black"", ""white""], [""yes"", ""no""], [""frayed"", ""straight"", ""curved"", ""double-stitched""], [""yes"", ""no""]]","[""light blue"", ""yes"", ""frayed"", ""yes""]"
|
145 |
+
142,"[""What color is the leather crossbody bag?"", ""Does the bag feature an adjustable strap?"", ""What type of closure does the bag have?"", ""Is there a visible logo on the bag?"", ""What is the general shape of the bag?""]","[[""black"", ""brown"", ""red"", ""blue""], [""yes"", ""no""], [""zipper"", ""button"", ""magnet"", ""snap""], [""yes"", ""no""], [""rectangle"", ""circle"", ""oval"", ""square""]]","[""brown"", ""yes"", ""zipper"", ""no"", ""rectangle""]"
|
146 |
+
143,"[""What pattern is featured on the shirt?"", ""Are the sleeves of the shirt rolled up?"", ""What color scheme is primarily used in the shirt?"", ""Is the shirt short-sleeved or long-sleeved?""]","[[""polka dots"", ""striped"", ""plaid"", ""solid""], [""yes"", ""no""], [""monochrome"", ""pastel"", ""bright colors"", ""neutral tones""], [""short-sleeved"", ""long-sleeved""]]","[""striped"", ""yes"", ""neutral tones"", ""long-sleeved""]"
|
147 |
+
144,"[""What type of skirt is depicted in the image?"", ""What color palette is primarily used in the watercolor print?"", ""Does the skirt have a defined waistline or is it more flowy?"", ""Are there any patterns or designs visible in the watercolor print?"", ""Is the skirt knee-length, ankle-length, or floor-length?""]","[[""pencil skirt"", ""midi skirt"", ""maxi skirt"", ""mini skirt""], [""pastels"", ""neon colors"", ""monochrome"", ""earth tones""], [""defined waistline"", ""flowy"", ""tight fit"", ""structured""], [""floral"", ""geometric"", ""abstract"", ""solid color""], [""knee-length"", ""ankle-length"", ""floor-length"", ""short""]]","[""midi skirt"", ""pastels"", ""flowy"", ""floral"", ""ankle-length""]"
|
148 |
+
145,"[""What color is the t-shirt?"", ""What type of neck does the t-shirt have?"", ""What fabric style is the t-shirt made of?"", ""Is the t-shirt short-sleeved or long-sleeved?""]","[[""pastel pink"", ""blue"", ""green"", ""black""], [""crew neck"", ""v-neck"", ""collar"", ""scoop neck""], [""denim"", ""soft jersey"", ""cotton"", ""silk""], [""short-sleeved"", ""long-sleeved"", ""sleeveless"", ""three-quarter sleeve""]]","[""pastel pink"", ""crew neck"", ""soft jersey"", ""short-sleeved""]"
|
149 |
+
146,"[""What color is the beanie?"", ""What texture is visible on the beanie?"", ""Is the beanie fitted or slouchy in style?"", ""Are there any visible patterns on the beanie?""]","[[""charcoal gray"", ""black"", ""light gray"", ""navy blue""], [""ribbed"", ""smooth"", ""floral"", ""polka dot""], [""fitted"", ""slouchy"", ""bucket"", ""visor""], [""yes"", ""no""]]","[""charcoal gray"", ""ribbed"", ""slouchy"", ""no""]"
|
150 |
+
147,"[""What color is the sweater?"", ""What type of fabric is the sweater made of?"", ""What is the general style of the sweater?"", ""Are there any patterns on the sweater?"", ""What type of neckline does the sweater have?""]","[[""red"", ""navy blue"", ""green"", ""black""], [""cotton"", ""wool"", ""cashmere"", ""linen""], [""casual"", ""formal"", ""sporty"", ""business""], [""stripes"", ""plaid"", ""solid"", ""floral""], [""crew neck"", ""v-neck"", ""turtleneck"", ""scoop neck""]]","[""navy blue"", ""cashmere"", ""casual"", ""solid"", ""crew neck""]"
|
151 |
+
148,"[""What color are the jeans?"", ""What style of jeans is depicted?"", ""Do the jeans have a high waist?"", ""What type of wash do the jeans have?"", ""Are there any embellishments on the jeans?""]","[[""light wash"", ""dark wash"", ""medium wash"", ""black""], [""skinny"", ""high-waisted"", ""bootcut"", ""flared""], [""yes"", ""no""], [""distressed"", ""dark wash"", ""acid wash"", ""faded""], [""yes"", ""no""]]","[""dark wash"", ""high-waisted"", ""yes"", ""dark wash"", ""no""]"
|
152 |
+
149,"[""What color is the sundress?"", ""What type of skirt does the dress have?"", ""Is the sundress patterned or solid?"", ""What is the overall style of the dress?""]","[[""red"", ""yellow"", ""blue"", ""green""], [""flared"", ""straight"", ""pencil"", ""A-line""], [""patterned"", ""solid"", ""striped"", ""polka-dotted""], [""casual"", ""formal"", ""athletic"", ""business""]]","[""yellow"", ""flared"", ""solid"", ""casual""]"
|
153 |
+
150,"[""What color is primarily seen on the denim jacket?"", ""Does the jacket have any visible distressing features?"", ""Is the finish of the jacket shiny or faded?"", ""What type of closure does the jacket likely have?"", ""Are there any additional elements like patches or embroidery on the jacket?""]","[[""blue"", ""black"", ""red"", ""green""], [""yes"", ""no""], [""shiny"", ""faded""], [""buttons"", ""zippers"", ""velcro"", ""none""], [""yes"", ""no""]]","[""blue"", ""yes"", ""faded"", ""buttons"", ""no""]"
|
154 |
+
151,"[""What color is the parka?"", ""Does the parka have a hood?"", ""Are there drawstrings on the parka?"", ""What type of clothing is depicted in the image?""]","[[""red"", ""navy"", ""green"", ""black""], [""yes"", ""no""], [""yes"", ""no""], [""jacket"", ""dress"", ""parka"", ""shirt""]]","[""navy"", ""yes"", ""yes"", ""parka""]"
|
155 |
+
152,"[""What color are the trousers?"", ""What material do the trousers appear to be made of?"", ""Are the trousers designed with any specific texture?"", ""What is the style of the trousers?""]","[[""metallic gold"", ""silver"", ""black"", ""white""], [""satin"", ""denim"", ""cotton"", ""leather""], [""pleated"", ""smooth"", ""ruffled"", ""fuzzy""], [""skinny"", ""wide-leg"", ""pleated"", ""cargo""]]","[""metallic gold"", ""satin"", ""pleated"", ""pleated""]"
|
156 |
+
153,"[""What color are the jeans depicted in the image?"", ""Are there any visible rips or tears in the jeans?"", ""What is the overall fit of the jeans?"", ""What style of jeans is shown in the image?""]","[[""blue"", ""black"", ""white"", ""green""], [""yes"", ""no""], [""tight"", ""relaxed"", ""baggy"", ""skinny""], [""distressed boyfriend"", ""skinny"", ""straight"", ""wide-leg""]]","[""blue"", ""yes"", ""relaxed"", ""distressed boyfriend""]"
|
157 |
+
154,"[""What color is the beanie?"", ""Does the beanie have a cuffed edge?"", ""What is the style of the beanie?"", ""Is the beanie textured or smooth?""]","[[""forest green"", ""black"", ""navy blue"", ""red""], [""yes"", ""no""], [""slouchy"", ""cuffed"", ""beanie hat"", ""bucket hat""], [""textured"", ""smooth"", ""striped"", ""polka-dotted""]]","[""forest green"", ""yes"", ""cuffed"", ""smooth""]"
|
158 |
+
155,"[""What type of fabric is featured in the leggings?"", ""Are the leggings designed for a specific activity?"", ""Is there a visible mesh panel in the design?"", ""What color are the leggings predominantly?"", ""Do the leggings have a high waistband?""]","[[""cotton"", ""mesh"", ""denim"", ""silk""], [""yes"", ""no""], [""yes"", ""no""], [""black"", ""blue"", ""green"", ""red""], [""yes"", ""no""]]","[""mesh"", ""yes"", ""yes"", ""black"", ""yes""]"
|
159 |
+
156,"[""What color is the bold graphic print on the tote bag?"", ""Is the tote bag made of a soft or rigid material?"", ""What type of graphic elements can be seen on the tote bag?"", ""Does the tote bag have handles?"", ""Is the graphic print on the tote bag simple or intricate?""]","[[""red"", ""blue"", ""black"", ""green""], [""soft"", ""rigid""], [""text"", ""geometric shapes"", ""floral patterns"", ""abstract designs""], [""yes"", ""no""], [""simple"", ""intricate""]]","[""blue"", ""soft"", ""geometric shapes"", ""yes"", ""intricate""]"
|
160 |
+
157,"[""What color is the top?"", ""Does the top have long sleeves?"", ""Is there a tie detail in the design?"", ""What is the style of the top?"", ""Is the fabric of the top described as textured?""]","[[""white"", ""black"", ""blue"", ""red""], [""yes"", ""no""], [""yes"", ""no""], [""wrap"", ""t-shirt"", ""tank"", ""hoodie""], [""yes"", ""no""]]","[""white"", ""yes"", ""yes"", ""wrap"", ""no""]"
|
161 |
+
158,"[""What type of dress is depicted in the image?"", ""What pattern is featured on the dress?"", ""How does the hem of the dress appear?"", ""What color scheme is likely present in the animal print?""]","[[""maxi dress"", ""midi dress"", ""mini dress"", ""short dress""], [""floral"", ""geometric"", ""animal print"", ""solid color""], [""straight"", ""flowy"", ""asymmetrical"", ""ruffled""], [""monochrome"", ""vibrant colors"", ""pastel colors"", ""earth tones""]]","[""midi dress"", ""animal print"", ""flowy"", ""vibrant colors""]"
|
162 |
+
159,"[""What color are the tailored shorts?"", ""Does the image show a visible zipper?"", ""What is the style of the shorts depicted?"", ""Are there any patterns on the shorts?""]","[[""white"", ""black"", ""blue"", ""red""], [""yes"", ""no""], [""tailored"", ""baggy"", ""cargo"", ""running""], [""yes"", ""no""]]","[""white"", ""no"", ""tailored"", ""no""]"
|
163 |
+
160,"[""What color is the blazer?"", ""What type of clothing is depicted in the image?"", ""Does the blazer have any visible buttons?"", ""What style of the blazer is represented?""]","[[""burgundy"", ""navy"", ""black"", ""green""], [""sweater"", ""blazer"", ""shirt"", ""coat""], [""yes"", ""no""], [""fitted"", ""loose"", ""oversized"", ""crop""]]","[""burgundy"", ""blazer"", ""yes"", ""fitted""]"
|
164 |
+
161,"[""What color is the vest?"", ""What type of pockets does the vest have?"", ""Is the vest designed with a pattern?"", ""What is the style of the vest?""]","[[""blue"", ""green"", ""bright red"", ""black""], [""zip pockets"", ""button pockets"", ""no pockets""], [""striped"", ""plaid"", ""quilted"", ""polka dot""], [""puffer"", ""sleeveless"", ""long-sleeved"", ""hooded""]]","[""bright red"", ""zip pockets"", ""quilted"", ""puffer""]"
|
165 |
+
162,"[""What is the primary color of the scarf?"", ""What is the color of the spots on the scarf?"", ""What pattern is featured on the scarf?"", ""Is the scarf made of a patterned fabric?"", ""Does the scarf have a solid color background?""]","[[""red"", ""navy"", ""green"", ""black""], [""blue"", ""white"", ""red"", ""yellow""], [""stripes"", ""polka dots"", ""plaid"", ""floral""], [""yes"", ""no""], [""yes"", ""no""]]","[""navy"", ""white"", ""polka dots"", ""yes"", ""no""]"
|
166 |
+
163,"[""What is the primary fabric of the kimono?"", ""How would you describe the sleeves of the kimono?"", ""What type of pattern is featured on the kimono?"", ""Is the kimono designed to be fitted or loose?"", ""What color scheme is likely present in the floral chiffon?""]","[[""silk"", ""cotton"", ""chiffon"", ""wool""], [""narrow"", ""wide"", ""long"", ""short""], [""striped"", ""floral"", ""solid"", ""geometric""], [""fitted"", ""loose"", ""tailored"", ""structured""], [""monochrome"", ""pastel"", ""bold"", ""neon""]]","[""chiffon"", ""wide"", ""floral"", ""loose"", ""pastel""]"
|
data/gen_descriptions.py
ADDED
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import openai
|
2 |
+
import pandas as pd
|
3 |
+
import random
|
4 |
+
import string
|
5 |
+
import os
|
6 |
+
from typing import List, Dict
|
7 |
+
import argparse
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
starting_id = 0
|
11 |
+
def new_id() -> int:
|
12 |
+
"""Return a new ID that is the next integer in the sequence"""
|
13 |
+
global starting_id
|
14 |
+
temp = starting_id
|
15 |
+
starting_id += 1
|
16 |
+
return temp
|
17 |
+
|
18 |
+
def setup_openai_client(api_key: str):
|
19 |
+
"""Set up and return an OpenAI client."""
|
20 |
+
client = openai.OpenAI(api_key=api_key)
|
21 |
+
return client
|
22 |
+
|
23 |
+
def read_existing_descriptions(file_path: str) -> set:
|
24 |
+
"""Read and return existing descriptions from a CSV file using pandas."""
|
25 |
+
if not os.path.exists(file_path):
|
26 |
+
return set()
|
27 |
+
|
28 |
+
df = pd.read_csv(file_path)
|
29 |
+
if 'description' in df.columns:
|
30 |
+
return set(df['description'].str.lower())
|
31 |
+
return set()
|
32 |
+
|
33 |
+
def get_prompt_for_category(category: str, count: int, max_length: int, target_avg_length: int) -> str:
|
34 |
+
"""Return a specific prompt based on the category."""
|
35 |
+
|
36 |
+
if category == "landscapes":
|
37 |
+
return f"""
|
38 |
+
Generate {count} short, generic descriptions of landscapes.
|
39 |
+
|
40 |
+
Requirements:
|
41 |
+
Each landscape description should be concise, around {target_avg_length} characters on average
|
42 |
+
No description should exceed {max_length} characters
|
43 |
+
Do NOT include any brand names, trademarks, or personal names
|
44 |
+
Do NOT include any people, even generically
|
45 |
+
Descriptions should be varied and creative
|
46 |
+
Only provide the descriptions, one per line, with no numbering or additional text
|
47 |
+
Focus on natural scenes, vistas, and environments
|
48 |
+
|
49 |
+
Examples:
|
50 |
+
a purple forest at dusk
|
51 |
+
a lighthouse overlooking the ocean
|
52 |
+
a green lagoon under a cloudy sky
|
53 |
+
a snowy plain
|
54 |
+
a starlit night over snow-covered peaks
|
55 |
+
"""
|
56 |
+
|
57 |
+
elif category == "abstract":
|
58 |
+
return f"""
|
59 |
+
Generate {count} short, generic descriptions of abstract art or geometric compositions.
|
60 |
+
|
61 |
+
Requirements:
|
62 |
+
Each abstract description should be concise, around {target_avg_length} characters on average
|
63 |
+
No description should exceed {max_length} characters
|
64 |
+
Do NOT include any brand names, trademarks, or personal names
|
65 |
+
Focus on geometric shapes, patterns, and colors
|
66 |
+
Be creative with color combinations and spatial arrangements
|
67 |
+
Only provide the descriptions, one per line, with no numbering or additional text
|
68 |
+
|
69 |
+
Examples:
|
70 |
+
crimson rectangles forming a chaotic grid
|
71 |
+
purple pyramids spiraling around a bronze cone
|
72 |
+
magenta trapezoids layered on a transluscent silver sheet
|
73 |
+
khaki triangles and azure crescents
|
74 |
+
a maroon dodecahedron interwoven with teal threads
|
75 |
+
"""
|
76 |
+
|
77 |
+
elif category == "fashion":
|
78 |
+
return f"""
|
79 |
+
Generate {count} short, generic descriptions of fashion items and clothing.
|
80 |
+
|
81 |
+
Requirements:
|
82 |
+
Each fashion description should be concise, around {target_avg_length} characters on average
|
83 |
+
No description should exceed {max_length} characters
|
84 |
+
Do NOT include any brand names, trademarks, or personal names
|
85 |
+
Do NOT include any people, even generically
|
86 |
+
Focus on clothing items, accessories, fabrics, patterns, and colors
|
87 |
+
Be specific about materials, cuts, and design features
|
88 |
+
Only provide the descriptions, one per line, with no numbering or additional text
|
89 |
+
|
90 |
+
Examples:
|
91 |
+
gray wool coat with a faux fur collar
|
92 |
+
burgundy corduroy pants with patch pockets and silver buttons
|
93 |
+
orange corduroy overalls
|
94 |
+
a purple silk scarf with tassel trim
|
95 |
+
black and white checkered pants
|
96 |
+
"""
|
97 |
+
|
98 |
+
else:
|
99 |
+
# Generic prompt for additional categories
|
100 |
+
return f"""
|
101 |
+
Generate {count} short, generic descriptions of {category}.
|
102 |
+
|
103 |
+
Requirements:
|
104 |
+
- Each description should be concise, around {target_avg_length} characters on average
|
105 |
+
- No description should exceed {max_length} characters
|
106 |
+
- Do NOT include any brand names, trademarks, or personal names
|
107 |
+
- Do NOT include any people, even generically
|
108 |
+
- Descriptions should be varied and creative
|
109 |
+
- Only provide the descriptions, one per line, with no numbering or additional text
|
110 |
+
"""
|
111 |
+
|
112 |
+
def generate_descriptions(
|
113 |
+
client,
|
114 |
+
categories: List[str],
|
115 |
+
count_per_category: int,
|
116 |
+
max_length: int = 200,
|
117 |
+
target_avg_length: int = 50,
|
118 |
+
existing_descriptions: set = set()
|
119 |
+
) -> Dict[str, List[str]]:
|
120 |
+
"""Generate descriptions for each category using GPT-4o mini with separate prompts."""
|
121 |
+
|
122 |
+
results = {category: [] for category in categories}
|
123 |
+
|
124 |
+
for category in categories:
|
125 |
+
print(f"Generating {count_per_category} descriptions for category: {category}")
|
126 |
+
|
127 |
+
# Get the specific prompt for this category
|
128 |
+
system_prompt = get_prompt_for_category(
|
129 |
+
category=category,
|
130 |
+
count=count_per_category,
|
131 |
+
max_length=max_length,
|
132 |
+
target_avg_length=target_avg_length
|
133 |
+
)
|
134 |
+
|
135 |
+
unique_descriptions = set()
|
136 |
+
|
137 |
+
try:
|
138 |
+
while len(unique_descriptions) < count_per_category:
|
139 |
+
remaining = count_per_category - len(unique_descriptions)
|
140 |
+
print(f"Generating {remaining} more unique descriptions for {category}...")
|
141 |
+
|
142 |
+
# Make the API call
|
143 |
+
response = client.chat.completions.create(
|
144 |
+
model="gpt-4o-mini", # Using GPT-4o mini as requested
|
145 |
+
messages=[
|
146 |
+
{"role": "system", "content": system_prompt},
|
147 |
+
{"role": "user", "content": f"Generate {remaining} {category} descriptions."}
|
148 |
+
],
|
149 |
+
temperature=0.7,
|
150 |
+
max_tokens=8000
|
151 |
+
)
|
152 |
+
|
153 |
+
# Process the response
|
154 |
+
content = response.choices[0].message.content
|
155 |
+
descriptions = [line.strip() for line in content.split('\n') if line.strip()]
|
156 |
+
|
157 |
+
# Filter out any descriptions that are too long, already existing, or duplicates
|
158 |
+
for desc in descriptions:
|
159 |
+
desc_lower = desc.lower()
|
160 |
+
if (len(desc) <= max_length and
|
161 |
+
desc_lower not in {d.lower() for d in unique_descriptions} and
|
162 |
+
desc_lower not in existing_descriptions):
|
163 |
+
unique_descriptions.add(desc)
|
164 |
+
|
165 |
+
if len(unique_descriptions) >= count_per_category:
|
166 |
+
break
|
167 |
+
|
168 |
+
# Convert to list
|
169 |
+
results[category] = list(unique_descriptions)
|
170 |
+
|
171 |
+
except Exception as e:
|
172 |
+
print(f"Error generating descriptions for {category}: {e}")
|
173 |
+
|
174 |
+
return results
|
175 |
+
|
176 |
+
def write_to_csv_pandas(
|
177 |
+
descriptions_dict: Dict[str, List[str]],
|
178 |
+
output_file: str,
|
179 |
+
append: bool = False
|
180 |
+
) -> None:
|
181 |
+
"""Write or append the generated descriptions to a CSV file using pandas."""
|
182 |
+
|
183 |
+
# Create a list of dictionaries for our new data
|
184 |
+
data = []
|
185 |
+
for category, descriptions in descriptions_dict.items():
|
186 |
+
for description in descriptions:
|
187 |
+
data.append({
|
188 |
+
"id": new_id(),
|
189 |
+
"description": description,
|
190 |
+
"category": category
|
191 |
+
})
|
192 |
+
|
193 |
+
# Create a DataFrame from our data
|
194 |
+
new_df = pd.DataFrame(data)
|
195 |
+
|
196 |
+
# Append or create new file
|
197 |
+
if append and os.path.exists(output_file):
|
198 |
+
existing_df = pd.read_csv(output_file)
|
199 |
+
combined_df = pd.concat([existing_df, new_df], ignore_index=True)
|
200 |
+
combined_df.to_csv(output_file, index=False)
|
201 |
+
print(f"Appended {len(new_df)} descriptions to {output_file}")
|
202 |
+
else:
|
203 |
+
new_df.to_csv(output_file, index=False)
|
204 |
+
print(f"Wrote {len(new_df)} descriptions to {output_file}")
|
205 |
+
|
206 |
+
def main():
|
207 |
+
csv_path = "data/descriptions.csv"
|
208 |
+
output_file = "data/descriptions.csv"
|
209 |
+
append = True
|
210 |
+
count = 50
|
211 |
+
categories = ["landscapes", "abstract", "fashion"]
|
212 |
+
|
213 |
+
load_dotenv()
|
214 |
+
api_key = os.getenv("OPENAI_API_KEY")
|
215 |
+
if api_key is None:
|
216 |
+
raise ValueError("OPENAI_API_KEY is not set")
|
217 |
+
|
218 |
+
# Set up the OpenAI client
|
219 |
+
client = setup_openai_client(api_key)
|
220 |
+
|
221 |
+
# If appending, read existing descriptions to avoid duplicates
|
222 |
+
existing_descriptions = set()
|
223 |
+
if append and os.path.exists(csv_path):
|
224 |
+
global starting_id
|
225 |
+
starting_id = pd.read_csv(csv_path)["id"].max()
|
226 |
+
existing_descriptions = read_existing_descriptions(csv_path)
|
227 |
+
print(f"Found {len(existing_descriptions)} existing descriptions")
|
228 |
+
|
229 |
+
# Generate the descriptions
|
230 |
+
descriptions_dict = generate_descriptions(
|
231 |
+
client=client,
|
232 |
+
categories=categories,
|
233 |
+
count_per_category=count,
|
234 |
+
existing_descriptions=existing_descriptions
|
235 |
+
)
|
236 |
+
|
237 |
+
# Write to CSV using pandas
|
238 |
+
write_to_csv_pandas(
|
239 |
+
descriptions_dict=descriptions_dict,
|
240 |
+
output_file=output_file,
|
241 |
+
append=append
|
242 |
+
)
|
243 |
+
|
244 |
+
if __name__ == "__main__":
|
245 |
+
main()
|
data/gen_vqa.py
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import json
|
3 |
+
import time
|
4 |
+
import os
|
5 |
+
from openai import OpenAI
|
6 |
+
from tqdm import tqdm # for progress bar
|
7 |
+
import dotenv
|
8 |
+
|
9 |
+
dotenv.load_dotenv()
|
10 |
+
|
11 |
+
# Initialize OpenAI client
|
12 |
+
api_key = os.environ.get("OPENAI_API_KEY")
|
13 |
+
if not api_key:
|
14 |
+
api_key = input("Enter your OpenAI API key: ")
|
15 |
+
client = OpenAI(api_key=api_key)
|
16 |
+
|
17 |
+
def generate_evaluation_data(description):
|
18 |
+
"""
|
19 |
+
Use GPT-4o mini to generate evaluation questions, choices, and answers for an SVG image description
|
20 |
+
"""
|
21 |
+
prompt = f"""
|
22 |
+
Based on the following description of an SVG image:
|
23 |
+
"{description}"
|
24 |
+
|
25 |
+
Generate 3-5 questions about visual elements that would be in this image, along with multiple-choice options and the correct answers.
|
26 |
+
|
27 |
+
For each question:
|
28 |
+
1. The question should be answerable by looking at the image that matches the description
|
29 |
+
2. Provide 2-4 possible answer choices for each question
|
30 |
+
3. Indicate the correct answer that matches the description
|
31 |
+
|
32 |
+
Format your response as a JSON object with exactly these three keys:
|
33 |
+
- "question": a list of question strings
|
34 |
+
- "choices": a list of lists, where each inner list contains the possible choices for the corresponding question
|
35 |
+
- "answer": a list of strings, where each string is the correct answer for the corresponding question
|
36 |
+
|
37 |
+
Example format:
|
38 |
+
{{
|
39 |
+
"question": ["Is there a red circle?", "What shape is present?"],
|
40 |
+
"choices": [["yes", "no"], ["square", "circle", "triangle", "hexagon"]],
|
41 |
+
"answer": ["yes", "circle"]
|
42 |
+
}}
|
43 |
+
|
44 |
+
Make sure your response is strictly in this JSON format with no additional text.
|
45 |
+
"""
|
46 |
+
|
47 |
+
try:
|
48 |
+
response = client.chat.completions.create(
|
49 |
+
model="gpt-4o-mini",
|
50 |
+
messages=[{"role": "user", "content": prompt}],
|
51 |
+
temperature=0.7,
|
52 |
+
max_tokens=1000,
|
53 |
+
response_format={"type": "json_object"}
|
54 |
+
)
|
55 |
+
|
56 |
+
# Parse the JSON response
|
57 |
+
result = json.loads(response.choices[0].message.content)
|
58 |
+
|
59 |
+
# Validate the response structure
|
60 |
+
if not all(key in result for key in ["question", "choices", "answer"]):
|
61 |
+
print(f"Warning: Response missing required keys for '{description}'")
|
62 |
+
return None
|
63 |
+
|
64 |
+
# Check that all lists are the same length
|
65 |
+
if not (len(result["question"]) == len(result["choices"]) == len(result["answer"])):
|
66 |
+
print(f"Warning: Lists in response have inconsistent lengths for '{description}'")
|
67 |
+
return None
|
68 |
+
|
69 |
+
return result
|
70 |
+
|
71 |
+
except Exception as e:
|
72 |
+
print(f"Error generating evaluation data for '{description}': {e}")
|
73 |
+
return None
|
74 |
+
|
75 |
+
def create_evaluation_dataset(csv_path, output_path):
|
76 |
+
"""
|
77 |
+
Process a CSV file with descriptions and create an evaluation dataset
|
78 |
+
"""
|
79 |
+
# Read the CSV file
|
80 |
+
df = pd.read_csv(csv_path)
|
81 |
+
print(f"Loaded {len(df)} descriptions from {csv_path}")
|
82 |
+
|
83 |
+
# Initialize lists to store the evaluation data
|
84 |
+
ids = []
|
85 |
+
questions = []
|
86 |
+
choices = []
|
87 |
+
answers = []
|
88 |
+
|
89 |
+
# Process each row in the CSV
|
90 |
+
for _, row in tqdm(df.iterrows(), total=len(df), desc="Processing descriptions"):
|
91 |
+
item_id = row["id"]
|
92 |
+
description = row["description"]
|
93 |
+
|
94 |
+
# Generate evaluation data
|
95 |
+
eval_data = generate_evaluation_data(description)
|
96 |
+
|
97 |
+
if eval_data:
|
98 |
+
ids.append(item_id)
|
99 |
+
questions.append(json.dumps(eval_data["question"]))
|
100 |
+
choices.append(json.dumps(eval_data["choices"]))
|
101 |
+
answers.append(json.dumps(eval_data["answer"]))
|
102 |
+
|
103 |
+
# Sleep briefly to avoid hitting API rate limits
|
104 |
+
time.sleep(0.5)
|
105 |
+
|
106 |
+
# Create a DataFrame with the evaluation data
|
107 |
+
eval_df = pd.DataFrame({
|
108 |
+
"id": ids,
|
109 |
+
"question": questions,
|
110 |
+
"choices": choices,
|
111 |
+
"answer": answers
|
112 |
+
})
|
113 |
+
|
114 |
+
# Save as CSV
|
115 |
+
eval_df.to_csv(output_path, index=False)
|
116 |
+
print(f"CSV version saved to {output_path}")
|
117 |
+
|
118 |
+
return eval_df
|
119 |
+
|
120 |
+
def main():
|
121 |
+
# Get input/output paths
|
122 |
+
input_path = "data/descriptions.csv"
|
123 |
+
output_path = "data/eval.csv"
|
124 |
+
|
125 |
+
# Create the evaluation dataset
|
126 |
+
eval_df = create_evaluation_dataset(input_path, output_path)
|
127 |
+
|
128 |
+
# Display sample of the generated dataset
|
129 |
+
print("\nSample of generated evaluation data:")
|
130 |
+
print(eval_df.head())
|
131 |
+
|
132 |
+
# Show stats
|
133 |
+
print(f"\nGenerated evaluation data for {len(eval_df)} out of {pd.read_csv(input_path).shape[0]} descriptions")
|
134 |
+
|
135 |
+
if __name__ == "__main__":
|
136 |
+
main()
|
improved-aesthetic-predictor/F5WsLD0XoAAviiV (1).jpeg
ADDED
![]() |
improved-aesthetic-predictor/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
improved-aesthetic-predictor/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# CLIP+MLP Aesthetic Score Predictor
|
2 |
+
|
3 |
+
Train, use and visualize an aesthetic score predictor ( how much people like on average an image ) based on a simple neural net that takes CLIP embeddings as inputs.
|
4 |
+
|
5 |
+
|
6 |
+
Link to the AVA training data ( already prepared) :
|
7 |
+
https://drive.google.com/drive/folders/186XiniJup5Rt9FXsHiAGWhgWz-nmCK_r?usp=sharing
|
8 |
+
|
9 |
+
|
10 |
+
Visualizations of all images from LAION 5B (english subset with 2.37B images) in 40 buckets with the model sac+logos+ava1-l14-linearMSE.pth:
|
11 |
+
http://captions.christoph-schuhmann.de/aesthetic_viz_laion_sac+logos+ava1-l14-linearMSE-en-2.37B.html
|
12 |
+
|
13 |
+
|
improved-aesthetic-predictor/prepare-data-for-training.py
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
# This script prepares the training images and ratings for the training.
|
3 |
+
# It assumes that all images are stored as files that PIL can read.
|
4 |
+
# It also assumes that the paths to the images files and the average ratings are in a .parquet files that can be read into a dataframe ( df ).
|
5 |
+
|
6 |
+
from datasets import load_dataset
|
7 |
+
import pandas as pd
|
8 |
+
import statistics
|
9 |
+
from torch.utils.data import Dataset, DataLoader
|
10 |
+
import clip
|
11 |
+
import torch
|
12 |
+
from PIL import Image, ImageFile
|
13 |
+
import numpy as np
|
14 |
+
import time
|
15 |
+
|
16 |
+
def normalized(a, axis=-1, order=2):
|
17 |
+
import numpy as np # pylint: disable=import-outside-toplevel
|
18 |
+
|
19 |
+
l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
|
20 |
+
l2[l2 == 0] = 1
|
21 |
+
return a / np.expand_dims(l2, axis)
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
26 |
+
model, preprocess = clip.load("ViT-L/14", device=device)
|
27 |
+
|
28 |
+
|
29 |
+
f = "trainingdata.parquet"
|
30 |
+
df = pd.read_parquet(f) #assumes that the df has the columns IMAGEPATH & AVERAGE_RATING
|
31 |
+
|
32 |
+
|
33 |
+
x = []
|
34 |
+
y = []
|
35 |
+
c= 0
|
36 |
+
|
37 |
+
for idx, row in df.iterrows():
|
38 |
+
start = time.time()
|
39 |
+
|
40 |
+
average_rating = float(row.AVERAGE_RATING)
|
41 |
+
print(average_rating)
|
42 |
+
if average_rating <1:
|
43 |
+
continue
|
44 |
+
|
45 |
+
img= row.IMAGEPATH #assumes that the df has the column IMAGEPATH
|
46 |
+
print(img)
|
47 |
+
|
48 |
+
try:
|
49 |
+
image = preprocess(Image.open(img)).unsqueeze(0).to(device)
|
50 |
+
except:
|
51 |
+
continue
|
52 |
+
|
53 |
+
with torch.no_grad():
|
54 |
+
image_features = model.encode_image(image)
|
55 |
+
|
56 |
+
im_emb_arr = image_features.cpu().detach().numpy()
|
57 |
+
x.append(normalized ( im_emb_arr) ) # all CLIP embeddings are getting normalized. This also has to be done when inputting an embedding later for inference
|
58 |
+
y_ = np.zeros((1, 1))
|
59 |
+
y_[0][0] = average_rating
|
60 |
+
#y_[0][1] = stdev # I initially considered also predicting the standard deviation, but then didn't do it
|
61 |
+
|
62 |
+
y.append(y_)
|
63 |
+
|
64 |
+
|
65 |
+
print(c)
|
66 |
+
c+=1
|
67 |
+
|
68 |
+
|
69 |
+
|
70 |
+
|
71 |
+
x = np.vstack(x)
|
72 |
+
y = np.vstack(y)
|
73 |
+
print(x.shape)
|
74 |
+
print(y.shape)
|
75 |
+
np.save('x_OpenAI_CLIP_L14_embeddings.npy', x)
|
76 |
+
np.save('y_ratings.npy', y)
|
improved-aesthetic-predictor/simple_inference.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import webdataset as wds
|
2 |
+
from PIL import Image
|
3 |
+
import io
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import os
|
6 |
+
import json
|
7 |
+
|
8 |
+
from warnings import filterwarnings
|
9 |
+
|
10 |
+
|
11 |
+
# os.environ["CUDA_VISIBLE_DEVICES"] = "0" # choose GPU if you are on a multi GPU server
|
12 |
+
import numpy as np
|
13 |
+
import torch
|
14 |
+
import pytorch_lightning as pl
|
15 |
+
import torch.nn as nn
|
16 |
+
from torchvision import datasets, transforms
|
17 |
+
import tqdm
|
18 |
+
|
19 |
+
from os.path import join
|
20 |
+
from datasets import load_dataset
|
21 |
+
import pandas as pd
|
22 |
+
from torch.utils.data import Dataset, DataLoader
|
23 |
+
import json
|
24 |
+
|
25 |
+
import clip
|
26 |
+
|
27 |
+
|
28 |
+
from PIL import Image, ImageFile
|
29 |
+
|
30 |
+
|
31 |
+
##### This script will predict the aesthetic score for this image file:
|
32 |
+
|
33 |
+
img_path = "test.jpg"
|
34 |
+
|
35 |
+
|
36 |
+
|
37 |
+
|
38 |
+
|
39 |
+
# if you changed the MLP architecture during training, change it also here:
|
40 |
+
class MLP(pl.LightningModule):
|
41 |
+
def __init__(self, input_size, xcol='emb', ycol='avg_rating'):
|
42 |
+
super().__init__()
|
43 |
+
self.input_size = input_size
|
44 |
+
self.xcol = xcol
|
45 |
+
self.ycol = ycol
|
46 |
+
self.layers = nn.Sequential(
|
47 |
+
nn.Linear(self.input_size, 1024),
|
48 |
+
#nn.ReLU(),
|
49 |
+
nn.Dropout(0.2),
|
50 |
+
nn.Linear(1024, 128),
|
51 |
+
#nn.ReLU(),
|
52 |
+
nn.Dropout(0.2),
|
53 |
+
nn.Linear(128, 64),
|
54 |
+
#nn.ReLU(),
|
55 |
+
nn.Dropout(0.1),
|
56 |
+
|
57 |
+
nn.Linear(64, 16),
|
58 |
+
#nn.ReLU(),
|
59 |
+
|
60 |
+
nn.Linear(16, 1)
|
61 |
+
)
|
62 |
+
|
63 |
+
def forward(self, x):
|
64 |
+
return self.layers(x)
|
65 |
+
|
66 |
+
def training_step(self, batch, batch_idx):
|
67 |
+
x = batch[self.xcol]
|
68 |
+
y = batch[self.ycol].reshape(-1, 1)
|
69 |
+
x_hat = self.layers(x)
|
70 |
+
loss = F.mse_loss(x_hat, y)
|
71 |
+
return loss
|
72 |
+
|
73 |
+
def validation_step(self, batch, batch_idx):
|
74 |
+
x = batch[self.xcol]
|
75 |
+
y = batch[self.ycol].reshape(-1, 1)
|
76 |
+
x_hat = self.layers(x)
|
77 |
+
loss = F.mse_loss(x_hat, y)
|
78 |
+
return loss
|
79 |
+
|
80 |
+
def configure_optimizers(self):
|
81 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
82 |
+
return optimizer
|
83 |
+
|
84 |
+
def normalized(a, axis=-1, order=2):
|
85 |
+
import numpy as np # pylint: disable=import-outside-toplevel
|
86 |
+
|
87 |
+
l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
|
88 |
+
l2[l2 == 0] = 1
|
89 |
+
return a / np.expand_dims(l2, axis)
|
90 |
+
|
91 |
+
|
92 |
+
model = MLP(768) # CLIP embedding dim is 768 for CLIP ViT L 14
|
93 |
+
|
94 |
+
s = torch.load("sac+logos+ava1-l14-linearMSE.pth") # load the model you trained previously or the model available in this repo
|
95 |
+
|
96 |
+
model.load_state_dict(s)
|
97 |
+
|
98 |
+
model.to("cuda")
|
99 |
+
model.eval()
|
100 |
+
|
101 |
+
|
102 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
103 |
+
model2, preprocess = clip.load("ViT-L/14", device=device) #RN50x64
|
104 |
+
|
105 |
+
|
106 |
+
pil_image = Image.open(img_path)
|
107 |
+
|
108 |
+
image = preprocess(pil_image).unsqueeze(0).to(device)
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
with torch.no_grad():
|
113 |
+
image_features = model2.encode_image(image)
|
114 |
+
|
115 |
+
im_emb_arr = normalized(image_features.cpu().detach().numpy() )
|
116 |
+
|
117 |
+
prediction = model(torch.from_numpy(im_emb_arr).to(device).type(torch.cuda.FloatTensor))
|
118 |
+
|
119 |
+
print( "Aesthetic score predicted by the model:")
|
120 |
+
print( prediction )
|
121 |
+
|
122 |
+
|
improved-aesthetic-predictor/train_predictor.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
# os.environ['CUDA_VISIBLE_DEVICES'] = "0" # in case you are using a multi GPU workstation, choose your GPU here
|
3 |
+
import tqdm
|
4 |
+
import pytorch_lightning as pl
|
5 |
+
import torch
|
6 |
+
import torch.nn as nn
|
7 |
+
from torch.utils.data import DataLoader
|
8 |
+
import torch.nn.functional as F
|
9 |
+
import pandas as pd
|
10 |
+
from datasets import load_dataset
|
11 |
+
from torch.utils.data import TensorDataset, DataLoader
|
12 |
+
|
13 |
+
import numpy as np
|
14 |
+
|
15 |
+
#define your neural net here:
|
16 |
+
|
17 |
+
class MLP(pl.LightningModule):
|
18 |
+
def __init__(self, input_size, xcol='emb', ycol='avg_rating'):
|
19 |
+
super().__init__()
|
20 |
+
self.input_size = input_size
|
21 |
+
self.xcol = xcol
|
22 |
+
self.ycol = ycol
|
23 |
+
self.layers = nn.Sequential(
|
24 |
+
nn.Linear(self.input_size, 1024),
|
25 |
+
#nn.ReLU(),
|
26 |
+
nn.Dropout(0.2),
|
27 |
+
nn.Linear(1024, 128),
|
28 |
+
#nn.ReLU(),
|
29 |
+
nn.Dropout(0.2),
|
30 |
+
nn.Linear(128, 64),
|
31 |
+
#nn.ReLU(),
|
32 |
+
nn.Dropout(0.1),
|
33 |
+
|
34 |
+
nn.Linear(64, 16),
|
35 |
+
#nn.ReLU(),
|
36 |
+
|
37 |
+
nn.Linear(16, 1)
|
38 |
+
)
|
39 |
+
|
40 |
+
def forward(self, x):
|
41 |
+
return self.layers(x)
|
42 |
+
|
43 |
+
def training_step(self, batch, batch_idx):
|
44 |
+
x = batch[self.xcol]
|
45 |
+
y = batch[self.ycol].reshape(-1, 1)
|
46 |
+
x_hat = self.layers(x)
|
47 |
+
loss = F.mse_loss(x_hat, y)
|
48 |
+
return loss
|
49 |
+
|
50 |
+
def validation_step(self, batch, batch_idx):
|
51 |
+
x = batch[self.xcol]
|
52 |
+
y = batch[self.ycol].reshape(-1, 1)
|
53 |
+
x_hat = self.layers(x)
|
54 |
+
loss = F.mse_loss(x_hat, y)
|
55 |
+
return loss
|
56 |
+
|
57 |
+
def configure_optimizers(self):
|
58 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
59 |
+
return optimizer
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
# load the training data
|
64 |
+
|
65 |
+
x = np.load ("/mnt/spirit/ava_x.npy")
|
66 |
+
|
67 |
+
y = np.load ("/mnt/spirit/ava_y.npy")
|
68 |
+
|
69 |
+
val_percentage = 0.05 # 5% of the trainingdata will be used for validation
|
70 |
+
|
71 |
+
train_border = int(x.shape()[0] * (1 - val_percentage) )
|
72 |
+
|
73 |
+
train_tensor_x = torch.Tensor(x[:train_border]) # transform to torch tensor
|
74 |
+
train_tensor_y = torch.Tensor(y[:train_border])
|
75 |
+
|
76 |
+
train_dataset = TensorDataset(train_tensor_x,train_tensor_y) # create your datset
|
77 |
+
train_loader = DataLoader(train_dataset, batch_size=256, shuffle=True, num_workers=16) # create your dataloader
|
78 |
+
|
79 |
+
|
80 |
+
val_tensor_x = torch.Tensor(x[train_border:]) # transform to torch tensor
|
81 |
+
val_tensor_y = torch.Tensor(y[train_border:])
|
82 |
+
|
83 |
+
'''
|
84 |
+
print(train_tensor_x.size())
|
85 |
+
print(val_tensor_x.size())
|
86 |
+
print( val_tensor_x.dtype)
|
87 |
+
print( val_tensor_x[0].dtype)
|
88 |
+
'''
|
89 |
+
|
90 |
+
val_dataset = TensorDataset(val_tensor_x,val_tensor_y) # create your datset
|
91 |
+
val_loader = DataLoader(val_dataset, batch_size=512, num_workers=16) # create your dataloader
|
92 |
+
|
93 |
+
|
94 |
+
|
95 |
+
|
96 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
97 |
+
|
98 |
+
model = MLP(768).to(device) # CLIP embedding dim is 768 for CLIP ViT L 14
|
99 |
+
|
100 |
+
optimizer = torch.optim.Adam(model.parameters())
|
101 |
+
|
102 |
+
# choose the loss you want to optimze for
|
103 |
+
criterion = nn.MSELoss()
|
104 |
+
criterion2 = nn.L1Loss()
|
105 |
+
|
106 |
+
epochs = 50
|
107 |
+
|
108 |
+
model.train()
|
109 |
+
best_loss =999
|
110 |
+
save_name = "linear_predictor_L14_MSE.pth"
|
111 |
+
|
112 |
+
|
113 |
+
for epoch in range(epochs):
|
114 |
+
losses = []
|
115 |
+
losses2 = []
|
116 |
+
for batch_num, input_data in enumerate(train_loader):
|
117 |
+
optimizer.zero_grad()
|
118 |
+
x, y = input_data
|
119 |
+
x = x.to(device).float()
|
120 |
+
y = y.to(device)
|
121 |
+
|
122 |
+
output = model(x)
|
123 |
+
loss = criterion(output, y)
|
124 |
+
loss.backward()
|
125 |
+
losses.append(loss.item())
|
126 |
+
|
127 |
+
|
128 |
+
optimizer.step()
|
129 |
+
|
130 |
+
if batch_num % 1000 == 0:
|
131 |
+
print('\tEpoch %d | Batch %d | Loss %6.2f' % (epoch, batch_num, loss.item()))
|
132 |
+
#print(y)
|
133 |
+
|
134 |
+
print('Epoch %d | Loss %6.2f' % (epoch, sum(losses)/len(losses)))
|
135 |
+
losses = []
|
136 |
+
losses2 = []
|
137 |
+
|
138 |
+
for batch_num, input_data in enumerate(val_loader):
|
139 |
+
optimizer.zero_grad()
|
140 |
+
x, y = input_data
|
141 |
+
x = x.to(device).float()
|
142 |
+
y = y.to(device)
|
143 |
+
|
144 |
+
output = model(x)
|
145 |
+
loss = criterion(output, y)
|
146 |
+
lossMAE = criterion2(output, y)
|
147 |
+
#loss.backward()
|
148 |
+
losses.append(loss.item())
|
149 |
+
losses2.append(lossMAE.item())
|
150 |
+
#optimizer.step()
|
151 |
+
|
152 |
+
if batch_num % 1000 == 0:
|
153 |
+
print('\tValidation - Epoch %d | Batch %d | MSE Loss %6.2f' % (epoch, batch_num, loss.item()))
|
154 |
+
print('\tValidation - Epoch %d | Batch %d | MAE Loss %6.2f' % (epoch, batch_num, lossMAE.item()))
|
155 |
+
|
156 |
+
#print(y)
|
157 |
+
|
158 |
+
print('Validation - Epoch %d | MSE Loss %6.2f' % (epoch, sum(losses)/len(losses)))
|
159 |
+
print('Validation - Epoch %d | MAE Loss %6.2f' % (epoch, sum(losses2)/len(losses2)))
|
160 |
+
if sum(losses)/len(losses) < best_loss:
|
161 |
+
print("Best MAE Val loss so far. Saving model")
|
162 |
+
best_loss = sum(losses)/len(losses)
|
163 |
+
print( best_loss )
|
164 |
+
|
165 |
+
torch.save(model.state_dict(), save_name )
|
166 |
+
|
167 |
+
|
168 |
+
torch.save(model.state_dict(), save_name)
|
169 |
+
|
170 |
+
print( best_loss )
|
171 |
+
|
172 |
+
print("training done")
|
173 |
+
# inferece test with dummy samples from the val set, sanity check
|
174 |
+
print( "inferece test with dummy samples from the val set, sanity check")
|
175 |
+
model.eval()
|
176 |
+
output = model(x[:5].to(device))
|
177 |
+
print(output.size())
|
178 |
+
print(output)
|
improved-aesthetic-predictor/visulaize_100k_from_LAION400M.py
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import webdataset as wds
|
2 |
+
from PIL import Image
|
3 |
+
import io
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import os
|
6 |
+
import json
|
7 |
+
|
8 |
+
from warnings import filterwarnings
|
9 |
+
|
10 |
+
|
11 |
+
# os.environ["CUDA_VISIBLE_DEVICES"] = "0" # choose GPU if you are on a multi GPU server
|
12 |
+
import numpy as np
|
13 |
+
import torch
|
14 |
+
import pytorch_lightning as pl
|
15 |
+
import torch.nn as nn
|
16 |
+
from torchvision import datasets, transforms
|
17 |
+
import tqdm
|
18 |
+
|
19 |
+
from os.path import join
|
20 |
+
from datasets import load_dataset
|
21 |
+
import pandas as pd
|
22 |
+
from torch.utils.data import Dataset, DataLoader
|
23 |
+
import json
|
24 |
+
|
25 |
+
import clip
|
26 |
+
#import open_clip
|
27 |
+
|
28 |
+
from PIL import Image, ImageFile
|
29 |
+
|
30 |
+
|
31 |
+
# if you changed the MLP architecture during training, change it also here:
|
32 |
+
|
33 |
+
class MLP(pl.LightningModule):
|
34 |
+
def __init__(self, input_size, xcol='emb', ycol='avg_rating'):
|
35 |
+
super().__init__()
|
36 |
+
self.input_size = input_size
|
37 |
+
self.xcol = xcol
|
38 |
+
self.ycol = ycol
|
39 |
+
self.layers = nn.Sequential(
|
40 |
+
nn.Linear(self.input_size, 1024),
|
41 |
+
#nn.ReLU(),
|
42 |
+
nn.Dropout(0.2),
|
43 |
+
nn.Linear(1024, 128),
|
44 |
+
#nn.ReLU(),
|
45 |
+
nn.Dropout(0.2),
|
46 |
+
nn.Linear(128, 64),
|
47 |
+
#nn.ReLU(),
|
48 |
+
nn.Dropout(0.1),
|
49 |
+
|
50 |
+
nn.Linear(64, 16),
|
51 |
+
#nn.ReLU(),
|
52 |
+
|
53 |
+
nn.Linear(16, 1)
|
54 |
+
)
|
55 |
+
|
56 |
+
def forward(self, x):
|
57 |
+
return self.layers(x)
|
58 |
+
|
59 |
+
def training_step(self, batch, batch_idx):
|
60 |
+
x = batch[self.xcol]
|
61 |
+
y = batch[self.ycol].reshape(-1, 1)
|
62 |
+
x_hat = self.layers(x)
|
63 |
+
loss = F.mse_loss(x_hat, y)
|
64 |
+
return loss
|
65 |
+
|
66 |
+
def validation_step(self, batch, batch_idx):
|
67 |
+
x = batch[self.xcol]
|
68 |
+
y = batch[self.ycol].reshape(-1, 1)
|
69 |
+
x_hat = self.layers(x)
|
70 |
+
loss = F.mse_loss(x_hat, y)
|
71 |
+
return loss
|
72 |
+
|
73 |
+
def configure_optimizers(self):
|
74 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
75 |
+
return optimizer
|
76 |
+
|
77 |
+
def normalized(a, axis=-1, order=2):
|
78 |
+
import numpy as np # pylint: disable=import-outside-toplevel
|
79 |
+
|
80 |
+
l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
|
81 |
+
l2[l2 == 0] = 1
|
82 |
+
return a / np.expand_dims(l2, axis)
|
83 |
+
|
84 |
+
|
85 |
+
model = MLP(768) # CLIP embedding dim is 768 for CLIP ViT L 14
|
86 |
+
|
87 |
+
s = torch.load("ava+logos-l14-linearMSE.pth") # load the model you trained previously or the model available in this repo
|
88 |
+
|
89 |
+
model.load_state_dict(s)
|
90 |
+
|
91 |
+
|
92 |
+
model.to("cuda")
|
93 |
+
model.eval()
|
94 |
+
|
95 |
+
|
96 |
+
|
97 |
+
|
98 |
+
|
99 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
100 |
+
model2, preprocess = clip.load("ViT-L/14", device=device) #RN50x64
|
101 |
+
|
102 |
+
|
103 |
+
|
104 |
+
c=0
|
105 |
+
urls= []
|
106 |
+
predictions=[]
|
107 |
+
|
108 |
+
# this will run inference over 10 webdataset tar files from LAION 400M and sort them into 20 categories
|
109 |
+
# you can DL LAION 400M and convert it to wds tar files with img2dataset ( https://github.com/rom1504/img2dataset )
|
110 |
+
|
111 |
+
|
112 |
+
for j in range(10):
|
113 |
+
if j<10:
|
114 |
+
# change the path to the tar files accordingly
|
115 |
+
dataset = wds.WebDataset("pipe:aws s3 cp s3://s-datasets/laion400m/laion400m-dat-release/0000"+str(j)+".tar -") #"pipe:aws s3 cp s3://s-datasets/laion400m/laion400m-dat-release/00625.tar -")
|
116 |
+
else:
|
117 |
+
dataset = wds.WebDataset("pipe:aws s3 cp s3://s-datasets/laion400m/laion400m-dat-release/000"+str(j)+".tar -") #"pipe:aws s3 cp s3://s-datasets/laion400m/laion400m-dat-release/00625.tar -")
|
118 |
+
|
119 |
+
|
120 |
+
for i, d in enumerate(dataset):
|
121 |
+
print(c)
|
122 |
+
|
123 |
+
metadata= json.loads(d['json'])
|
124 |
+
|
125 |
+
pil_image = Image.open(io.BytesIO(d['jpg']))
|
126 |
+
c=c+1
|
127 |
+
try:
|
128 |
+
image = preprocess(pil_image).unsqueeze(0).to(device)
|
129 |
+
|
130 |
+
except:
|
131 |
+
continue
|
132 |
+
|
133 |
+
with torch.no_grad():
|
134 |
+
image_features = model2.encode_image(image)
|
135 |
+
|
136 |
+
|
137 |
+
im_emb_arr = normalized(image_features.cpu().detach().numpy() )
|
138 |
+
|
139 |
+
prediction = model(torch.from_numpy(im_emb_arr).to(device).type(torch.cuda.FloatTensor))
|
140 |
+
urls.append(metadata["url"])
|
141 |
+
predictions.append(prediction)
|
142 |
+
|
143 |
+
|
144 |
+
df = pd.DataFrame(list(zip(urls, predictions)),
|
145 |
+
columns =['filepath', 'prediction'])
|
146 |
+
|
147 |
+
|
148 |
+
buckets = [(i, i+1) for i in range(20)]
|
149 |
+
|
150 |
+
|
151 |
+
html= "<h1>Aesthetic subsets in LAION 100k samples</h1>"
|
152 |
+
|
153 |
+
i =0
|
154 |
+
for [a,b] in buckets:
|
155 |
+
a = a/2
|
156 |
+
b = b/2
|
157 |
+
total_part = df[( (df["prediction"] ) *1>= a) & ( (df["prediction"] ) *1 <= b)]
|
158 |
+
print(a,b)
|
159 |
+
print(len(total_part) )
|
160 |
+
count_part = len(total_part) / len(df) * 100
|
161 |
+
estimated =int ( len(total_part) )
|
162 |
+
part = total_part[:50]
|
163 |
+
|
164 |
+
html+=f"<h2>In bucket {a} - {b} there is {count_part:.2f}% samples:{estimated:.2f} </h2> <div>"
|
165 |
+
for filepath in part["filepath"]:
|
166 |
+
html+='<img src="'+filepath +'" height="200" />'
|
167 |
+
|
168 |
+
|
169 |
+
html+="</div>"
|
170 |
+
i+=1
|
171 |
+
print(i)
|
172 |
+
with open("./aesthetic_viz_laion_ava+logos_L14_100k-linearMSE.html", "w") as f:
|
173 |
+
f.write(html)
|
174 |
+
|
175 |
+
|
kaggle_evaluation/__init__.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
Competition helper module for the Drawing With LLMs Kaggle Competition.
|
3 |
+
|
4 |
+
Supports the `test` function for users to validate their Model, and internal functions
|
5 |
+
used by Kaggle's scoring system.
|
6 |
+
'''
|
7 |
+
|
8 |
+
import pathlib
|
9 |
+
import sys
|
10 |
+
|
11 |
+
# Provide additional import management since grpc_tools.protoc doesn't support relative imports
|
12 |
+
module_path = pathlib.Path(__file__).parent
|
13 |
+
gen_path = module_path / 'core' / 'generated'
|
14 |
+
|
15 |
+
if not (gen_path / 'kaggle_evaluation_pb2.py').exists():
|
16 |
+
msg = 'Missing required kaggle_evaluation proto / gRPC generated files.'
|
17 |
+
raise ImportError(msg)
|
18 |
+
|
19 |
+
sys.path.append(str(module_path))
|
20 |
+
sys.path.append(str(gen_path))
|
21 |
+
|
22 |
+
from .svg import test, _run_gateway, _run_inference_server
|
23 |
+
__all__ = ['test']
|
24 |
+
|
25 |
+
__version__ = '0.5.0'
|
kaggle_evaluation/core/__init__.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
|
4 |
+
|
5 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
kaggle_evaluation/core/base_gateway.py
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
''' Lower level implementation details of the gateway.
|
2 |
+
Hosts should not need to review this file before writing their competition specific gateway.
|
3 |
+
'''
|
4 |
+
|
5 |
+
import enum
|
6 |
+
import json
|
7 |
+
import os
|
8 |
+
import pathlib
|
9 |
+
import re
|
10 |
+
import subprocess
|
11 |
+
import tempfile
|
12 |
+
|
13 |
+
from socket import gaierror
|
14 |
+
from typing import Any, List, Optional, Tuple, Union
|
15 |
+
|
16 |
+
import grpc
|
17 |
+
import numpy as np
|
18 |
+
import pandas as pd
|
19 |
+
import polars as pl
|
20 |
+
|
21 |
+
import kaggle_evaluation.core.relay
|
22 |
+
|
23 |
+
|
24 |
+
_FILE_SHARE_DIR = '/kaggle/shared/'
|
25 |
+
IS_RERUN = os.getenv('KAGGLE_IS_COMPETITION_RERUN') is not None
|
26 |
+
|
27 |
+
|
28 |
+
class GatewayRuntimeErrorType(enum.Enum):
|
29 |
+
''' Allow-listed error types that Gateways can raise, which map to canned error messages to show users.'''
|
30 |
+
UNSPECIFIED = 0
|
31 |
+
SERVER_NEVER_STARTED = 1
|
32 |
+
SERVER_CONNECTION_FAILED = 2
|
33 |
+
SERVER_RAISED_EXCEPTION = 3
|
34 |
+
SERVER_MISSING_ENDPOINT = 4
|
35 |
+
# Default error type if an exception was raised that was not explicitly handled by the Gateway
|
36 |
+
GATEWAY_RAISED_EXCEPTION = 5
|
37 |
+
INVALID_SUBMISSION = 6
|
38 |
+
|
39 |
+
|
40 |
+
class GatewayRuntimeError(Exception):
|
41 |
+
''' Gateways can raise this error to capture a user-visible error enum from above and host-visible error details.'''
|
42 |
+
def __init__(self, error_type: GatewayRuntimeErrorType, error_details: Optional[str]=None):
|
43 |
+
self.error_type = error_type
|
44 |
+
self.error_details = error_details
|
45 |
+
|
46 |
+
|
47 |
+
class BaseGateway():
|
48 |
+
def __init__(self, target_column_name: Optional[str]=None):
|
49 |
+
self.client = kaggle_evaluation.core.relay.Client('inference_server' if IS_RERUN else 'localhost')
|
50 |
+
self.server = None # The gateway can have a server but it isn't typically necessary.
|
51 |
+
self.target_column_name = target_column_name # Only used if the predictions are made as a primitive type (int, bool, etc) rather than a dataframe.
|
52 |
+
|
53 |
+
def validate_prediction_batch(
|
54 |
+
self,
|
55 |
+
prediction_batch: Any,
|
56 |
+
row_ids: Union[pl.DataFrame, pl.Series, pd.DataFrame, pd.Series]
|
57 |
+
):
|
58 |
+
''' If competitors can submit fewer rows than expected they can save all predictions for the last batch and
|
59 |
+
bypass the benefits of the Kaggle evaluation service. This attack was seen in a real competition with the older time series API:
|
60 |
+
https://www.kaggle.com/competitions/riiid-test-answer-prediction/discussion/196066
|
61 |
+
It's critically important that this check be run every time predict() is called.
|
62 |
+
|
63 |
+
If your predictions may take a variable number of rows and you need to write a custom version of this check,
|
64 |
+
you still must specify a minimum row count greater than zero per prediction batch.
|
65 |
+
'''
|
66 |
+
if prediction_batch is None:
|
67 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, 'No prediction received')
|
68 |
+
num_received_rows = None
|
69 |
+
# Special handling for numpy ints only as numpy floats are python floats, but numpy ints aren't python ints
|
70 |
+
for primitive_type in [int, float, str, bool, np.int_]:
|
71 |
+
if isinstance(prediction_batch, primitive_type):
|
72 |
+
# Types that only support one predictions per batch don't need to be validated.
|
73 |
+
# Basic types are valid for prediction, but either don't have a length (int) or the length isn't relevant for
|
74 |
+
# purposes of this check (str).
|
75 |
+
num_received_rows = 1
|
76 |
+
if num_received_rows is None:
|
77 |
+
if type(prediction_batch) not in [pl.DataFrame, pl.Series, pd.DataFrame, pd.Series]:
|
78 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, f'Invalid prediction data type, received: {type(prediction_batch)}')
|
79 |
+
num_received_rows = len(prediction_batch)
|
80 |
+
if type(row_ids) not in [pl.DataFrame, pl.Series, pd.DataFrame, pd.Series]:
|
81 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.GATEWAY_RAISED_EXCEPTION, f'Invalid row ID type {type(row_ids)}; expected Polars DataFrame or similar')
|
82 |
+
num_expected_rows = len(row_ids)
|
83 |
+
if len(row_ids) == 0:
|
84 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.GATEWAY_RAISED_EXCEPTION, 'Missing row IDs for batch')
|
85 |
+
if num_received_rows != num_expected_rows:
|
86 |
+
raise GatewayRuntimeError(
|
87 |
+
GatewayRuntimeErrorType.INVALID_SUBMISSION,
|
88 |
+
f'Invalid predictions: expected {num_expected_rows} rows but received {num_received_rows}'
|
89 |
+
)
|
90 |
+
|
91 |
+
def _standardize_and_validate_paths(
|
92 |
+
self,
|
93 |
+
input_paths: List[Union[str, pathlib.Path]]
|
94 |
+
) -> List[pathlib.Path]:
|
95 |
+
# Accept a list of str or pathlib.Path, but standardize on list of str
|
96 |
+
for path in input_paths:
|
97 |
+
if os.pardir in str(path):
|
98 |
+
raise ValueError(f'Send files path contains {os.pardir}: {path}')
|
99 |
+
if str(path) != str(os.path.normpath(path)):
|
100 |
+
# Raise an error rather than sending users unexpectedly altered paths
|
101 |
+
raise ValueError(f'Send files path {path} must be normalized. See `os.path.normpath`')
|
102 |
+
if type(path) not in (pathlib.Path, str):
|
103 |
+
raise ValueError('All paths must be of type str or pathlib.Path')
|
104 |
+
if not os.path.exists(path):
|
105 |
+
raise ValueError(f'Input path {path} does not exist')
|
106 |
+
|
107 |
+
input_paths = [os.path.abspath(path) for path in input_paths]
|
108 |
+
if len(set(input_paths)) != len(input_paths):
|
109 |
+
raise ValueError('Duplicate input paths found')
|
110 |
+
|
111 |
+
if not self.file_share_dir.endswith(os.path.sep):
|
112 |
+
# Ensure output dir is valid for later use
|
113 |
+
output_dir = self.file_share_dir + os.path.sep
|
114 |
+
|
115 |
+
if not os.path.exists(self.file_share_dir) or not os.path.isdir(self.file_share_dir):
|
116 |
+
raise ValueError(f'Invalid output directory {self.file_share_dir}')
|
117 |
+
# Can't use os.path.join for output_dir + path: os.path.join won't prepend to an abspath
|
118 |
+
output_paths = [output_dir + path for path in input_paths]
|
119 |
+
return input_paths, output_paths
|
120 |
+
|
121 |
+
def share_files(
|
122 |
+
self,
|
123 |
+
input_paths: List[Union[str, pathlib.Path]],
|
124 |
+
) -> List[str]:
|
125 |
+
''' Makes files and/or directories available to the user's inference_server. They will be mirrored under the
|
126 |
+
self.file_share_dir directory, using the full absolute path. An input like:
|
127 |
+
/kaggle/input/mycomp/test.csv
|
128 |
+
Would be written to:
|
129 |
+
/kaggle/shared/kaggle/input/mycomp/test.csv
|
130 |
+
|
131 |
+
Args:
|
132 |
+
input_paths: List of paths to files and/or directories that should be shared.
|
133 |
+
|
134 |
+
Returns:
|
135 |
+
The output paths that were shared.
|
136 |
+
|
137 |
+
Raises:
|
138 |
+
ValueError if any invalid paths are passed.
|
139 |
+
'''
|
140 |
+
input_paths, output_paths = self._standardize_and_validate_paths(input_paths)
|
141 |
+
for in_path, out_path in zip(input_paths, output_paths):
|
142 |
+
os.makedirs(os.path.dirname(out_path), exist_ok=True)
|
143 |
+
|
144 |
+
# This makes the files available to the InferenceServer as read-only. Only the Gateway can mount files.
|
145 |
+
# mount will only work in live kaggle evaluation rerun sessions. Otherwise use a symlink.
|
146 |
+
if IS_RERUN:
|
147 |
+
if not os.path.isdir(out_path):
|
148 |
+
pathlib.Path(out_path).touch()
|
149 |
+
subprocess.run(f'mount --bind {in_path} {out_path}', shell=True, check=True)
|
150 |
+
else:
|
151 |
+
subprocess.run(f'ln -s {in_path} {out_path}', shell=True, check=True)
|
152 |
+
|
153 |
+
return output_paths
|
154 |
+
|
155 |
+
def write_submission(self, predictions, row_ids: List[Union[pl.Series, pl.DataFrame, pd.Series, pd.DataFrame]]) -> pathlib.Path:
|
156 |
+
''' Export the predictions to a submission file.'''
|
157 |
+
if isinstance(predictions, list):
|
158 |
+
if isinstance(predictions[0], pd.DataFrame):
|
159 |
+
predictions = pd.concat(predictions, ignore_index=True)
|
160 |
+
elif isinstance(predictions[0], pl.DataFrame):
|
161 |
+
try:
|
162 |
+
predictions = pl.concat(predictions, how='vertical_relaxed')
|
163 |
+
except pl.exceptions.SchemaError:
|
164 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, 'Inconsistent prediction types')
|
165 |
+
except pl.exceptions.ComputeError:
|
166 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, 'Inconsistent prediction column counts')
|
167 |
+
elif isinstance(predictions[0], pl.Series):
|
168 |
+
try:
|
169 |
+
predictions = pl.concat(predictions, how='vertical')
|
170 |
+
except pl.exceptions.SchemaError:
|
171 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, 'Inconsistent prediction types')
|
172 |
+
except pl.exceptions.ComputeError:
|
173 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, 'Inconsistent prediction column counts')
|
174 |
+
|
175 |
+
if type(row_ids[0]) in [pl.Series, pl.DataFrame]:
|
176 |
+
row_ids = pl.concat(row_ids)
|
177 |
+
elif type(row_ids[0]) in [pd.Series, pd.DataFrame]:
|
178 |
+
row_ids = pd.concat(row_ids).reset_index(drop=True)
|
179 |
+
else:
|
180 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.GATEWAY_RAISED_EXCEPTION, f'Invalid row ID datatype {type(row_ids[0])}. Expected Polars series or dataframe.')
|
181 |
+
if self.target_column_name is None:
|
182 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.GATEWAY_RAISED_EXCEPTION, '`target_column_name` must be set in order to use scalar value predictions.')
|
183 |
+
predictions = pl.DataFrame(data={row_ids.columns[0]: row_ids, self.target_column_name: predictions})
|
184 |
+
|
185 |
+
submission_path = pathlib.Path('/kaggle/working/submission.csv')
|
186 |
+
if not IS_RERUN:
|
187 |
+
with tempfile.NamedTemporaryFile(prefix='kaggle-evaluation-submission-', suffix='.csv', delete=False, mode='w+') as f:
|
188 |
+
submission_path = pathlib.Path(f.name)
|
189 |
+
|
190 |
+
if isinstance(predictions, pd.DataFrame):
|
191 |
+
predictions.to_csv(submission_path, index=False)
|
192 |
+
elif isinstance(predictions, pl.DataFrame):
|
193 |
+
pl.DataFrame(predictions).write_csv(submission_path)
|
194 |
+
else:
|
195 |
+
raise ValueError(f"Unsupported predictions type {type(predictions)}; can't write submission file")
|
196 |
+
|
197 |
+
return submission_path
|
198 |
+
|
199 |
+
def write_result(self, error: Optional[GatewayRuntimeError]=None):
|
200 |
+
''' Export a result.json containing error details if applicable.'''
|
201 |
+
result = { 'Succeeded': error is None }
|
202 |
+
|
203 |
+
if error is not None:
|
204 |
+
result['ErrorType'] = error.error_type.value
|
205 |
+
result['ErrorName'] = error.error_type.name
|
206 |
+
# Max error detail length is 8000
|
207 |
+
result['ErrorDetails'] = str(error.error_details[:8000]) if error.error_details else None
|
208 |
+
|
209 |
+
with open('result.json', 'w') as f_open:
|
210 |
+
json.dump(result, f_open)
|
211 |
+
|
212 |
+
def handle_server_error(self, exception: Exception, endpoint: str):
|
213 |
+
''' Determine how to handle an exception raised when calling the inference server. Typically just format the
|
214 |
+
error into a GatewayRuntimeError and raise.
|
215 |
+
'''
|
216 |
+
exception_str = str(exception)
|
217 |
+
if isinstance(exception, gaierror) or (isinstance(exception, RuntimeError) and 'Failed to connect to server after waiting' in exception_str):
|
218 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.SERVER_NEVER_STARTED) from None
|
219 |
+
if f'No listener for {endpoint} was registered' in exception_str:
|
220 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.SERVER_MISSING_ENDPOINT, f'Server did not register a listener for {endpoint}') from None
|
221 |
+
if 'Exception calling application' in exception_str:
|
222 |
+
# Extract just the exception message raised by the inference server
|
223 |
+
message_match = re.search('"Exception calling application: (.*)"', exception_str, re.IGNORECASE)
|
224 |
+
message = message_match.group(1) if message_match else exception_str
|
225 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.SERVER_RAISED_EXCEPTION, message) from None
|
226 |
+
if isinstance(exception, grpc._channel._InactiveRpcError):
|
227 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.SERVER_CONNECTION_FAILED, exception_str) from None
|
228 |
+
|
229 |
+
raise exception
|
kaggle_evaluation/core/generated/__init__.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
|
4 |
+
|
5 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
kaggle_evaluation/core/generated/kaggle_evaluation_pb2.py
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
3 |
+
# source: kaggle_evaluation.proto
|
4 |
+
# Protobuf Python Version: 4.25.1
|
5 |
+
"""Generated protocol buffer code."""
|
6 |
+
from google.protobuf import descriptor as _descriptor
|
7 |
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
8 |
+
from google.protobuf import symbol_database as _symbol_database
|
9 |
+
from google.protobuf.internal import builder as _builder
|
10 |
+
# @@protoc_insertion_point(imports)
|
11 |
+
|
12 |
+
_sym_db = _symbol_database.Default()
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17kaggle_evaluation.proto\x12\x18kaggle_evaluation_client\"\xf9\x01\n\x17KaggleEvaluationRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04\x61rgs\x18\x02 \x03(\x0b\x32!.kaggle_evaluation_client.Payload\x12M\n\x06kwargs\x18\x03 \x03(\x0b\x32=.kaggle_evaluation_client.KaggleEvaluationRequest.KwargsEntry\x1aP\n\x0bKwargsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.kaggle_evaluation_client.Payload:\x02\x38\x01\"N\n\x18KaggleEvaluationResponse\x12\x32\n\x07payload\x18\x01 \x01(\x0b\x32!.kaggle_evaluation_client.Payload\"\x8d\x04\n\x07Payload\x12\x13\n\tstr_value\x18\x01 \x01(\tH\x00\x12\x14\n\nbool_value\x18\x02 \x01(\x08H\x00\x12\x13\n\tint_value\x18\x03 \x01(\x12H\x00\x12\x15\n\x0b\x66loat_value\x18\x04 \x01(\x02H\x00\x12\x14\n\nnone_value\x18\x05 \x01(\x08H\x00\x12;\n\nlist_value\x18\x06 \x01(\x0b\x32%.kaggle_evaluation_client.PayloadListH\x00\x12<\n\x0btuple_value\x18\x07 \x01(\x0b\x32%.kaggle_evaluation_client.PayloadListH\x00\x12:\n\ndict_value\x18\x08 \x01(\x0b\x32$.kaggle_evaluation_client.PayloadMapH\x00\x12 \n\x16pandas_dataframe_value\x18\t \x01(\x0cH\x00\x12 \n\x16polars_dataframe_value\x18\n \x01(\x0cH\x00\x12\x1d\n\x13pandas_series_value\x18\x0b \x01(\x0cH\x00\x12\x1d\n\x13polars_series_value\x18\x0c \x01(\x0cH\x00\x12\x1b\n\x11numpy_array_value\x18\r \x01(\x0cH\x00\x12\x1c\n\x12numpy_scalar_value\x18\x0e \x01(\x0cH\x00\x12\x18\n\x0e\x62ytes_io_value\x18\x0f \x01(\x0cH\x00\x42\x07\n\x05value\"B\n\x0bPayloadList\x12\x33\n\x08payloads\x18\x01 \x03(\x0b\x32!.kaggle_evaluation_client.Payload\"\xad\x01\n\nPayloadMap\x12I\n\x0bpayload_map\x18\x01 \x03(\x0b\x32\x34.kaggle_evaluation_client.PayloadMap.PayloadMapEntry\x1aT\n\x0fPayloadMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.kaggle_evaluation_client.Payload:\x02\x38\x01\x32\x8a\x01\n\x17KaggleEvaluationService\x12o\n\x04Send\x12\x31.kaggle_evaluation_client.KaggleEvaluationRequest\x1a\x32.kaggle_evaluation_client.KaggleEvaluationResponse\"\x00\x62\x06proto3')
|
18 |
+
|
19 |
+
_globals = globals()
|
20 |
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
21 |
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'kaggle_evaluation_pb2', _globals)
|
22 |
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
23 |
+
DESCRIPTOR._options = None
|
24 |
+
_globals['_KAGGLEEVALUATIONREQUEST_KWARGSENTRY']._options = None
|
25 |
+
_globals['_KAGGLEEVALUATIONREQUEST_KWARGSENTRY']._serialized_options = b'8\001'
|
26 |
+
_globals['_PAYLOADMAP_PAYLOADMAPENTRY']._options = None
|
27 |
+
_globals['_PAYLOADMAP_PAYLOADMAPENTRY']._serialized_options = b'8\001'
|
28 |
+
_globals['_KAGGLEEVALUATIONREQUEST']._serialized_start=54
|
29 |
+
_globals['_KAGGLEEVALUATIONREQUEST']._serialized_end=303
|
30 |
+
_globals['_KAGGLEEVALUATIONREQUEST_KWARGSENTRY']._serialized_start=223
|
31 |
+
_globals['_KAGGLEEVALUATIONREQUEST_KWARGSENTRY']._serialized_end=303
|
32 |
+
_globals['_KAGGLEEVALUATIONRESPONSE']._serialized_start=305
|
33 |
+
_globals['_KAGGLEEVALUATIONRESPONSE']._serialized_end=383
|
34 |
+
_globals['_PAYLOAD']._serialized_start=386
|
35 |
+
_globals['_PAYLOAD']._serialized_end=911
|
36 |
+
_globals['_PAYLOADLIST']._serialized_start=913
|
37 |
+
_globals['_PAYLOADLIST']._serialized_end=979
|
38 |
+
_globals['_PAYLOADMAP']._serialized_start=982
|
39 |
+
_globals['_PAYLOADMAP']._serialized_end=1155
|
40 |
+
_globals['_PAYLOADMAP_PAYLOADMAPENTRY']._serialized_start=1071
|
41 |
+
_globals['_PAYLOADMAP_PAYLOADMAPENTRY']._serialized_end=1155
|
42 |
+
_globals['_KAGGLEEVALUATIONSERVICE']._serialized_start=1158
|
43 |
+
_globals['_KAGGLEEVALUATIONSERVICE']._serialized_end=1296
|
44 |
+
# @@protoc_insertion_point(module_scope)
|
kaggle_evaluation/core/generated/kaggle_evaluation_pb2_grpc.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
2 |
+
"""Client and server classes corresponding to protobuf-defined services."""
|
3 |
+
import grpc
|
4 |
+
|
5 |
+
import kaggle_evaluation_pb2 as kaggle__evaluation__pb2
|
6 |
+
|
7 |
+
|
8 |
+
class KaggleEvaluationServiceStub(object):
|
9 |
+
"""Missing associated documentation comment in .proto file."""
|
10 |
+
|
11 |
+
def __init__(self, channel):
|
12 |
+
"""Constructor.
|
13 |
+
|
14 |
+
Args:
|
15 |
+
channel: A grpc.Channel.
|
16 |
+
"""
|
17 |
+
self.Send = channel.unary_unary(
|
18 |
+
'/kaggle_evaluation_client.KaggleEvaluationService/Send',
|
19 |
+
request_serializer=kaggle__evaluation__pb2.KaggleEvaluationRequest.SerializeToString,
|
20 |
+
response_deserializer=kaggle__evaluation__pb2.KaggleEvaluationResponse.FromString,
|
21 |
+
)
|
22 |
+
|
23 |
+
|
24 |
+
class KaggleEvaluationServiceServicer(object):
|
25 |
+
"""Missing associated documentation comment in .proto file."""
|
26 |
+
|
27 |
+
def Send(self, request, context):
|
28 |
+
"""Missing associated documentation comment in .proto file."""
|
29 |
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
30 |
+
context.set_details('Method not implemented!')
|
31 |
+
raise NotImplementedError('Method not implemented!')
|
32 |
+
|
33 |
+
|
34 |
+
def add_KaggleEvaluationServiceServicer_to_server(servicer, server):
|
35 |
+
rpc_method_handlers = {
|
36 |
+
'Send': grpc.unary_unary_rpc_method_handler(
|
37 |
+
servicer.Send,
|
38 |
+
request_deserializer=kaggle__evaluation__pb2.KaggleEvaluationRequest.FromString,
|
39 |
+
response_serializer=kaggle__evaluation__pb2.KaggleEvaluationResponse.SerializeToString,
|
40 |
+
),
|
41 |
+
}
|
42 |
+
generic_handler = grpc.method_handlers_generic_handler(
|
43 |
+
'kaggle_evaluation_client.KaggleEvaluationService', rpc_method_handlers)
|
44 |
+
server.add_generic_rpc_handlers((generic_handler,))
|
45 |
+
|
46 |
+
|
47 |
+
# This class is part of an EXPERIMENTAL API.
|
48 |
+
class KaggleEvaluationService(object):
|
49 |
+
"""Missing associated documentation comment in .proto file."""
|
50 |
+
|
51 |
+
@staticmethod
|
52 |
+
def Send(request,
|
53 |
+
target,
|
54 |
+
options=(),
|
55 |
+
channel_credentials=None,
|
56 |
+
call_credentials=None,
|
57 |
+
insecure=False,
|
58 |
+
compression=None,
|
59 |
+
wait_for_ready=None,
|
60 |
+
timeout=None,
|
61 |
+
metadata=None):
|
62 |
+
return grpc.experimental.unary_unary(request, target, '/kaggle_evaluation_client.KaggleEvaluationService/Send',
|
63 |
+
kaggle__evaluation__pb2.KaggleEvaluationRequest.SerializeToString,
|
64 |
+
kaggle__evaluation__pb2.KaggleEvaluationResponse.FromString,
|
65 |
+
options, channel_credentials,
|
66 |
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
kaggle_evaluation/core/kaggle_evaluation.proto
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Defines the proto service for KaggleEvaluation communication, aiming to provide native
|
2 |
+
// support for passing a variety of python primitives + common data science
|
3 |
+
// objects, and nested objects thereof.
|
4 |
+
|
5 |
+
syntax = "proto3";
|
6 |
+
|
7 |
+
package kaggle_evaluation_client;
|
8 |
+
|
9 |
+
service KaggleEvaluationService {
|
10 |
+
rpc Send(KaggleEvaluationRequest) returns (KaggleEvaluationResponse) {};
|
11 |
+
}
|
12 |
+
|
13 |
+
message KaggleEvaluationRequest {
|
14 |
+
string name = 1;
|
15 |
+
// Support generic python method calls using standard args / kwargs format.
|
16 |
+
repeated Payload args = 2;
|
17 |
+
map<string, Payload> kwargs = 3;
|
18 |
+
}
|
19 |
+
|
20 |
+
message KaggleEvaluationResponse {
|
21 |
+
Payload payload = 1;
|
22 |
+
}
|
23 |
+
|
24 |
+
// Core object representing a python value.
|
25 |
+
message Payload {
|
26 |
+
oneof value {
|
27 |
+
// Primitives
|
28 |
+
string str_value = 1;
|
29 |
+
bool bool_value = 2;
|
30 |
+
sint64 int_value = 3;
|
31 |
+
float float_value = 4;
|
32 |
+
// Value is ignored, being set at all means `None`
|
33 |
+
bool none_value = 5;
|
34 |
+
|
35 |
+
// Iterables for nested types
|
36 |
+
PayloadList list_value = 6;
|
37 |
+
PayloadList tuple_value = 7;
|
38 |
+
// Only supports dict with keys of type str and values that are serializable
|
39 |
+
// to Payload as well.
|
40 |
+
PayloadMap dict_value = 8;
|
41 |
+
|
42 |
+
// Allowlisted special types
|
43 |
+
// pandas.DataFrame
|
44 |
+
bytes pandas_dataframe_value = 9;
|
45 |
+
// polars.DataFrame
|
46 |
+
bytes polars_dataframe_value = 10;
|
47 |
+
// pandas.Series
|
48 |
+
bytes pandas_series_value = 11;
|
49 |
+
// polars.Series
|
50 |
+
bytes polars_series_value = 12;
|
51 |
+
// numpy.ndarray
|
52 |
+
bytes numpy_array_value = 13;
|
53 |
+
// numpy.scalar. Distinct from numpy.ndarray to avoid issues with dimensionless numpy arrays
|
54 |
+
bytes numpy_scalar_value = 14;
|
55 |
+
// io.BytesIO
|
56 |
+
bytes bytes_io_value = 15;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
message PayloadList {
|
61 |
+
repeated Payload payloads = 1;
|
62 |
+
}
|
63 |
+
|
64 |
+
message PayloadMap {
|
65 |
+
map<string, Payload> payload_map = 1;
|
66 |
+
}
|
kaggle_evaluation/core/relay.py
ADDED
@@ -0,0 +1,343 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
Core implementation of the client module, implementing generic communication
|
3 |
+
patterns with Python in / Python out supporting many (nested) primitives +
|
4 |
+
special data science types like DataFrames or np.ndarrays, with gRPC + protobuf
|
5 |
+
as a backing implementation.
|
6 |
+
'''
|
7 |
+
|
8 |
+
import grpc
|
9 |
+
import io
|
10 |
+
import json
|
11 |
+
import socket
|
12 |
+
import time
|
13 |
+
|
14 |
+
from concurrent import futures
|
15 |
+
from typing import Callable, List, Tuple
|
16 |
+
|
17 |
+
import numpy as np
|
18 |
+
import pandas as pd
|
19 |
+
import polars as pl
|
20 |
+
import pyarrow
|
21 |
+
|
22 |
+
import kaggle_evaluation.core.generated.kaggle_evaluation_pb2 as kaggle_evaluation_proto
|
23 |
+
import kaggle_evaluation.core.generated.kaggle_evaluation_pb2_grpc as kaggle_evaluation_grpc
|
24 |
+
|
25 |
+
|
26 |
+
_SERVICE_CONFIG = {
|
27 |
+
# Service config proto: https://github.com/grpc/grpc-proto/blob/ec886024c2f7b7f597ba89d5b7d60c3f94627b17/grpc/service_config/service_config.proto#L377
|
28 |
+
'methodConfig': [
|
29 |
+
{
|
30 |
+
'name': [{}], # Applies to all methods
|
31 |
+
# See retry policy docs: https://grpc.io/docs/guides/retry/
|
32 |
+
'retryPolicy': {
|
33 |
+
'maxAttempts': 5,
|
34 |
+
'initialBackoff': '0.1s',
|
35 |
+
'maxBackoff': '1s',
|
36 |
+
'backoffMultiplier': 1, # Ensure relatively rapid feedback in the event of a crash
|
37 |
+
'retryableStatusCodes': ['UNAVAILABLE'],
|
38 |
+
},
|
39 |
+
}
|
40 |
+
]
|
41 |
+
}
|
42 |
+
_GRPC_PORT = 50051
|
43 |
+
_GRPC_CHANNEL_OPTIONS = [
|
44 |
+
# -1 for unlimited message send/receive size
|
45 |
+
# https://github.com/grpc/grpc/blob/v1.64.x/include/grpc/impl/channel_arg_names.h#L39
|
46 |
+
('grpc.max_send_message_length', -1),
|
47 |
+
('grpc.max_receive_message_length', -1),
|
48 |
+
# https://github.com/grpc/grpc/blob/master/doc/keepalive.md
|
49 |
+
('grpc.keepalive_time_ms', 60_000), # Time between heartbeat pings
|
50 |
+
('grpc.keepalive_timeout_ms', 5_000), # Time allowed to respond to pings
|
51 |
+
('grpc.http2.max_pings_without_data', 0), # Remove another cap on pings
|
52 |
+
('grpc.keepalive_permit_without_calls', 1), # Allow heartbeat pings at any time
|
53 |
+
('grpc.http2.min_ping_interval_without_data_ms', 1_000),
|
54 |
+
('grpc.service_config', json.dumps(_SERVICE_CONFIG)),
|
55 |
+
]
|
56 |
+
|
57 |
+
|
58 |
+
DEFAULT_DEADLINE_SECONDS = 60 * 60
|
59 |
+
_RETRY_SLEEP_SECONDS = 1
|
60 |
+
# Enforce a relatively strict server startup time so users can get feedback quickly if they're not
|
61 |
+
# configuring KaggleEvaluation correctly. We really don't want notebooks timing out after nine hours
|
62 |
+
# somebody forgot to start their inference_server. Slow steps like loading models
|
63 |
+
# can happen during the first inference call if necessary.
|
64 |
+
STARTUP_LIMIT_SECONDS = 60 * 15
|
65 |
+
|
66 |
+
### Utils shared by client and server for data transfer
|
67 |
+
|
68 |
+
# pl.Enum is currently unstable, but we should eventually consider supporting it.
|
69 |
+
# https://docs.pola.rs/api/python/stable/reference/api/polars.datatypes.Enum.html#polars.datatypes.Enum
|
70 |
+
_POLARS_TYPE_DENYLIST = set([pl.Enum, pl.Object, pl.Unknown])
|
71 |
+
|
72 |
+
def _serialize(data) -> kaggle_evaluation_proto.Payload:
|
73 |
+
'''Maps input data of one of several allow-listed types to a protobuf message to be sent over gRPC.
|
74 |
+
|
75 |
+
Args:
|
76 |
+
data: The input data to be mapped. Any of the types listed below are accepted.
|
77 |
+
|
78 |
+
Returns:
|
79 |
+
The Payload protobuf message.
|
80 |
+
|
81 |
+
Raises:
|
82 |
+
TypeError if data is of an unsupported type.
|
83 |
+
'''
|
84 |
+
# Python primitives and Numpy scalars
|
85 |
+
if isinstance(data, np.generic):
|
86 |
+
# Numpy functions that return a single number return numpy scalars instead of python primitives.
|
87 |
+
# In some cases this difference matters: https://numpy.org/devdocs/release/2.0.0-notes.html#representation-of-numpy-scalars-changed
|
88 |
+
# Ex: np.mean(1,2) yields np.float64(1.5) instead of 1.5.
|
89 |
+
# Check for numpy scalars first since most of them also inherit from python primitives.
|
90 |
+
# For example, `np.float64(1.5)` is an instance of `float` among many other things.
|
91 |
+
# https://numpy.org/doc/stable/reference/arrays.scalars.html
|
92 |
+
assert data.shape == () # Additional validation that the np.generic type remains solely for scalars
|
93 |
+
assert isinstance(data, np.number) or isinstance(data, np.bool_) # No support for bytes, strings, objects, etc
|
94 |
+
buffer = io.BytesIO()
|
95 |
+
np.save(buffer, data, allow_pickle=False)
|
96 |
+
return kaggle_evaluation_proto.Payload(numpy_scalar_value=buffer.getvalue())
|
97 |
+
elif isinstance(data, str):
|
98 |
+
return kaggle_evaluation_proto.Payload(str_value=data)
|
99 |
+
elif isinstance(data, bool): # bool is a subclass of int, so check that first
|
100 |
+
return kaggle_evaluation_proto.Payload(bool_value=data)
|
101 |
+
elif isinstance(data, int):
|
102 |
+
return kaggle_evaluation_proto.Payload(int_value=data)
|
103 |
+
elif isinstance(data, float):
|
104 |
+
return kaggle_evaluation_proto.Payload(float_value=data)
|
105 |
+
elif data is None:
|
106 |
+
return kaggle_evaluation_proto.Payload(none_value=True)
|
107 |
+
# Iterables for nested types
|
108 |
+
if isinstance(data, list):
|
109 |
+
return kaggle_evaluation_proto.Payload(list_value=kaggle_evaluation_proto.PayloadList(payloads=map(_serialize, data)))
|
110 |
+
elif isinstance(data, tuple):
|
111 |
+
return kaggle_evaluation_proto.Payload(tuple_value=kaggle_evaluation_proto.PayloadList(payloads=map(_serialize, data)))
|
112 |
+
elif isinstance(data, dict):
|
113 |
+
serialized_dict = {}
|
114 |
+
for key, value in data.items():
|
115 |
+
if not isinstance(key, str):
|
116 |
+
raise TypeError(f'KaggleEvaluation only supports dicts with keys of type str, found {type(key)}.')
|
117 |
+
serialized_dict[key] = _serialize(value)
|
118 |
+
return kaggle_evaluation_proto.Payload(dict_value=kaggle_evaluation_proto.PayloadMap(payload_map=serialized_dict))
|
119 |
+
# Allowlisted special types
|
120 |
+
if isinstance(data, pd.DataFrame):
|
121 |
+
buffer = io.BytesIO()
|
122 |
+
data.to_parquet(buffer, index=False, compression='lz4')
|
123 |
+
return kaggle_evaluation_proto.Payload(pandas_dataframe_value=buffer.getvalue())
|
124 |
+
elif isinstance(data, pl.DataFrame):
|
125 |
+
data_types = set(i.base_type() for i in data.dtypes)
|
126 |
+
banned_types = _POLARS_TYPE_DENYLIST.intersection(data_types)
|
127 |
+
if len(banned_types) > 0:
|
128 |
+
raise TypeError(f'Unsupported Polars data type(s): {banned_types}')
|
129 |
+
|
130 |
+
table = data.to_arrow()
|
131 |
+
buffer = io.BytesIO()
|
132 |
+
with pyarrow.ipc.new_stream(buffer, table.schema, options=pyarrow.ipc.IpcWriteOptions(compression='lz4')) as writer:
|
133 |
+
writer.write_table(table)
|
134 |
+
return kaggle_evaluation_proto.Payload(polars_dataframe_value=buffer.getvalue())
|
135 |
+
elif isinstance(data, pd.Series):
|
136 |
+
buffer = io.BytesIO()
|
137 |
+
# Can't serialize a pd.Series directly to parquet, must use intermediate DataFrame
|
138 |
+
pd.DataFrame(data).to_parquet(buffer, index=False, compression='lz4')
|
139 |
+
return kaggle_evaluation_proto.Payload(pandas_series_value=buffer.getvalue())
|
140 |
+
elif isinstance(data, pl.Series):
|
141 |
+
buffer = io.BytesIO()
|
142 |
+
# Can't serialize a pl.Series directly to parquet, must use intermediate DataFrame
|
143 |
+
pl.DataFrame(data).write_parquet(buffer, compression='lz4', statistics=False)
|
144 |
+
return kaggle_evaluation_proto.Payload(polars_series_value=buffer.getvalue())
|
145 |
+
elif isinstance(data, np.ndarray):
|
146 |
+
buffer = io.BytesIO()
|
147 |
+
np.save(buffer, data, allow_pickle=False)
|
148 |
+
return kaggle_evaluation_proto.Payload(numpy_array_value=buffer.getvalue())
|
149 |
+
elif isinstance(data, io.BytesIO):
|
150 |
+
return kaggle_evaluation_proto.Payload(bytes_io_value=data.getvalue())
|
151 |
+
|
152 |
+
raise TypeError(f'Type {type(data)} not supported for KaggleEvaluation.')
|
153 |
+
|
154 |
+
|
155 |
+
def _deserialize(payload: kaggle_evaluation_proto.Payload):
|
156 |
+
'''Maps a Payload protobuf message to a value of whichever type was set on the message.
|
157 |
+
|
158 |
+
Args:
|
159 |
+
payload: The message to be mapped.
|
160 |
+
|
161 |
+
Returns:
|
162 |
+
A value of one of several allow-listed types.
|
163 |
+
|
164 |
+
Raises:
|
165 |
+
TypeError if an unexpected value data type is found.
|
166 |
+
'''
|
167 |
+
# Primitives
|
168 |
+
if payload.WhichOneof('value') == 'str_value':
|
169 |
+
return payload.str_value
|
170 |
+
elif payload.WhichOneof('value') == 'bool_value':
|
171 |
+
return payload.bool_value
|
172 |
+
elif payload.WhichOneof('value') == 'int_value':
|
173 |
+
return payload.int_value
|
174 |
+
elif payload.WhichOneof('value') == 'float_value':
|
175 |
+
return payload.float_value
|
176 |
+
elif payload.WhichOneof('value') == 'none_value':
|
177 |
+
return None
|
178 |
+
# Iterables for nested types
|
179 |
+
elif payload.WhichOneof('value') == 'list_value':
|
180 |
+
return list(map(_deserialize, payload.list_value.payloads))
|
181 |
+
elif payload.WhichOneof('value') == 'tuple_value':
|
182 |
+
return tuple(map(_deserialize, payload.tuple_value.payloads))
|
183 |
+
elif payload.WhichOneof('value') == 'dict_value':
|
184 |
+
return {key: _deserialize(value) for key, value in payload.dict_value.payload_map.items()}
|
185 |
+
# Allowlisted special types
|
186 |
+
elif payload.WhichOneof('value') == 'pandas_dataframe_value':
|
187 |
+
return pd.read_parquet(io.BytesIO(payload.pandas_dataframe_value))
|
188 |
+
elif payload.WhichOneof('value') == 'polars_dataframe_value':
|
189 |
+
with pyarrow.ipc.open_stream(payload.polars_dataframe_value) as reader:
|
190 |
+
table = reader.read_all()
|
191 |
+
return pl.from_arrow(table)
|
192 |
+
elif payload.WhichOneof('value') == 'pandas_series_value':
|
193 |
+
# Pandas will still read a single column csv as a DataFrame.
|
194 |
+
df = pd.read_parquet(io.BytesIO(payload.pandas_series_value))
|
195 |
+
return pd.Series(df[df.columns[0]])
|
196 |
+
elif payload.WhichOneof('value') == 'polars_series_value':
|
197 |
+
return pl.Series(pl.read_parquet(io.BytesIO(payload.polars_series_value)))
|
198 |
+
elif payload.WhichOneof('value') == 'numpy_array_value':
|
199 |
+
return np.load(io.BytesIO(payload.numpy_array_value), allow_pickle=False)
|
200 |
+
elif payload.WhichOneof('value') == 'numpy_scalar_value':
|
201 |
+
data = np.load(io.BytesIO(payload.numpy_scalar_value), allow_pickle=False)
|
202 |
+
# As of Numpy 2.0.2, np.load for a numpy scalar yields a dimensionless array instead of a scalar
|
203 |
+
data = data.dtype.type(data) # Restore the expected numpy scalar type.
|
204 |
+
assert data.shape == () # Additional validation that the np.generic type remains solely for scalars
|
205 |
+
assert isinstance(data, np.number) or isinstance(data, np.bool_) # No support for bytes, strings, objects, etc
|
206 |
+
return data
|
207 |
+
elif payload.WhichOneof('value') == 'bytes_io_value':
|
208 |
+
return io.BytesIO(payload.bytes_io_value)
|
209 |
+
|
210 |
+
raise TypeError(f'Found unknown Payload case {payload.WhichOneof("value")}')
|
211 |
+
|
212 |
+
### Client code
|
213 |
+
|
214 |
+
class Client():
|
215 |
+
'''
|
216 |
+
Class which allows callers to make KaggleEvaluation requests.
|
217 |
+
'''
|
218 |
+
def __init__(self, channel_address: str='localhost'):
|
219 |
+
self.channel_address = channel_address
|
220 |
+
self.channel = grpc.insecure_channel(f'{channel_address}:{_GRPC_PORT}', options=_GRPC_CHANNEL_OPTIONS)
|
221 |
+
self._made_first_connection = False
|
222 |
+
self.endpoint_deadline_seconds = DEFAULT_DEADLINE_SECONDS
|
223 |
+
self.stub = kaggle_evaluation_grpc.KaggleEvaluationServiceStub(self.channel)
|
224 |
+
|
225 |
+
def _send_with_deadline(self, request):
|
226 |
+
''' Sends a message to the server while also:
|
227 |
+
- Throwing an error as soon as the inference_server container has been shut down.
|
228 |
+
- Setting a deadline of STARTUP_LIMIT_SECONDS for the inference_server to startup.
|
229 |
+
'''
|
230 |
+
if self._made_first_connection:
|
231 |
+
return self.stub.Send(request, wait_for_ready=False, timeout=self.endpoint_deadline_seconds)
|
232 |
+
|
233 |
+
first_call_time = time.time()
|
234 |
+
# Allow time for the server to start as long as its container is running
|
235 |
+
while time.time() - first_call_time < STARTUP_LIMIT_SECONDS:
|
236 |
+
try:
|
237 |
+
response = self.stub.Send(request, wait_for_ready=False)
|
238 |
+
self._made_first_connection = True
|
239 |
+
break
|
240 |
+
except grpc._channel._InactiveRpcError as err:
|
241 |
+
if 'StatusCode.UNAVAILABLE' not in str(err):
|
242 |
+
raise err
|
243 |
+
# Confirm the inference_server container is still alive & it's worth waiting on the server.
|
244 |
+
# If the inference_server container is no longer running this will throw a socket.gaierror.
|
245 |
+
socket.gethostbyname(self.channel_address)
|
246 |
+
time.sleep(_RETRY_SLEEP_SECONDS)
|
247 |
+
|
248 |
+
if not self._made_first_connection:
|
249 |
+
raise RuntimeError(f'Failed to connect to server after waiting {STARTUP_LIMIT_SECONDS} seconds')
|
250 |
+
return response
|
251 |
+
|
252 |
+
def serialize_request(self, name: str, *args, **kwargs) -> kaggle_evaluation_proto.KaggleEvaluationRequest:
|
253 |
+
''' Serialize a single request. Exists as a separate function from `send`
|
254 |
+
to enable gateway concurrency for some competitions.
|
255 |
+
'''
|
256 |
+
already_serialized = (len(args) == 1) and isinstance(args[0], kaggle_evaluation_proto.KaggleEvaluationRequest)
|
257 |
+
if already_serialized:
|
258 |
+
return args[0] # args is a tuple of length 1 containing the request
|
259 |
+
return kaggle_evaluation_proto.KaggleEvaluationRequest(
|
260 |
+
name=name,
|
261 |
+
args=map(_serialize, args),
|
262 |
+
kwargs={key: _serialize(value) for key, value in kwargs.items()}
|
263 |
+
)
|
264 |
+
|
265 |
+
def send(self, name: str, *args, **kwargs):
|
266 |
+
'''Sends a single KaggleEvaluation request.
|
267 |
+
|
268 |
+
Args:
|
269 |
+
name: The endpoint name for the request.
|
270 |
+
*args: Variable-length/type arguments to be supplied on the request.
|
271 |
+
**kwargs: Key-value arguments to be supplied on the request.
|
272 |
+
|
273 |
+
Returns:
|
274 |
+
The response, which is of one of several allow-listed data types.
|
275 |
+
'''
|
276 |
+
request = self.serialize_request(name, *args, **kwargs)
|
277 |
+
response = self._send_with_deadline(request)
|
278 |
+
return _deserialize(response.payload)
|
279 |
+
|
280 |
+
def close(self):
|
281 |
+
self.channel.close()
|
282 |
+
|
283 |
+
|
284 |
+
### Server code
|
285 |
+
|
286 |
+
class KaggleEvaluationServiceServicer(kaggle_evaluation_grpc.KaggleEvaluationServiceServicer):
|
287 |
+
'''
|
288 |
+
Class which allows serving responses to KaggleEvaluation requests. The inference_server will run this service to listen for and respond
|
289 |
+
to requests from the Gateway. The Gateway may also listen for requests from the inference_server in some cases.
|
290 |
+
'''
|
291 |
+
def __init__(self, listeners: List[callable]):
|
292 |
+
self.listeners_map = dict((func.__name__, func) for func in listeners)
|
293 |
+
|
294 |
+
# pylint: disable=unused-argument
|
295 |
+
def Send(self, request: kaggle_evaluation_proto.KaggleEvaluationRequest, context: grpc.ServicerContext) -> kaggle_evaluation_proto.KaggleEvaluationResponse:
|
296 |
+
'''Handler for gRPC requests that deserializes arguments, calls a user-registered function for handling the
|
297 |
+
requested endpoint, then serializes and returns the response.
|
298 |
+
|
299 |
+
Args:
|
300 |
+
request: The KaggleEvaluationRequest protobuf message.
|
301 |
+
context: (Unused) gRPC context.
|
302 |
+
|
303 |
+
Returns:
|
304 |
+
The KaggleEvaluationResponse protobuf message.
|
305 |
+
|
306 |
+
Raises:
|
307 |
+
NotImplementedError if the caller has not registered a handler for the requested endpoint.
|
308 |
+
'''
|
309 |
+
if request.name not in self.listeners_map:
|
310 |
+
raise NotImplementedError(f'No listener for {request.name} was registered.')
|
311 |
+
|
312 |
+
args = map(_deserialize, request.args)
|
313 |
+
kwargs = {key: _deserialize(value) for key, value in request.kwargs.items()}
|
314 |
+
response_function = self.listeners_map[request.name]
|
315 |
+
response_payload = _serialize(response_function(*args, **kwargs))
|
316 |
+
return kaggle_evaluation_proto.KaggleEvaluationResponse(payload=response_payload)
|
317 |
+
|
318 |
+
def define_server(*endpoint_listeners: Tuple[Callable]) -> grpc.server:
|
319 |
+
'''Registers the endpoints that the container is able to respond to, then starts a server which listens for
|
320 |
+
those endpoints. The endpoints that need to be implemented will depend on the specific competition.
|
321 |
+
|
322 |
+
Args:
|
323 |
+
endpoint_listeners: Tuple of functions that define how requests to the endpoint of the function name should be
|
324 |
+
handled.
|
325 |
+
|
326 |
+
Returns:
|
327 |
+
The gRPC server object, which has been started. It should be stopped at exit time.
|
328 |
+
|
329 |
+
Raises:
|
330 |
+
ValueError if parameter values are invalid.
|
331 |
+
'''
|
332 |
+
if not endpoint_listeners:
|
333 |
+
raise ValueError('Must pass at least one endpoint listener, e.g. `predict`')
|
334 |
+
for func in endpoint_listeners:
|
335 |
+
if not isinstance(func, Callable):
|
336 |
+
raise ValueError('Endpoint listeners passed to `serve` must be functions')
|
337 |
+
if func.__name__ == '<lambda>':
|
338 |
+
raise ValueError('Functions passed as endpoint listeners must be named')
|
339 |
+
|
340 |
+
server = grpc.server(futures.ThreadPoolExecutor(max_workers=1), options=_GRPC_CHANNEL_OPTIONS)
|
341 |
+
kaggle_evaluation_grpc.add_KaggleEvaluationServiceServicer_to_server(KaggleEvaluationServiceServicer(endpoint_listeners), server)
|
342 |
+
server.add_insecure_port(f'[::]:{_GRPC_PORT}')
|
343 |
+
return server
|
kaggle_evaluation/core/templates.py
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''Template for the two classes hosts should customize for each competition.'''
|
2 |
+
|
3 |
+
import abc
|
4 |
+
import os
|
5 |
+
import pathlib
|
6 |
+
import polars as pl
|
7 |
+
import time
|
8 |
+
import sys
|
9 |
+
import traceback
|
10 |
+
import warnings
|
11 |
+
|
12 |
+
from typing import Callable, Generator, Tuple
|
13 |
+
|
14 |
+
import kaggle_evaluation.core.base_gateway
|
15 |
+
import kaggle_evaluation.core.relay
|
16 |
+
|
17 |
+
|
18 |
+
_initial_import_time = time.time()
|
19 |
+
_issued_startup_time_warning = False
|
20 |
+
|
21 |
+
|
22 |
+
class Gateway(kaggle_evaluation.core.base_gateway.BaseGateway, abc.ABC):
|
23 |
+
'''
|
24 |
+
Template to start with when writing a new gateway.
|
25 |
+
In most cases, hosts should only need to write get_all_predictions.
|
26 |
+
There are two main methods for sending data to the inference_server hosts should understand:
|
27 |
+
- Small datasets: use `self.predict`. Competitors will receive the data passed to self.predict as
|
28 |
+
Python objects in memory. This is just a wrapper for self.client.send(); you can write additional
|
29 |
+
wrappers if necessary.
|
30 |
+
- Large datasets: it's much faster to send data via self.share_files, which is equivalent to making
|
31 |
+
files available via symlink. See base_gateway.BaseGateway.share_files for the full details.
|
32 |
+
'''
|
33 |
+
|
34 |
+
@abc.abstractmethod
|
35 |
+
def generate_data_batches(self) -> Generator:
|
36 |
+
''' Used by the default implementation of `get_all_predictions` so we can
|
37 |
+
ensure `validate_prediction_batch` is run every time `predict` is called.
|
38 |
+
|
39 |
+
This method must yield both the batch of data to be sent to `predict` and a series
|
40 |
+
of row IDs to be sent to `validate_prediction_batch`.
|
41 |
+
'''
|
42 |
+
raise NotImplementedError
|
43 |
+
|
44 |
+
def get_all_predictions(self):
|
45 |
+
all_predictions = []
|
46 |
+
all_row_ids = []
|
47 |
+
for data_batch, row_ids in self.generate_data_batches():
|
48 |
+
predictions = self.predict(*data_batch)
|
49 |
+
predictions = pl.Series(self.target_column_name, predictions)
|
50 |
+
self.validate_prediction_batch(predictions, row_ids)
|
51 |
+
all_predictions.append(predictions)
|
52 |
+
all_row_ids.append(row_ids)
|
53 |
+
return all_predictions, all_row_ids
|
54 |
+
|
55 |
+
def predict(self, *args, **kwargs):
|
56 |
+
''' self.predict will send all data in args and kwargs to the user container, and
|
57 |
+
instruct the user container to generate a `predict` response.
|
58 |
+
'''
|
59 |
+
try:
|
60 |
+
return self.client.send('predict', *args, **kwargs)
|
61 |
+
except Exception as e:
|
62 |
+
self.handle_server_error(e, 'predict')
|
63 |
+
|
64 |
+
def set_response_timeout_seconds(self, timeout_seconds: float):
|
65 |
+
# Also store timeout_seconds in an easy place for for competitor to access.
|
66 |
+
self.timeout_seconds = timeout_seconds
|
67 |
+
# Set a response deadline that will apply after the very first repsonse
|
68 |
+
self.client.endpoint_deadline_seconds = timeout_seconds
|
69 |
+
|
70 |
+
def run(self) -> pathlib.Path:
|
71 |
+
error = None
|
72 |
+
submission_path = None
|
73 |
+
try:
|
74 |
+
predictions, row_ids = self.get_all_predictions()
|
75 |
+
submission_path = self.write_submission(predictions, row_ids)
|
76 |
+
except kaggle_evaluation.core.base_gateway.GatewayRuntimeError as gre:
|
77 |
+
error = gre
|
78 |
+
except Exception:
|
79 |
+
# Get the full stack trace
|
80 |
+
exc_type, exc_value, exc_traceback = sys.exc_info()
|
81 |
+
error_str = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
|
82 |
+
|
83 |
+
error = kaggle_evaluation.core.base_gateway.GatewayRuntimeError(
|
84 |
+
kaggle_evaluation.core.base_gateway.GatewayRuntimeErrorType.GATEWAY_RAISED_EXCEPTION,
|
85 |
+
error_str
|
86 |
+
)
|
87 |
+
|
88 |
+
self.client.close()
|
89 |
+
if self.server:
|
90 |
+
self.server.stop(0)
|
91 |
+
|
92 |
+
if kaggle_evaluation.core.base_gateway.IS_RERUN:
|
93 |
+
self.write_result(error)
|
94 |
+
elif error:
|
95 |
+
# For local testing
|
96 |
+
raise error
|
97 |
+
|
98 |
+
return submission_path
|
99 |
+
|
100 |
+
|
101 |
+
class InferenceServer(abc.ABC):
|
102 |
+
'''
|
103 |
+
Base class for competition participants to inherit from when writing their submission. In most cases, users should
|
104 |
+
only need to implement a `predict` function or other endpoints to pass to this class's constructor, and hosts will
|
105 |
+
provide a mock Gateway for testing.
|
106 |
+
'''
|
107 |
+
def __init__(self, endpoint_listeners: Tuple[Callable]):
|
108 |
+
self.server = kaggle_evaluation.core.relay.define_server(endpoint_listeners)
|
109 |
+
self.client = None # The inference_server can have a client but it isn't typically necessary.
|
110 |
+
|
111 |
+
def serve(self):
|
112 |
+
self.server.start()
|
113 |
+
if os.getenv('KAGGLE_IS_COMPETITION_RERUN') is not None:
|
114 |
+
self.server.wait_for_termination() # This will block all other code
|
kaggle_evaluation/svg.py
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import inspect
|
2 |
+
import pathlib
|
3 |
+
from types import ModuleType
|
4 |
+
|
5 |
+
from kaggle_evaluation.core import relay, templates
|
6 |
+
from kaggle_evaluation.svg_gateway import SVGGateway
|
7 |
+
|
8 |
+
|
9 |
+
def test(model_cls: type, data_path: str | pathlib.Path | None = None) -> None:
|
10 |
+
'''Tests this competition's inference loop over the given Model class.
|
11 |
+
|
12 |
+
The provided Model class should have a `predict` function which accepts input(s)
|
13 |
+
and returns output(s) with the shapes and types required by this competition.
|
14 |
+
This function performs best-effort validation of this by running an inference
|
15 |
+
loop with a dummy test set over Model.predict.
|
16 |
+
By default the test set is taken from the `kaggle_evaluation` directory, but you
|
17 |
+
may override to another directory with the same test file structure via the
|
18 |
+
`data_path` arg.'''
|
19 |
+
print('Creating Model instance...')
|
20 |
+
model = model_cls()
|
21 |
+
if not hasattr(model, 'predict') or not inspect.ismethod(model.predict):
|
22 |
+
msg = f'Model does not have method predict.'
|
23 |
+
raise ValueError(msg)
|
24 |
+
|
25 |
+
print('Running inference tests...')
|
26 |
+
server = relay.define_server(model.predict)
|
27 |
+
server.start()
|
28 |
+
try:
|
29 |
+
gateway = SVGGateway(data_path)
|
30 |
+
submission_path = gateway.run()
|
31 |
+
print(f'Wrote test submission file to "{str(submission_path)}".')
|
32 |
+
except Exception as err:
|
33 |
+
raise err from None
|
34 |
+
finally:
|
35 |
+
server.stop(0)
|
36 |
+
|
37 |
+
print('Success!')
|
38 |
+
|
39 |
+
|
40 |
+
def _run_gateway() -> None:
|
41 |
+
'''Internal function for running the Gateway during a Kaggle scoring session.
|
42 |
+
|
43 |
+
Starts a scoring session which assumes existence of an Inference Server to return
|
44 |
+
inferences over the test set.'''
|
45 |
+
gateway = SVGGateway()
|
46 |
+
gateway.run()
|
47 |
+
|
48 |
+
|
49 |
+
def _run_inference_server(module: ModuleType) -> None:
|
50 |
+
'''Internal function for running the Inference Server during a Kaggle scoring session.
|
51 |
+
|
52 |
+
Takes the user's submitted, imported module and sets up the inference server exposing
|
53 |
+
their required method(s).'''
|
54 |
+
model = module.Model()
|
55 |
+
server = templates.InferenceServer(model.predict)
|
56 |
+
server.serve()
|
kaggle_evaluation/svg_constraints.py
ADDED
@@ -0,0 +1,311 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from dataclasses import dataclass, field
|
2 |
+
|
3 |
+
from defusedxml import ElementTree as etree
|
4 |
+
|
5 |
+
|
6 |
+
@dataclass(frozen=True)
|
7 |
+
class SVGConstraints:
|
8 |
+
"""Defines constraints for validating SVG documents.
|
9 |
+
|
10 |
+
Attributes
|
11 |
+
----------
|
12 |
+
max_svg_size : int, default=10000
|
13 |
+
Maximum allowed size of an SVG file in bytes.
|
14 |
+
allowed_elements : dict[str, set[str]]
|
15 |
+
Mapping of the allowed elements to the allowed attributes of each element.
|
16 |
+
"""
|
17 |
+
|
18 |
+
max_svg_size: int = 10000
|
19 |
+
allowed_elements: dict[str, set[str]] = field(
|
20 |
+
default_factory=lambda: {
|
21 |
+
'common': {
|
22 |
+
'id',
|
23 |
+
'clip-path',
|
24 |
+
'clip-rule',
|
25 |
+
'color',
|
26 |
+
'color-interpolation',
|
27 |
+
'color-interpolation-filters',
|
28 |
+
'color-rendering',
|
29 |
+
'display',
|
30 |
+
'fill',
|
31 |
+
'fill-opacity',
|
32 |
+
'fill-rule',
|
33 |
+
'filter',
|
34 |
+
'flood-color',
|
35 |
+
'flood-opacity',
|
36 |
+
'lighting-color',
|
37 |
+
'marker-end',
|
38 |
+
'marker-mid',
|
39 |
+
'marker-start',
|
40 |
+
'mask',
|
41 |
+
'opacity',
|
42 |
+
'paint-order',
|
43 |
+
'stop-color',
|
44 |
+
'stop-opacity',
|
45 |
+
'stroke',
|
46 |
+
'stroke-dasharray',
|
47 |
+
'stroke-dashoffset',
|
48 |
+
'stroke-linecap',
|
49 |
+
'stroke-linejoin',
|
50 |
+
'stroke-miterlimit',
|
51 |
+
'stroke-opacity',
|
52 |
+
'stroke-width',
|
53 |
+
'transform',
|
54 |
+
},
|
55 |
+
'svg': {
|
56 |
+
'width',
|
57 |
+
'height',
|
58 |
+
'viewBox',
|
59 |
+
'preserveAspectRatio',
|
60 |
+
},
|
61 |
+
'g': {'viewBox'},
|
62 |
+
'defs': set(),
|
63 |
+
'symbol': {'viewBox', 'x', 'y', 'width', 'height'},
|
64 |
+
'use': {'x', 'y', 'width', 'height', 'href'},
|
65 |
+
'marker': {
|
66 |
+
'viewBox',
|
67 |
+
'preserveAspectRatio',
|
68 |
+
'refX',
|
69 |
+
'refY',
|
70 |
+
'markerUnits',
|
71 |
+
'markerWidth',
|
72 |
+
'markerHeight',
|
73 |
+
'orient',
|
74 |
+
},
|
75 |
+
'pattern': {
|
76 |
+
'viewBox',
|
77 |
+
'preserveAspectRatio',
|
78 |
+
'x',
|
79 |
+
'y',
|
80 |
+
'width',
|
81 |
+
'height',
|
82 |
+
'patternUnits',
|
83 |
+
'patternContentUnits',
|
84 |
+
'patternTransform',
|
85 |
+
'href',
|
86 |
+
},
|
87 |
+
'linearGradient': {
|
88 |
+
'x1',
|
89 |
+
'x2',
|
90 |
+
'y1',
|
91 |
+
'y2',
|
92 |
+
'gradientUnits',
|
93 |
+
'gradientTransform',
|
94 |
+
'spreadMethod',
|
95 |
+
'href',
|
96 |
+
},
|
97 |
+
'radialGradient': {
|
98 |
+
'cx',
|
99 |
+
'cy',
|
100 |
+
'r',
|
101 |
+
'fx',
|
102 |
+
'fy',
|
103 |
+
'fr',
|
104 |
+
'gradientUnits',
|
105 |
+
'gradientTransform',
|
106 |
+
'spreadMethod',
|
107 |
+
'href',
|
108 |
+
},
|
109 |
+
'stop': {'offset'},
|
110 |
+
'filter': {
|
111 |
+
'x',
|
112 |
+
'y',
|
113 |
+
'width',
|
114 |
+
'height',
|
115 |
+
'filterUnits',
|
116 |
+
'primitiveUnits',
|
117 |
+
},
|
118 |
+
'feBlend': {'result', 'in', 'in2', 'mode'},
|
119 |
+
'feColorMatrix': {'result', 'in', 'type', 'values'},
|
120 |
+
'feComposite': {
|
121 |
+
'result',
|
122 |
+
'style',
|
123 |
+
'in',
|
124 |
+
'in2',
|
125 |
+
'operator',
|
126 |
+
'k1',
|
127 |
+
'k2',
|
128 |
+
'k3',
|
129 |
+
'k4',
|
130 |
+
},
|
131 |
+
'feFlood': {'result'},
|
132 |
+
'feGaussianBlur': {
|
133 |
+
'result',
|
134 |
+
'in',
|
135 |
+
'stdDeviation',
|
136 |
+
'edgeMode',
|
137 |
+
},
|
138 |
+
'feMerge': {
|
139 |
+
'result',
|
140 |
+
'x',
|
141 |
+
'y',
|
142 |
+
'width',
|
143 |
+
'height',
|
144 |
+
'result',
|
145 |
+
},
|
146 |
+
'feMergeNode': {'result', 'in'},
|
147 |
+
'feOffset': {'result', 'in', 'dx', 'dy'},
|
148 |
+
'feTurbulence': {
|
149 |
+
'result',
|
150 |
+
'baseFrequency',
|
151 |
+
'numOctaves',
|
152 |
+
'seed',
|
153 |
+
'stitchTiles',
|
154 |
+
'type',
|
155 |
+
},
|
156 |
+
'path': {'d'},
|
157 |
+
'rect': {'x', 'y', 'width', 'height', 'rx', 'ry'},
|
158 |
+
'circle': {'cx', 'cy', 'r'},
|
159 |
+
'ellipse': {'cx', 'cy', 'rx', 'ry'},
|
160 |
+
'line': {'x1', 'y1', 'x2', 'y2'},
|
161 |
+
'polyline': {'points'},
|
162 |
+
'polygon': {'points'},
|
163 |
+
}
|
164 |
+
)
|
165 |
+
|
166 |
+
def validate_svg(self, svg_code: str) -> None:
|
167 |
+
"""Validates an SVG string against a set of predefined constraints.
|
168 |
+
|
169 |
+
Parameters
|
170 |
+
----------
|
171 |
+
svg_code : str
|
172 |
+
The SVG string to validate.
|
173 |
+
|
174 |
+
Raises
|
175 |
+
------
|
176 |
+
ValueError
|
177 |
+
If the SVG violates any of the defined constraints.
|
178 |
+
"""
|
179 |
+
# Check file size
|
180 |
+
if len(svg_code.encode('utf-8')) > self.max_svg_size:
|
181 |
+
raise ValueError('SVG exceeds allowed size')
|
182 |
+
|
183 |
+
# Parse XML
|
184 |
+
tree = etree.fromstring(
|
185 |
+
svg_code.encode('utf-8'),
|
186 |
+
forbid_dtd=True,
|
187 |
+
forbid_entities=True,
|
188 |
+
forbid_external=True,
|
189 |
+
)
|
190 |
+
|
191 |
+
elements = set(self.allowed_elements.keys())
|
192 |
+
|
193 |
+
# Check elements and attributes
|
194 |
+
for element in tree.iter():
|
195 |
+
# Check for disallowed elements
|
196 |
+
tag_name = element.tag.split('}')[-1]
|
197 |
+
if tag_name not in elements:
|
198 |
+
raise ValueError(f'Disallowed element: {tag_name}')
|
199 |
+
|
200 |
+
# Check attributes
|
201 |
+
for attr, attr_value in element.attrib.items():
|
202 |
+
# Check for disallowed attributes
|
203 |
+
attr_name = attr.split('}')[-1]
|
204 |
+
if (
|
205 |
+
attr_name not in self.allowed_elements[tag_name]
|
206 |
+
and attr_name not in self.allowed_elements['common']
|
207 |
+
):
|
208 |
+
raise ValueError(f'Disallowed attribute: {attr_name}')
|
209 |
+
|
210 |
+
# Check for embedded data
|
211 |
+
if 'data:' in attr_value.lower():
|
212 |
+
raise ValueError('Embedded data not allowed')
|
213 |
+
if ';base64' in attr_value:
|
214 |
+
raise ValueError('Base64 encoded content not allowed')
|
215 |
+
|
216 |
+
# Check that href attributes are internal references
|
217 |
+
if attr_name == 'href':
|
218 |
+
if not attr_value.startswith('#'):
|
219 |
+
raise ValueError(
|
220 |
+
f'Invalid href attribute in <{tag_name}>. Only internal references (starting with "#") are allowed. Found: "{attr_value}"'
|
221 |
+
)
|
222 |
+
|
223 |
+
|
224 |
+
if __name__ == '__main__':
|
225 |
+
svg_validator = SVGConstraints()
|
226 |
+
|
227 |
+
valid_svg = """
|
228 |
+
<svg width="100" height="100">
|
229 |
+
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
|
230 |
+
</svg>
|
231 |
+
"""
|
232 |
+
|
233 |
+
invalid_size_svg = '<svg>' + ' ' * 6000 + '</svg>' # Exceeds default 5000 bytes
|
234 |
+
|
235 |
+
invalid_element_svg = """
|
236 |
+
<svg>
|
237 |
+
<script>alert('bad');</script>
|
238 |
+
</svg>
|
239 |
+
"""
|
240 |
+
|
241 |
+
invalid_attribute_svg = """
|
242 |
+
<svg>
|
243 |
+
<rect width="100" height="100" onclick="alert('bad')"/>
|
244 |
+
</svg>
|
245 |
+
"""
|
246 |
+
|
247 |
+
invalid_href_svg = """
|
248 |
+
<svg>
|
249 |
+
<use href="http://example.com/image.svg" />
|
250 |
+
</svg>
|
251 |
+
"""
|
252 |
+
|
253 |
+
invalid_embedded_image_element_svg = """
|
254 |
+
<svg width="100" height="100">
|
255 |
+
<image href="data:image/png;base64,iVBOAAAANSUhEUgAAAAUAAAAFCAYAAACN==" width="50" height="50"/>
|
256 |
+
</svg>
|
257 |
+
"""
|
258 |
+
|
259 |
+
invalid_data_uri_attribute_svg = """
|
260 |
+
<svg width="100" height="100">
|
261 |
+
<rect width="50" height="50" fill="url(data:image/png;base64,iVBOAAAANSUhEUgAAAAUAAAAFCAYAAACN==)" />
|
262 |
+
</svg>
|
263 |
+
"""
|
264 |
+
|
265 |
+
print('Running SVG validation examples:')
|
266 |
+
|
267 |
+
print('\nValid SVG example:')
|
268 |
+
svg_validator.validate_svg(valid_svg)
|
269 |
+
print(' Validation successful!')
|
270 |
+
|
271 |
+
print('\nSVG exceeding size limit:')
|
272 |
+
try:
|
273 |
+
svg_validator.validate_svg(invalid_size_svg)
|
274 |
+
print(' Validation successful! (This should not happen)')
|
275 |
+
except ValueError as e:
|
276 |
+
print(f' Validation failed as expected with error: {e}')
|
277 |
+
|
278 |
+
print('\nSVG with disallowed element:')
|
279 |
+
try:
|
280 |
+
svg_validator.validate_svg(invalid_element_svg)
|
281 |
+
print(' Validation successful! (This should not happen)')
|
282 |
+
except ValueError as e:
|
283 |
+
print(f' Validation failed as expected with error: {e}')
|
284 |
+
|
285 |
+
print('\nSVG with disallowed attribute:')
|
286 |
+
try:
|
287 |
+
svg_validator.validate_svg(invalid_attribute_svg)
|
288 |
+
print(' Validation successful! (This should not happen)')
|
289 |
+
except ValueError as e:
|
290 |
+
print(f' Validation failed as expected with error: {e}')
|
291 |
+
|
292 |
+
print('\nSVG with invalid external href:')
|
293 |
+
try:
|
294 |
+
svg_validator.validate_svg(invalid_href_svg)
|
295 |
+
print(' Validation successful! (This should not happen)')
|
296 |
+
except ValueError as e:
|
297 |
+
print(f' Validation failed as expected with error: {e}')
|
298 |
+
|
299 |
+
print('\nSVG with disallowed <image> element:')
|
300 |
+
try:
|
301 |
+
svg_validator.validate_svg(invalid_embedded_image_element_svg)
|
302 |
+
print(' Validation successful! (This should not happen)')
|
303 |
+
except ValueError as e:
|
304 |
+
print(f' Validation failed as expected with error: {e}')
|
305 |
+
|
306 |
+
print('\nSVG with invalid data URI in attribute (fill):')
|
307 |
+
try:
|
308 |
+
svg_validator.validate_svg(invalid_data_uri_attribute_svg)
|
309 |
+
print(' Validation successful! (This should not happen)')
|
310 |
+
except ValueError as e:
|
311 |
+
print(f' Validation failed as expected with error: {e}')
|
kaggle_evaluation/svg_gateway.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Gateway notebook for SVG Image Generation"""
|
2 |
+
|
3 |
+
import os
|
4 |
+
import tempfile
|
5 |
+
from pathlib import Path
|
6 |
+
from typing import Any
|
7 |
+
|
8 |
+
import pandas as pd
|
9 |
+
import polars as pl
|
10 |
+
|
11 |
+
from kaggle_evaluation.core.base_gateway import GatewayRuntimeError, GatewayRuntimeErrorType, IS_RERUN
|
12 |
+
import kaggle_evaluation.core.templates
|
13 |
+
from kaggle_evaluation.svg_constraints import SVGConstraints
|
14 |
+
|
15 |
+
|
16 |
+
class SVGGateway(kaggle_evaluation.core.templates.Gateway):
|
17 |
+
def __init__(self, data_path: str | Path | None = None):
|
18 |
+
super().__init__(target_column_name='svg')
|
19 |
+
self.set_response_timeout_seconds(60 * 5)
|
20 |
+
self.row_id_column_name = 'id'
|
21 |
+
self.data_path: Path = Path(data_path) if data_path else Path(__file__).parent
|
22 |
+
self.constraints: SVGConstraints = SVGConstraints()
|
23 |
+
|
24 |
+
def generate_data_batches(self):
|
25 |
+
test = pl.read_csv(self.data_path / 'test.csv')
|
26 |
+
for _, group in test.group_by('id'):
|
27 |
+
yield group.item(0, 0), group.item(0, 1) # id, description
|
28 |
+
|
29 |
+
def get_all_predictions(self):
|
30 |
+
row_ids, predictions = [], []
|
31 |
+
for id, description in self.generate_data_batches():
|
32 |
+
svg = self.predict(description)
|
33 |
+
if not isinstance(svg, str):
|
34 |
+
raise ValueError("Predicted SVG must have `str` type.")
|
35 |
+
self.validate(svg)
|
36 |
+
row_ids.append(id)
|
37 |
+
predictions.append(svg)
|
38 |
+
|
39 |
+
return predictions, row_ids
|
40 |
+
|
41 |
+
def validate(self, svg: str):
|
42 |
+
try:
|
43 |
+
self.constraints.validate_svg(svg)
|
44 |
+
except ValueError as err:
|
45 |
+
msg = f'SVG failed validation: {str(err)}'
|
46 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, msg)
|
47 |
+
|
48 |
+
def write_submission(self, predictions: list, row_ids: list) -> Path:
|
49 |
+
predictions = pl.DataFrame(
|
50 |
+
data={
|
51 |
+
self.row_id_column_name: row_ids,
|
52 |
+
self.target_column_name: predictions,
|
53 |
+
}
|
54 |
+
)
|
55 |
+
|
56 |
+
submission_path = Path('/kaggle/working/submission.csv')
|
57 |
+
if not IS_RERUN:
|
58 |
+
with tempfile.NamedTemporaryFile(prefix='kaggle-evaluation-submission-', suffix='.csv', delete=False, mode='w+') as f:
|
59 |
+
submission_path = Path(f.name)
|
60 |
+
|
61 |
+
predictions.write_csv(submission_path)
|
62 |
+
|
63 |
+
return submission_path
|
kaggle_evaluation/svg_gateway.py~
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Gateway notebook for SVG Image Generation"""
|
2 |
+
|
3 |
+
import os
|
4 |
+
import tempfile
|
5 |
+
from pathlib import Path
|
6 |
+
from typing import Any
|
7 |
+
|
8 |
+
import pandas as pd
|
9 |
+
import polars as pl
|
10 |
+
|
11 |
+
from kaggle_evaluation.core.base_gateway import GatewayRuntimeError, GatewayRuntimeErrorType, IS_RERUN
|
12 |
+
import kaggle_evaluation.core.templates
|
13 |
+
from kaggle_evaluation.svg_constraints import SVGConstraints
|
14 |
+
|
15 |
+
|
16 |
+
class SVGGateway(kaggle_evaluation.core.templates.Gateway):
|
17 |
+
def __init__(self, data_path: str | Path | None = None):
|
18 |
+
super().__init__(target_column_name='svg')
|
19 |
+
self.set_response_timeout_seconds(60 * 5)
|
20 |
+
self.row_id_column_name = 'id'
|
21 |
+
self.data_path: Path = Path(data_path) if data_path else Path(__file__).parent
|
22 |
+
self.constraints: SVGConstraints = SVGConstraints()
|
23 |
+
|
24 |
+
def generate_data_batches(self):
|
25 |
+
test = pl.read_csv(self.data_path / 'test.csv')
|
26 |
+
for _, group in test.group_by('id'):
|
27 |
+
yield group.item(0, 0), group.item(0, 1) # id, description
|
28 |
+
|
29 |
+
def get_all_predictions(self):
|
30 |
+
row_ids, predictions = [], []
|
31 |
+
for id, description in self.generate_data_batches():
|
32 |
+
svg = self.predict(description)
|
33 |
+
self.validate(svg)
|
34 |
+
row_ids.append(id)
|
35 |
+
predictions.append(svg)
|
36 |
+
|
37 |
+
return predictions, row_ids
|
38 |
+
|
39 |
+
def validate(self, svg: str):
|
40 |
+
try:
|
41 |
+
self.constraints.validate_svg(svg)
|
42 |
+
except ValueError as err:
|
43 |
+
msg = f'SVG failed validation: {str(err)}'
|
44 |
+
raise GatewayRuntimeError(GatewayRuntimeErrorType.INVALID_SUBMISSION, msg)
|
45 |
+
|
46 |
+
def write_submission(self, predictions: list, row_ids: list) -> Path:
|
47 |
+
predictions = pl.DataFrame(
|
48 |
+
data={
|
49 |
+
self.row_id_column_name: row_ids,
|
50 |
+
self.target_column_name: predictions,
|
51 |
+
}
|
52 |
+
)
|
53 |
+
|
54 |
+
submission_path = Path('/kaggle/working/submission.csv')
|
55 |
+
if not IS_RERUN:
|
56 |
+
with tempfile.NamedTemporaryFile(prefix='kaggle-evaluation-submission-', suffix='.csv', delete=False, mode='w+') as f:
|
57 |
+
submission_path = Path(f.name)
|
58 |
+
|
59 |
+
predictions.write_csv(submission_path)
|
60 |
+
|
61 |
+
return submission_path
|
kaggle_evaluation/test.csv
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
id,description
|
metric.py
ADDED
@@ -0,0 +1,558 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import ast
|
2 |
+
import io
|
3 |
+
import math
|
4 |
+
import statistics
|
5 |
+
import string
|
6 |
+
|
7 |
+
import cairosvg
|
8 |
+
import clip
|
9 |
+
import cv2
|
10 |
+
import kagglehub
|
11 |
+
import matplotlib.pyplot as plt
|
12 |
+
import numpy as np
|
13 |
+
import pandas as pd
|
14 |
+
import torch
|
15 |
+
import torch.nn as nn
|
16 |
+
from more_itertools import chunked
|
17 |
+
from PIL import Image, ImageFilter
|
18 |
+
from transformers import (
|
19 |
+
AutoProcessor,
|
20 |
+
BitsAndBytesConfig,
|
21 |
+
PaliGemmaForConditionalGeneration,
|
22 |
+
)
|
23 |
+
|
24 |
+
svg_constraints = kagglehub.package_import('metric/svg-constraints')
|
25 |
+
|
26 |
+
|
27 |
+
class ParticipantVisibleError(Exception):
|
28 |
+
pass
|
29 |
+
|
30 |
+
|
31 |
+
def score(
|
32 |
+
solution: pd.DataFrame, submission: pd.DataFrame, row_id_column_name: str, random_seed: int = 0
|
33 |
+
) -> float:
|
34 |
+
"""Calculates a fidelity score by comparing generated SVG images to target text descriptions.
|
35 |
+
|
36 |
+
Parameters
|
37 |
+
----------
|
38 |
+
solution : pd.DataFrame
|
39 |
+
A DataFrame containing target questions, choices, and answers about an SVG image.
|
40 |
+
submission : pd.DataFrame
|
41 |
+
A DataFrame containing generated SVG strings. Must have a column named 'svg'.
|
42 |
+
row_id_column_name : str
|
43 |
+
The name of the column containing row identifiers. This column is removed before scoring.
|
44 |
+
random_seed : int
|
45 |
+
A seed to set the random state.
|
46 |
+
|
47 |
+
Returns
|
48 |
+
-------
|
49 |
+
float
|
50 |
+
The mean fidelity score (a value between 0 and 1) representing the average similarity between the generated SVGs and their descriptions.
|
51 |
+
A higher score indicates better fidelity.
|
52 |
+
|
53 |
+
Raises
|
54 |
+
------
|
55 |
+
ParticipantVisibleError
|
56 |
+
If the 'svg' column in the submission DataFrame is not of string type or if validation of the SVG fails.
|
57 |
+
|
58 |
+
Examples
|
59 |
+
--------
|
60 |
+
>>> import pandas as pd
|
61 |
+
>>> solution = pd.DataFrame({
|
62 |
+
... 'id': ["abcde"],
|
63 |
+
... 'question': ['["Is there a red circle?", "What shape is present?"]'],
|
64 |
+
... 'choices': ['[["yes", "no"], ["square", "circle", "triangle", "hexagon"]]'],
|
65 |
+
... 'answer': ['["yes", "circle"]'],
|
66 |
+
... })
|
67 |
+
>>> submission = pd.DataFrame({
|
68 |
+
... 'id': ["abcde"],
|
69 |
+
... 'svg': ['<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red"/></svg>'],
|
70 |
+
... })
|
71 |
+
>>> score(solution, submission, 'row_id', random_seed=42)
|
72 |
+
0...
|
73 |
+
"""
|
74 |
+
# Convert solution fields to list dtypes and expand
|
75 |
+
for colname in ['question', 'choices', 'answer']:
|
76 |
+
solution[colname] = solution[colname].apply(ast.literal_eval)
|
77 |
+
solution = solution.explode(['question', 'choices', 'answer'])
|
78 |
+
|
79 |
+
# Validate
|
80 |
+
if not pd.api.types.is_string_dtype(submission.loc[:, 'svg']):
|
81 |
+
raise ParticipantVisibleError('svg must be a string.')
|
82 |
+
|
83 |
+
# Check that SVG code meets defined constraints
|
84 |
+
constraints = svg_constraints.SVGConstraints()
|
85 |
+
try:
|
86 |
+
for svg in submission.loc[:, 'svg']:
|
87 |
+
constraints.validate_svg(svg)
|
88 |
+
except:
|
89 |
+
raise ParticipantVisibleError('SVG code violates constraints.')
|
90 |
+
|
91 |
+
# Score
|
92 |
+
vqa_evaluator = VQAEvaluator()
|
93 |
+
aesthetic_evaluator = AestheticEvaluator()
|
94 |
+
|
95 |
+
results = []
|
96 |
+
rng = np.random.RandomState(random_seed)
|
97 |
+
try:
|
98 |
+
df = solution.merge(submission, on='id')
|
99 |
+
for i, (_, group) in enumerate(df.loc[
|
100 |
+
:, ['id', 'question', 'choices', 'answer', 'svg']
|
101 |
+
].groupby('id')):
|
102 |
+
questions, choices, answers, svg = [
|
103 |
+
group[col_name].to_list()
|
104 |
+
for col_name in group.drop('id', axis=1).columns
|
105 |
+
]
|
106 |
+
svg = svg[0] # unpack singleton from list
|
107 |
+
group_seed = rng.randint(0, np.iinfo(np.int32).max)
|
108 |
+
image_processor = ImageProcessor(image=svg_to_png(svg), seed=group_seed).apply()
|
109 |
+
image = image_processor.image.copy()
|
110 |
+
aesthetic_score = aesthetic_evaluator.score(image)
|
111 |
+
vqa_score = vqa_evaluator.score(questions, choices, answers, image)
|
112 |
+
image_processor.reset().apply_random_crop_resize().apply_jpeg_compression(quality=90)
|
113 |
+
ocr_score = vqa_evaluator.ocr(image_processor.image)
|
114 |
+
instance_score = (
|
115 |
+
harmonic_mean(vqa_score, aesthetic_score, beta=0.5) * ocr_score
|
116 |
+
)
|
117 |
+
results.append(instance_score)
|
118 |
+
|
119 |
+
except:
|
120 |
+
raise ParticipantVisibleError('SVG failed to score.')
|
121 |
+
|
122 |
+
fidelity = statistics.mean(results)
|
123 |
+
return float(fidelity)
|
124 |
+
|
125 |
+
|
126 |
+
class VQAEvaluator:
|
127 |
+
"""Evaluates images based on their similarity to a given text description using multiple choice questions."""
|
128 |
+
|
129 |
+
def __init__(self):
|
130 |
+
self.quantization_config = BitsAndBytesConfig(
|
131 |
+
load_in_4bit=True,
|
132 |
+
bnb_4bit_quant_type='nf4',
|
133 |
+
bnb_4bit_use_double_quant=True,
|
134 |
+
bnb_4bit_compute_dtype=torch.float16,
|
135 |
+
)
|
136 |
+
self.letters = string.ascii_uppercase
|
137 |
+
self.model_path = kagglehub.model_download(
|
138 |
+
'google/paligemma-2/transformers/paligemma2-10b-mix-448'
|
139 |
+
)
|
140 |
+
self.processor = AutoProcessor.from_pretrained(self.model_path)
|
141 |
+
self.model = PaliGemmaForConditionalGeneration.from_pretrained(
|
142 |
+
self.model_path,
|
143 |
+
low_cpu_mem_usage=True,
|
144 |
+
quantization_config=self.quantization_config,
|
145 |
+
).to('cuda')
|
146 |
+
|
147 |
+
def score(self, questions, choices, answers, image, n=4):
|
148 |
+
scores = []
|
149 |
+
batches = (chunked(qs, n) for qs in [questions, choices, answers])
|
150 |
+
for question_batch, choice_batch, answer_batch in zip(*batches, strict=True):
|
151 |
+
scores.extend(
|
152 |
+
self.score_batch(
|
153 |
+
image,
|
154 |
+
question_batch,
|
155 |
+
choice_batch,
|
156 |
+
answer_batch,
|
157 |
+
)
|
158 |
+
)
|
159 |
+
return statistics.mean(scores)
|
160 |
+
|
161 |
+
def score_batch(
|
162 |
+
self,
|
163 |
+
image: Image.Image,
|
164 |
+
questions: list[str],
|
165 |
+
choices_list: list[list[str]],
|
166 |
+
answers: list[str],
|
167 |
+
) -> list[float]:
|
168 |
+
"""Evaluates the image based on multiple choice questions and answers.
|
169 |
+
|
170 |
+
Parameters
|
171 |
+
----------
|
172 |
+
image : PIL.Image.Image
|
173 |
+
The image to evaluate.
|
174 |
+
questions : list[str]
|
175 |
+
List of questions about the image.
|
176 |
+
choices_list : list[list[str]]
|
177 |
+
List of lists of possible answer choices, corresponding to each question.
|
178 |
+
answers : list[str]
|
179 |
+
List of correct answers from the choices, corresponding to each question.
|
180 |
+
|
181 |
+
Returns
|
182 |
+
-------
|
183 |
+
list[float]
|
184 |
+
List of scores (values between 0 and 1) representing the probability of the correct answer for each question.
|
185 |
+
"""
|
186 |
+
prompts = [
|
187 |
+
self.format_prompt(question, choices)
|
188 |
+
for question, choices in zip(questions, choices_list, strict=True)
|
189 |
+
]
|
190 |
+
batched_choice_probabilities = self.get_choice_probability(
|
191 |
+
image, prompts, choices_list
|
192 |
+
)
|
193 |
+
|
194 |
+
scores = []
|
195 |
+
for i, _ in enumerate(questions):
|
196 |
+
choice_probabilities = batched_choice_probabilities[i]
|
197 |
+
answer = answers[i]
|
198 |
+
answer_probability = 0.0
|
199 |
+
for choice, prob in choice_probabilities.items():
|
200 |
+
if choice == answer:
|
201 |
+
answer_probability = prob
|
202 |
+
break
|
203 |
+
scores.append(answer_probability)
|
204 |
+
|
205 |
+
return scores
|
206 |
+
|
207 |
+
def format_prompt(self, question: str, choices: list[str]) -> str:
|
208 |
+
prompt = f'<image>answer en Question: {question}\nChoices:\n'
|
209 |
+
for i, choice in enumerate(choices):
|
210 |
+
prompt += f'{self.letters[i]}. {choice}\n'
|
211 |
+
return prompt
|
212 |
+
|
213 |
+
def mask_choices(self, logits, choices_list):
|
214 |
+
"""Masks logits for the first token of each choice letter for each question in the batch."""
|
215 |
+
batch_size = logits.shape[0]
|
216 |
+
masked_logits = torch.full_like(logits, float('-inf'))
|
217 |
+
|
218 |
+
for batch_idx in range(batch_size):
|
219 |
+
choices = choices_list[batch_idx]
|
220 |
+
for i in range(len(choices)):
|
221 |
+
letter_token = self.letters[i]
|
222 |
+
|
223 |
+
first_token = self.processor.tokenizer.encode(
|
224 |
+
letter_token, add_special_tokens=False
|
225 |
+
)[0]
|
226 |
+
first_token_with_space = self.processor.tokenizer.encode(
|
227 |
+
' ' + letter_token, add_special_tokens=False
|
228 |
+
)[0]
|
229 |
+
|
230 |
+
if isinstance(first_token, int):
|
231 |
+
masked_logits[batch_idx, first_token] = logits[
|
232 |
+
batch_idx, first_token
|
233 |
+
]
|
234 |
+
if isinstance(first_token_with_space, int):
|
235 |
+
masked_logits[batch_idx, first_token_with_space] = logits[
|
236 |
+
batch_idx, first_token_with_space
|
237 |
+
]
|
238 |
+
|
239 |
+
return masked_logits
|
240 |
+
|
241 |
+
def get_choice_probability(self, image, prompts, choices_list) -> list[dict]:
|
242 |
+
inputs = self.processor(
|
243 |
+
images=[image] * len(prompts),
|
244 |
+
text=prompts,
|
245 |
+
return_tensors='pt',
|
246 |
+
padding='longest',
|
247 |
+
).to('cuda')
|
248 |
+
|
249 |
+
with torch.no_grad():
|
250 |
+
outputs = self.model(**inputs)
|
251 |
+
logits = outputs.logits[:, -1, :] # Logits for the last (predicted) token
|
252 |
+
masked_logits = self.mask_choices(logits, choices_list)
|
253 |
+
probabilities = torch.softmax(masked_logits, dim=-1)
|
254 |
+
|
255 |
+
batched_choice_probabilities = []
|
256 |
+
for batch_idx in range(len(prompts)):
|
257 |
+
choice_probabilities = {}
|
258 |
+
choices = choices_list[batch_idx]
|
259 |
+
for i, choice in enumerate(choices):
|
260 |
+
letter_token = self.letters[i]
|
261 |
+
first_token = self.processor.tokenizer.encode(
|
262 |
+
letter_token, add_special_tokens=False
|
263 |
+
)[0]
|
264 |
+
first_token_with_space = self.processor.tokenizer.encode(
|
265 |
+
' ' + letter_token, add_special_tokens=False
|
266 |
+
)[0]
|
267 |
+
|
268 |
+
prob = 0.0
|
269 |
+
if isinstance(first_token, int):
|
270 |
+
prob += probabilities[batch_idx, first_token].item()
|
271 |
+
if isinstance(first_token_with_space, int):
|
272 |
+
prob += probabilities[batch_idx, first_token_with_space].item()
|
273 |
+
choice_probabilities[choice] = prob
|
274 |
+
|
275 |
+
# Renormalize probabilities for each question
|
276 |
+
total_prob = sum(choice_probabilities.values())
|
277 |
+
if total_prob > 0:
|
278 |
+
renormalized_probabilities = {
|
279 |
+
choice: prob / total_prob
|
280 |
+
for choice, prob in choice_probabilities.items()
|
281 |
+
}
|
282 |
+
else:
|
283 |
+
renormalized_probabilities = (
|
284 |
+
choice_probabilities # Avoid division by zero if total_prob is 0
|
285 |
+
)
|
286 |
+
batched_choice_probabilities.append(renormalized_probabilities)
|
287 |
+
|
288 |
+
return batched_choice_probabilities
|
289 |
+
|
290 |
+
def ocr(self, image, free_chars=4):
|
291 |
+
inputs = (
|
292 |
+
self.processor(
|
293 |
+
text='<image>ocr\n',
|
294 |
+
images=image,
|
295 |
+
return_tensors='pt',
|
296 |
+
)
|
297 |
+
.to(torch.float16)
|
298 |
+
.to(self.model.device)
|
299 |
+
)
|
300 |
+
input_len = inputs['input_ids'].shape[-1]
|
301 |
+
|
302 |
+
with torch.inference_mode():
|
303 |
+
outputs = self.model.generate(**inputs, max_new_tokens=32, do_sample=False)
|
304 |
+
outputs = outputs[0][input_len:]
|
305 |
+
decoded = self.processor.decode(outputs, skip_special_tokens=True)
|
306 |
+
|
307 |
+
num_char = len(decoded)
|
308 |
+
|
309 |
+
# Exponentially decreasing towards 0.0 if more than free_chars detected
|
310 |
+
return min(1.0, math.exp(-num_char + free_chars))
|
311 |
+
|
312 |
+
|
313 |
+
class AestheticPredictor(nn.Module):
|
314 |
+
def __init__(self, input_size):
|
315 |
+
super().__init__()
|
316 |
+
self.input_size = input_size
|
317 |
+
self.layers = nn.Sequential(
|
318 |
+
nn.Linear(self.input_size, 1024),
|
319 |
+
nn.Dropout(0.2),
|
320 |
+
nn.Linear(1024, 128),
|
321 |
+
nn.Dropout(0.2),
|
322 |
+
nn.Linear(128, 64),
|
323 |
+
nn.Dropout(0.1),
|
324 |
+
nn.Linear(64, 16),
|
325 |
+
nn.Linear(16, 1),
|
326 |
+
)
|
327 |
+
|
328 |
+
def forward(self, x):
|
329 |
+
return self.layers(x)
|
330 |
+
|
331 |
+
|
332 |
+
class AestheticEvaluator:
|
333 |
+
def __init__(self):
|
334 |
+
self.model_path = 'improved-aesthetic-predictor/sac+logos+ava1-l14-linearMSE.pth'
|
335 |
+
self.clip_model_path = 'ViT-L/14'
|
336 |
+
self.predictor, self.clip_model, self.preprocessor = self.load()
|
337 |
+
|
338 |
+
def load(self):
|
339 |
+
"""Loads the aesthetic predictor model and CLIP model."""
|
340 |
+
state_dict = torch.load(self.model_path, weights_only=True, map_location='cuda')
|
341 |
+
|
342 |
+
# CLIP embedding dim is 768 for CLIP ViT L 14
|
343 |
+
predictor = AestheticPredictor(768)
|
344 |
+
predictor.load_state_dict(state_dict)
|
345 |
+
predictor.to('cuda')
|
346 |
+
predictor.eval()
|
347 |
+
clip_model, preprocessor = clip.load(self.clip_model_path, device='cuda')
|
348 |
+
|
349 |
+
return predictor, clip_model, preprocessor
|
350 |
+
|
351 |
+
def score(self, image: Image.Image) -> float:
|
352 |
+
"""Predicts the CLIP aesthetic score of an image."""
|
353 |
+
image = self.preprocessor(image).unsqueeze(0).to('cuda')
|
354 |
+
|
355 |
+
with torch.no_grad():
|
356 |
+
image_features = self.clip_model.encode_image(image)
|
357 |
+
# l2 normalize
|
358 |
+
image_features /= image_features.norm(dim=-1, keepdim=True)
|
359 |
+
image_features = image_features.cpu().detach().numpy()
|
360 |
+
|
361 |
+
score = self.predictor(torch.from_numpy(image_features).to('cuda').float())
|
362 |
+
|
363 |
+
return score.item() / 10.0 # scale to [0, 1]
|
364 |
+
|
365 |
+
|
366 |
+
def harmonic_mean(a: float, b: float, beta: float = 1.0) -> float:
|
367 |
+
"""
|
368 |
+
Calculate the harmonic mean of two values, weighted using a beta parameter.
|
369 |
+
|
370 |
+
Args:
|
371 |
+
a: First value (e.g., precision)
|
372 |
+
b: Second value (e.g., recall)
|
373 |
+
beta: Weighting parameter
|
374 |
+
|
375 |
+
Returns:
|
376 |
+
Weighted harmonic mean
|
377 |
+
"""
|
378 |
+
# Handle zero values to prevent division by zero
|
379 |
+
if a <= 0 or b <= 0:
|
380 |
+
return 0.0
|
381 |
+
return (1 + beta**2) * (a * b) / (beta**2 * a + b)
|
382 |
+
|
383 |
+
|
384 |
+
def svg_to_png(svg_code: str, size: tuple = (384, 384)) -> Image.Image:
|
385 |
+
"""
|
386 |
+
Converts an SVG string to a PNG image using CairoSVG.
|
387 |
+
|
388 |
+
If the SVG does not define a `viewBox`, it will add one using the provided size.
|
389 |
+
|
390 |
+
Parameters
|
391 |
+
----------
|
392 |
+
svg_code : str
|
393 |
+
The SVG string to convert.
|
394 |
+
size : tuple[int, int], default=(384, 384)
|
395 |
+
The desired size of the output PNG image (width, height).
|
396 |
+
|
397 |
+
Returns
|
398 |
+
-------
|
399 |
+
PIL.Image.Image
|
400 |
+
The generated PNG image.
|
401 |
+
"""
|
402 |
+
# Ensure SVG has proper size attributes
|
403 |
+
if 'viewBox' not in svg_code:
|
404 |
+
svg_code = svg_code.replace('<svg', f'<svg viewBox="0 0 {size[0]} {size[1]}"')
|
405 |
+
|
406 |
+
# Convert SVG to PNG
|
407 |
+
png_data = cairosvg.svg2png(bytestring=svg_code.encode('utf-8'))
|
408 |
+
return Image.open(io.BytesIO(png_data)).convert('RGB').resize(size)
|
409 |
+
|
410 |
+
|
411 |
+
class ImageProcessor:
|
412 |
+
def __init__(self, image: Image.Image, seed=None):
|
413 |
+
"""Initialize with either a path to an image or a PIL Image object."""
|
414 |
+
self.image = image
|
415 |
+
self.original_image = self.image.copy()
|
416 |
+
if seed is not None:
|
417 |
+
self.rng = np.random.RandomState(seed)
|
418 |
+
else:
|
419 |
+
self.rng = np.random
|
420 |
+
|
421 |
+
def reset(self):
|
422 |
+
self.image = self.original_image.copy()
|
423 |
+
return self
|
424 |
+
|
425 |
+
def visualize_comparison(
|
426 |
+
self,
|
427 |
+
original_name='Original',
|
428 |
+
processed_name='Processed',
|
429 |
+
figsize=(10, 5),
|
430 |
+
show=True,
|
431 |
+
):
|
432 |
+
"""Display original and processed images side by side."""
|
433 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)
|
434 |
+
ax1.imshow(np.asarray(self.original_image))
|
435 |
+
ax1.set_title(original_name)
|
436 |
+
ax1.axis('off')
|
437 |
+
|
438 |
+
ax2.imshow(np.asarray(self.image))
|
439 |
+
ax2.set_title(processed_name)
|
440 |
+
ax2.axis('off')
|
441 |
+
|
442 |
+
title = f'{original_name} vs {processed_name}'
|
443 |
+
fig.suptitle(title)
|
444 |
+
fig.tight_layout()
|
445 |
+
if show:
|
446 |
+
plt.show()
|
447 |
+
return fig
|
448 |
+
|
449 |
+
def apply_median_filter(self, size=3):
|
450 |
+
"""Apply median filter to remove outlier pixel values.
|
451 |
+
|
452 |
+
Args:
|
453 |
+
size: Size of the median filter window.
|
454 |
+
"""
|
455 |
+
self.image = self.image.filter(ImageFilter.MedianFilter(size=size))
|
456 |
+
return self
|
457 |
+
|
458 |
+
def apply_bilateral_filter(self, d=9, sigma_color=75, sigma_space=75):
|
459 |
+
"""Apply bilateral filter to smooth while preserving edges.
|
460 |
+
|
461 |
+
Args:
|
462 |
+
d: Diameter of each pixel neighborhood
|
463 |
+
sigma_color: Filter sigma in the color space
|
464 |
+
sigma_space: Filter sigma in the coordinate space
|
465 |
+
"""
|
466 |
+
# Convert PIL Image to numpy array for OpenCV
|
467 |
+
img_array = np.asarray(self.image)
|
468 |
+
|
469 |
+
# Apply bilateral filter
|
470 |
+
filtered = cv2.bilateralFilter(img_array, d, sigma_color, sigma_space)
|
471 |
+
|
472 |
+
# Convert back to PIL Image
|
473 |
+
self.image = Image.fromarray(filtered)
|
474 |
+
return self
|
475 |
+
|
476 |
+
def apply_fft_low_pass(self, cutoff_frequency=0.5):
|
477 |
+
"""Apply low-pass filter in the frequency domain using FFT.
|
478 |
+
|
479 |
+
Args:
|
480 |
+
cutoff_frequency: Normalized cutoff frequency (0-1).
|
481 |
+
Lower values remove more high frequencies.
|
482 |
+
"""
|
483 |
+
# Convert to numpy array, ensuring float32 for FFT
|
484 |
+
img_array = np.array(self.image, dtype=np.float32)
|
485 |
+
|
486 |
+
# Process each color channel separately
|
487 |
+
result = np.zeros_like(img_array)
|
488 |
+
for i in range(3): # For RGB channels
|
489 |
+
# Apply FFT
|
490 |
+
f = np.fft.fft2(img_array[:, :, i])
|
491 |
+
fshift = np.fft.fftshift(f)
|
492 |
+
|
493 |
+
# Create a low-pass filter mask
|
494 |
+
rows, cols = img_array[:, :, i].shape
|
495 |
+
crow, ccol = rows // 2, cols // 2
|
496 |
+
mask = np.zeros((rows, cols), np.float32)
|
497 |
+
r = int(min(crow, ccol) * cutoff_frequency)
|
498 |
+
center = [crow, ccol]
|
499 |
+
x, y = np.ogrid[:rows, :cols]
|
500 |
+
mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r * r
|
501 |
+
mask[mask_area] = 1
|
502 |
+
|
503 |
+
# Apply mask and inverse FFT
|
504 |
+
fshift_filtered = fshift * mask
|
505 |
+
f_ishift = np.fft.ifftshift(fshift_filtered)
|
506 |
+
img_back = np.fft.ifft2(f_ishift)
|
507 |
+
img_back = np.real(img_back)
|
508 |
+
|
509 |
+
result[:, :, i] = img_back
|
510 |
+
|
511 |
+
# Clip to 0-255 range and convert to uint8 after processing all channels
|
512 |
+
result = np.clip(result, 0, 255).astype(np.uint8)
|
513 |
+
|
514 |
+
# Convert back to PIL Image
|
515 |
+
self.image = Image.fromarray(result)
|
516 |
+
return self
|
517 |
+
|
518 |
+
def apply_jpeg_compression(self, quality=85):
|
519 |
+
"""Apply JPEG compression.
|
520 |
+
|
521 |
+
Args:
|
522 |
+
quality: JPEG quality (0-95). Lower values increase compression.
|
523 |
+
"""
|
524 |
+
buffer = io.BytesIO()
|
525 |
+
self.image.save(buffer, format='JPEG', quality=quality)
|
526 |
+
buffer.seek(0)
|
527 |
+
self.image = Image.open(buffer)
|
528 |
+
return self
|
529 |
+
|
530 |
+
def apply_random_crop_resize(self, crop_percent=0.05):
|
531 |
+
"""Randomly crop and resize back to original dimensions.
|
532 |
+
|
533 |
+
Args:
|
534 |
+
crop_percent: Percentage of image to crop (0-0.4).
|
535 |
+
"""
|
536 |
+
width, height = self.image.size
|
537 |
+
crop_pixels_w = int(width * crop_percent)
|
538 |
+
crop_pixels_h = int(height * crop_percent)
|
539 |
+
|
540 |
+
left = self.rng.randint(0, crop_pixels_w + 1)
|
541 |
+
top = self.rng.randint(0, crop_pixels_h + 1)
|
542 |
+
right = width - self.rng.randint(0, crop_pixels_w + 1)
|
543 |
+
bottom = height - self.rng.randint(0, crop_pixels_h + 1)
|
544 |
+
|
545 |
+
self.image = self.image.crop((left, top, right, bottom))
|
546 |
+
self.image = self.image.resize((width, height), Image.BILINEAR)
|
547 |
+
return self
|
548 |
+
|
549 |
+
def apply(self):
|
550 |
+
"""Apply an ensemble of defenses."""
|
551 |
+
return (
|
552 |
+
self.apply_random_crop_resize(crop_percent=0.03)
|
553 |
+
.apply_jpeg_compression(quality=95)
|
554 |
+
.apply_median_filter(size=9)
|
555 |
+
.apply_fft_low_pass(cutoff_frequency=0.5)
|
556 |
+
.apply_bilateral_filter(d=5, sigma_color=75, sigma_space=75)
|
557 |
+
.apply_jpeg_compression(quality=92)
|
558 |
+
)
|
requirements.txt
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
kagglehub
|
2 |
+
polars
|
3 |
+
grpcio
|
4 |
+
numpy
|
5 |
+
pandas
|
6 |
+
pyarrow
|
7 |
+
protobuf
|
8 |
+
defusedxml
|
9 |
+
keras
|
10 |
+
cairosvg
|
11 |
+
bitsandbytes
|
12 |
+
opencv-python
|
13 |
+
matplotlib
|
14 |
+
transformers
|
15 |
+
accelerate
|
16 |
+
openai
|
17 |
+
tqdm
|
18 |
+
dotenv
|
19 |
+
|
20 |
+
# pip install 'tensorflow[and-cuda]'
|
21 |
+
# pip install git+https://github.com/openai/CLIP.git
|
22 |
+
# sudo apt-get update
|
23 |
+
# sudo apt-get install -y build-essential
|
starter.ipynb
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 2,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [
|
8 |
+
{
|
9 |
+
"name": "stderr",
|
10 |
+
"output_type": "stream",
|
11 |
+
"text": [
|
12 |
+
"/home/user/miniconda3/envs/dwl/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
13 |
+
" from .autonotebook import tqdm as notebook_tqdm\n"
|
14 |
+
]
|
15 |
+
},
|
16 |
+
{
|
17 |
+
"data": {
|
18 |
+
"text/html": [
|
19 |
+
"<div><style>\n",
|
20 |
+
".dataframe > thead > tr,\n",
|
21 |
+
".dataframe > tbody > tr {\n",
|
22 |
+
" text-align: right;\n",
|
23 |
+
" white-space: pre-wrap;\n",
|
24 |
+
"}\n",
|
25 |
+
"</style>\n",
|
26 |
+
"<small>shape: (5, 2)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>id</th><th>description</th></tr><tr><td>str</td><td>str</td></tr></thead><tbody><tr><td>"02d892"</td><td>"a purple forest at dusk"</td></tr><tr><td>"0dcd2e"</td><td>"gray wool coat with a faux furβ¦</td></tr><tr><td>"1e9ac1"</td><td>"a lighthouse overlooking the oβ¦</td></tr><tr><td>"2b25db"</td><td>"burgundy corduroy pants with pβ¦</td></tr><tr><td>"4e6a54"</td><td>"orange corduroy overalls"</td></tr></tbody></table></div>"
|
27 |
+
],
|
28 |
+
"text/plain": [
|
29 |
+
"shape: (5, 2)\n",
|
30 |
+
"ββββββββββ¬ββββββββββββββββββββββββββββββββββ\n",
|
31 |
+
"β id β description β\n",
|
32 |
+
"β --- β --- β\n",
|
33 |
+
"β str β str β\n",
|
34 |
+
"ββββββββββͺββββββββββββββββββββββββββββββββββ‘\n",
|
35 |
+
"β 02d892 β a purple forest at dusk β\n",
|
36 |
+
"β 0dcd2e β gray wool coat with a faux furβ¦ β\n",
|
37 |
+
"β 1e9ac1 β a lighthouse overlooking the oβ¦ β\n",
|
38 |
+
"β 2b25db β burgundy corduroy pants with pβ¦ β\n",
|
39 |
+
"β 4e6a54 β orange corduroy overalls β\n",
|
40 |
+
"ββββββββββ΄ββββββββββββββββββββββββββββββββββ"
|
41 |
+
]
|
42 |
+
},
|
43 |
+
"execution_count": 2,
|
44 |
+
"metadata": {},
|
45 |
+
"output_type": "execute_result"
|
46 |
+
}
|
47 |
+
],
|
48 |
+
"source": [
|
49 |
+
"# We can load and explore the competition's train set to get a feel for the data.\n",
|
50 |
+
"# We're not going to export this cell as it's not needed for our exported inferenceable model.\n",
|
51 |
+
"\n",
|
52 |
+
"import kagglehub\n",
|
53 |
+
"import polars as pl\n",
|
54 |
+
"\n",
|
55 |
+
"train_path = kagglehub.competition_download('drawing-with-llms', 'train.csv')\n",
|
56 |
+
"train = pl.read_csv(train_path)\n",
|
57 |
+
"\n",
|
58 |
+
"train.head()"
|
59 |
+
]
|
60 |
+
},
|
61 |
+
{
|
62 |
+
"cell_type": "code",
|
63 |
+
"execution_count": 3,
|
64 |
+
"metadata": {},
|
65 |
+
"outputs": [],
|
66 |
+
"source": [
|
67 |
+
"class Model:\n",
|
68 |
+
" def __init__(self):\n",
|
69 |
+
" '''Optional constructor, performs any setup logic, model instantiation, etc.'''\n",
|
70 |
+
" pass\n",
|
71 |
+
" \n",
|
72 |
+
" def predict(self, prompt: str) -> str:\n",
|
73 |
+
" '''Generates SVG which produces an image described by the prompt.\n",
|
74 |
+
"\n",
|
75 |
+
" Args:\n",
|
76 |
+
" prompt (str): A prompt describing an image\n",
|
77 |
+
" Returns:\n",
|
78 |
+
" String of valid SVG code.\n",
|
79 |
+
" '''\n",
|
80 |
+
" # Renders a simple circle regardless of input\n",
|
81 |
+
" return '<svg width=\"100\" height=\"100\" viewBox=\"0 0 100 100\"><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\" /></svg>'"
|
82 |
+
]
|
83 |
+
},
|
84 |
+
{
|
85 |
+
"cell_type": "code",
|
86 |
+
"execution_count": 4,
|
87 |
+
"metadata": {},
|
88 |
+
"outputs": [
|
89 |
+
{
|
90 |
+
"name": "stdout",
|
91 |
+
"output_type": "stream",
|
92 |
+
"text": [
|
93 |
+
"<svg width=\"100\" height=\"100\" viewBox=\"0 0 100 100\"><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\" /></svg>\n"
|
94 |
+
]
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"data": {
|
98 |
+
"image/svg+xml": [
|
99 |
+
"<svg width=\"100\" height=\"100\" viewBox=\"0 0 100 100\"><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\"/></svg>"
|
100 |
+
],
|
101 |
+
"text/plain": [
|
102 |
+
"<IPython.core.display.SVG object>"
|
103 |
+
]
|
104 |
+
},
|
105 |
+
"metadata": {},
|
106 |
+
"output_type": "display_data"
|
107 |
+
}
|
108 |
+
],
|
109 |
+
"source": [
|
110 |
+
"from IPython.display import SVG\n",
|
111 |
+
"\n",
|
112 |
+
"model = Model()\n",
|
113 |
+
"svg = model.predict('a goose winning a gold medal')\n",
|
114 |
+
"\n",
|
115 |
+
"print(svg)\n",
|
116 |
+
"display(SVG(svg))"
|
117 |
+
]
|
118 |
+
},
|
119 |
+
{
|
120 |
+
"cell_type": "code",
|
121 |
+
"execution_count": 6,
|
122 |
+
"metadata": {},
|
123 |
+
"outputs": [
|
124 |
+
{
|
125 |
+
"data": {
|
126 |
+
"text/plain": [
|
127 |
+
"['RN50',\n",
|
128 |
+
" 'RN101',\n",
|
129 |
+
" 'RN50x4',\n",
|
130 |
+
" 'RN50x16',\n",
|
131 |
+
" 'RN50x64',\n",
|
132 |
+
" 'ViT-B/32',\n",
|
133 |
+
" 'ViT-B/16',\n",
|
134 |
+
" 'ViT-L/14',\n",
|
135 |
+
" 'ViT-L/14@336px']"
|
136 |
+
]
|
137 |
+
},
|
138 |
+
"execution_count": 6,
|
139 |
+
"metadata": {},
|
140 |
+
"output_type": "execute_result"
|
141 |
+
}
|
142 |
+
],
|
143 |
+
"source": [
|
144 |
+
"import clip\n",
|
145 |
+
"clip.available_models()"
|
146 |
+
]
|
147 |
+
},
|
148 |
+
{
|
149 |
+
"cell_type": "code",
|
150 |
+
"execution_count": 7,
|
151 |
+
"metadata": {},
|
152 |
+
"outputs": [
|
153 |
+
{
|
154 |
+
"name": "stderr",
|
155 |
+
"output_type": "stream",
|
156 |
+
"text": [
|
157 |
+
"2025-04-20 13:55:34.589770: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:467] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
158 |
+
"WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
|
159 |
+
"E0000 00:00:1745171734.600777 13214 cuda_dnn.cc:8579] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
160 |
+
"E0000 00:00:1745171734.603957 13214 cuda_blas.cc:1407] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
161 |
+
"W0000 00:00:1745171734.615566 13214 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
|
162 |
+
"W0000 00:00:1745171734.615584 13214 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
|
163 |
+
"W0000 00:00:1745171734.615585 13214 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
|
164 |
+
"W0000 00:00:1745171734.615586 13214 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
|
165 |
+
"2025-04-20 13:55:34.618659: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
|
166 |
+
"To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n",
|
167 |
+
"Using a slow image processor as `use_fast` is unset and a slow processor was saved with this model. `use_fast=True` will be the default behavior in v4.52, even if the model was saved with a slow processor. This will result in minor differences in outputs. You'll still be able to use a slow processor with `use_fast=False`.\n",
|
168 |
+
"Loading checkpoint shards: 100%|ββββββββββ| 4/4 [00:18<00:00, 4.68s/it]\n"
|
169 |
+
]
|
170 |
+
}
|
171 |
+
],
|
172 |
+
"source": [
|
173 |
+
"import pandas as pd\n",
|
174 |
+
"import importlib\n",
|
175 |
+
"metric = importlib.import_module('metric')\n",
|
176 |
+
"importlib.reload(metric)\n",
|
177 |
+
"\n",
|
178 |
+
"vqa_evaluator = metric.VQAEvaluator()\n",
|
179 |
+
"aesthetic_evaluator = metric.AestheticEvaluator()"
|
180 |
+
]
|
181 |
+
},
|
182 |
+
{
|
183 |
+
"cell_type": "code",
|
184 |
+
"execution_count": 11,
|
185 |
+
"metadata": {},
|
186 |
+
"outputs": [
|
187 |
+
{
|
188 |
+
"name": "stdout",
|
189 |
+
"output_type": "stream",
|
190 |
+
"text": [
|
191 |
+
"VQA Score: 0.9996758976500401\n",
|
192 |
+
"Aesthetic Score: 0.5749330520629883\n",
|
193 |
+
"Final Fidelity Score: 0.8709845773271212\n"
|
194 |
+
]
|
195 |
+
}
|
196 |
+
],
|
197 |
+
"source": [
|
198 |
+
"# score gpt4o generated images\n",
|
199 |
+
"import ast\n",
|
200 |
+
"import numpy as np\n",
|
201 |
+
"from PIL import Image\n",
|
202 |
+
"\n",
|
203 |
+
"# Load the first sample from descriptions.csv\n",
|
204 |
+
"descriptions_df = pd.read_csv('data/descriptions.csv')\n",
|
205 |
+
"first_description = descriptions_df.iloc[1]\n",
|
206 |
+
"\n",
|
207 |
+
"eval_df = pd.read_csv('data/eval.csv')\n",
|
208 |
+
"first_eval = eval_df.iloc[1]\n",
|
209 |
+
"\n",
|
210 |
+
"# Load the image\n",
|
211 |
+
"image_path = 'data/gray_coat.png' # Assuming the image is saved with this name\n",
|
212 |
+
"image = Image.open(image_path)\n",
|
213 |
+
"\n",
|
214 |
+
"# Prepare the inputs for scoring - need to parse the string representations\n",
|
215 |
+
"questions = ast.literal_eval(first_eval['question'])\n",
|
216 |
+
"choices = ast.literal_eval(first_eval['choices'])\n",
|
217 |
+
"answers = ast.literal_eval(first_eval['answer'])\n",
|
218 |
+
"\n",
|
219 |
+
"# Calculate VQA score - don't wrap in additional lists\n",
|
220 |
+
"vqa_score = vqa_evaluator.score(questions, choices, answers, image)\n",
|
221 |
+
"\n",
|
222 |
+
"# Calculate aesthetic score\n",
|
223 |
+
"aesthetic_score = aesthetic_evaluator.score(image)\n",
|
224 |
+
"\n",
|
225 |
+
"# Apply image processing as done in the metric.score function\n",
|
226 |
+
"image_processor = metric.ImageProcessor(image=image, seed=0).apply()\n",
|
227 |
+
"processed_image = image_processor.image.copy()\n",
|
228 |
+
"\n",
|
229 |
+
"# Calculate final fidelity score\n",
|
230 |
+
"instance_score = metric.harmonic_mean(vqa_score, aesthetic_score, beta=0.5)\n",
|
231 |
+
"\n",
|
232 |
+
"print(f\"VQA Score: {vqa_score}\")\n",
|
233 |
+
"print(f\"Aesthetic Score: {aesthetic_score}\")\n",
|
234 |
+
"print(f\"Final Fidelity Score: {instance_score}\")"
|
235 |
+
]
|
236 |
+
}
|
237 |
+
],
|
238 |
+
"metadata": {
|
239 |
+
"kernelspec": {
|
240 |
+
"display_name": "dwl",
|
241 |
+
"language": "python",
|
242 |
+
"name": "python3"
|
243 |
+
},
|
244 |
+
"language_info": {
|
245 |
+
"codemirror_mode": {
|
246 |
+
"name": "ipython",
|
247 |
+
"version": 3
|
248 |
+
},
|
249 |
+
"file_extension": ".py",
|
250 |
+
"mimetype": "text/x-python",
|
251 |
+
"name": "python",
|
252 |
+
"nbconvert_exporter": "python",
|
253 |
+
"pygments_lexer": "ipython3",
|
254 |
+
"version": "3.11.11"
|
255 |
+
}
|
256 |
+
},
|
257 |
+
"nbformat": 4,
|
258 |
+
"nbformat_minor": 2
|
259 |
+
}
|