Spaces:
Sleeping
Sleeping
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 +243 -0
- deepfashion2_evaluation.py +405 -0
- deepfashion2_utils.py +280 -0
- fast.py +196 -0
- requirements.txt +3 -0
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
|