Samuel-Collins-CV-Benchmarking 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. samuel_collins_cv_benchmarking-1.0.0/LICENSE +21 -0
  2. samuel_collins_cv_benchmarking-1.0.0/MANIFEST.in +13 -0
  3. samuel_collins_cv_benchmarking-1.0.0/PKG-INFO +267 -0
  4. samuel_collins_cv_benchmarking-1.0.0/README.md +216 -0
  5. samuel_collins_cv_benchmarking-1.0.0/pyproject.toml +53 -0
  6. samuel_collins_cv_benchmarking-1.0.0/setup.cfg +4 -0
  7. samuel_collins_cv_benchmarking-1.0.0/src/Samuel_Collins_CV_Benchmarking.egg-info/PKG-INFO +267 -0
  8. samuel_collins_cv_benchmarking-1.0.0/src/Samuel_Collins_CV_Benchmarking.egg-info/SOURCES.txt +57 -0
  9. samuel_collins_cv_benchmarking-1.0.0/src/Samuel_Collins_CV_Benchmarking.egg-info/dependency_links.txt +1 -0
  10. samuel_collins_cv_benchmarking-1.0.0/src/Samuel_Collins_CV_Benchmarking.egg-info/requires.txt +14 -0
  11. samuel_collins_cv_benchmarking-1.0.0/src/Samuel_Collins_CV_Benchmarking.egg-info/top_level.txt +1 -0
  12. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/__init__.py +10 -0
  13. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/_config.py +19 -0
  14. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/benchmark.py +400 -0
  15. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/classical_models.py +125 -0
  16. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/data_loader.py +847 -0
  17. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/evaluation.py +276 -0
  18. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/neural_models.py +324 -0
  19. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/preprocessing.py +259 -0
  20. samuel_collins_cv_benchmarking-1.0.0/src/samuel_collins_cv_benchmarking/visualization.py +388 -0
  21. samuel_collins_cv_benchmarking-1.0.0/tests/conftest.py +28 -0
  22. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/cat/cat_01.jpeg +0 -0
  23. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/cat/cat_02.jpeg +0 -0
  24. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/cat/cat_03.jpeg +0 -0
  25. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/cat/cat_corrupt.jpeg +1 -0
  26. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/dog/dog_01.jpeg +0 -0
  27. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/dog/dog_02.jpeg +0 -0
  28. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/dog/dog_03.jpeg +0 -0
  29. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/horse/horse_01.jpeg +0 -0
  30. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/horse/horse_02.jpeg +0 -0
  31. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken/horse/horse_03.jpeg +0 -0
  32. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken_labels.csv +12 -0
  33. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken_labels.json +46 -0
  34. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/broken_labels.jsonl +11 -0
  35. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/cat/cat_bmp.bmp +0 -0
  36. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/cat/cat_jpeg.jpeg +0 -0
  37. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/cat/cat_jpg.jpg +0 -0
  38. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/cat/cat_png.png +0 -0
  39. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/cat/cat_tiff.tiff +0 -0
  40. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/dog/dog_bmp.bmp +0 -0
  41. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/dog/dog_jpeg.jpeg +0 -0
  42. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/dog/dog_jpg.jpg +0 -0
  43. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/dog/dog_png.png +0 -0
  44. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/dog/dog_tiff.tiff +0 -0
  45. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/horse/horse_bmp.bmp +0 -0
  46. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/horse/horse_jpeg.jpeg +0 -0
  47. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/horse/horse_jpg.jpg +0 -0
  48. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/horse/horse_png.png +0 -0
  49. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini/horse/horse_tiff.tiff +0 -0
  50. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini_labels.csv +16 -0
  51. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini_labels.json +62 -0
  52. samuel_collins_cv_benchmarking-1.0.0/tests/fixtures/mini_labels.jsonl +15 -0
  53. samuel_collins_cv_benchmarking-1.0.0/tests/test_benchmark.py +333 -0
  54. samuel_collins_cv_benchmarking-1.0.0/tests/test_data_loaders.py +1046 -0
  55. samuel_collins_cv_benchmarking-1.0.0/tests/test_evaluation.py +518 -0
  56. samuel_collins_cv_benchmarking-1.0.0/tests/test_models.py +525 -0
  57. samuel_collins_cv_benchmarking-1.0.0/tests/test_preprocessing.py +269 -0
  58. samuel_collins_cv_benchmarking-1.0.0/tests/test_stratification.py +213 -0
  59. samuel_collins_cv_benchmarking-1.0.0/tests/test_visualization.py +341 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Samuel Collins
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # The sdist picked up tests/test_*.py automatically but not conftest.py or
2
+ # the fixture images, which left a test suite that could not run: conftest
3
+ # is what puts src/ on the path and supplies the fixtures_dir fixture.
4
+ include README.md LICENSE
5
+ recursive-include tests *.py
6
+ recursive-include tests/fixtures *.jpeg *.jpg *.png *.bmp *.tiff *.csv *.json *.jsonl
7
+
8
+ # Never ship the datasets, the results, the report or personal notes.
9
+ prune data
10
+ prune benchmark_results
11
+ prune class_notes
12
+ prune report
13
+ prune scripts
@@ -0,0 +1,267 @@
1
+ Metadata-Version: 2.4
2
+ Name: Samuel_Collins_CV_Benchmarking
3
+ Version: 1.0.0
4
+ Summary: Benchmark classical machine-learning and neural-network image classifiers through one public function.
5
+ Author: Samuel Collins
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Samuel Collins
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/srcollins785/Samuel_Collins_CV_Benchmarking
29
+ Project-URL: Repository, https://github.com/srcollins785/Samuel_Collins_CV_Benchmarking
30
+ Keywords: computer-vision,image-classification,benchmarking,scikit-learn
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Operating System :: OS Independent
34
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
35
+ Requires-Python: >=3.9
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE
38
+ Requires-Dist: numpy>=1.24
39
+ Requires-Dist: pandas>=2.0
40
+ Requires-Dist: pillow>=10.0
41
+ Requires-Dist: scikit-learn>=1.3
42
+ Requires-Dist: matplotlib>=3.7
43
+ Requires-Dist: torch>=2.0
44
+ Provides-Extra: dev
45
+ Requires-Dist: pytest>=7.4; extra == "dev"
46
+ Requires-Dist: build>=1.0; extra == "dev"
47
+ Requires-Dist: twine>=4.0; extra == "dev"
48
+ Provides-Extra: report
49
+ Requires-Dist: markdown>=3.5; extra == "report"
50
+ Dynamic: license-file
51
+
52
+ # Samuel_Collins_CV_Benchmarking
53
+
54
+ Benchmark classical machine-learning and neural-network image classifiers
55
+ through a single public function. Give it a labeled image dataset in any of
56
+ four organizations; it standardizes the images, builds one stratified split,
57
+ trains every model on that split, and saves comparable metrics, plots and
58
+ reports.
59
+
60
+ > **Status: scaffolding.** The package layout, metadata and test fixtures are
61
+ > in place. The loaders, models and evaluation pipeline are not implemented
62
+ > yet — `benchmark_image_classification()` validates its arguments and then
63
+ > raises `NotImplementedError`.
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pip install Samuel_Collins_CV_Benchmarking
69
+ ```
70
+
71
+ From a clone, for development:
72
+
73
+ ```bash
74
+ pip install -e ".[dev]"
75
+ ```
76
+
77
+ ## Usage
78
+
79
+ ```python
80
+ from samuel_collins_cv_benchmarking import benchmark_image_classification
81
+
82
+ results = benchmark_image_classification(
83
+ dataset="./data/animals10_n500/images",
84
+ dataset_type="folder",
85
+ target_labels=["cat", "dog", "horse"],
86
+ color_mode="rgb",
87
+ )
88
+ ```
89
+
90
+ ### Parameters
91
+
92
+ | Parameter | Meaning |
93
+ |---|---|
94
+ | `dataset` | Dataset root directory, CSV/JSON/JSONL manifest path, Pandas DataFrame, or NumPy image array |
95
+ | `dataset_type` | One of `"folder"`, `"csv"`, `"json"`, `"array"` |
96
+ | `target_labels` | Class-folder names, manifest label-field name, DataFrame label column, or a label vector |
97
+ | `color_mode` | `"grayscale"` for one channel, `"rgb"` for three |
98
+
99
+ Image size (64x64), random seed (42), split ratio (80/20) and output location
100
+ are internal constants — callers configure nothing beyond the four parameters
101
+ above.
102
+
103
+ ## The four dataset organizations
104
+
105
+ **1. Class folders** — each subfolder name is the label. PNG, JPG, JPEG, BMP
106
+ and TIFF are supported.
107
+
108
+ ```
109
+ data/animals10_n500/images/
110
+ ├── cat/cat_001.jpeg
111
+ ├── dog/dog_001.jpeg
112
+ └── horse/horse_001.jpeg
113
+ ```
114
+
115
+ ```python
116
+ benchmark_image_classification(
117
+ dataset="./data/animals10_n500/images", dataset_type="folder",
118
+ target_labels=["cat", "dog", "horse"], color_mode="rgb")
119
+ ```
120
+
121
+ **2. CSV manifest** — an `image_path` column plus a label column named by
122
+ `target_labels`. Relative paths resolve from the manifest's own location.
123
+
124
+ ```csv
125
+ image_path,class_name
126
+ images/cat/cat_001.jpeg,cat
127
+ ```
128
+
129
+ ```python
130
+ benchmark_image_classification(
131
+ dataset="./data/animals10_n500/labels.csv", dataset_type="csv",
132
+ target_labels="class_name", color_mode="rgb")
133
+ ```
134
+
135
+ **3. JSON / JSONL manifest** — a JSON list of records, or one JSON record per
136
+ line. Every record carries `image_path` and the label field.
137
+
138
+ ```json
139
+ [{"image_path": "images/cat/cat_001.jpeg", "class_name": "cat"}]
140
+ ```
141
+
142
+ ```python
143
+ benchmark_image_classification(
144
+ dataset="./data/animals10_n500/labels.json", dataset_type="json",
145
+ target_labels="class_name", color_mode="rgb")
146
+ ```
147
+
148
+ **4. NumPy array / in-memory** — `dataset` is the image tensor, `target_labels`
149
+ the label vector. Accepted shapes: `(N, H, W)`, `(N, H, W, 1)`, `(N, H, W, 3)`.
150
+
151
+ ```python
152
+ benchmark_image_classification(
153
+ dataset=X_images, dataset_type="array",
154
+ target_labels=y_labels, color_mode="grayscale")
155
+ ```
156
+
157
+ ## Datasets
158
+
159
+ **RGB - Animals-10.** 10 classes. The images are **not committed to this
160
+ repository**: Animals-10 is assembled from web-scraped photographs, so
161
+ redistributing it here is not appropriate. Rebuild it in one command (needs
162
+ Kaggle API credentials at `~/.kaggle/kaggle.json`):
163
+
164
+ ```bash
165
+ python scripts/download_animals10.py # 500/class -> data/animals10_n500
166
+ python scripts/download_animals10.py --per-class 10 # fast smoke set
167
+ python scripts/download_animals10.py --per-class 100 --out data/custom
168
+ ```
169
+
170
+ Each tier lands in its own directory containing `images/` plus `labels.csv`,
171
+ `labels.json` and `labels.jsonl`, so several sizes coexist:
172
+
173
+ ```
174
+ data/animals10_n500/
175
+ ├── images/<class>/<class>_001.jpeg
176
+ ├── labels.csv
177
+ ├── labels.json
178
+ └── labels.jsonl
179
+ ```
180
+
181
+ ### Sampling method
182
+
183
+ Reported subset: **500 images per class, 5,000 total**, drawn from
184
+ `alessiocorrado99/animals10`. Per class, the file list is sorted, shuffled with
185
+ `random.Random(<english class name>)`, and the first N images that decode
186
+ successfully are taken. Every file is opened, verified and RGB-converted before
187
+ selection; undecodable files are skipped and counted.
188
+
189
+ The seed depends only on the class name, never on N, so the tiers are **nested**:
190
+ `n10` is byte-identical to the first 10 images of `n100`, filenames included.
191
+ A comparison across tiers is therefore a genuine learning curve rather than
192
+ three unrelated samples.
193
+
194
+ Source folder names are Italian and are mapped to English (`cane`->`dog`,
195
+ `gatto`->`cat`, `ragno`->`spider`, ...). The per-class ceiling is set by the
196
+ smallest class, elephant, at 1,446 images.
197
+
198
+ **Grayscale - not yet added.**
199
+
200
+ ## Results
201
+
202
+ Two runs over nested subsets of Animals-10, ten classes, RGB at 64x64. The
203
+ tiers share one fixed ordering, so `n100` is a byte-identical subset of
204
+ `n500` and reading across them is a learning curve rather than a comparison
205
+ of unrelated samples. Chance for ten classes is 0.100.
206
+
207
+ | Model | Macro F1 @ 100/class | Macro F1 @ 500/class | change |
208
+ |---|---|---|---|
209
+ | Simple CNN | 0.295 | **0.434** | +47% |
210
+ | SVM | 0.242 | 0.352 | +45% |
211
+ | Random Forest | 0.294 | 0.319 | +9% |
212
+ | Neural Network | 0.178 | 0.281 | +58% |
213
+ | Logistic Regression | 0.213 | 0.225 | +6% |
214
+ | Decision Tree | 0.093 | 0.180 | +94% |
215
+
216
+ At 100 images per class the CNN and Random Forest are tied. At 500 the CNN
217
+ leads by 36%, and Logistic Regression and Random Forest have nearly
218
+ flattened while the CNN and SVM are still climbing steeply. Reporting only
219
+ the smaller run would have supported the conclusion that a CNN and an
220
+ ensemble of trees are equivalent here - true at that size, and misleading as
221
+ a finding.
222
+
223
+ Cost at 500 per class tells a different story from accuracy alone:
224
+
225
+ | Model | Training | Inference |
226
+ |---|---|---|
227
+ | SVM | 547.4 s | 150.1 ms/image |
228
+ | Simple CNN | 44.8 s | 0.43 ms/image |
229
+ | Decision Tree | 20.2 s | 0.002 ms/image |
230
+ | Logistic Regression | 9.5 s | 0.040 ms/image |
231
+ | Random Forest | 3.3 s | 0.028 ms/image |
232
+ | Neural Network | 1.3 s | 0.025 ms/image |
233
+
234
+ The SVM buys third place at 75,000 times the Decision Tree's inference cost:
235
+ classifying a thousand images would take it two and a half minutes against
236
+ Random Forest's 0.03 seconds for a slightly better score.
237
+
238
+ Full outputs are under `benchmark_results/<tier>/`. Reproduce them with:
239
+
240
+ ```bash
241
+ python scripts/download_animals10.py --per-class 500
242
+ python scripts/run_benchmarks.py
243
+ ```
244
+
245
+ The 500/class run takes about 13 minutes, 9 of which are the SVM.
246
+
247
+ ## Tests
248
+
249
+ ```bash
250
+ pytest tests/
251
+ ```
252
+
253
+ `tests/fixtures/` holds small committed datasets so the suite runs in a clean
254
+ checkout with no downloads:
255
+
256
+ | Fixture | Contents |
257
+ |---|---|
258
+ | `mini/` | 3 classes x 5 images, pristine. One image per required extension (`.jpeg`, `.jpg`, `.png`, `.bmp`, `.tiff`) at five different dimensions, so resizing and aspect handling are exercised. |
259
+ | `broken/` | 3 classes x 3 images plus one undecodable file and, in the manifests, one row pointing at a file that is not on disk. Covers the skip-and-report path. |
260
+
261
+ Each tree has matching `*_labels.csv`, `.json` and `.jsonl` manifests, so all
262
+ four dataset organizations can be tested against committed data.
263
+
264
+ ## License
265
+
266
+ MIT. See [LICENSE](LICENSE). The license covers this source code, not the
267
+ third-party image datasets it consumes.
@@ -0,0 +1,216 @@
1
+ # Samuel_Collins_CV_Benchmarking
2
+
3
+ Benchmark classical machine-learning and neural-network image classifiers
4
+ through a single public function. Give it a labeled image dataset in any of
5
+ four organizations; it standardizes the images, builds one stratified split,
6
+ trains every model on that split, and saves comparable metrics, plots and
7
+ reports.
8
+
9
+ > **Status: scaffolding.** The package layout, metadata and test fixtures are
10
+ > in place. The loaders, models and evaluation pipeline are not implemented
11
+ > yet — `benchmark_image_classification()` validates its arguments and then
12
+ > raises `NotImplementedError`.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install Samuel_Collins_CV_Benchmarking
18
+ ```
19
+
20
+ From a clone, for development:
21
+
22
+ ```bash
23
+ pip install -e ".[dev]"
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```python
29
+ from samuel_collins_cv_benchmarking import benchmark_image_classification
30
+
31
+ results = benchmark_image_classification(
32
+ dataset="./data/animals10_n500/images",
33
+ dataset_type="folder",
34
+ target_labels=["cat", "dog", "horse"],
35
+ color_mode="rgb",
36
+ )
37
+ ```
38
+
39
+ ### Parameters
40
+
41
+ | Parameter | Meaning |
42
+ |---|---|
43
+ | `dataset` | Dataset root directory, CSV/JSON/JSONL manifest path, Pandas DataFrame, or NumPy image array |
44
+ | `dataset_type` | One of `"folder"`, `"csv"`, `"json"`, `"array"` |
45
+ | `target_labels` | Class-folder names, manifest label-field name, DataFrame label column, or a label vector |
46
+ | `color_mode` | `"grayscale"` for one channel, `"rgb"` for three |
47
+
48
+ Image size (64x64), random seed (42), split ratio (80/20) and output location
49
+ are internal constants — callers configure nothing beyond the four parameters
50
+ above.
51
+
52
+ ## The four dataset organizations
53
+
54
+ **1. Class folders** — each subfolder name is the label. PNG, JPG, JPEG, BMP
55
+ and TIFF are supported.
56
+
57
+ ```
58
+ data/animals10_n500/images/
59
+ ├── cat/cat_001.jpeg
60
+ ├── dog/dog_001.jpeg
61
+ └── horse/horse_001.jpeg
62
+ ```
63
+
64
+ ```python
65
+ benchmark_image_classification(
66
+ dataset="./data/animals10_n500/images", dataset_type="folder",
67
+ target_labels=["cat", "dog", "horse"], color_mode="rgb")
68
+ ```
69
+
70
+ **2. CSV manifest** — an `image_path` column plus a label column named by
71
+ `target_labels`. Relative paths resolve from the manifest's own location.
72
+
73
+ ```csv
74
+ image_path,class_name
75
+ images/cat/cat_001.jpeg,cat
76
+ ```
77
+
78
+ ```python
79
+ benchmark_image_classification(
80
+ dataset="./data/animals10_n500/labels.csv", dataset_type="csv",
81
+ target_labels="class_name", color_mode="rgb")
82
+ ```
83
+
84
+ **3. JSON / JSONL manifest** — a JSON list of records, or one JSON record per
85
+ line. Every record carries `image_path` and the label field.
86
+
87
+ ```json
88
+ [{"image_path": "images/cat/cat_001.jpeg", "class_name": "cat"}]
89
+ ```
90
+
91
+ ```python
92
+ benchmark_image_classification(
93
+ dataset="./data/animals10_n500/labels.json", dataset_type="json",
94
+ target_labels="class_name", color_mode="rgb")
95
+ ```
96
+
97
+ **4. NumPy array / in-memory** — `dataset` is the image tensor, `target_labels`
98
+ the label vector. Accepted shapes: `(N, H, W)`, `(N, H, W, 1)`, `(N, H, W, 3)`.
99
+
100
+ ```python
101
+ benchmark_image_classification(
102
+ dataset=X_images, dataset_type="array",
103
+ target_labels=y_labels, color_mode="grayscale")
104
+ ```
105
+
106
+ ## Datasets
107
+
108
+ **RGB - Animals-10.** 10 classes. The images are **not committed to this
109
+ repository**: Animals-10 is assembled from web-scraped photographs, so
110
+ redistributing it here is not appropriate. Rebuild it in one command (needs
111
+ Kaggle API credentials at `~/.kaggle/kaggle.json`):
112
+
113
+ ```bash
114
+ python scripts/download_animals10.py # 500/class -> data/animals10_n500
115
+ python scripts/download_animals10.py --per-class 10 # fast smoke set
116
+ python scripts/download_animals10.py --per-class 100 --out data/custom
117
+ ```
118
+
119
+ Each tier lands in its own directory containing `images/` plus `labels.csv`,
120
+ `labels.json` and `labels.jsonl`, so several sizes coexist:
121
+
122
+ ```
123
+ data/animals10_n500/
124
+ ├── images/<class>/<class>_001.jpeg
125
+ ├── labels.csv
126
+ ├── labels.json
127
+ └── labels.jsonl
128
+ ```
129
+
130
+ ### Sampling method
131
+
132
+ Reported subset: **500 images per class, 5,000 total**, drawn from
133
+ `alessiocorrado99/animals10`. Per class, the file list is sorted, shuffled with
134
+ `random.Random(<english class name>)`, and the first N images that decode
135
+ successfully are taken. Every file is opened, verified and RGB-converted before
136
+ selection; undecodable files are skipped and counted.
137
+
138
+ The seed depends only on the class name, never on N, so the tiers are **nested**:
139
+ `n10` is byte-identical to the first 10 images of `n100`, filenames included.
140
+ A comparison across tiers is therefore a genuine learning curve rather than
141
+ three unrelated samples.
142
+
143
+ Source folder names are Italian and are mapped to English (`cane`->`dog`,
144
+ `gatto`->`cat`, `ragno`->`spider`, ...). The per-class ceiling is set by the
145
+ smallest class, elephant, at 1,446 images.
146
+
147
+ **Grayscale - not yet added.**
148
+
149
+ ## Results
150
+
151
+ Two runs over nested subsets of Animals-10, ten classes, RGB at 64x64. The
152
+ tiers share one fixed ordering, so `n100` is a byte-identical subset of
153
+ `n500` and reading across them is a learning curve rather than a comparison
154
+ of unrelated samples. Chance for ten classes is 0.100.
155
+
156
+ | Model | Macro F1 @ 100/class | Macro F1 @ 500/class | change |
157
+ |---|---|---|---|
158
+ | Simple CNN | 0.295 | **0.434** | +47% |
159
+ | SVM | 0.242 | 0.352 | +45% |
160
+ | Random Forest | 0.294 | 0.319 | +9% |
161
+ | Neural Network | 0.178 | 0.281 | +58% |
162
+ | Logistic Regression | 0.213 | 0.225 | +6% |
163
+ | Decision Tree | 0.093 | 0.180 | +94% |
164
+
165
+ At 100 images per class the CNN and Random Forest are tied. At 500 the CNN
166
+ leads by 36%, and Logistic Regression and Random Forest have nearly
167
+ flattened while the CNN and SVM are still climbing steeply. Reporting only
168
+ the smaller run would have supported the conclusion that a CNN and an
169
+ ensemble of trees are equivalent here - true at that size, and misleading as
170
+ a finding.
171
+
172
+ Cost at 500 per class tells a different story from accuracy alone:
173
+
174
+ | Model | Training | Inference |
175
+ |---|---|---|
176
+ | SVM | 547.4 s | 150.1 ms/image |
177
+ | Simple CNN | 44.8 s | 0.43 ms/image |
178
+ | Decision Tree | 20.2 s | 0.002 ms/image |
179
+ | Logistic Regression | 9.5 s | 0.040 ms/image |
180
+ | Random Forest | 3.3 s | 0.028 ms/image |
181
+ | Neural Network | 1.3 s | 0.025 ms/image |
182
+
183
+ The SVM buys third place at 75,000 times the Decision Tree's inference cost:
184
+ classifying a thousand images would take it two and a half minutes against
185
+ Random Forest's 0.03 seconds for a slightly better score.
186
+
187
+ Full outputs are under `benchmark_results/<tier>/`. Reproduce them with:
188
+
189
+ ```bash
190
+ python scripts/download_animals10.py --per-class 500
191
+ python scripts/run_benchmarks.py
192
+ ```
193
+
194
+ The 500/class run takes about 13 minutes, 9 of which are the SVM.
195
+
196
+ ## Tests
197
+
198
+ ```bash
199
+ pytest tests/
200
+ ```
201
+
202
+ `tests/fixtures/` holds small committed datasets so the suite runs in a clean
203
+ checkout with no downloads:
204
+
205
+ | Fixture | Contents |
206
+ |---|---|
207
+ | `mini/` | 3 classes x 5 images, pristine. One image per required extension (`.jpeg`, `.jpg`, `.png`, `.bmp`, `.tiff`) at five different dimensions, so resizing and aspect handling are exercised. |
208
+ | `broken/` | 3 classes x 3 images plus one undecodable file and, in the manifests, one row pointing at a file that is not on disk. Covers the skip-and-report path. |
209
+
210
+ Each tree has matching `*_labels.csv`, `.json` and `.jsonl` manifests, so all
211
+ four dataset organizations can be tested against committed data.
212
+
213
+ ## License
214
+
215
+ MIT. See [LICENSE](LICENSE). The license covers this source code, not the
216
+ third-party image datasets it consumes.
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "Samuel_Collins_CV_Benchmarking"
7
+ version = "1.0.0"
8
+ description = "Benchmark classical machine-learning and neural-network image classifiers through one public function."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Samuel Collins" }]
13
+ keywords = ["computer-vision", "image-classification", "benchmarking", "scikit-learn"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Scientific/Engineering :: Image Recognition",
19
+ ]
20
+ dependencies = [
21
+ "numpy>=1.24",
22
+ "pandas>=2.0",
23
+ "pillow>=10.0",
24
+ "scikit-learn>=1.3",
25
+ "matplotlib>=3.7",
26
+ "torch>=2.0",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ dev = ["pytest>=7.4", "build>=1.0", "twine>=4.0"]
31
+ # Only the report tooling in scripts/ needs these; the library itself does
32
+ # not, so they stay out of the default install.
33
+ report = ["markdown>=3.5"]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/srcollins785/Samuel_Collins_CV_Benchmarking"
37
+ Repository = "https://github.com/srcollins785/Samuel_Collins_CV_Benchmarking"
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+
42
+ [tool.pytest.ini_options]
43
+ testpaths = ["tests"]
44
+ filterwarnings = [
45
+ # numpy 2.0 built against Apple's Accelerate BLAS raises these on matmul
46
+ # calls whose inputs and outputs are entirely finite. Verified spurious:
47
+ # a clean `a @ b` of random normals emits all three. Filtered narrowly so
48
+ # the suite output stays readable; NOT suppressed in the package itself,
49
+ # where a real overflow must still reach the user.
50
+ "ignore:divide by zero encountered in matmul:RuntimeWarning",
51
+ "ignore:overflow encountered in matmul:RuntimeWarning",
52
+ "ignore:invalid value encountered in matmul:RuntimeWarning",
53
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+