fxxkingusername's picture
Upload src/cli.py with huggingface_hub
3406633 verified
#!/usr/bin/env python3
"""
Command Line Interface for Architectural Style Classifier
"""
import argparse
import sys
import os
from pathlib import Path
import torch
from PIL import Image
import json
# Add the src directory to the path
sys.path.append(str(Path(__file__).parent))
from models.simple_advanced_classifier import SimpleAdvancedClassifier
from training.data_loader import ArchitecturalDataset
def load_model(checkpoint_path: str = None):
"""Load the trained EfficientNet-B0 model."""
model = SimpleAdvancedClassifier(num_classes=25)
if checkpoint_path and os.path.exists(checkpoint_path):
checkpoint = torch.load(checkpoint_path, map_location='cpu')
if 'state_dict' in checkpoint:
state_dict = checkpoint['state_dict']
# Remove 'model.' prefix if present
new_state_dict = {}
for key, value in state_dict.items():
if key.startswith('model.'):
new_key = key[6:] # Remove 'model.' prefix
else:
new_key = key
new_state_dict[new_key] = value
model.load_state_dict(new_state_dict, strict=False)
else:
model.load_state_dict(checkpoint, strict=False)
else:
print("Warning: No checkpoint found, using untrained model")
model.eval()
return model
def predict_image(model, image_path: str, style_mapping: dict = None):
"""Predict architectural style for a single image."""
from torchvision import transforms
# Load and preprocess image
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
try:
image = Image.open(image_path).convert('RGB')
input_tensor = transform(image).unsqueeze(0)
with torch.no_grad():
outputs = model(input_tensor)
probabilities = torch.softmax(outputs, dim=1)
predicted_class = torch.argmax(probabilities, dim=1).item()
confidence = probabilities[0][predicted_class].item()
# Get top 3 predictions
top3_probs, top3_indices = torch.topk(probabilities[0], 3)
results = {
'predicted_class': predicted_class,
'confidence': confidence,
'style_name': style_mapping.get(str(predicted_class), f"Style_{predicted_class}") if style_mapping else f"Style_{predicted_class}",
'top3_predictions': [
{
'class': idx.item(),
'confidence': prob.item(),
'style_name': style_mapping.get(str(idx.item()), f"Style_{idx.item()}") if style_mapping else f"Style_{idx.item()}"
}
for idx, prob in zip(top3_indices, top3_probs)
]
}
return results
except Exception as e:
print(f"Error processing image {image_path}: {e}")
return None
def load_style_mapping(mapping_path: str = None):
"""Load architectural style mapping."""
if mapping_path and os.path.exists(mapping_path):
with open(mapping_path, 'r') as f:
return json.load(f)
return {str(i): f"Style_{i}" for i in range(25)}
def main():
parser = argparse.ArgumentParser(
description="Architectural Style Classifier - EfficientNet-B0 Model",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Predict single image
architectural-classifier predict image.jpg
# Predict with custom checkpoint
architectural-classifier predict image.jpg --checkpoint checkpoints/best_model/model.ckpt
# Predict with style mapping
architectural-classifier predict image.jpg --style-mapping data/style_mapping.json
# Batch prediction
architectural-classifier predict-batch images_folder/
# Show model info
architectural-classifier info
"""
)
subparsers = parser.add_subparsers(dest='command', help='Available commands')
# Predict command
predict_parser = subparsers.add_parser('predict', help='Predict architectural style for a single image')
predict_parser.add_argument('image_path', help='Path to the image file')
predict_parser.add_argument('--checkpoint', default='checkpoints/best_model/efficientnet_b0-epoch=04-val_acc=0.997.ckpt',
help='Path to model checkpoint')
predict_parser.add_argument('--style-mapping', help='Path to style mapping JSON file')
predict_parser.add_argument('--output', help='Output file for results (JSON)')
# Batch predict command
batch_parser = subparsers.add_parser('predict-batch', help='Predict architectural styles for multiple images')
batch_parser.add_argument('folder_path', help='Path to folder containing images')
batch_parser.add_argument('--checkpoint', default='checkpoints/best_model/efficientnet_b0-epoch=04-val_acc=0.997.ckpt',
help='Path to model checkpoint')
batch_parser.add_argument('--style-mapping', help='Path to style mapping JSON file')
batch_parser.add_argument('--output', help='Output file for results (JSON)')
batch_parser.add_argument('--extensions', nargs='+', default=['.jpg', '.jpeg', '.png', '.bmp'],
help='Image file extensions to process')
# Info command
info_parser = subparsers.add_parser('info', help='Show model information')
args = parser.parse_args()
if not args.command:
parser.print_help()
return
# Load style mapping
style_mapping = load_style_mapping(args.style_mapping)
if args.command == 'predict':
# Load model
model = load_model(args.checkpoint)
# Predict
results = predict_image(model, args.image_path, style_mapping)
if results:
print(f"\n🏛️ Architectural Style Classification Results")
print(f"=" * 50)
print(f"Image: {args.image_path}")
print(f"Predicted Style: {results['style_name']}")
print(f"Confidence: {results['confidence']:.3f} ({results['confidence']*100:.1f}%)")
print(f"\nTop 3 Predictions:")
for i, pred in enumerate(results['top3_predictions'], 1):
print(f" {i}. {pred['style_name']}: {pred['confidence']:.3f} ({pred['confidence']*100:.1f}%)")
if args.output:
with open(args.output, 'w') as f:
json.dump(results, f, indent=2)
print(f"\nResults saved to: {args.output}")
elif args.command == 'predict-batch':
# Load model
model = load_model(args.checkpoint)
# Find images
folder_path = Path(args.folder_path)
image_files = []
for ext in args.extensions:
image_files.extend(folder_path.glob(f"*{ext}"))
image_files.extend(folder_path.glob(f"*{ext.upper()}"))
if not image_files:
print(f"No images found in {args.folder_path}")
return
print(f"Found {len(image_files)} images to process...")
# Process images
results = []
for i, image_path in enumerate(image_files, 1):
print(f"Processing {i}/{len(image_files)}: {image_path.name}")
result = predict_image(model, str(image_path), style_mapping)
if result:
result['image_path'] = str(image_path)
result['image_name'] = image_path.name
results.append(result)
# Save results
if args.output:
with open(args.output, 'w') as f:
json.dump(results, f, indent=2)
print(f"\nBatch results saved to: {args.output}")
# Print summary
print(f"\n📊 Batch Processing Summary")
print(f"=" * 50)
print(f"Total images processed: {len(results)}")
print(f"Successfully classified: {len(results)}")
# Show top predictions
if results:
print(f"\nTop predicted styles:")
style_counts = {}
for result in results:
style = result['style_name']
style_counts[style] = style_counts.get(style, 0) + 1
for style, count in sorted(style_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
print(f" {style}: {count} images")
elif args.command == 'info':
print(f"🏛️ Architectural Style Classifier - Model Information")
print(f"=" * 60)
print(f"Model: EfficientNet-B0")
print(f"Architecture: SimpleAdvancedClassifier")
print(f"Number of Classes: 25")
print(f"Input Size: 224x224")
print(f"Parameters: ~5.3M")
print(f"Validation Accuracy: 99.7%")
print(f"Test Accuracy: 100%")
print(f"Training Time: ~2 minutes")
print(f"Framework: PyTorch + PyTorch Lightning")
print(f"Pre-trained: ImageNet")
print(f"Transfer Learning: Yes")
print(f"\nKey Features:")
print(f" • Lightweight and efficient")
print(f" • High accuracy with minimal parameters")
print(f" • Perfect classification on test set")
print(f" • Suitable for real-world deployment")
print(f" • Heritage preservation applications")
print(f"\nUsage:")
print(f" architectural-classifier predict <image_path>")
print(f" architectural-classifier predict-batch <folder_path>")
print(f" architectural-classifier info")
if __name__ == "__main__":
main()