Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build a new model to implement the residual method idea #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added EA_deeplearning_ageestimator.pptx
Binary file not shown.
23,709 changes: 23,709 additions & 0 deletions UTKFace.csv

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self):
iaa.OneOf([
iaa.Sometimes(0.25, iaa.AdditiveGaussianNoise(scale=0.1 * 255)),
iaa.Sometimes(0.25, iaa.GaussianBlur(sigma=(0, 3.0)))
]),
]),
iaa.Affine(
rotate=(-20, 20), mode="edge",
scale={"x": (0.95, 1.05), "y": (0.95, 1.05)},
Expand Down Expand Up @@ -63,6 +63,7 @@ def __init__(self, data_dir, data_type, img_size=224, augment=False, age_stddev=
assert(img_path.is_file())
self.x.append(str(img_path))
self.y.append(row["apparent_age_avg"])
#self.y.append(row["real_age"])
self.std.append(row["apparent_age_std"])

def __len__(self):
Expand All @@ -77,10 +78,22 @@ def __getitem__(self, idx):

img = cv2.imread(str(img_path), 1)
img = cv2.resize(img, (self.img_size, self.img_size))

# crée une séquence d'images augmenteés
'''x = torch.from_numpy(np.transpose(img, (2, 0, 1)))
shape = x.shape
seq= torch.zeros((8, 3, 224,224))
index = 0
input_img = x.reshape([224,224,3])
for i in range(8):
img_aug = torch.from_numpy(np.transpose(self.transform(input_img).astype(np.float32), (2, 1, 0)))
seq[i] = img_aug'''
img = self.transform(img).astype(np.float32)
return torch.from_numpy(np.transpose(img, (2, 0, 1))), np.clip(round(age), 0, 100)




def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--data_dir", type=str, required=True)
Expand All @@ -95,3 +108,4 @@ def main():

if __name__ == '__main__':
main()

89 changes: 89 additions & 0 deletions datasetUTK.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import argparse
import better_exceptions
from pathlib import Path
import numpy as np
import pandas as pd
import torch
import cv2
from torch.utils.data import Dataset
from imgaug import augmenters as iaa


class ImgAugTransform:
def __init__(self):
self.aug = iaa.Sequential([
iaa.OneOf([
iaa.Sometimes(0.25, iaa.AdditiveGaussianNoise(scale=0.1 * 255)),
iaa.Sometimes(0.25, iaa.GaussianBlur(sigma=(0, 3.0)))
]),
iaa.Affine(
rotate=(-20, 20), mode="edge",
scale={"x": (0.95, 1.05), "y": (0.95, 1.05)},
translate_percent={"x": (-0.05, 0.05), "y": (-0.05, 0.05)}
),
iaa.AddToHueAndSaturation(value=(-10, 10), per_channel=True),
iaa.GammaContrast((0.3, 2)),
iaa.Fliplr(0.5),
])

def __call__(self, img):
img = np.array(img)
img = self.aug.augment_image(img)
return img


class FaceDataset(Dataset):
def __init__(self, data_dir, img_size=224, augment=False):
csv_path = data_dir+'.csv'
img_dir = Path(data_dir)
self.img_size = img_size
self.augment = augment

if augment:
self.transform = ImgAugTransform()
else:
self.transform = lambda i: i

self.x = []
self.y = []
df = pd.read_csv(str(csv_path))

for _, row in df.iterrows():
img_path = Path(data_dir).joinpath(row["img_dir"])
assert(img_path.is_file())
self.x.append(str(img_path))
self.y.append(row["age"])

# to have len devideble by batch size 32
self.x = self.x[:23680]
self.y = self.y[:23680]

def __len__(self):
return len(self.y)

def __getitem__(self, idx):
img_path = self.x[idx]
age = self.y[idx]

img = cv2.imread(str(img_path), 1)
img = cv2.resize(img, (self.img_size, self.img_size))
img = self.transform(img).astype(np.float32)
return torch.from_numpy(np.transpose(img, (2, 0, 1))), np.clip(round(age), 0, 116)


def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--data_dir", type=str, required=True)
args = parser.parse_args()
dataset = FaceDataset(args.data_dir, "train")
print("train dataset len: {}".format(len(dataset)))
dataset = FaceDataset(args.data_dir, "valid")
print("valid dataset len: {}".format(len(dataset)))
dataset = FaceDataset(args.data_dir, "test")
print("test dataset len: {}".format(len(dataset)))


if __name__ == '__main__':
main()


7 changes: 4 additions & 3 deletions defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
_C.TRAIN.LR_DECAY_RATE = 0.2
_C.TRAIN.MOMENTUM = 0.9
_C.TRAIN.WEIGHT_DECAY = 0.0
_C.TRAIN.BATCH_SIZE = 128
_C.TRAIN.EPOCHS = 80
_C.TRAIN.BATCH_SIZE = 30
_C.TRAIN.EPOCHS = 160
_C.TRAIN.AGE_STDDEV = 1.0

# Test
_C.TEST = CN()
_C.TEST.WORKERS = 8
_C.TEST.BATCH_SIZE = 128
_C.TEST.BATCH_SIZE = 32

5 changes: 2 additions & 3 deletions demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,8 @@ def main():

# predict ages
inputs = torch.from_numpy(np.transpose(faces.astype(np.float32), (0, 3, 1, 2))).to(device)
outputs = F.softmax(model(inputs), dim=-1).cpu().numpy()
ages = np.arange(0, 101)
predicted_ages = (outputs * ages).sum(axis=-1)
probs, ages= model(inputs)
predicted_ages = torch.sum(probs*ages, dim=1)

# draw results
for i, d in enumerate(detected):
Expand Down
89 changes: 83 additions & 6 deletions model.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,97 @@
import torch.nn as nn
import torch
import pretrainedmodels
import pretrainedmodels.utils
import numpy as np
import torch.nn.functional as F
import torchvision.models as models
from imgaug import augmenters as iaa


class ImgAugTransform:
def __init__(self):
self.aug = iaa.Sequential([
iaa.OneOf([
iaa.Sometimes(0.25, iaa.AdditiveGaussianNoise(scale=0.1 * 255)),
iaa.Sometimes(0.25, iaa.GaussianBlur(sigma=(0, 3.0)))
]),
iaa.Affine(
rotate=(-20, 20), mode="edge",
scale={"x": (0.95, 1.05), "y": (0.95, 1.05)},
translate_percent={"x": (-0.05, 0.05), "y": (-0.05, 0.05)}
),
iaa.AddToHueAndSaturation(value=(-10, 10), per_channel=True),
iaa.GammaContrast((0.3, 2)),
iaa.Fliplr(0.5),
])

def __call__(self, img):
#img = np.array(img.cpu()).astype(np.uint8)
img = self.aug.augment_image(img)
return img

class AE_model(nn.Module):
def __init__(self, model_name="se_resnext50_32x4d", age_range=75, pretrained="imagenet", emb_dim = 512, hidden_dim = 64, seq_len=8):
super(AE_model, self).__init__()
self.transform = ImgAugTransform()
self.seq_len = seq_len
self.age_range = age_range
self.emb_dim = emb_dim
self.hidden_dim = hidden_dim
self.CNN = pretrainedmodels.__dict__[model_name](pretrained=pretrained)
self.num_features = self.CNN.last_linear.in_features
self.CNN.last_linear = nn.Linear(in_features = self.num_features, out_features=emb_dim)
self.classifier = nn.Linear(in_features = emb_dim, out_features=age_range)
regressors = [nn.Linear(in_features = emb_dim, out_features=1) for i in range(age_range)]
self.regressors = nn.Sequential(*regressors)
# le bloc d'attention
'''self.Queries = nn.Linear(emb_dim, hidden_dim)
self.Keys = nn.Linear(emb_dim, hidden_dim)
self.Values = nn.Linear(emb_dim, emb_dim)
self.gru = nn.GRU(emb_dim, emb_dim, batch_first = True)
self.device = "cuda" if torch.cuda.is_available() else "cpu"'''


def forward(self, x):
# le codage par l'attention
'''shape = x.shape
#self.h0 = torch.randn(shape[0], self.hidden_dim).to(self.device)
seq= torch.zeros((shape[0], self.seq_len, self.emb_dim)).to(self.device)
index = 0
for input_imgs in x:
for i in range(self.seq_len):
img_aug = input_imgs[i].unsqueeze(0)
emb = self.CNN(img_aug).squeeze(0)
seq[index,i] = emb
index+=1
Q = self.Queries(seq) # (b,seq_len, emb_dim)
K = self.Keys(seq) #//
V = self.Values(seq) #torch.Size([b, seq_len, emb_dim])
A = torch.einsum('bld,bsd->bls', seq,seq) # (b, seq_len, seq_len)
A = F.softmax(A, dim=1)
y = torch.einsum('bsl, bsd->bld',A,seq) # (b, seq_len, emb_dim)
out, h = self.gru(y)
#print(y.shape)
embbeding = h[-1,:,:]
#embbeding = torch.sum(y, dim=1)'''

embbeding = self.CNN(x)
prob = F.softmax(self.classifier(embbeding), dim =1)
pred = torch.zeros_like(prob)
for i, reg in enumerate(self.regressors):
pred[:,i] = reg(embbeding).squeeze(1)
return prob, pred


def get_model(model_name="se_resnext50_32x4d", num_classes=101, pretrained="imagenet"):
model = pretrainedmodels.__dict__[model_name](pretrained=pretrained)
dim_feats = model.last_linear.in_features
model.last_linear = nn.Linear(dim_feats, num_classes)
model.avg_pool = nn.AdaptiveAvgPool2d(1)
model = AE_model()
return model


def main():
model = get_model()
model = AE_model()
print(model)


if __name__ == '__main__':
main()

Loading