dkrak737 commited on
Commit
2720e2f
Β·
verified Β·
1 Parent(s): 6ad07ed

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -0
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ── Gradio μ„€μΉ˜ ──────────────────────────
2
+ !pip install gradio -q
3
+
4
+ import gradio as gr
5
+ import torch
6
+ import torch.nn as nn
7
+ import torchvision.transforms as transforms
8
+ from PIL import Image
9
+ from datasets import load_dataset
10
+
11
+ # ── 클래슀 이름 κ°€μ Έμ˜€κΈ° ──────────────────
12
+ dataset = load_dataset("food101", split="train[:1%]")
13
+ class_names = dataset.features['label'].names
14
+
15
+ # ── λͺ¨λΈ μ •μ˜ (λ˜‘κ°™μ΄ λΆ™μ—¬λ„£κΈ°) ───────────
16
+ class BottleneckBlock(nn.Module):
17
+ expansion = 4
18
+
19
+ def __init__(self, in_channels, mid_channels, stride=1):
20
+ super().__init__()
21
+ self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, bias=False)
22
+ self.bn1 = nn.BatchNorm2d(mid_channels)
23
+ self.conv2 = nn.Conv2d(mid_channels, mid_channels, kernel_size=3,
24
+ stride=stride, padding=1, bias=False)
25
+ self.bn2 = nn.BatchNorm2d(mid_channels)
26
+ self.conv3 = nn.Conv2d(mid_channels, mid_channels * self.expansion,
27
+ kernel_size=1, bias=False)
28
+ self.bn3 = nn.BatchNorm2d(mid_channels * self.expansion)
29
+ self.relu = nn.ReLU(inplace=True)
30
+ self.shortcut = nn.Sequential()
31
+ if stride != 1 or in_channels != mid_channels * self.expansion:
32
+ self.shortcut = nn.Sequential(
33
+ nn.Conv2d(in_channels, mid_channels * self.expansion,
34
+ kernel_size=1, stride=stride, bias=False),
35
+ nn.BatchNorm2d(mid_channels * self.expansion)
36
+ )
37
+
38
+ def forward(self, x):
39
+ identity = x
40
+ out = self.relu(self.bn1(self.conv1(x)))
41
+ out = self.relu(self.bn2(self.conv2(out)))
42
+ out = self.bn3(self.conv3(out))
43
+ out += self.shortcut(identity)
44
+ out = self.relu(out)
45
+ return out
46
+
47
+ class ResNet50(nn.Module):
48
+ def __init__(self, num_classes=101):
49
+ super().__init__()
50
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
51
+ self.bn1 = nn.BatchNorm2d(64)
52
+ self.relu = nn.ReLU(inplace=True)
53
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
54
+ self.layer1 = self._make_layer( 64, 64, blocks=3, stride=1)
55
+ self.layer2 = self._make_layer(256, 128, blocks=4, stride=2)
56
+ self.layer3 = self._make_layer(512, 256, blocks=6, stride=2)
57
+ self.layer4 = self._make_layer(1024, 512, blocks=3, stride=2)
58
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
59
+ self.fc = nn.Linear(2048, num_classes)
60
+
61
+ def _make_layer(self, in_channels, mid_channels, blocks, stride):
62
+ layers = [BottleneckBlock(in_channels, mid_channels, stride=stride)]
63
+ for _ in range(1, blocks):
64
+ layers.append(BottleneckBlock(mid_channels * 4, mid_channels))
65
+ return nn.Sequential(*layers)
66
+
67
+ def forward(self, x):
68
+ x = self.maxpool(self.relu(self.bn1(self.conv1(x))))
69
+ x = self.layer1(x)
70
+ x = self.layer2(x)
71
+ x = self.layer3(x)
72
+ x = self.layer4(x)
73
+ x = self.avgpool(x)
74
+ x = torch.flatten(x, 1)
75
+ x = self.fc(x)
76
+ return x
77
+
78
+ # ── λͺ¨λΈ 뢈러였기 ─────────────────────────
79
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
80
+
81
+ model = ResNet50(num_classes=101)
82
+ model.load_state_dict(
83
+ torch.load('resnet50_food101.pth', map_location=device)
84
+ )
85
+ model = model.to(device)
86
+ model.eval()
87
+
88
+ # ── μ „μ²˜λ¦¬ ────────────────────────────────
89
+ transform = transforms.Compose([
90
+ transforms.Resize((224, 224)),
91
+ transforms.ToTensor(),
92
+ transforms.Normalize(
93
+ mean=[0.485, 0.456, 0.406],
94
+ std=[0.229, 0.224, 0.225]
95
+ )
96
+ ])
97
+
98
+ # ── 예츑 ν•¨μˆ˜ ─────────────────────────────
99
+ def predict(image):
100
+ # PIL 이미지 β†’ ν…μ„œ λ³€ν™˜
101
+ img_tensor = transform(image).unsqueeze(0).to(device)
102
+ # unsqueeze(0) = (3,224,224) β†’ (1,3,224,224) 배치 차원 μΆ”κ°€
103
+
104
+ with torch.no_grad():
105
+ output = model(img_tensor)
106
+ probs = torch.softmax(output, dim=1) # 점수 β†’ ν™•λ₯ 
107
+ top5 = probs.topk(5) # μƒμœ„ 5개
108
+
109
+ # κ²°κ³Ό λ”•μ…”λ„ˆλ¦¬λ‘œ λ°˜ν™˜
110
+ result = {}
111
+ for i in range(5):
112
+ label = class_names[top5.indices[0][i].item()]
113
+ prob = top5.values[0][i].item()
114
+ result[label] = prob
115
+
116
+ return result
117
+
118
+ # ── Gradio μΈν„°νŽ˜μ΄μŠ€ ──────────────────────
119
+ demo = gr.Interface(
120
+ fn=predict, # 예츑 ν•¨μˆ˜
121
+ inputs=gr.Image(type="pil"), # μž…λ ₯: 이미지
122
+ outputs=gr.Label(num_top_classes=5), # 좜λ ₯: μƒμœ„ 5개 클래슀
123
+ title="πŸ” Food-101 λΆ„λ₯˜κΈ°",
124
+ description="μŒμ‹ 사진��� 올리면 μ–΄λ–€ μŒμ‹μΈμ§€ λ§žμΆ°μ€˜μš”! (101κ°€μ§€ μŒμ‹ λΆ„λ₯˜)",
125
+ examples=[], # μ˜ˆμ‹œ 이미지 (있으면 μΆ”κ°€)
126
+ )
127
+
128
+ demo.launch()