alezsd commited on
Commit
adeb68b
·
1 Parent(s): 086dc61

Add application file

Browse files
Files changed (3) hide show
  1. best_caligrafia_model.pth +3 -0
  2. predictor.py +106 -0
  3. requirements.txt +4 -0
best_caligrafia_model.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6330ce56680a58105963cd292c1ebc3b3777cb5c3ee4180eb41d8f96d88a6eb6
3
+ size 75112706
predictor.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ PREDICTOR Caligrafía CRNN - SOLO PREDICCIONES
4
+ Carga best_caligrafia_model.pth → predict(imagen.png)
5
+ Optimizado Mac Intel i9 + AMD GPU
6
+ """
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torchvision.transforms as transforms
11
+ from PIL import Image
12
+ import platform
13
+ from pathlib import Path
14
+
15
+ # Detectar device (tu lógica original)
16
+ IS_APPLE_SILICON = platform.machine() == 'arm64'
17
+ def get_device():
18
+ if platform.machine() == 'arm64':
19
+ return torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
20
+ return torch.device('cpu') # PyTorch usa AMD automáticamente
21
+
22
+ device = get_device()
23
+
24
+ # Tu modelo CRNN (copiado exacto)
25
+ class CaligrafiaCRNN(nn.Module):
26
+ def __init__(self, num_classes=7):
27
+ super().__init__()
28
+ self.cnn = nn.Sequential(
29
+ nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(),
30
+ nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(),
31
+ nn.MaxPool2d(2, 2),
32
+ nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
33
+ nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(),
34
+ nn.MaxPool2d(2, 2),
35
+ nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(),
36
+ nn.Conv2d(128, 128, 3, padding=1), nn.ReLU(),
37
+ nn.AdaptiveAvgPool2d((4, 16)),
38
+ nn.Dropout2d(0.25)
39
+ )
40
+ self.lstm = nn.LSTM(8192, 256, bidirectional=True, batch_first=True, dropout=0.3)
41
+ self.attention = nn.MultiheadAttention(512, 8, batch_first=True)
42
+ self.classifier = nn.Sequential(
43
+ nn.Linear(512, 256), nn.ReLU(), nn.Dropout(0.5),
44
+ nn.Linear(256, num_classes)
45
+ )
46
+
47
+ def forward(self, x):
48
+ features = self.cnn(x)
49
+ B, C, H, W = features.shape
50
+ features = features.permute(0, 3, 1, 2).reshape(B, W, C*H)
51
+ lstm_out, _ = self.lstm(features)
52
+ attn_out, _ = self.attention(lstm_out, lstm_out, lstm_out)
53
+ pooled = attn_out.mean(dim=1)
54
+ return self.classifier(pooled)
55
+
56
+ # PREDICTOR (tu clase simplificada)
57
+ class CaligrafiaPredictor:
58
+ def __init__(self, model_path="best_caligrafia_model.pth"):
59
+ self.device = get_device()
60
+ self.model = CaligrafiaCRNN().to(self.device)
61
+ self.model.load_state_dict(torch.load(model_path, map_location=self.device))
62
+ self.model.eval()
63
+
64
+ self.transform = transforms.Compose([
65
+ transforms.Resize((64, 256)),
66
+ transforms.Grayscale(num_output_channels=1),
67
+ transforms.ToTensor(),
68
+ transforms.Normalize((0.5,), (0.5,))
69
+ ])
70
+
71
+ # Detecta clases reales del dataset
72
+ dataset_path = Path('dataset/train')
73
+ if dataset_path.exists():
74
+ self.clases = sorted([d.name for d in dataset_path.iterdir() if d.is_dir()])
75
+ else:
76
+ self.clases = [f'caligrafia_{i}' for i in range(7)]
77
+ print(f"🏷️ Clases: {self.clases}")
78
+
79
+ def predict(self, image_path):
80
+ image = Image.open(image_path).convert('RGB')
81
+ image = self.transform(image).unsqueeze(0).to(self.device)
82
+
83
+ with torch.no_grad():
84
+ logits = self.model(image)
85
+ probs = torch.softmax(logits, dim=1)
86
+ pred_class = probs.argmax(dim=1).cpu().item()
87
+ confidence = probs[0, pred_class].cpu().item()
88
+
89
+ return {
90
+ "caligrafia": self.clases[pred_class],
91
+ "confidence": float(confidence),
92
+ "probs": probs[0].cpu().tolist()
93
+ }
94
+
95
+ # USO DIRECTO
96
+ if __name__ == "__main__":
97
+ predictor = CaligrafiaPredictor("best_caligrafia_model.pth")
98
+
99
+ # Predice cualquier imagen PNG/JPG
100
+ imagen = "mi_caligrafia.png" # ← CAMBIA ESTA LÍNEA
101
+ resultado = predictor.predict(imagen)
102
+
103
+ print("🎯 RESULTADO:")
104
+ print(f"📝 Clase: {resultado['caligrafia']}")
105
+ print(f"✅ Confianza: {resultado['confidence']:.1%}")
106
+ print(f"📊 Todas probs: {resultado['probs']}")
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ gradio
4
+ pillow