deep-person-reid/models/ResNet.py

91 lines
3.1 KiB
Python
Raw Normal View History

2018-03-12 05:17:48 +08:00
from __future__ import absolute_import
import torch
from torch import nn
from torch.nn import functional as F
import torchvision
2018-03-12 06:36:46 +08:00
__all__ = ['ResNet50', 'ResNet50M']
2018-03-12 05:17:48 +08:00
class ResNet50(nn.Module):
2018-03-12 21:53:08 +08:00
def __init__(self, num_classes, loss={'xent'}, **kwargs):
2018-03-12 05:17:48 +08:00
super(ResNet50, self).__init__()
2018-03-12 21:53:08 +08:00
self.loss = loss
2018-03-12 05:17:48 +08:00
resnet50 = torchvision.models.resnet50(pretrained=True)
self.base = nn.Sequential(*list(resnet50.children())[:-2])
self.classifier = nn.Linear(2048, num_classes)
2018-03-22 06:26:43 +08:00
self.feat_dim = 2048 # feature dimension
2018-03-12 05:17:48 +08:00
def forward(self, x):
x = self.base(x)
x = F.avg_pool2d(x, x.size()[2:])
2018-03-12 21:53:08 +08:00
f = x.view(x.size(0), -1)
2018-03-12 05:17:48 +08:00
if not self.training:
2018-03-12 21:53:08 +08:00
return f
y = self.classifier(f)
if self.loss == {'xent'}:
return y
elif self.loss == {'xent', 'htri'}:
return y, f
2018-03-22 06:26:43 +08:00
elif self.loss == {'cent'}:
return y, f
2018-05-03 17:47:20 +08:00
elif self.loss == {'ring'}:
return y, f
2018-03-12 21:53:08 +08:00
else:
2018-03-22 06:26:43 +08:00
raise KeyError("Unsupported loss: {}".format(self.loss))
2018-03-12 06:36:46 +08:00
class ResNet50M(nn.Module):
"""ResNet50 + mid-level features.
Reference:
2018-03-26 20:04:22 +08:00
Yu et al. The Devil is in the Middle: Exploiting Mid-level Representations for
2018-03-12 06:36:46 +08:00
Cross-Domain Instance Matching. arXiv:1711.08106.
"""
2018-03-12 21:53:08 +08:00
def __init__(self, num_classes=0, loss={'xent'}, **kwargs):
2018-03-12 06:36:46 +08:00
super(ResNet50M, self).__init__()
2018-03-12 21:53:08 +08:00
self.loss = loss
2018-03-12 06:36:46 +08:00
resnet50 = torchvision.models.resnet50(pretrained=True)
2018-04-24 05:20:33 +08:00
base = nn.Sequential(*list(resnet50.children())[:-2])
self.layers1 = nn.Sequential(base[0], base[1], base[2])
self.layers2 = nn.Sequential(base[3], base[4])
self.layers3 = base[5]
self.layers4 = base[6]
self.layers5a = base[7][0]
self.layers5b = base[7][1]
self.layers5c = base[7][2]
2018-03-12 06:36:46 +08:00
self.fc_fuse = nn.Sequential(nn.Linear(4096, 1024), nn.BatchNorm1d(1024), nn.ReLU())
self.classifier = nn.Linear(3072, num_classes)
2018-03-22 06:26:43 +08:00
self.feat_dim = 3072 # feature dimension
2018-03-12 06:36:46 +08:00
def forward(self, x):
x1 = self.layers1(x)
x2 = self.layers2(x1)
x3 = self.layers3(x2)
x4 = self.layers4(x3)
x5a = self.layers5a(x4)
x5b = self.layers5b(x5a)
x5c = self.layers5c(x5b)
x5a_feat = F.avg_pool2d(x5a, x5a.size()[2:]).view(x5a.size(0), x5a.size(1))
x5b_feat = F.avg_pool2d(x5b, x5b.size()[2:]).view(x5b.size(0), x5b.size(1))
x5c_feat = F.avg_pool2d(x5c, x5c.size()[2:]).view(x5c.size(0), x5c.size(1))
midfeat = torch.cat((x5a_feat, x5b_feat), dim=1)
midfeat = self.fc_fuse(midfeat)
combofeat = torch.cat((x5c_feat, midfeat), dim=1)
if not self.training:
return combofeat
prelogits = self.classifier(combofeat)
2018-03-12 21:53:08 +08:00
if self.loss == {'xent'}:
return prelogits
elif self.loss == {'xent', 'htri'}:
return prelogits, combofeat
2018-03-22 06:26:43 +08:00
elif self.loss == {'cent'}:
return prelogits, combofeat
2018-05-03 17:47:20 +08:00
elif self.loss == {'ring'}:
return prelogits, combofeat
2018-03-12 21:53:08 +08:00
else:
2018-04-23 17:21:26 +08:00
raise KeyError("Unsupported loss: {}".format(self.loss))