prshanthreddy commited on
Commit
cbf524d
·
1 Parent(s): aa2261b

Add initial project setup with requirements, README updates, and image classification functionality

Browse files
.gitattributes CHANGED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  title: Clothing1m
3
  emoji: 🚀
4
- colorFrom: red
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.20.0
8
  app_file: app.py
 
1
  ---
2
  title: Clothing1m
3
  emoji: 🚀
4
+ colorFrom: purple
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 5.20.0
8
  app_file: app.py
examples/325.jpg ADDED
examples/48.jpg ADDED
examples/59.jpg ADDED
examples/83.jpg ADDED
examples/97.jpg ADDED
model/__pycache__/cifar_resnet.cpython-311.pyc ADDED
Binary file (8.86 kB). View file
 
model/__pycache__/cifar_resnet.cpython-312.pyc ADDED
Binary file (8.2 kB). View file
 
model/__pycache__/imagenet_resnet.cpython-311.pyc ADDED
Binary file (12.4 kB). View file
 
model/__pycache__/imagenet_resnet.cpython-312.pyc ADDED
Binary file (11.3 kB). View file
 
model/__pycache__/model.cpython-311.pyc ADDED
Binary file (6.18 kB). View file
 
model/__pycache__/model.cpython-312.pyc ADDED
Binary file (5.27 kB). View file
 
model/cifar_resnet.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """resnet in pytorch
2
+ [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun.
3
+ Deep Residual Learning for Image Recognition
4
+ https://arxiv.org/abs/1512.03385v1
5
+ """
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+
10
+
11
+ class BasicBlock(nn.Module):
12
+ """Basic Block for resnet 18 and resnet 34
13
+ """
14
+
15
+ #BasicBlock and BottleNeck block
16
+ #have different output size
17
+ #we use class attribute expansion
18
+ #to distinct
19
+ expansion = 1
20
+
21
+ def __init__(self, in_channels, out_channels, stride=1):
22
+ super().__init__()
23
+
24
+ #residual function
25
+ self.residual_function = nn.Sequential(
26
+ nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False),
27
+ nn.BatchNorm2d(out_channels),
28
+ nn.ReLU(inplace=True),
29
+ nn.Conv2d(out_channels, out_channels * BasicBlock.expansion, kernel_size=3, padding=1, bias=False),
30
+ nn.BatchNorm2d(out_channels * BasicBlock.expansion)
31
+ )
32
+
33
+ #shortcut
34
+ self.shortcut = nn.Sequential()
35
+
36
+ #the shortcut output dimension is not the same with residual function
37
+ #use 1*1 convolution to match the dimension
38
+ if stride != 1 or in_channels != BasicBlock.expansion * out_channels:
39
+ self.shortcut = nn.Sequential(
40
+ nn.Conv2d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=stride, bias=False),
41
+ nn.BatchNorm2d(out_channels * BasicBlock.expansion)
42
+ )
43
+
44
+ def forward(self, x):
45
+ return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x))
46
+
47
+
48
+ class BottleNeck(nn.Module):
49
+ """Residual block for resnet over 50 layers
50
+ """
51
+ expansion = 4
52
+ def __init__(self, in_channels, out_channels, stride=1):
53
+ super().__init__()
54
+ self.residual_function = nn.Sequential(
55
+ nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False),
56
+ nn.BatchNorm2d(out_channels),
57
+ nn.ReLU(inplace=True),
58
+ nn.Conv2d(out_channels, out_channels, stride=stride, kernel_size=3, padding=1, bias=False),
59
+ nn.BatchNorm2d(out_channels),
60
+ nn.ReLU(inplace=True),
61
+ nn.Conv2d(out_channels, out_channels * BottleNeck.expansion, kernel_size=1, bias=False),
62
+ nn.BatchNorm2d(out_channels * BottleNeck.expansion),
63
+ )
64
+
65
+ self.shortcut = nn.Sequential()
66
+
67
+ if stride != 1 or in_channels != out_channels * BottleNeck.expansion:
68
+ self.shortcut = nn.Sequential(
69
+ nn.Conv2d(in_channels, out_channels * BottleNeck.expansion, stride=stride, kernel_size=1, bias=False),
70
+ nn.BatchNorm2d(out_channels * BottleNeck.expansion)
71
+ )
72
+
73
+ def forward(self, x):
74
+ return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x))
75
+
76
+
77
+ class ResNet(nn.Module):
78
+
79
+ def __init__(self, block, num_block, num_classes=100):
80
+ super().__init__()
81
+
82
+ self.in_channels = 64
83
+
84
+ self.conv1 = nn.Sequential(
85
+ nn.Conv2d(3, 64, kernel_size=3, padding=1, bias=False),
86
+ nn.BatchNorm2d(64),
87
+ nn.ReLU(inplace=True))
88
+ #we use a different inputsize than the original paper
89
+ #so conv2_x's stride is 1
90
+ self.conv2_x = self._make_layer(block, 64, num_block[0], 1)
91
+ self.conv3_x = self._make_layer(block, 128, num_block[1], 2)
92
+ self.conv4_x = self._make_layer(block, 256, num_block[2], 2)
93
+ self.conv5_x = self._make_layer(block, 512, num_block[3], 2)
94
+ self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
95
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
96
+
97
+ def _make_layer(self, block, out_channels, num_blocks, stride):
98
+ """make resnet layers(by layer i didnt mean this 'layer' was the
99
+ same as a neuron netowork layer, ex. conv layer), one layer may
100
+ contain more than one residual block
101
+ Args:
102
+ block: block type, basic block or bottle neck block
103
+ out_channels: output depth channel number of this layer
104
+ num_blocks: how many blocks per layer
105
+ stride: the stride of the first block of this layer
106
+
107
+ Return:
108
+ return a resnet layer
109
+ """
110
+
111
+ # we have num_block blocks per layer, the first block
112
+ # could be 1 or 2, other blocks would always be 1
113
+ strides = [stride] + [1] * (num_blocks - 1)
114
+ layers = []
115
+ for stride in strides:
116
+ layers.append(block(self.in_channels, out_channels, stride))
117
+ self.in_channels = out_channels * block.expansion
118
+
119
+ return nn.Sequential(*layers)
120
+
121
+ def forward(self, x):
122
+ output = self.conv1(x)
123
+ output = self.conv2_x(output)
124
+ output = self.conv3_x(output)
125
+ output = self.conv4_x(output)
126
+ output = self.conv5_x(output)
127
+ output = self.avg_pool(output)
128
+ output = output.view(output.size(0), -1)
129
+ output = self.fc(output)
130
+
131
+ return output
132
+
133
+
134
+ def resnet18():
135
+ """ return a ResNet 18 object
136
+ """
137
+ return ResNet(BasicBlock, [2, 2, 2, 2])
138
+
139
+
140
+ def resnet34():
141
+ """ return a ResNet 34 object
142
+ """
143
+ return ResNet(BasicBlock, [3, 4, 6, 3])
144
+
145
+
146
+ def resnet50():
147
+ """ return a ResNet 50 object
148
+ """
149
+ return ResNet(BottleNeck, [3, 4, 6, 3])
150
+
151
+
152
+ def resnet101():
153
+ """ return a ResNet 101 object
154
+ """
155
+ return ResNet(BottleNeck, [3, 4, 23, 3])
156
+
157
+
158
+ def resnet152():
159
+ """ return a ResNet 152 object
160
+ """
161
+ return ResNet(BottleNeck, [3, 8, 36, 3])
model/imagenet_resnet.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ import numpy as np
5
+
6
+ from torch.autograd import Variable
7
+
8
+ import math
9
+ import torch.utils.model_zoo as model_zoo
10
+
11
+
12
+ __all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
13
+ 'resnet152']
14
+
15
+
16
+ model_urls = {
17
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
18
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
19
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
20
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
21
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
22
+ }
23
+
24
+
25
+ def conv3x3(in_planes, out_planes, stride=1):
26
+ """3x3 convolution with padding"""
27
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
28
+ padding=1, bias=False)
29
+
30
+
31
+ class BasicBlock(nn.Module):
32
+ expansion = 1
33
+
34
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
35
+ super(BasicBlock, self).__init__()
36
+ self.conv1 = conv3x3(inplanes, planes, stride)
37
+ self.bn1 = nn.BatchNorm2d(planes)
38
+ self.relu = nn.ReLU(inplace=True)
39
+ self.conv2 = conv3x3(planes, planes)
40
+ self.bn2 = nn.BatchNorm2d(planes)
41
+ self.downsample = downsample
42
+ self.stride = stride
43
+
44
+ def forward(self, x):
45
+ residual = x
46
+
47
+ out = self.conv1(x)
48
+ out = self.bn1(out)
49
+ out = self.relu(out)
50
+
51
+ out = self.conv2(out)
52
+ out = self.bn2(out)
53
+
54
+ if self.downsample is not None:
55
+ residual = self.downsample(x)
56
+
57
+ out += residual
58
+ out = self.relu(out)
59
+
60
+ return out
61
+
62
+
63
+ class Bottleneck(nn.Module):
64
+ expansion = 4
65
+
66
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
67
+ super(Bottleneck, self).__init__()
68
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
69
+ self.bn1 = nn.BatchNorm2d(planes)
70
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
71
+ padding=1, bias=False)
72
+ self.bn2 = nn.BatchNorm2d(planes)
73
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
74
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
75
+ self.relu = nn.ReLU(inplace=True)
76
+ self.downsample = downsample
77
+ self.stride = stride
78
+
79
+ def forward(self, x):
80
+ residual = x
81
+
82
+ out = self.conv1(x)
83
+ out = self.bn1(out)
84
+ out = self.relu(out)
85
+
86
+ out = self.conv2(out)
87
+ out = self.bn2(out)
88
+ out = self.relu(out)
89
+
90
+ out = self.conv3(out)
91
+ out = self.bn3(out)
92
+
93
+ if self.downsample is not None:
94
+ residual = self.downsample(x)
95
+
96
+ out += residual
97
+ out = self.relu(out)
98
+
99
+ return out
100
+
101
+
102
+ class ResNet(nn.Module):
103
+
104
+ def __init__(self, block, layers, num_classes=1000):
105
+ self.inplanes = 64
106
+ super(ResNet, self).__init__()
107
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
108
+ bias=False)
109
+ self.bn1 = nn.BatchNorm2d(64)
110
+ self.relu = nn.ReLU(inplace=True)
111
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
112
+ self.layer1 = self._make_layer(block, 64, layers[0])
113
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
114
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
115
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
116
+ self.avgpool = nn.AvgPool2d(7, stride=1)
117
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
118
+
119
+ self.mean_vector = torch.zeros(1, self.inplanes)
120
+ self.count_vector = torch.ones(1, 1)
121
+ self.label = []
122
+
123
+ for m in self.modules():
124
+ if isinstance(m, nn.Conv2d):
125
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
126
+ elif isinstance(m, nn.BatchNorm2d):
127
+ nn.init.constant_(m.weight, 1)
128
+ nn.init.constant_(m.bias, 0)
129
+
130
+ def _make_layer(self, block, planes, blocks, stride=1):
131
+ downsample = None
132
+ if stride != 1 or self.inplanes != planes * block.expansion:
133
+ downsample = nn.Sequential(
134
+ nn.Conv2d(self.inplanes, planes * block.expansion,
135
+ kernel_size=1, stride=stride, bias=False),
136
+ nn.BatchNorm2d(planes * block.expansion),
137
+ )
138
+
139
+ layers = []
140
+ layers.append(block(self.inplanes, planes, stride, downsample))
141
+ self.inplanes = planes * block.expansion
142
+ for i in range(1, blocks):
143
+ layers.append(block(self.inplanes, planes))
144
+
145
+ return nn.Sequential(*layers)
146
+
147
+ def update_buffer(self, x, y):
148
+ np_y = y.data.cpu().numpy()
149
+
150
+ for label in np.unique(np_y):
151
+
152
+ if label not in self.label:
153
+ self.label.append(label)
154
+
155
+ def forward(self, x):
156
+ output = self.conv1(x)
157
+ output = self.bn1(output)
158
+ output = self.relu(output)
159
+ output = self.maxpool(output)
160
+
161
+ output = self.layer1(output)
162
+ output = self.layer2(output)
163
+ output = self.layer3(output)
164
+ output = self.layer4(output)
165
+
166
+ output = self.avgpool(output)
167
+ output = output.view(x.size(0), -1)
168
+ output = self.fc(output)
169
+
170
+ return output
171
+
172
+
173
+ def resnet18(pretrained=False, **kwargs):
174
+ """Constructs a ResNet-18 model.
175
+ Args:
176
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
177
+ """
178
+ model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
179
+ if pretrained:
180
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
181
+ return model
182
+
183
+
184
+ def resnet34(pretrained=False, **kwargs):
185
+ """Constructs a ResNet-34 model.
186
+ Args:
187
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
188
+ """
189
+ model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
190
+ if pretrained:
191
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
192
+ return model
193
+
194
+
195
+ def resnet50(pretrained=False, **kwargs):
196
+ """Constructs a ResNet-50 model.
197
+ Args:
198
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
199
+ """
200
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
201
+ if pretrained:
202
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
203
+ return model
204
+
205
+
206
+ def resnet101(pretrained=False, **kwargs):
207
+ """Constructs a ResNet-101 model.
208
+ Args:
209
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
210
+ """
211
+ model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
212
+ if pretrained:
213
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
214
+ return model
215
+
216
+
217
+ def resnet152(pretrained=False, **kwargs):
218
+ """Constructs a ResNet-152 model.
219
+ Args:
220
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
221
+ """
222
+ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
223
+ if pretrained:
224
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
225
+ return model
model/model.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torchvision.models as models
2
+ import torch.nn as nn
3
+ import torch
4
+ import numpy as np
5
+ import torch.nn.functional as F
6
+ import torch.nn.init as init
7
+ import math
8
+ import model.cifar_resnet as cifar
9
+ import model.imagenet_resnet as imagenet
10
+
11
+
12
+ class NetFeat(nn.Module):
13
+ def __init__(self, arch, pretrained, dataset):
14
+ super(NetFeat, self).__init__()
15
+ if 'CIFAR' in dataset:
16
+ if 'resnet' in arch:
17
+ if arch == 'resnet18':
18
+ net = cifar.resnet18()
19
+
20
+ resnet_feature_layers = ['conv1','conv2_x','conv3_x','conv4_x','conv5_x']
21
+ resnet_module_list = [getattr(net,l) for l in resnet_feature_layers]
22
+ last_layer_idx = resnet_feature_layers.index('conv5_x')
23
+ featExtractor = nn.Sequential(*(resnet_module_list[:last_layer_idx+1] + [nn.AdaptiveAvgPool2d((1, 1))]))
24
+
25
+ self.feat_net = featExtractor
26
+ self.feat_dim = 512
27
+
28
+ elif dataset == 'Clothing1M':
29
+ if arch == 'resnet50':
30
+ net = imagenet.resnet50(pretrained=pretrained)
31
+ self.feat_dim = 2048
32
+
33
+ elif arch == 'resnet18':
34
+ net = imagenet.resnet18(pretrained=pretrained)
35
+ self.feat_dim = 512
36
+
37
+ resnet_feature_layers = ['conv1','bn1','relu','maxpool','layer1','layer2','layer3','layer4']
38
+ resnet_module_list = [getattr(net,l) for l in resnet_feature_layers]
39
+ last_layer_idx = resnet_feature_layers.index('layer4')
40
+ featExtractor = nn.Sequential(*(resnet_module_list[:last_layer_idx+1] + [nn.AvgPool2d(7, stride=1)]))
41
+
42
+ self.feat_net = featExtractor
43
+
44
+ def train(self, mode=True, freeze_bn=False):
45
+ """
46
+ Override the default train() to freeze the BN parameters
47
+ """
48
+ super(NetFeat, self).train(mode)
49
+ self.freeze_bn = freeze_bn
50
+ if self.freeze_bn:
51
+ for m in self.modules():
52
+ if isinstance(m, nn.BatchNorm2d):
53
+ m.eval()
54
+ m.weight.requires_grad = False
55
+ m.bias.requires_grad = False
56
+
57
+ def forward(self, x):
58
+ x = self.feat_net(x)
59
+ x = torch.flatten(x, 1)
60
+
61
+ return x
62
+
63
+
64
+ class NetClassifier(nn.Module):
65
+ def __init__(self, feat_dim, nb_cls):
66
+ super(NetClassifier, self).__init__()
67
+ self.weight = torch.nn.Parameter(nn.Linear(feat_dim, nb_cls, bias=False).weight.T, requires_grad=True) # dimension feat_dim * nb_cls
68
+
69
+ def getWeight(self):
70
+ return self.weight, self.bias, self.scale_cls
71
+
72
+ def forward(self, feature):
73
+ batchSize, nFeat = feature.size()
74
+ clsScore = torch.mm(feature, self.weight)
75
+
76
+ return clsScore
77
+
78
+
79
+ if __name__ == '__main__':
80
+
81
+ data = torch.randn(3, 3, 32, 32).to("cpu")
82
+ net_feat = NetFeat(arch='resnet18', pretrained=False, dataset='CIFAR100')
83
+ net_cls = NetClassifier(net_feat.feat_dim, 10)
84
+
85
+ net_feat.to("cpu")
86
+ net_cls.to("cpu")
87
+
88
+ feat = net_feat(data)
89
+ print (feat.size())
90
+ score = net_cls(feat)
91
+ print (score.size())
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ torchvision
4
+ Pillow
5
+ numpy
test.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import torchvision.transforms as transforms
4
+ from model import model
5
+ from PIL import Image
6
+
7
+ # Static model checkpoint path
8
+ RESUME_PATH = "netBest1.pth"
9
+
10
+ # Class Mapping
11
+ CLOTHING1M_CLASSES = {
12
+ 0: "T-shirt", 1: "Shirt", 2: "Knitwear", 3: "Chiffon", 4: "Sweater",
13
+ 5: "Hoodie", 6: "Windbreaker", 7: "Jacket", 8: "Down Coat", 9: "Suit",
14
+ 10: "Shawl", 11: "Dress", 12: "Vest", 13: "Underwear"
15
+ }
16
+
17
+ # Load model
18
+ def load_model():
19
+ net_feat = model.NetFeat(arch='resnet18', pretrained=False, dataset="Clothing1M")
20
+ net_cls = model.NetClassifier(feat_dim=net_feat.feat_dim, nb_cls=14)
21
+
22
+ param = torch.load(RESUME_PATH, map_location=torch.device("cpu"))
23
+ net_feat.load_state_dict(param['feat'])
24
+ net_cls.load_state_dict(param['cls'])
25
+
26
+ net_feat.eval()
27
+ net_cls.eval()
28
+ return net_feat, net_cls
29
+
30
+ # Image Preprocessing
31
+ def preprocess_image(image):
32
+ transform = transforms.Compose([
33
+ transforms.Resize(256),
34
+ transforms.CenterCrop(224),
35
+ transforms.ToTensor(),
36
+ transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
37
+ ])
38
+ image = image.convert("RGB")
39
+ return transform(image).unsqueeze(0) # Add batch dimension
40
+
41
+ # Image Classification
42
+ def classify_image(image):
43
+ net_feat, net_cls = load_model()
44
+ image_tensor = preprocess_image(image).to("cpu")
45
+
46
+ with torch.no_grad():
47
+ features = net_feat(image_tensor)
48
+ output = net_cls(features)
49
+ _, predicted = torch.max(output, 1)
50
+
51
+ return CLOTHING1M_CLASSES[predicted.item()]
52
+
53
+ # Gradio Interface
54
+ demo = gr.Interface(
55
+ fn=classify_image,
56
+ inputs=gr.Image(type="pil"),
57
+ outputs=gr.Textbox(label="Predicted Category"),
58
+ title="Clothing Image Classifier",
59
+ description="Upload an image to classify its clothing category.",
60
+ examples=[
61
+ ["examples/83.jpg"],
62
+ ["examples/48.jpg"]
63
+ ]
64
+ )
65
+
66
+ demo.launch()