Hashii1729 commited on
Commit
f8b306b
Β·
1 Parent(s): c96ca80

Integrate DeepFashion2 dataset: add evaluation module, utilities, and API endpoints for dataset management and analysis

Browse files
DEEPFASHION2_INTEGRATION.md ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DeepFashion2 Dataset Integration
2
+
3
+ This document describes the integration of the DeepFashion2 dataset with the Vestiq fashion analysis system.
4
+
5
+ ## Overview
6
+
7
+ DeepFashion2 is a comprehensive fashion dataset that provides:
8
+ - 491K diverse images of 13 popular clothing categories
9
+ - Bounding box annotations for fashion items
10
+ - Dense pose estimation
11
+ - Commercial-consumer clothes correspondence
12
+ - Scale, occlusion, zoom-in, and viewpoint labels
13
+
14
+ ## Integration Features
15
+
16
+ ### 1. Dataset Loading and Processing
17
+ - **DeepFashion2Dataset**: PyTorch dataset class for loading images and annotations
18
+ - **Category Mapping**: Maps DeepFashion2 categories to yainage90 model categories
19
+ - **Data Transforms**: Standard preprocessing for fashion images
20
+ - **Batch Processing**: Efficient DataLoader implementation
21
+
22
+ ### 2. Evaluation Framework
23
+ - **Detection Accuracy**: Evaluate fashion object detection performance
24
+ - **Feature Quality**: Assess feature extraction capabilities
25
+ - **Classification Metrics**: Precision, recall, F1-score, confusion matrix
26
+ - **Visualization**: Confusion matrix plots and performance charts
27
+
28
+ ### 3. API Endpoints
29
+ - `/deepfashion2/status` - Check integration status and dataset availability
30
+ - `/deepfashion2/statistics` - Get dataset statistics and category distribution
31
+ - `/deepfashion2/evaluate` - Run evaluation using DeepFashion2 as benchmark
32
+ - `/deepfashion2/setup-instructions` - Get setup instructions for the dataset
33
+
34
+ ## Category Mapping
35
+
36
+ DeepFashion2 uses 13 detailed categories that are mapped to yainage90's 7 categories:
37
+
38
+ | DeepFashion2 Category | yainage90 Category |
39
+ |----------------------|-------------------|
40
+ | short_sleeved_shirt | top |
41
+ | long_sleeved_shirt | top |
42
+ | short_sleeved_outwear| outer |
43
+ | long_sleeved_outwear | outer |
44
+ | vest | top |
45
+ | sling | top |
46
+ | shorts | bottom |
47
+ | trousers | bottom |
48
+ | skirt | bottom |
49
+ | short_sleeved_dress | dress |
50
+ | long_sleeved_dress | dress |
51
+ | vest_dress | dress |
52
+ | sling_dress | dress |
53
+
54
+ ## Setup Instructions
55
+
56
+ ### 1. Download the Dataset
57
+
58
+ The DeepFashion2 dataset requires manual download due to licensing requirements:
59
+
60
+ 1. Visit the official repository: https://github.com/switchablenorms/DeepFashion2
61
+ 2. Follow the dataset download instructions
62
+ 3. Register and download the dataset files
63
+
64
+ ### 2. Dataset Structure
65
+
66
+ Extract the dataset to `./data/deepfashion2/` with the following structure:
67
+
68
+ ```
69
+ deepfashion2/
70
+ β”œβ”€β”€ train/
71
+ β”‚ β”œβ”€β”€ image/ # Training images
72
+ β”‚ └── annos/ # Training annotations (JSON)
73
+ β”œβ”€β”€ validation/
74
+ β”‚ β”œβ”€β”€ image/ # Validation images
75
+ β”‚ └── annos/ # Validation annotations (JSON)
76
+ └── test/
77
+ β”œβ”€β”€ image/ # Test images
78
+ └── annos/ # Test annotations (JSON)
79
+ ```
80
+
81
+ ### 3. Install Dependencies
82
+
83
+ Install additional dependencies for evaluation:
84
+
85
+ ```bash
86
+ pip install scikit-learn matplotlib seaborn
87
+ ```
88
+
89
+ ### 4. Verify Setup
90
+
91
+ Check the integration status:
92
+
93
+ ```bash
94
+ curl http://localhost:7861/deepfashion2/status
95
+ ```
96
+
97
+ ## Usage Examples
98
+
99
+ ### 1. Basic Dataset Loading
100
+
101
+ ```python
102
+ from deepfashion2_utils import DeepFashion2Config, DeepFashion2Dataset
103
+
104
+ config = DeepFashion2Config()
105
+ dataset = DeepFashion2Dataset(
106
+ root_dir=config.dataset_root,
107
+ split='validation',
108
+ load_annotations=True
109
+ )
110
+
111
+ # Get a sample
112
+ sample = dataset[0]
113
+ print(f"Image: {sample['image_path']}")
114
+ print(f"Categories: {dataset.get_categories_in_image(sample['annotations'])}")
115
+ ```
116
+
117
+ ### 2. Running Evaluation
118
+
119
+ ```python
120
+ from deepfashion2_evaluation import run_full_evaluation
121
+ from fast import analyzer
122
+
123
+ # Run evaluation with 100 samples
124
+ report_path = run_full_evaluation(analyzer, max_samples=100)
125
+ print(f"Evaluation report saved to: {report_path}")
126
+ ```
127
+
128
+ ### 3. API Usage
129
+
130
+ ```bash
131
+ # Check status
132
+ curl -X GET "http://localhost:7861/deepfashion2/status"
133
+
134
+ # Get dataset statistics
135
+ curl -X GET "http://localhost:7861/deepfashion2/statistics"
136
+
137
+ # Run evaluation
138
+ curl -X POST "http://localhost:7861/deepfashion2/evaluate?max_samples=50"
139
+
140
+ # Get setup instructions
141
+ curl -X GET "http://localhost:7861/deepfashion2/setup-instructions"
142
+ ```
143
+
144
+ ## Evaluation Metrics
145
+
146
+ ### Detection Accuracy
147
+ - **Category-level accuracy**: How well the model detects clothing categories
148
+ - **Detection score**: IoU-like metric for category overlap
149
+ - **Confusion matrix**: Detailed breakdown of predictions vs ground truth
150
+
151
+ ### Feature Quality
152
+ - **Feature dimension**: Dimensionality of extracted features
153
+ - **Intra-category similarity**: How similar features are within the same category
154
+ - **Inter-category distance**: How well features separate different categories
155
+ - **Feature separability**: Overall quality metric for feature discrimination
156
+
157
+ ## Configuration Options
158
+
159
+ ### DeepFashion2Config
160
+
161
+ ```python
162
+ @dataclass
163
+ class DeepFashion2Config:
164
+ dataset_root: str = "./data/deepfashion2"
165
+ categories: List[str] = None # Auto-populated with 13 categories
166
+ image_size: Tuple[int, int] = (224, 224)
167
+ batch_size: int = 32
168
+ num_workers: int = 4
169
+ ```
170
+
171
+ ### Customization
172
+
173
+ You can customize the configuration for your specific needs:
174
+
175
+ ```python
176
+ config = DeepFashion2Config(
177
+ dataset_root="/path/to/your/deepfashion2",
178
+ image_size=(256, 256),
179
+ batch_size=16
180
+ )
181
+ ```
182
+
183
+ ## Performance Considerations
184
+
185
+ ### Memory Usage
186
+ - The dataset is large (~15GB), ensure sufficient disk space
187
+ - Use appropriate batch sizes based on available GPU memory
188
+ - Consider using `num_workers` for faster data loading
189
+
190
+ ### CPU Optimization
191
+ - The system automatically detects CPU vs GPU and optimizes accordingly
192
+ - CPU inference uses float32 precision and limited threads
193
+ - GPU inference uses float16 precision for better performance
194
+
195
+ ### Evaluation Speed
196
+ - Limit `max_samples` for faster evaluation during development
197
+ - Full evaluation on the entire validation set may take significant time
198
+ - Consider running evaluations on a subset for quick feedback
199
+
200
+ ## Troubleshooting
201
+
202
+ ### Common Issues
203
+
204
+ 1. **Dataset not found**: Ensure the dataset is extracted to the correct path
205
+ 2. **Permission errors**: Check file permissions for the dataset directory
206
+ 3. **Memory errors**: Reduce batch size or number of workers
207
+ 4. **Import errors**: Install missing dependencies (scikit-learn, matplotlib, seaborn)
208
+
209
+ ### Debug Mode
210
+
211
+ Enable debug logging to troubleshoot issues:
212
+
213
+ ```python
214
+ import logging
215
+ logging.basicConfig(level=logging.DEBUG)
216
+ ```
217
+
218
+ ## Future Enhancements
219
+
220
+ ### Planned Features
221
+ - **Training Pipeline**: Fine-tune models on DeepFashion2 data
222
+ - **Advanced Metrics**: Add more sophisticated evaluation metrics
223
+ - **Visualization Tools**: Enhanced plotting and analysis tools
224
+ - **Benchmark Comparisons**: Compare against other fashion datasets
225
+
226
+ ### Contributing
227
+
228
+ To contribute to the DeepFashion2 integration:
229
+
230
+ 1. Fork the repository
231
+ 2. Create a feature branch
232
+ 3. Add tests for new functionality
233
+ 4. Submit a pull request
234
+
235
+ ## References
236
+
237
+ - [DeepFashion2 Paper](https://arxiv.org/abs/1901.07973)
238
+ - [DeepFashion2 Repository](https://github.com/switchablenorms/DeepFashion2)
239
+ - [yainage90 Models](https://huggingface.co/yainage90)
240
+
241
+ ## License
242
+
243
+ This integration follows the same license as the main Vestiq project. The DeepFashion2 dataset has its own licensing terms that must be respected.
deepfashion2_evaluation.py ADDED
@@ -0,0 +1,405 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ DeepFashion2 Evaluation Module
3
+ Provides evaluation capabilities using DeepFashion2 dataset as benchmark
4
+ for the Vestiq fashion analysis system.
5
+ """
6
+
7
+ import torch
8
+ import numpy as np
9
+ from typing import Dict, List, Tuple, Optional
10
+ from sklearn.metrics import accuracy_score, precision_recall_fscore_support, confusion_matrix
11
+ import matplotlib.pyplot as plt
12
+ import seaborn as sns
13
+ from pathlib import Path
14
+ import json
15
+ from tqdm import tqdm
16
+
17
+ from deepfashion2_utils import (
18
+ DeepFashion2Config,
19
+ DeepFashion2Dataset,
20
+ DeepFashion2CategoryMapper,
21
+ create_deepfashion2_dataloader
22
+ )
23
+
24
+ class DeepFashion2Evaluator:
25
+ """Evaluate fashion models using DeepFashion2 dataset"""
26
+
27
+ def __init__(self, config: DeepFashion2Config, analyzer=None):
28
+ """
29
+ Initialize evaluator
30
+
31
+ Args:
32
+ config: DeepFashion2 configuration
33
+ analyzer: HuggingFaceFashionAnalyzer instance
34
+ """
35
+ self.config = config
36
+ self.analyzer = analyzer
37
+ self.category_mapper = DeepFashion2CategoryMapper()
38
+ self.results = {}
39
+
40
+ def evaluate_detection_accuracy(self, split: str = 'validation',
41
+ max_samples: Optional[int] = None) -> Dict:
42
+ """
43
+ Evaluate fashion object detection accuracy on DeepFashion2
44
+
45
+ Args:
46
+ split: Dataset split to evaluate on
47
+ max_samples: Maximum number of samples to evaluate (None for all)
48
+
49
+ Returns:
50
+ Dictionary containing evaluation metrics
51
+ """
52
+ if not self.analyzer:
53
+ raise ValueError("Analyzer not provided")
54
+
55
+ print(f"Evaluating detection accuracy on {split} split...")
56
+
57
+ # Load dataset
58
+ dataset = DeepFashion2Dataset(
59
+ root_dir=self.config.dataset_root,
60
+ split=split,
61
+ transform=None,
62
+ load_annotations=True
63
+ )
64
+
65
+ if max_samples:
66
+ dataset.image_files = dataset.image_files[:max_samples]
67
+
68
+ # Evaluation metrics
69
+ true_categories = []
70
+ predicted_categories = []
71
+ detection_scores = []
72
+
73
+ for i in tqdm(range(len(dataset)), desc="Evaluating detection"):
74
+ try:
75
+ item = dataset[i]
76
+ image_path = item['image_path']
77
+ annotations = item['annotations']
78
+
79
+ # Get ground truth categories
80
+ gt_categories = dataset.get_categories_in_image(annotations)
81
+ gt_yainage_categories = [
82
+ self.category_mapper.map_to_yainage90(cat)
83
+ for cat in gt_categories
84
+ ]
85
+ gt_yainage_categories = list(set(gt_yainage_categories))
86
+
87
+ if not gt_yainage_categories:
88
+ continue
89
+
90
+ # Get model predictions
91
+ with open(image_path, 'rb') as f:
92
+ image_bytes = f.read()
93
+
94
+ detection_results = self.analyzer.detect_fashion_objects(
95
+ self.analyzer.process_image_from_bytes(image_bytes)
96
+ )
97
+
98
+ if 'detected_items' in detection_results:
99
+ pred_categories = [
100
+ item['category'] for item in detection_results['detected_items']
101
+ if item['confidence'] > 0.5
102
+ ]
103
+ pred_categories = list(set(pred_categories))
104
+
105
+ # Calculate detection score (IoU-like for categories)
106
+ if pred_categories and gt_yainage_categories:
107
+ intersection = set(pred_categories) & set(gt_yainage_categories)
108
+ union = set(pred_categories) | set(gt_yainage_categories)
109
+ score = len(intersection) / len(union) if union else 0
110
+ detection_scores.append(score)
111
+
112
+ # Store for classification metrics
113
+ for gt_cat in gt_yainage_categories:
114
+ true_categories.append(gt_cat)
115
+ predicted_categories.append(
116
+ gt_cat if gt_cat in pred_categories else 'none'
117
+ )
118
+
119
+ except Exception as e:
120
+ print(f"Error processing image {i}: {e}")
121
+ continue
122
+
123
+ # Calculate metrics
124
+ metrics = self._calculate_classification_metrics(
125
+ true_categories, predicted_categories
126
+ )
127
+
128
+ metrics['detection_scores'] = detection_scores
129
+ metrics['mean_detection_score'] = np.mean(detection_scores) if detection_scores else 0
130
+ metrics['num_samples'] = len(dataset)
131
+
132
+ self.results['detection_accuracy'] = metrics
133
+ return metrics
134
+
135
+ def evaluate_feature_extraction(self, split: str = 'validation',
136
+ max_samples: Optional[int] = None) -> Dict:
137
+ """
138
+ Evaluate feature extraction quality using DeepFashion2
139
+
140
+ Args:
141
+ split: Dataset split to evaluate on
142
+ max_samples: Maximum number of samples to evaluate
143
+
144
+ Returns:
145
+ Dictionary containing feature evaluation metrics
146
+ """
147
+ if not self.analyzer:
148
+ raise ValueError("Analyzer not provided")
149
+
150
+ print(f"Evaluating feature extraction on {split} split...")
151
+
152
+ dataset = DeepFashion2Dataset(
153
+ root_dir=self.config.dataset_root,
154
+ split=split,
155
+ transform=None,
156
+ load_annotations=True
157
+ )
158
+
159
+ if max_samples:
160
+ dataset.image_files = dataset.image_files[:max_samples]
161
+
162
+ features_by_category = {}
163
+ feature_dimensions = []
164
+
165
+ for i in tqdm(range(len(dataset)), desc="Extracting features"):
166
+ try:
167
+ item = dataset[i]
168
+ image_path = item['image_path']
169
+ annotations = item['annotations']
170
+
171
+ # Get ground truth categories
172
+ gt_categories = dataset.get_categories_in_image(annotations)
173
+ gt_yainage_categories = [
174
+ self.category_mapper.map_to_yainage90(cat)
175
+ for cat in gt_categories
176
+ ]
177
+
178
+ if not gt_yainage_categories:
179
+ continue
180
+
181
+ # Extract features
182
+ with open(image_path, 'rb') as f:
183
+ image_bytes = f.read()
184
+
185
+ feature_results = self.analyzer.extract_fashion_features(
186
+ self.analyzer.process_image_from_bytes(image_bytes)
187
+ )
188
+
189
+ if 'feature_vector' in feature_results:
190
+ features = np.array(feature_results['feature_vector'])
191
+ feature_dimensions.append(feature_results['feature_dimension'])
192
+
193
+ # Group features by category
194
+ for category in gt_yainage_categories:
195
+ if category not in features_by_category:
196
+ features_by_category[category] = []
197
+ features_by_category[category].append(features)
198
+
199
+ except Exception as e:
200
+ print(f"Error processing image {i}: {e}")
201
+ continue
202
+
203
+ # Calculate feature quality metrics
204
+ metrics = {
205
+ 'feature_dimension': np.mean(feature_dimensions) if feature_dimensions else 0,
206
+ 'categories_found': list(features_by_category.keys()),
207
+ 'samples_per_category': {
208
+ cat: len(feats) for cat, feats in features_by_category.items()
209
+ }
210
+ }
211
+
212
+ # Calculate intra-category similarity and inter-category distance
213
+ if len(features_by_category) > 1:
214
+ intra_similarities = []
215
+ inter_distances = []
216
+
217
+ categories = list(features_by_category.keys())
218
+ for i, cat1 in enumerate(categories):
219
+ cat1_features = np.array(features_by_category[cat1])
220
+
221
+ # Intra-category similarity
222
+ if len(cat1_features) > 1:
223
+ similarities = []
224
+ for j in range(len(cat1_features)):
225
+ for k in range(j+1, len(cat1_features)):
226
+ sim = np.dot(cat1_features[j], cat1_features[k])
227
+ similarities.append(sim)
228
+ intra_similarities.extend(similarities)
229
+
230
+ # Inter-category distance
231
+ for j, cat2 in enumerate(categories[i+1:], i+1):
232
+ cat2_features = np.array(features_by_category[cat2])
233
+ for feat1 in cat1_features:
234
+ for feat2 in cat2_features:
235
+ dist = np.linalg.norm(feat1 - feat2)
236
+ inter_distances.append(dist)
237
+
238
+ metrics['mean_intra_similarity'] = np.mean(intra_similarities) if intra_similarities else 0
239
+ metrics['mean_inter_distance'] = np.mean(inter_distances) if inter_distances else 0
240
+ metrics['feature_separability'] = (
241
+ metrics['mean_inter_distance'] - metrics['mean_intra_similarity']
242
+ )
243
+
244
+ self.results['feature_extraction'] = metrics
245
+ return metrics
246
+
247
+ def _calculate_classification_metrics(self, y_true: List[str],
248
+ y_pred: List[str]) -> Dict:
249
+ """Calculate classification metrics"""
250
+ if not y_true or not y_pred:
251
+ return {}
252
+
253
+ # Get unique labels
254
+ labels = list(set(y_true + y_pred))
255
+
256
+ # Calculate metrics
257
+ accuracy = accuracy_score(y_true, y_pred)
258
+ precision, recall, f1, support = precision_recall_fscore_support(
259
+ y_true, y_pred, labels=labels, average='weighted', zero_division=0
260
+ )
261
+
262
+ # Per-class metrics
263
+ precision_per_class, recall_per_class, f1_per_class, support_per_class = \
264
+ precision_recall_fscore_support(
265
+ y_true, y_pred, labels=labels, average=None, zero_division=0
266
+ )
267
+
268
+ per_class_metrics = {}
269
+ for i, label in enumerate(labels):
270
+ per_class_metrics[label] = {
271
+ 'precision': precision_per_class[i],
272
+ 'recall': recall_per_class[i],
273
+ 'f1': f1_per_class[i],
274
+ 'support': support_per_class[i]
275
+ }
276
+
277
+ return {
278
+ 'accuracy': accuracy,
279
+ 'precision': precision,
280
+ 'recall': recall,
281
+ 'f1': f1,
282
+ 'per_class_metrics': per_class_metrics,
283
+ 'confusion_matrix': confusion_matrix(y_true, y_pred, labels=labels).tolist(),
284
+ 'labels': labels
285
+ }
286
+
287
+ def generate_evaluation_report(self, output_dir: str = "./evaluation_results") -> str:
288
+ """Generate comprehensive evaluation report"""
289
+ output_path = Path(output_dir)
290
+ output_path.mkdir(exist_ok=True)
291
+
292
+ report_file = output_path / "deepfashion2_evaluation_report.json"
293
+
294
+ # Compile all results
295
+ full_report = {
296
+ 'config': {
297
+ 'dataset_root': self.config.dataset_root,
298
+ 'categories': self.config.categories,
299
+ 'image_size': self.config.image_size
300
+ },
301
+ 'results': self.results,
302
+ 'summary': self._generate_summary()
303
+ }
304
+
305
+ # Save report
306
+ with open(report_file, 'w') as f:
307
+ json.dump(full_report, f, indent=2)
308
+
309
+ print(f"Evaluation report saved to: {report_file}")
310
+ return str(report_file)
311
+
312
+ def _generate_summary(self) -> Dict:
313
+ """Generate evaluation summary"""
314
+ summary = {}
315
+
316
+ if 'detection_accuracy' in self.results:
317
+ det_results = self.results['detection_accuracy']
318
+ summary['detection'] = {
319
+ 'accuracy': det_results.get('accuracy', 0),
320
+ 'f1_score': det_results.get('f1', 0),
321
+ 'mean_detection_score': det_results.get('mean_detection_score', 0)
322
+ }
323
+
324
+ if 'feature_extraction' in self.results:
325
+ feat_results = self.results['feature_extraction']
326
+ summary['features'] = {
327
+ 'feature_dimension': feat_results.get('feature_dimension', 0),
328
+ 'categories_evaluated': len(feat_results.get('categories_found', [])),
329
+ 'feature_separability': feat_results.get('feature_separability', 0)
330
+ }
331
+
332
+ return summary
333
+
334
+ def plot_confusion_matrix(self, output_dir: str = "./evaluation_results"):
335
+ """Plot confusion matrix for detection results"""
336
+ if 'detection_accuracy' not in self.results:
337
+ print("No detection results available for plotting")
338
+ return
339
+
340
+ results = self.results['detection_accuracy']
341
+ if 'confusion_matrix' not in results:
342
+ return
343
+
344
+ cm = np.array(results['confusion_matrix'])
345
+ labels = results['labels']
346
+
347
+ plt.figure(figsize=(10, 8))
348
+ sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
349
+ xticklabels=labels, yticklabels=labels)
350
+ plt.title('Fashion Object Detection Confusion Matrix')
351
+ plt.xlabel('Predicted')
352
+ plt.ylabel('Actual')
353
+
354
+ output_path = Path(output_dir)
355
+ output_path.mkdir(exist_ok=True)
356
+ plt.savefig(output_path / 'confusion_matrix.png', dpi=300, bbox_inches='tight')
357
+ plt.close()
358
+
359
+ print(f"Confusion matrix saved to: {output_path / 'confusion_matrix.png'}")
360
+
361
+ def run_full_evaluation(analyzer, config: Optional[DeepFashion2Config] = None,
362
+ max_samples: int = 100) -> str:
363
+ """
364
+ Run full evaluation pipeline
365
+
366
+ Args:
367
+ analyzer: HuggingFaceFashionAnalyzer instance
368
+ config: DeepFashion2 configuration
369
+ max_samples: Maximum samples to evaluate
370
+
371
+ Returns:
372
+ Path to evaluation report
373
+ """
374
+ if config is None:
375
+ config = DeepFashion2Config()
376
+
377
+ evaluator = DeepFashion2Evaluator(config, analyzer)
378
+
379
+ print("Starting DeepFashion2 evaluation...")
380
+
381
+ # Run detection evaluation
382
+ try:
383
+ evaluator.evaluate_detection_accuracy(max_samples=max_samples)
384
+ print("βœ“ Detection evaluation completed")
385
+ except Exception as e:
386
+ print(f"βœ— Detection evaluation failed: {e}")
387
+
388
+ # Run feature extraction evaluation
389
+ try:
390
+ evaluator.evaluate_feature_extraction(max_samples=max_samples)
391
+ print("βœ“ Feature extraction evaluation completed")
392
+ except Exception as e:
393
+ print(f"βœ— Feature extraction evaluation failed: {e}")
394
+
395
+ # Generate report
396
+ report_path = evaluator.generate_evaluation_report()
397
+
398
+ # Plot confusion matrix
399
+ try:
400
+ evaluator.plot_confusion_matrix()
401
+ print("βœ“ Confusion matrix plotted")
402
+ except Exception as e:
403
+ print(f"βœ— Confusion matrix plotting failed: {e}")
404
+
405
+ return report_path
deepfashion2_utils.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ DeepFashion2 Dataset Integration Utilities
3
+ Provides tools for loading, processing, and using the DeepFashion2 dataset
4
+ with the Vestiq fashion analysis system.
5
+ """
6
+
7
+ import os
8
+ import json
9
+ import torch
10
+ import numpy as np
11
+ from PIL import Image
12
+ from torch.utils.data import Dataset, DataLoader
13
+ from pathlib import Path
14
+ from typing import Dict, List, Tuple, Optional, Union
15
+ import torchvision.transforms as transforms
16
+ from dataclasses import dataclass, field
17
+ import requests
18
+ import zipfile
19
+ import shutil
20
+
21
+ @dataclass
22
+ class DeepFashion2Config:
23
+ """Configuration for DeepFashion2 dataset"""
24
+ dataset_root: str = "./data/deepfashion2"
25
+ download_url: str = "https://github.com/switchablenorms/DeepFashion2/releases/download/v1.0/deepfashion2.zip"
26
+ categories: List[str] = field(default_factory=list)
27
+ image_size: Tuple[int, int] = (224, 224)
28
+ batch_size: int = 32
29
+ num_workers: int = 4
30
+
31
+ def __post_init__(self):
32
+ if not self.categories:
33
+ # DeepFashion2 13 categories
34
+ self.categories = [
35
+ 'short_sleeved_shirt', 'long_sleeved_shirt', 'short_sleeved_outwear',
36
+ 'long_sleeved_outwear', 'vest', 'sling', 'shorts', 'trousers',
37
+ 'skirt', 'short_sleeved_dress', 'long_sleeved_dress', 'vest_dress', 'sling_dress'
38
+ ]
39
+
40
+ class DeepFashion2CategoryMapper:
41
+ """Maps DeepFashion2 categories to yainage90 model categories"""
42
+
43
+ def __init__(self):
44
+ # Mapping from DeepFashion2 categories to yainage90 categories
45
+ self.df2_to_yainage90 = {
46
+ 'short_sleeved_shirt': 'top',
47
+ 'long_sleeved_shirt': 'top',
48
+ 'short_sleeved_outwear': 'outer',
49
+ 'long_sleeved_outwear': 'outer',
50
+ 'vest': 'top',
51
+ 'sling': 'top',
52
+ 'shorts': 'bottom',
53
+ 'trousers': 'bottom',
54
+ 'skirt': 'bottom',
55
+ 'short_sleeved_dress': 'dress',
56
+ 'long_sleeved_dress': 'dress',
57
+ 'vest_dress': 'dress',
58
+ 'sling_dress': 'dress'
59
+ }
60
+
61
+ # Reverse mapping
62
+ self.yainage90_to_df2 = {}
63
+ for df2_cat, yainage_cat in self.df2_to_yainage90.items():
64
+ if yainage_cat not in self.yainage90_to_df2:
65
+ self.yainage90_to_df2[yainage_cat] = []
66
+ self.yainage90_to_df2[yainage_cat].append(df2_cat)
67
+
68
+ def map_to_yainage90(self, df2_category: str) -> str:
69
+ """Map DeepFashion2 category to yainage90 category"""
70
+ return self.df2_to_yainage90.get(df2_category, 'unknown')
71
+
72
+ def map_from_yainage90(self, yainage_category: str) -> List[str]:
73
+ """Map yainage90 category to DeepFashion2 categories"""
74
+ return self.yainage90_to_df2.get(yainage_category, [])
75
+
76
+ class DeepFashion2Dataset(Dataset):
77
+ """PyTorch Dataset for DeepFashion2"""
78
+
79
+ def __init__(self,
80
+ root_dir: str,
81
+ split: str = 'train',
82
+ transform: Optional[transforms.Compose] = None,
83
+ load_annotations: bool = True):
84
+ """
85
+ Initialize DeepFashion2 dataset
86
+
87
+ Args:
88
+ root_dir: Root directory of DeepFashion2 dataset
89
+ split: Dataset split ('train', 'validation', 'test')
90
+ transform: Image transformations
91
+ load_annotations: Whether to load bounding box annotations
92
+ """
93
+ self.root_dir = Path(root_dir)
94
+ self.split = split
95
+ self.transform = transform
96
+ self.load_annotations = load_annotations
97
+ self.category_mapper = DeepFashion2CategoryMapper()
98
+
99
+ # Load dataset metadata
100
+ self.images_dir = self.root_dir / split / "image"
101
+ self.annos_dir = self.root_dir / split / "annos"
102
+
103
+ # Get all image files
104
+ self.image_files = []
105
+ if self.images_dir.exists():
106
+ self.image_files = list(self.images_dir.glob("*.jpg"))
107
+
108
+ print(f"Found {len(self.image_files)} images in {split} split")
109
+
110
+ def __len__(self):
111
+ return len(self.image_files)
112
+
113
+ def __getitem__(self, idx):
114
+ """Get dataset item"""
115
+ image_path = self.image_files[idx]
116
+ image_name = image_path.stem
117
+
118
+ # Load image
119
+ image = Image.open(image_path).convert('RGB')
120
+
121
+ # Load annotations if requested
122
+ annotations = None
123
+ if self.load_annotations:
124
+ anno_path = self.annos_dir / f"{image_name}.json"
125
+ if anno_path.exists():
126
+ with open(anno_path, 'r') as f:
127
+ annotations = json.load(f)
128
+
129
+ # Apply transforms
130
+ if self.transform:
131
+ image = self.transform(image)
132
+
133
+ return {
134
+ 'image': image,
135
+ 'image_path': str(image_path),
136
+ 'image_name': image_name,
137
+ 'annotations': annotations
138
+ }
139
+
140
+ def get_categories_in_image(self, annotations: Dict) -> List[str]:
141
+ """Extract categories from annotations"""
142
+ if not annotations or 'item' not in annotations:
143
+ return []
144
+
145
+ categories = []
146
+ for item_id, item_data in annotations['item'].items():
147
+ if 'category_name' in item_data:
148
+ categories.append(item_data['category_name'])
149
+
150
+ return list(set(categories))
151
+
152
+ class DeepFashion2Downloader:
153
+ """Download and setup DeepFashion2 dataset"""
154
+
155
+ def __init__(self, config: DeepFashion2Config):
156
+ self.config = config
157
+ self.dataset_root = Path(config.dataset_root)
158
+
159
+ def download_dataset(self, force_download: bool = False) -> bool:
160
+ """
161
+ Download DeepFashion2 dataset
162
+
163
+ Args:
164
+ force_download: Force re-download even if dataset exists
165
+
166
+ Returns:
167
+ True if successful, False otherwise
168
+ """
169
+ if self.dataset_root.exists() and not force_download:
170
+ print(f"Dataset already exists at {self.dataset_root}")
171
+ return True
172
+
173
+ print("DeepFashion2 dataset download requires manual setup.")
174
+ print("Please follow these steps:")
175
+ print("1. Visit: https://github.com/switchablenorms/DeepFashion2")
176
+ print("2. Follow the dataset download instructions")
177
+ print("3. Extract the dataset to:", self.dataset_root)
178
+ print("4. Ensure the directory structure is:")
179
+ print(" deepfashion2/")
180
+ print(" β”œβ”€β”€ train/")
181
+ print(" β”‚ β”œβ”€β”€ image/")
182
+ print(" β”‚ └── annos/")
183
+ print(" β”œβ”€β”€ validation/")
184
+ print(" β”‚ β”œβ”€β”€ image/")
185
+ print(" β”‚ └── annos/")
186
+ print(" └── test/")
187
+ print(" β”œβ”€β”€ image/")
188
+ print(" └── annos/")
189
+
190
+ return False
191
+
192
+ def verify_dataset(self) -> bool:
193
+ """Verify dataset structure"""
194
+ required_dirs = [
195
+ self.dataset_root / "train" / "image",
196
+ self.dataset_root / "train" / "annos",
197
+ self.dataset_root / "validation" / "image",
198
+ self.dataset_root / "validation" / "annos"
199
+ ]
200
+
201
+ for dir_path in required_dirs:
202
+ if not dir_path.exists():
203
+ print(f"Missing required directory: {dir_path}")
204
+ return False
205
+
206
+ print("Dataset structure verified successfully")
207
+ return True
208
+
209
+ def create_deepfashion2_transforms(image_size: Tuple[int, int] = (224, 224)) -> transforms.Compose:
210
+ """Create standard transforms for DeepFashion2 images"""
211
+ return transforms.Compose([
212
+ transforms.Resize(image_size),
213
+ transforms.ToTensor(),
214
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
215
+ ])
216
+
217
+ def create_deepfashion2_dataloader(config: DeepFashion2Config,
218
+ split: str = 'train',
219
+ shuffle: bool = True) -> DataLoader:
220
+ """Create DataLoader for DeepFashion2 dataset"""
221
+ transform = create_deepfashion2_transforms(config.image_size)
222
+
223
+ dataset = DeepFashion2Dataset(
224
+ root_dir=config.dataset_root,
225
+ split=split,
226
+ transform=transform,
227
+ load_annotations=True
228
+ )
229
+
230
+ return DataLoader(
231
+ dataset,
232
+ batch_size=config.batch_size,
233
+ shuffle=shuffle,
234
+ num_workers=config.num_workers,
235
+ pin_memory=torch.cuda.is_available()
236
+ )
237
+
238
+ def get_deepfashion2_statistics(config: DeepFashion2Config) -> Dict:
239
+ """Get statistics about the DeepFashion2 dataset"""
240
+ stats = {
241
+ 'splits': {},
242
+ 'total_images': 0,
243
+ 'categories': config.categories,
244
+ 'category_counts': {cat: 0 for cat in config.categories}
245
+ }
246
+
247
+ for split in ['train', 'validation', 'test']:
248
+ try:
249
+ dataset = DeepFashion2Dataset(
250
+ root_dir=config.dataset_root,
251
+ split=split,
252
+ transform=None,
253
+ load_annotations=True
254
+ )
255
+
256
+ split_stats = {
257
+ 'num_images': len(dataset),
258
+ 'categories_found': set()
259
+ }
260
+
261
+ # Sample a few images to get category statistics
262
+ sample_size = min(100, len(dataset))
263
+ for i in range(0, len(dataset), max(1, len(dataset) // sample_size)):
264
+ item = dataset[i]
265
+ if item['annotations']:
266
+ categories = dataset.get_categories_in_image(item['annotations'])
267
+ split_stats['categories_found'].update(categories)
268
+ for cat in categories:
269
+ if cat in stats['category_counts']:
270
+ stats['category_counts'][cat] += 1
271
+
272
+ split_stats['categories_found'] = list(split_stats['categories_found'])
273
+ stats['splits'][split] = split_stats
274
+ stats['total_images'] += split_stats['num_images']
275
+
276
+ except Exception as e:
277
+ print(f"Error processing {split} split: {e}")
278
+ stats['splits'][split] = {'error': str(e)}
279
+
280
+ return stats
fast.py CHANGED
@@ -16,6 +16,9 @@ import torchvision.transforms as v2
16
  from huggingface_hub import PyTorchModelHubMixin
17
  import numpy as np
18
  import warnings
 
 
 
19
 
20
  # Suppress specific warnings for cleaner output
21
  warnings.filterwarnings("ignore", message=".*use_fast.*")
@@ -1586,9 +1589,28 @@ class HuggingFaceFashionAnalyzer:
1586
  else:
1587
  return "Offers unique styling opportunities for specific occasions."
1588
 
 
 
 
 
 
 
 
 
 
1589
  # Initialize analyzer
1590
  analyzer = HuggingFaceFashionAnalyzer()
1591
 
 
 
 
 
 
 
 
 
 
 
1592
  # Request/Response models
1593
  class AnalysisResponse(BaseModel):
1594
  analysis: str
@@ -1617,6 +1639,7 @@ async def root():
1617
  <br>
1618
  <button onclick="analyzeImage()" style="padding: 10px 20px; margin: 10px;">Analyze Fashion (Detailed)</button>
1619
  <button onclick="analyzeStructured()" style="padding: 10px 20px; margin: 10px;">Analyze Fashion (Structured)</button>
 
1620
  <br>
1621
  <a href="/refined-prompt" target="_blank" style="color: #007bff; text-decoration: none;">View Refined Prompt Format</a>
1622
  </div>
@@ -1682,6 +1705,77 @@ async def root():
1682
  document.getElementById('analysisText').textContent = 'Error: ' + error.message;
1683
  }
1684
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1685
  </script>
1686
  </body>
1687
  </html>
@@ -1800,5 +1894,107 @@ async def health_check():
1800
  except Exception as e:
1801
  return {"status": "unhealthy", "error": str(e)}
1802
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1803
  if __name__ == "__main__":
1804
  uvicorn.run(app, host="0.0.0.0", port=7861)
 
16
  from huggingface_hub import PyTorchModelHubMixin
17
  import numpy as np
18
  import warnings
19
+ import os
20
+ import json
21
+ from pathlib import Path
22
 
23
  # Suppress specific warnings for cleaner output
24
  warnings.filterwarnings("ignore", message=".*use_fast.*")
 
1589
  else:
1590
  return "Offers unique styling opportunities for specific occasions."
1591
 
1592
+ # Import DeepFashion2 utilities
1593
+ try:
1594
+ from deepfashion2_utils import DeepFashion2Config, get_deepfashion2_statistics
1595
+ from deepfashion2_evaluation import run_full_evaluation
1596
+ DEEPFASHION2_AVAILABLE = True
1597
+ except ImportError as e:
1598
+ print(f"DeepFashion2 utilities not available: {e}")
1599
+ DEEPFASHION2_AVAILABLE = False
1600
+
1601
  # Initialize analyzer
1602
  analyzer = HuggingFaceFashionAnalyzer()
1603
 
1604
+ # Initialize DeepFashion2 configuration if available
1605
+ deepfashion2_config = None
1606
+ if DEEPFASHION2_AVAILABLE:
1607
+ try:
1608
+ deepfashion2_config = DeepFashion2Config()
1609
+ print(f"DeepFashion2 integration initialized. Dataset root: {deepfashion2_config.dataset_root}")
1610
+ except Exception as e:
1611
+ print(f"Failed to initialize DeepFashion2 config: {e}")
1612
+ DEEPFASHION2_AVAILABLE = False
1613
+
1614
  # Request/Response models
1615
  class AnalysisResponse(BaseModel):
1616
  analysis: str
 
1639
  <br>
1640
  <button onclick="analyzeImage()" style="padding: 10px 20px; margin: 10px;">Analyze Fashion (Detailed)</button>
1641
  <button onclick="analyzeStructured()" style="padding: 10px 20px; margin: 10px;">Analyze Fashion (Structured)</button>
1642
+ <button onclick="checkDeepFashion2Status()" style="padding: 10px 20px; margin: 10px; background-color: #6f42c1; color: white;">DeepFashion2 Status</button>
1643
  <br>
1644
  <a href="/refined-prompt" target="_blank" style="color: #007bff; text-decoration: none;">View Refined Prompt Format</a>
1645
  </div>
 
1705
  document.getElementById('analysisText').textContent = 'Error: ' + error.message;
1706
  }
1707
  }
1708
+
1709
+ async function checkDeepFashion2Status() {
1710
+ document.getElementById('analysisText').textContent = 'Checking DeepFashion2 status...';
1711
+ document.getElementById('result').style.display = 'block';
1712
+
1713
+ try {
1714
+ const response = await fetch('/deepfashion2/status');
1715
+ const result = await response.json();
1716
+
1717
+ let statusText = 'DeepFashion2 Integration Status:\\n\\n';
1718
+ statusText += `Available: ${result.available}\\n`;
1719
+
1720
+ if (result.available) {
1721
+ statusText += `Dataset Exists: ${result.dataset_exists}\\n`;
1722
+ statusText += `Dataset Root: ${result.dataset_root}\\n`;
1723
+ statusText += `Categories: ${result.categories.length} categories\\n`;
1724
+ statusText += `Image Size: ${result.image_size[0]}x${result.image_size[1]}\\n\\n`;
1725
+
1726
+ if (!result.dataset_exists) {
1727
+ statusText += 'Dataset not found. Click "Setup Instructions" for download guide.\\n';
1728
+ } else {
1729
+ statusText += 'Dataset ready! You can run evaluations.\\n';
1730
+ }
1731
+ } else {
1732
+ statusText += `Message: ${result.message}\\n`;
1733
+ }
1734
+
1735
+ document.getElementById('analysisText').textContent = statusText;
1736
+
1737
+ // Add setup instructions button if needed
1738
+ if (result.available && !result.dataset_exists) {
1739
+ const setupBtn = document.createElement('button');
1740
+ setupBtn.textContent = 'Get Setup Instructions';
1741
+ setupBtn.onclick = getSetupInstructions;
1742
+ setupBtn.style.cssText = 'padding: 10px 20px; margin: 10px; background-color: #17a2b8; color: white;';
1743
+ document.getElementById('result').appendChild(setupBtn);
1744
+ }
1745
+
1746
+ } catch (error) {
1747
+ document.getElementById('analysisText').textContent = 'Error checking status: ' + error.message;
1748
+ }
1749
+ }
1750
+
1751
+ async function getSetupInstructions() {
1752
+ try {
1753
+ const response = await fetch('/deepfashion2/setup-instructions');
1754
+ const result = await response.json();
1755
+
1756
+ let instructionsText = result.title + '\\n\\n';
1757
+
1758
+ result.steps.forEach(step => {
1759
+ instructionsText += `Step ${step.step}: ${step.description}\\n`;
1760
+ if (step.url) instructionsText += `URL: ${step.url}\\n`;
1761
+ if (step.command) instructionsText += `Command: ${step.command}\\n`;
1762
+ if (step.structure) {
1763
+ instructionsText += 'Structure:\\n';
1764
+ step.structure.forEach(line => instructionsText += ` ${line}\\n`);
1765
+ }
1766
+ if (step.endpoint) instructionsText += `Endpoint: ${step.endpoint}\\n`;
1767
+ instructionsText += '\\n';
1768
+ });
1769
+
1770
+ instructionsText += 'Notes:\\n';
1771
+ result.notes.forEach(note => instructionsText += `β€’ ${note}\\n`);
1772
+
1773
+ document.getElementById('analysisText').textContent = instructionsText;
1774
+
1775
+ } catch (error) {
1776
+ document.getElementById('analysisText').textContent = 'Error getting instructions: ' + error.message;
1777
+ }
1778
+ }
1779
  </script>
1780
  </body>
1781
  </html>
 
1894
  except Exception as e:
1895
  return {"status": "unhealthy", "error": str(e)}
1896
 
1897
+ # DeepFashion2 API endpoints
1898
+ @app.get("/deepfashion2/status")
1899
+ async def deepfashion2_status():
1900
+ """Get DeepFashion2 integration status"""
1901
+ if not DEEPFASHION2_AVAILABLE:
1902
+ return {"available": False, "message": "DeepFashion2 utilities not available"}
1903
+
1904
+ if not deepfashion2_config:
1905
+ return {"available": False, "message": "DeepFashion2 configuration not initialized"}
1906
+
1907
+ # Check if dataset exists
1908
+ dataset_path = Path(deepfashion2_config.dataset_root)
1909
+ dataset_exists = dataset_path.exists()
1910
+
1911
+ return {
1912
+ "available": True,
1913
+ "dataset_exists": dataset_exists,
1914
+ "dataset_root": deepfashion2_config.dataset_root,
1915
+ "categories": deepfashion2_config.categories,
1916
+ "image_size": deepfashion2_config.image_size
1917
+ }
1918
+
1919
+ @app.get("/deepfashion2/statistics")
1920
+ async def deepfashion2_statistics():
1921
+ """Get DeepFashion2 dataset statistics"""
1922
+ if not DEEPFASHION2_AVAILABLE or not deepfashion2_config:
1923
+ raise HTTPException(status_code=503, detail="DeepFashion2 not available")
1924
+
1925
+ try:
1926
+ stats = get_deepfashion2_statistics(deepfashion2_config)
1927
+ return stats
1928
+ except Exception as e:
1929
+ raise HTTPException(status_code=500, detail=f"Error getting statistics: {str(e)}")
1930
+
1931
+ @app.post("/deepfashion2/evaluate")
1932
+ async def deepfashion2_evaluate(max_samples: int = 50):
1933
+ """Run evaluation using DeepFashion2 dataset"""
1934
+ if not DEEPFASHION2_AVAILABLE or not deepfashion2_config:
1935
+ raise HTTPException(status_code=503, detail="DeepFashion2 not available")
1936
+
1937
+ try:
1938
+ # Run evaluation in background (for demo purposes, limit samples)
1939
+ report_path = run_full_evaluation(analyzer, deepfashion2_config, max_samples=max_samples)
1940
+
1941
+ return {
1942
+ "status": "completed",
1943
+ "report_path": report_path,
1944
+ "max_samples": max_samples,
1945
+ "message": f"Evaluation completed with {max_samples} samples"
1946
+ }
1947
+ except Exception as e:
1948
+ raise HTTPException(status_code=500, detail=f"Evaluation failed: {str(e)}")
1949
+
1950
+ @app.get("/deepfashion2/setup-instructions")
1951
+ async def deepfashion2_setup_instructions():
1952
+ """Get setup instructions for DeepFashion2 dataset"""
1953
+ return {
1954
+ "title": "DeepFashion2 Dataset Setup Instructions",
1955
+ "steps": [
1956
+ {
1957
+ "step": 1,
1958
+ "description": "Visit the official DeepFashion2 repository",
1959
+ "url": "https://github.com/switchablenorms/DeepFashion2"
1960
+ },
1961
+ {
1962
+ "step": 2,
1963
+ "description": "Follow the dataset download instructions in the repository"
1964
+ },
1965
+ {
1966
+ "step": 3,
1967
+ "description": "Create the dataset directory",
1968
+ "command": f"mkdir -p {deepfashion2_config.dataset_root if deepfashion2_config else './data/deepfashion2'}"
1969
+ },
1970
+ {
1971
+ "step": 4,
1972
+ "description": "Extract the dataset with the following structure:",
1973
+ "structure": [
1974
+ "deepfashion2/",
1975
+ "β”œβ”€β”€ train/",
1976
+ "β”‚ β”œβ”€β”€ image/",
1977
+ "β”‚ └── annos/",
1978
+ "β”œβ”€β”€ validation/",
1979
+ "β”‚ β”œβ”€β”€ image/",
1980
+ "β”‚ └── annos/",
1981
+ "└── test/",
1982
+ " β”œβ”€β”€ image/",
1983
+ " └── annos/"
1984
+ ]
1985
+ },
1986
+ {
1987
+ "step": 5,
1988
+ "description": "Verify the setup by checking the status endpoint",
1989
+ "endpoint": "/deepfashion2/status"
1990
+ }
1991
+ ],
1992
+ "notes": [
1993
+ "The DeepFashion2 dataset is large (~15GB) and requires registration",
1994
+ "Make sure you have sufficient disk space",
1995
+ "The dataset contains 491K images across 13 clothing categories"
1996
+ ]
1997
+ }
1998
+
1999
  if __name__ == "__main__":
2000
  uvicorn.run(app, host="0.0.0.0", port=7861)
requirements.txt CHANGED
@@ -54,3 +54,6 @@ triton==3.3.1
54
  typing_extensions==4.14.0
55
  urllib3==2.5.0
56
  uvicorn==0.24.0
 
 
 
 
54
  typing_extensions==4.14.0
55
  urllib3==2.5.0
56
  uvicorn==0.24.0
57
+ scikit-learn==1.5.2
58
+ matplotlib==3.9.3
59
+ seaborn==0.13.2