Skip to content

Commit 03257a8

Browse files
authored
Merge pull request #240 from 1adrianb/python-comp
Python comp
2 parents 19e04a8 + b8d744a commit 03257a8

File tree

12 files changed

+140
-110
lines changed

12 files changed

+140
-110
lines changed

conda/meta.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ requirements:
2424
- scipy
2525
- opencv
2626
- tqdm
27+
- numba
2728

2829
about:
2930
home: https://github.com/1adrianb/face-alignment

face_alignment/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
__email__ = '[email protected]'
55
__version__ = '1.3.0'
66

7-
from .api import FaceAlignment, LandmarksType, NetworkSize
7+
from .api import FaceAlignment, LandmarksType, NetworkSize

face_alignment/api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,11 @@ def get_landmarks_from_image(self, image_or_path, detected_faces=None):
128128
out = self.face_alignment_net(inp).detach()
129129
if self.flip_input:
130130
out += flip(self.face_alignment_net(flip(inp)).detach(), is_label=True)
131-
out = out.cpu()
131+
out = out.cpu().numpy()
132132

133133
pts, pts_img = get_preds_fromhm(out, center, scale)
134134
pts, pts_img = pts.view(68, 2) * 4, pts_img.view(68, 2)
135+
pts, pts_img = torch.from_numpy(pts), torch.from_numpy(pts_img)
135136

136137
if self.landmarks_type == LandmarksType._3D:
137138
heatmaps = np.zeros((68, 256, 256), dtype=np.float32)

face_alignment/detection/core.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from tqdm import tqdm
44
import numpy as np
55
import torch
6-
import cv2
76
from skimage import io
87

98

face_alignment/detection/sfd/bbox.py

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,6 @@
1-
import os
2-
import sys
3-
import cv2
4-
import random
5-
import datetime
6-
import time
71
import math
8-
import argparse
92
import numpy as np
10-
import torch
11-
12-
try:
13-
from iou import IOU
14-
except BaseException:
15-
# IOU cython speedup 10x
16-
def IOU(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2):
17-
sa = abs((ax2 - ax1) * (ay2 - ay1))
18-
sb = abs((bx2 - bx1) * (by2 - by1))
19-
x1, y1 = max(ax1, bx1), max(ay1, by1)
20-
x2, y2 = min(ax2, bx2), min(ay2, by2)
21-
w = x2 - x1
22-
h = y2 - y1
23-
if w < 0 or h < 0:
24-
return 0.0
25-
else:
26-
return 1.0 * w * h / (sa + sb - w * h)
27-
28-
29-
def bboxlog(x1, y1, x2, y2, axc, ayc, aww, ahh):
30-
xc, yc, ww, hh = (x2 + x1) / 2, (y2 + y1) / 2, x2 - x1, y2 - y1
31-
dx, dy = (xc - axc) / aww, (yc - ayc) / ahh
32-
dw, dh = math.log(ww / aww), math.log(hh / ahh)
33-
return dx, dy, dw, dh
34-
35-
36-
def bboxloginv(dx, dy, dw, dh, axc, ayc, aww, ahh):
37-
xc, yc = dx * aww + axc, dy * ahh + ayc
38-
ww, hh = math.exp(dw) * aww, math.exp(dh) * ahh
39-
x1, x2, y1, y2 = xc - ww / 2, xc + ww / 2, yc - hh / 2, yc + hh / 2
40-
return x1, y1, x2, y2
3+
from numba import jit
414

425

436
def nms(dets, thresh):
@@ -82,11 +45,13 @@ def encode(matched, priors, variances):
8245
g_cxcy /= (variances[0] * priors[:, 2:])
8346
# match wh / prior wh
8447
g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:]
85-
g_wh = torch.log(g_wh) / variances[1]
48+
g_wh = np.log(g_wh) / variances[1]
49+
8650
# return target for smooth_l1_loss
87-
return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4]
51+
return np.concatenate([g_cxcy, g_wh], 1) # [num_priors,4]
8852

8953

54+
@jit(nopython=True)
9055
def decode(loc, priors, variances):
9156
"""Decode locations from predictions using priors to undo
9257
the encoding we did for offset regression at train time.
@@ -100,9 +65,9 @@ def decode(loc, priors, variances):
10065
decoded bounding box predictions
10166
"""
10267

103-
boxes = torch.cat((
68+
boxes = np.concatenate((
10469
priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
105-
priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1)
70+
priors[:, 2:] * np.exp(loc[:, 2:] * variances[1])), 1)
10671
boxes[:, :2] -= boxes[:, 2:] / 2
10772
boxes[:, 2:] += boxes[:, :2]
10873
return boxes

face_alignment/detection/sfd/detect.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
import torch
22
import torch.nn.functional as F
33

4-
import os
5-
import sys
64
import cv2
7-
import random
8-
import datetime
9-
import math
10-
import argparse
115
import numpy as np
6+
from numba import jit
7+
from numba.typed import List
128

13-
import scipy.io as sio
14-
import zipfile
15-
from .net_s3fd import s3fd
169
from .bbox import *
1710

1811

1912
def detect(net, img, device):
2013
img = img.transpose(2, 0, 1)
2114
# Creates a batch of 1
22-
img = img.reshape((1,) + img.shape)
15+
img = np.expand_dims(img, 0)
2316

24-
img = torch.from_numpy(img).float().to(device)
17+
img = torch.from_numpy(img).to(device, dtype=torch.float32)
2518

2619
return batch_detect(net, img, device)
2720

@@ -35,37 +28,41 @@ def batch_detect(net, img_batch, device):
3528
if 'cuda' in device:
3629
torch.backends.cudnn.benchmark = True
3730

38-
BB, CC, HH, WW = img_batch.size()
31+
batch_size = img_batch.size(0)
32+
img_batch = img_batch.to(device, dtype=torch.float32)
3933

4034
img_batch = img_batch.flip(-3) # RGB to BGR
41-
img_batch = img_batch - torch.Tensor([104, 117, 123]).view(1, 3, 1, 1)
35+
img_batch = img_batch - torch.tensor([104.0, 117.0, 123.0], device=device).view(1, 3, 1, 1)
4236

4337
with torch.no_grad():
44-
olist = net(img_batch.float()) # patched uint8_t overflow error
38+
olist = net(img_batch) # patched uint8_t overflow error
4539

4640
for i in range(len(olist) // 2):
4741
olist[i * 2] = F.softmax(olist[i * 2], dim=1)
4842

49-
bboxlists = []
43+
olist = [oelem.data.cpu().numpy() for oelem in olist]
44+
45+
bboxlists = get_predictions(List(olist), batch_size)
46+
return bboxlists
5047

51-
olist = [oelem.data.cpu() for oelem in olist]
5248

53-
for j in range(BB):
49+
@jit(nopython=True)
50+
def get_predictions(olist, batch_size):
51+
bboxlists = []
52+
variances = [0.1, 0.2]
53+
for j in range(batch_size):
5454
bboxlist = []
5555
for i in range(len(olist) // 2):
5656
ocls, oreg = olist[i * 2], olist[i * 2 + 1]
57-
FB, FC, FH, FW = ocls.size() # feature map size
5857
stride = 2**(i + 2) # 4,8,16,32,64,128
59-
anchor = stride * 4
6058
poss = zip(*np.where(ocls[:, 1, :, :] > 0.05))
6159
for Iindex, hindex, windex in poss:
6260
axc, ayc = stride / 2 + windex * stride, stride / 2 + hindex * stride
6361
score = ocls[j, 1, hindex, windex]
64-
loc = oreg[j, :, hindex, windex].contiguous().view(1, 4)
65-
priors = torch.Tensor([[axc / 1.0, ayc / 1.0, stride * 4 / 1.0, stride * 4 / 1.0]])
66-
variances = [0.1, 0.2]
62+
loc = oreg[j, :, hindex, windex].copy().reshape(1, 4)
63+
priors = np.array([[axc / 1.0, ayc / 1.0, stride * 4 / 1.0, stride * 4 / 1.0]])
6764
box = decode(loc, priors, variances)
68-
x1, y1, x2, y2 = box[0] * 1.0
65+
x1, y1, x2, y2 = box[0]
6966
bboxlist.append([x1, y1, x2, y2, score])
7067

7168
bboxlists.append(bboxlist)

face_alignment/detection/sfd/net_s3fd.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,40 +68,40 @@ def __init__(self):
6868
self.conv7_2_mbox_loc = nn.Conv2d(256, 4, kernel_size=3, stride=1, padding=1)
6969

7070
def forward(self, x):
71-
h = F.relu(self.conv1_1(x))
72-
h = F.relu(self.conv1_2(h))
71+
h = F.relu(self.conv1_1(x), inplace=True)
72+
h = F.relu(self.conv1_2(h), inplace=True)
7373
h = F.max_pool2d(h, 2, 2)
7474

75-
h = F.relu(self.conv2_1(h))
76-
h = F.relu(self.conv2_2(h))
75+
h = F.relu(self.conv2_1(h), inplace=True)
76+
h = F.relu(self.conv2_2(h), inplace=True)
7777
h = F.max_pool2d(h, 2, 2)
7878

79-
h = F.relu(self.conv3_1(h))
80-
h = F.relu(self.conv3_2(h))
81-
h = F.relu(self.conv3_3(h))
79+
h = F.relu(self.conv3_1(h), inplace=True)
80+
h = F.relu(self.conv3_2(h), inplace=True)
81+
h = F.relu(self.conv3_3(h), inplace=True)
8282
f3_3 = h
8383
h = F.max_pool2d(h, 2, 2)
8484

85-
h = F.relu(self.conv4_1(h))
86-
h = F.relu(self.conv4_2(h))
87-
h = F.relu(self.conv4_3(h))
85+
h = F.relu(self.conv4_1(h), inplace=True)
86+
h = F.relu(self.conv4_2(h), inplace=True)
87+
h = F.relu(self.conv4_3(h), inplace=True)
8888
f4_3 = h
8989
h = F.max_pool2d(h, 2, 2)
9090

91-
h = F.relu(self.conv5_1(h))
92-
h = F.relu(self.conv5_2(h))
93-
h = F.relu(self.conv5_3(h))
91+
h = F.relu(self.conv5_1(h), inplace=True)
92+
h = F.relu(self.conv5_2(h), inplace=True)
93+
h = F.relu(self.conv5_3(h), inplace=True)
9494
f5_3 = h
9595
h = F.max_pool2d(h, 2, 2)
9696

97-
h = F.relu(self.fc6(h))
98-
h = F.relu(self.fc7(h))
97+
h = F.relu(self.fc6(h), inplace=True)
98+
h = F.relu(self.fc7(h), inplace=True)
9999
ffc7 = h
100-
h = F.relu(self.conv6_1(h))
101-
h = F.relu(self.conv6_2(h))
100+
h = F.relu(self.conv6_1(h), inplace=True)
101+
h = F.relu(self.conv6_2(h), inplace=True)
102102
f6_2 = h
103-
h = F.relu(self.conv7_1(h))
104-
h = F.relu(self.conv7_2(h))
103+
h = F.relu(self.conv7_1(h), inplace=True)
104+
h = F.relu(self.conv7_2(h), inplace=True)
105105
f7_2 = h
106106

107107
f3_3 = self.conv3_3_norm(f3_3)

face_alignment/detection/sfd/sfd_detector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _filter_bboxes(self, bboxlist, threshold=0.5):
3434
if len(bboxlist) > 0:
3535
keep = nms(bboxlist, 0.3)
3636
bboxlist = bboxlist[keep, :]
37-
bboxlist = [x for x in bboxlist if x[-1] > 0.5]
37+
bboxlist = [x for x in bboxlist if x[-1] > threshold]
3838

3939
return bboxlist
4040

0 commit comments

Comments
 (0)