Skip to content
Permalink
Browse files

Upgraded to TF version 1.13.2

Removed the wait at first launch for most graphics cards.

Increased speed of training by 10-20%, but you have to retrain all models from scratch.

SAEHD:

added option 'use float16'
	Experimental option. Reduces the model size by half.
	Increases the speed of training.
	Decreases the accuracy of the model.
	The model may collapse or not train.
	Model may not learn the mask in large resolutions.

true_face_training option is replaced by
"True face power". 0.0000 .. 1.0
Experimental option. Discriminates the result face to be more like the src face. Higher value - stronger discrimination.
Comparison - https://i.imgur.com/czScS9q.png
  • Loading branch information
iperov committed Jan 25, 2020
1 parent a3dfcb9 commit 76ca79216ea356b0bc2aaa4b05aaa161733bc836
Showing with 1,323 additions and 1,300 deletions.
  1. +1 −1 DFLIMG/DFLIMG.py
  2. +1 −1 DFLIMG/DFLJPG.py
  3. +5 −5 DFLIMG/DFLPNG.py
  4. +1 −1 core/imagelib/IEPolys.py
  5. +46 −46 core/imagelib/color_transfer.py
  6. +5 −5 core/imagelib/common.py
  7. +2 −2 core/imagelib/text.py
  8. +3 −3 core/imagelib/warp.py
  9. +35 −35 core/interact/interact.py
  10. +1 −1 core/joblib/SubprocessGenerator.py
  11. +3 −3 core/joblib/SubprocessorBase.py
  12. +24 −24 core/leras/device.py
  13. +3 −6 core/leras/initializers.py
  14. +161 −106 core/leras/layers.py
  15. +142 −60 core/leras/nn.py
  16. +11 −5 core/leras/optimizers.py
  17. +140 −125 core/leras/tensor_ops.py
  18. +7 −7 core/pathex.py
  19. +1 −1 core/randomex.py
  20. +9 −6 facelib/FANExtractor.py
  21. +22 −22 facelib/FaceEnhancer.py
  22. +1 −1 facelib/FaceType.py
  23. +25 −25 facelib/LandmarksProcessor.py
  24. +53 −53 facelib/S3FDExtractor.py
  25. +48 −169 facelib/TernausNet.py
  26. +24 −24 main.py
  27. +18 −18 mainscripts/Extractor.py
  28. +31 −31 mainscripts/FacesetEnhancer.py
  29. +5 −5 mainscripts/MaskEditorTool.py
  30. +10 −10 mainscripts/Merger.py
  31. +1 −1 mainscripts/Sorter.py
  32. +15 −15 mainscripts/Trainer.py
  33. +19 −19 mainscripts/Util.py
  34. +6 −6 mainscripts/VideoEd.py
  35. +121 −122 mainscripts/dev_misc.py
  36. +6 −6 merger/MergeAvatar.py
  37. +12 −12 merger/MergeMasked.py
  38. +1 −1 merger/MergerConfig.py
  39. +14 −14 models/ModelBase.py
  40. +67 −78 models/Model_Quick96/Model.py
  41. +172 −176 models/Model_SAEHD/Model.py
  42. +1 −1 requirements-colab.txt
  43. +1 −1 requirements-cuda.txt
  44. +1 −1 samplelib/PackedFaceset.py
  45. +7 −7 samplelib/Sample.py
  46. +9 −9 samplelib/SampleGeneratorFaceTemporal.py
  47. +1 −1 samplelib/SampleGeneratorImageTemporal.py
  48. +10 −14 samplelib/SampleHost.py
  49. +21 −15 samplelib/SampleProcessor.py
@@ -4,7 +4,7 @@
from .DFLPNG import DFLPNG

class DFLIMG():

@staticmethod
def load(filepath, loader_func=None):
if filepath.suffix == '.png':
@@ -197,7 +197,7 @@ def embed_data(filename, face_type=None,
else:
io.log_err("Unable to encode fanseg_mask for %s" % (filename) )
fanseg_mask = None

if ie_polys is not None:
if not isinstance(ie_polys, list):
ie_polys = ie_polys.dump()
@@ -287,7 +287,7 @@ def embed_dfldict(filename, dfl_dict):
f.write ( inst.dump() )
except:
raise Exception( 'cannot save %s' % (filename) )

@staticmethod
def embed_data(filename, face_type=None,
landmarks=None,
@@ -312,11 +312,11 @@ def embed_data(filename, face_type=None,
else:
io.log_err("Unable to encode fanseg_mask for %s" % (filename) )
fanseg_mask = None

if ie_polys is not None:
if not isinstance(ie_polys, list):
ie_polys = ie_polys.dump()

DFLPNG.embed_dfldict (filename, {'face_type': face_type,
'landmarks': landmarks,
'ie_polys' : ie_polys,
@@ -351,7 +351,7 @@ def embed_and_set(self, filename, face_type=None,
if fanseg_mask is None: fanseg_mask = self.get_fanseg_mask()
if eyebrows_expand_mod is None: eyebrows_expand_mod = self.get_eyebrows_expand_mod()
if relighted is None: relighted = self.get_relighted()

DFLPNG.embed_data (filename, face_type=face_type,
landmarks=landmarks,
ie_polys=ie_polys,
@@ -368,7 +368,7 @@ def remove_ie_polys(self):

def remove_fanseg_mask(self):
self.dfl_dict['fanseg_mask'] = None

def remove_source_filename(self):
self.dfl_dict['source_filename'] = None

@@ -54,7 +54,7 @@ def n_dec(self):
self.n = max(0, self.n-1)
self.dirty = True
return self.n

def n_inc(self):
self.n = min(len(self.list), self.n+1)
self.dirty = True
@@ -9,15 +9,15 @@
def color_transfer_sot(src,trg, steps=10, batch_size=5, reg_sigmaXY=16.0, reg_sigmaV=5.0):
"""
Color Transform via Sliced Optimal Transfer
ported by @iperov from https://github.com/dcoeurjo/OTColorTransfer
ported by @iperov from https://github.com/dcoeurjo/OTColorTransfer
src - any float range any channel image
dst - any float range any channel image, same shape as src
steps - number of solver steps
batch_size - solver batch size
reg_sigmaXY - apply regularization and sigmaXY of filter, otherwise set to 0.0
reg_sigmaV - sigmaV of filter
return value - clip it manually
"""
if not np.issubdtype(src.dtype, np.floating):
@@ -27,11 +27,11 @@ def color_transfer_sot(src,trg, steps=10, batch_size=5, reg_sigmaXY=16.0, reg_si

if len(src.shape) != 3:
raise ValueError("src shape must have rank 3 (h,w,c)")

if src.shape != trg.shape:
raise ValueError("src and trg shapes must be equal")
raise ValueError("src and trg shapes must be equal")

src_dtype = src.dtype
src_dtype = src.dtype
h,w,c = src.shape
new_src = src.copy()

@@ -59,63 +59,63 @@ def color_transfer_sot(src,trg, steps=10, batch_size=5, reg_sigmaXY=16.0, reg_si
src_diff_filt = src_diff_filt[...,None]
new_src = src + src_diff_filt
return new_src

def color_transfer_mkl(x0, x1):
eps = np.finfo(float).eps

h,w,c = x0.shape
h1,w1,c1 = x1.shape

x0 = x0.reshape ( (h*w,c) )
x1 = x1.reshape ( (h1*w1,c1) )

a = np.cov(x0.T)
b = np.cov(x1.T)

Da2, Ua = np.linalg.eig(a)
Da = np.diag(np.sqrt(Da2.clip(eps, None)))
Da = np.diag(np.sqrt(Da2.clip(eps, None)))

C = np.dot(np.dot(np.dot(np.dot(Da, Ua.T), b), Ua), Da)

Dc2, Uc = np.linalg.eig(C)
Dc = np.diag(np.sqrt(Dc2.clip(eps, None)))
Dc = np.diag(np.sqrt(Dc2.clip(eps, None)))

Da_inv = np.diag(1./(np.diag(Da)))

t = np.dot(np.dot(np.dot(np.dot(np.dot(np.dot(Ua, Da_inv), Uc), Dc), Uc.T), Da_inv), Ua.T)
t = np.dot(np.dot(np.dot(np.dot(np.dot(np.dot(Ua, Da_inv), Uc), Dc), Uc.T), Da_inv), Ua.T)

mx0 = np.mean(x0, axis=0)
mx1 = np.mean(x1, axis=0)

result = np.dot(x0-mx0, t) + mx1
return np.clip ( result.reshape ( (h,w,c) ).astype(x0.dtype), 0, 1)

def color_transfer_idt(i0, i1, bins=256, n_rot=20):
relaxation = 1 / n_rot
h,w,c = i0.shape
h1,w1,c1 = i1.shape

i0 = i0.reshape ( (h*w,c) )
i1 = i1.reshape ( (h1*w1,c1) )

n_dims = c

d0 = i0.T
d1 = i1.T

for i in range(n_rot):

r = sp.stats.special_ortho_group.rvs(n_dims).astype(np.float32)

d0r = np.dot(r, d0)
d1r = np.dot(r, d1)
d_r = np.empty_like(d0)

for j in range(n_dims):

lo = min(d0r[j].min(), d1r[j].min())
hi = max(d0r[j].max(), d1r[j].max())

p0r, edges = np.histogram(d0r[j], bins=bins, range=[lo, hi])
p1r, _ = np.histogram(d1r[j], bins=bins, range=[lo, hi])

@@ -124,11 +124,11 @@ def color_transfer_idt(i0, i1, bins=256, n_rot=20):

cp1r = p1r.cumsum().astype(np.float32)
cp1r /= cp1r[-1]

f = np.interp(cp0r, cp1r, edges[1:])

d_r[j] = np.interp(d0r[j], edges[1:], f, left=0, right=bins)

d0 = relaxation * np.linalg.solve(r, (d_r - d0r)) + d0

return np.clip ( d0.T.reshape ( (h,w,c) ).astype(i0.dtype) , 0, 1)
@@ -137,16 +137,16 @@ def laplacian_matrix(n, m):
mat_D = scipy.sparse.lil_matrix((m, m))
mat_D.setdiag(-1, -1)
mat_D.setdiag(4)
mat_D.setdiag(-1, 1)
mat_A = scipy.sparse.block_diag([mat_D] * n).tolil()
mat_D.setdiag(-1, 1)
mat_A = scipy.sparse.block_diag([mat_D] * n).tolil()
mat_A.setdiag(-1, 1*m)
mat_A.setdiag(-1, -1*m)
mat_A.setdiag(-1, -1*m)
return mat_A

def seamless_clone(source, target, mask):
h, w,c = target.shape
result = []

mat_A = laplacian_matrix(h, w)
laplacian = mat_A.tocsc()

@@ -155,30 +155,30 @@ def seamless_clone(source, target, mask):
mask[:,0] = 1
mask[:,-1] = 1
q = np.argwhere(mask==0)

k = q[:,1]+q[:,0]*w
mat_A[k, k] = 1
mat_A[k, k + 1] = 0
mat_A[k, k - 1] = 0
mat_A[k, k + w] = 0
mat_A[k, k - w] = 0

mat_A = mat_A.tocsc()
mat_A = mat_A.tocsc()
mask_flat = mask.flatten()
for channel in range(c):

source_flat = source[:, :, channel].flatten()
target_flat = target[:, :, channel].flatten()
target_flat = target[:, :, channel].flatten()

mat_b = laplacian.dot(source_flat)*0.75
mat_b[mask_flat==0] = target_flat[mask_flat==0]

x = spsolve(mat_A, mat_b).reshape((h, w))
result.append (x)


return np.clip( np.dstack(result), 0, 1 )

def reinhard_color_transfer(target, source, clip=False, preserve_paper=False, source_mask=None, target_mask=None):
"""
Transfers the color distribution from the source to the target
@@ -368,26 +368,26 @@ def color_hist_match(src_im, tar_im, hist_match_threshold=255):
def color_transfer_mix(img_src,img_trg):
img_src = (img_src*255.0).astype(np.uint8)
img_trg = (img_trg*255.0).astype(np.uint8)

img_src_lab = cv2.cvtColor(img_src, cv2.COLOR_BGR2LAB)
img_trg_lab = cv2.cvtColor(img_trg, cv2.COLOR_BGR2LAB)
rct_light = np.clip ( linear_color_transfer(img_src_lab[...,0:1].astype(np.float32)/255.0,

rct_light = np.clip ( linear_color_transfer(img_src_lab[...,0:1].astype(np.float32)/255.0,
img_trg_lab[...,0:1].astype(np.float32)/255.0 )[...,0]*255.0,
0, 255).astype(np.uint8)
0, 255).astype(np.uint8)

img_src_lab[...,0] = (np.ones_like (rct_light)*100).astype(np.uint8)
img_src_lab = cv2.cvtColor(img_src_lab, cv2.COLOR_LAB2BGR)
img_src_lab = cv2.cvtColor(img_src_lab, cv2.COLOR_LAB2BGR)

img_trg_lab[...,0] = (np.ones_like (rct_light)*100).astype(np.uint8)
img_trg_lab = cv2.cvtColor(img_trg_lab, cv2.COLOR_LAB2BGR)

img_rct = color_transfer_sot( img_src_lab.astype(np.float32), img_trg_lab.astype(np.float32) )
img_rct = np.clip(img_rct, 0, 255).astype(np.uint8)
img_rct = cv2.cvtColor(img_rct, cv2.COLOR_BGR2LAB)

img_rct = cv2.cvtColor(img_rct, cv2.COLOR_BGR2LAB)
img_rct[...,0] = rct_light
img_rct = cv2.cvtColor(img_rct, cv2.COLOR_LAB2BGR)


return (img_rct / 255.0).astype(np.float32)
@@ -13,24 +13,24 @@ def normalize_channels(img, target_channels):
if c == 0 and target_channels > 0:
img = img[...,np.newaxis]
c = 1

if c == 1 and target_channels > 1:
img = np.repeat (img, target_channels, -1)
c = target_channels

if c > target_channels:
img = img[...,0:target_channels]
c = target_channels

return img

def cut_odd_image(img):
h, w, c = img.shape
wm, hm = w % 2, h % 2
if wm + hm != 0:
if wm + hm != 0:
img = img[0:h-hm,0:w-wm,:]
return img

def overlay_alpha_image(img_target, img_source, xy_offset=(0,0) ):
(h,w,c) = img_source.shape
if c != 4:
@@ -16,7 +16,7 @@ def _get_pil_font (font, size):

def get_text_image( shape, text, color=(1,1,1), border=0.2, font=None):
h,w,c = shape
try:
try:
pil_font = _get_pil_font( localization.get_default_ttf_font_name() , h-2)

canvas = Image.new('RGB', (w,h) , (0,0,0) )
@@ -25,7 +25,7 @@ def get_text_image( shape, text, color=(1,1,1), border=0.2, font=None):
draw.text(offset, text, font=pil_font, fill=tuple((np.array(color)*255).astype(np.int)) )

result = np.asarray(canvas) / 255

if c > 3:
result = np.concatenate ( (result, np.ones ((h,w,c-3)) ), axis=-1 )
elif c < 3:
@@ -6,7 +6,7 @@ def gen_warp_params (source, flip, rotation_range=[-10,10], scale_range=[-0.5, 0
h,w,c = source.shape
if (h != w):
raise ValueError ('gen_warp_params accepts only square images.')

if rnd_seed != None:
rnd_state = np.random.RandomState (rnd_seed)
else:
@@ -15,9 +15,9 @@ def gen_warp_params (source, flip, rotation_range=[-10,10], scale_range=[-0.5, 0
rotation = rnd_state.uniform( rotation_range[0], rotation_range[1] )
scale = rnd_state.uniform(1 +scale_range[0], 1 +scale_range[1])
tx = rnd_state.uniform( tx_range[0], tx_range[1] )
ty = rnd_state.uniform( ty_range[0], ty_range[1] )
ty = rnd_state.uniform( ty_range[0], ty_range[1] )
p_flip = flip and rnd_state.randint(10) < 4

#random warp by grid
cell_size = [ w // (2**i) for i in range(1,4) ] [ rnd_state.randint(3) ]
cell_count = w // cell_size + 1

0 comments on commit 76ca792

Please sign in to comment.
You can’t perform that action at this time.