mirror of
https://github.com/iperov/DeepFaceLab.git
synced 2025-08-21 22:13:20 -07:00
Merge branch 'master' into feature/ms-ssim-loss-2
This commit is contained in:
commit
c5aaa0541f
8 changed files with 138 additions and 72 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -5,11 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
|
||||||
- [Random color training option](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/random-color)
|
|
||||||
- [MS-SSIM loss training option](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/ms-ssim-loss-2)
|
|
||||||
### In Progress
|
### In Progress
|
||||||
|
- [MS-SSIM loss training option](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/ms-ssim-loss-2)
|
||||||
- [Freezeable layers (encoder/decoder/etc.)](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/freezable-weights)
|
- [Freezeable layers (encoder/decoder/etc.)](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/freezable-weights)
|
||||||
|
- [GAN stability improvements](https://github.com/faceshiftlabs/DeepFaceLab/tree/feature/gan-updates)
|
||||||
|
|
||||||
|
## [1.2.0] - 2020-03-17
|
||||||
|
### Added
|
||||||
|
- [Random color training option](doc/features/random-color/README.md)
|
||||||
|
|
||||||
|
## [1.1.5] - 2020-03-16
|
||||||
|
### Fixed
|
||||||
|
- Fixed unclosed websocket in Web UI client when exiting
|
||||||
|
|
||||||
|
## [1.1.4] - 2020-03-16
|
||||||
|
### Fixed
|
||||||
|
- Fixed bug when exiting from Web UI
|
||||||
|
|
||||||
## [1.1.3] - 2020-03-16
|
## [1.1.3] - 2020-03-16
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -34,7 +45,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Reset stale master branch to [seranus/DeepFaceLab](https://github.com/seranus/DeepFaceLab),
|
- Reset stale master branch to [seranus/DeepFaceLab](https://github.com/seranus/DeepFaceLab),
|
||||||
21 commits ahead of [iperov/DeepFaceLab](https://github.com/iperov/DeepFaceLab) ([compare](https://github.com/iperov/DeepFaceLab/compare/4818183...seranus:3f5ae05))
|
21 commits ahead of [iperov/DeepFaceLab](https://github.com/iperov/DeepFaceLab) ([compare](https://github.com/iperov/DeepFaceLab/compare/4818183...seranus:3f5ae05))
|
||||||
|
|
||||||
[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.2...HEAD
|
[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.2.0...HEAD
|
||||||
|
[1.2.0]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.5...v1.2.0
|
||||||
|
[1.1.5]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.4...v1.1.5
|
||||||
|
[1.1.4]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.3...v1.1.4
|
||||||
|
[1.1.3]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.2...v1.1.3
|
||||||
[1.1.2]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.1...v1.1.2
|
[1.1.2]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.1...v1.1.2
|
||||||
[1.1.1]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.0...v1.1.1
|
[1.1.1]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.1.0...v1.1.1
|
||||||
[1.1.0]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.0.0...v1.1.0
|
[1.1.0]: https://github.com/faceshiftlabs/DeepFaceLab/compare/v1.0.0...v1.1.0
|
||||||
|
|
|
@ -381,6 +381,25 @@ def color_augmentation(img):
|
||||||
return (face / 255.0).astype(np.float32)
|
return (face / 255.0).astype(np.float32)
|
||||||
|
|
||||||
|
|
||||||
|
def random_lab_rotation(image, seed=None):
|
||||||
|
"""
|
||||||
|
Randomly rotates image color around the L axis in LAB colorspace,
|
||||||
|
keeping perceptual lightness constant.
|
||||||
|
"""
|
||||||
|
image = cv2.cvtColor(image.astype(np.float32), cv2.COLOR_BGR2LAB)
|
||||||
|
M = np.eye(3)
|
||||||
|
M[1:, 1:] = special_ortho_group.rvs(2, 1, seed)
|
||||||
|
image = image.dot(M)
|
||||||
|
l, a, b = cv2.split(image)
|
||||||
|
l = np.clip(l, 0, 100)
|
||||||
|
a = np.clip(a, -127, 127)
|
||||||
|
b = np.clip(b, -127, 127)
|
||||||
|
image = cv2.merge([l, a, b])
|
||||||
|
image = cv2.cvtColor(image.astype(np.float32), cv2.COLOR_LAB2BGR)
|
||||||
|
np.clip(image, 0, 1, out=image)
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
def random_lab(image):
|
def random_lab(image):
|
||||||
""" Perform random color/lightness adjustment in L*a*b* colorspace """
|
""" Perform random color/lightness adjustment in L*a*b* colorspace """
|
||||||
amount_l = 30 / 100
|
amount_l = 30 / 100
|
||||||
|
|
22
doc/features/random-color/README.md
Normal file
22
doc/features/random-color/README.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Random Color option
|
||||||
|
|
||||||
|
Helps train the model to generalize perceptual color and lightness, and improves color transfer between src and dst.
|
||||||
|
|
||||||
|
- [DESCRIPTION](#description)
|
||||||
|
- [USAGE](#usage)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
|
||||||
|
Converts images to [CIE L\*a\*b* colorspace](https://en.wikipedia.org/wiki/CIELAB_color_space),
|
||||||
|
and then randomly rotates around the `L*` axis. While the perceptual lightness stays constant, only the `a*` and `b*`
|
||||||
|
color channels are modified. After rotation, converts back to BGR (blue/green/red) colorspace.
|
||||||
|
|
||||||
|
If visualized using the [CIE L\*a\*b* cylindical model](https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_model),
|
||||||
|
this is a random rotation of `h°` (hue angle, angle of the hue in the CIELAB color wheel),
|
||||||
|
maintaining the same `C*` (chroma, relative saturation).
|
||||||
|
|
||||||
|
## USAGE
|
||||||
|
|
||||||
|
`[n] Random color ( y/n ?:help ) : y`
|
BIN
doc/features/random-color/example.jpeg
Normal file
BIN
doc/features/random-color/example.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 133 KiB |
|
@ -13,12 +13,24 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
|
const socket = io.connect();
|
||||||
|
socket.on('preview', function(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
$('img#preview').attr("src", "{{ url_for('preview_image') }}?q=" + new Date().getTime());
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('loss', function(loss_string) {
|
||||||
|
console.log(loss_string);
|
||||||
|
$('div#loss').html(loss_string);
|
||||||
|
});
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
$.post("{{ url_for('save') }}");
|
$.post("{{ url_for('save') }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
function exit() {
|
function exit() {
|
||||||
$.post("{{ url_for('exit') }}");
|
$.post("{{ url_for('exit') }}");
|
||||||
|
socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
@ -63,17 +75,6 @@
|
||||||
$('button#zoom_next').click(zoom_next);
|
$('button#zoom_next').click(zoom_next);
|
||||||
|
|
||||||
$('img#preview').click(update);
|
$('img#preview').click(update);
|
||||||
|
|
||||||
const socket = io.connect();
|
|
||||||
socket.on('preview', function(msg) {
|
|
||||||
console.log(msg);
|
|
||||||
$('img#preview').attr("src", "{{ url_for('preview_image') }}?q=" + new Date().getTime());
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('loss', function(loss_string) {
|
|
||||||
console.log(loss_string);
|
|
||||||
$('div#loss').html(loss_string);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -446,7 +446,7 @@ def main(**kwargs):
|
||||||
while True:
|
while True:
|
||||||
if not c2s.empty():
|
if not c2s.empty():
|
||||||
item = c2s.get()
|
item = c2s.get()
|
||||||
op = input['op']
|
op = item['op']
|
||||||
if op == 'show':
|
if op == 'show':
|
||||||
is_waiting_preview = False
|
is_waiting_preview = False
|
||||||
loss_history = item['loss_history'] if 'loss_history' in item.keys() else None
|
loss_history = item['loss_history'] if 'loss_history' in item.keys() else None
|
||||||
|
|
|
@ -60,6 +60,7 @@ class SAEHDModel(ModelBase):
|
||||||
default_face_style_power = self.options['face_style_power'] = self.load_or_def_option('face_style_power', 0.0)
|
default_face_style_power = self.options['face_style_power'] = self.load_or_def_option('face_style_power', 0.0)
|
||||||
default_bg_style_power = self.options['bg_style_power'] = self.load_or_def_option('bg_style_power', 0.0)
|
default_bg_style_power = self.options['bg_style_power'] = self.load_or_def_option('bg_style_power', 0.0)
|
||||||
default_ct_mode = self.options['ct_mode'] = self.load_or_def_option('ct_mode', 'none')
|
default_ct_mode = self.options['ct_mode'] = self.load_or_def_option('ct_mode', 'none')
|
||||||
|
default_random_color = self.options['random_color'] = self.load_or_def_option('random_color', False)
|
||||||
default_clipgrad = self.options['clipgrad'] = self.load_or_def_option('clipgrad', False)
|
default_clipgrad = self.options['clipgrad'] = self.load_or_def_option('clipgrad', False)
|
||||||
default_pretrain = self.options['pretrain'] = self.load_or_def_option('pretrain', False)
|
default_pretrain = self.options['pretrain'] = self.load_or_def_option('pretrain', False)
|
||||||
|
|
||||||
|
@ -171,6 +172,7 @@ Examples: df, liae, df-d, df-ud, liae-ud, ...
|
||||||
self.options['bg_style_power'] = np.clip ( io.input_number("Background style power", default_bg_style_power, add_info="0.0..100.0", help_message="Learn the area outside mask of the predicted face to be the same as dst. If you want to use this option with 'whole_face' you have to use XSeg trained mask. For whole_face you have to use XSeg trained mask. This can make face more like dst. Enabling this option increases the chance of model collapse. Typical value is 2.0"), 0.0, 100.0 )
|
self.options['bg_style_power'] = np.clip ( io.input_number("Background style power", default_bg_style_power, add_info="0.0..100.0", help_message="Learn the area outside mask of the predicted face to be the same as dst. If you want to use this option with 'whole_face' you have to use XSeg trained mask. For whole_face you have to use XSeg trained mask. This can make face more like dst. Enabling this option increases the chance of model collapse. Typical value is 2.0"), 0.0, 100.0 )
|
||||||
|
|
||||||
self.options['ct_mode'] = io.input_str (f"Color transfer for src faceset", default_ct_mode, ['none','rct','lct','mkl','idt','sot', 'fs-aug'], help_message="Change color distribution of src samples close to dst samples. Try all modes to find the best. FS aug adds random color to dst and src")
|
self.options['ct_mode'] = io.input_str (f"Color transfer for src faceset", default_ct_mode, ['none','rct','lct','mkl','idt','sot', 'fs-aug'], help_message="Change color distribution of src samples close to dst samples. Try all modes to find the best. FS aug adds random color to dst and src")
|
||||||
|
self.options['random_color'] = io.input_bool ("Random color", default_random_color, help_message="Samples are randomly rotated around the L axis in LAB colorspace, helps generalize training")
|
||||||
self.options['clipgrad'] = io.input_bool ("Enable gradient clipping", default_clipgrad, help_message="Gradient clipping reduces chance of model collapse, sacrificing speed of training.")
|
self.options['clipgrad'] = io.input_bool ("Enable gradient clipping", default_clipgrad, help_message="Gradient clipping reduces chance of model collapse, sacrificing speed of training.")
|
||||||
|
|
||||||
self.options['pretrain'] = io.input_bool ("Enable pretraining mode", default_pretrain, help_message="Pretrain the model with large amount of various faces. After that, model can be used to train the fakes more quickly.")
|
self.options['pretrain'] = io.input_bool ("Enable pretraining mode", default_pretrain, help_message="Pretrain the model with large amount of various faces. After that, model can be used to train the fakes more quickly.")
|
||||||
|
@ -672,11 +674,13 @@ Examples: df, liae, df-d, df-ud, liae-ud, ...
|
||||||
if ct_mode == 'fs-aug':
|
if ct_mode == 'fs-aug':
|
||||||
fs_aug = 'fs-aug'
|
fs_aug = 'fs-aug'
|
||||||
|
|
||||||
|
channel_type = SampleProcessor.ChannelType.LAB_RAND_TRANSFORM if self.options['random_color'] else SampleProcessor.ChannelType.BGR
|
||||||
|
|
||||||
self.set_training_data_generators ([
|
self.set_training_data_generators ([
|
||||||
SampleGeneratorFace(training_data_src_path, random_ct_samples_path=random_ct_samples_path, debug=self.is_debug(), batch_size=self.get_batch_size(),
|
SampleGeneratorFace(training_data_src_path, random_ct_samples_path=random_ct_samples_path, debug=self.is_debug(), batch_size=self.get_batch_size(),
|
||||||
sample_process_options=SampleProcessor.Options(random_flip=self.random_flip),
|
sample_process_options=SampleProcessor.Options(random_flip=self.random_flip),
|
||||||
output_sample_types = [ {'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':random_warp, 'transform':True, 'channel_type' : SampleProcessor.ChannelType.BGR, 'ct_mode': ct_mode, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
output_sample_types = [ {'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':random_warp, 'transform':True, 'channel_type' : channel_type, 'ct_mode': ct_mode, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.BGR, 'ct_mode': ct_mode, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':False , 'transform':True, 'channel_type' : channel_type, 'ct_mode': ct_mode, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE_EYES, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE_EYES, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
],
|
],
|
||||||
|
@ -685,8 +689,8 @@ Examples: df, liae, df-d, df-ud, liae-ud, ...
|
||||||
|
|
||||||
SampleGeneratorFace(training_data_dst_path, debug=self.is_debug(), batch_size=self.get_batch_size(),
|
SampleGeneratorFace(training_data_dst_path, debug=self.is_debug(), batch_size=self.get_batch_size(),
|
||||||
sample_process_options=SampleProcessor.Options(random_flip=self.random_flip),
|
sample_process_options=SampleProcessor.Options(random_flip=self.random_flip),
|
||||||
output_sample_types = [ {'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':random_warp, 'transform':True, 'channel_type' : SampleProcessor.ChannelType.BGR, 'ct_mode': fs_aug, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
output_sample_types = [ {'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':random_warp, 'transform':True, 'channel_type' : channel_type, 'ct_mode': fs_aug, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.BGR, 'ct_mode': fs_aug, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_IMAGE,'warp':False , 'transform':True, 'channel_type' : channel_type, 'ct_mode': fs_aug, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE_EYES, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
{'sample_type': SampleProcessor.SampleType.FACE_MASK, 'warp':False , 'transform':True, 'channel_type' : SampleProcessor.ChannelType.G, 'face_mask_type' : SampleProcessor.FaceMaskType.FULL_FACE_EYES, 'face_type':self.face_type, 'data_format':nn.data_format, 'resolution': resolution},
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,6 +8,7 @@ import numpy as np
|
||||||
from core import imagelib
|
from core import imagelib
|
||||||
from core.cv2ex import *
|
from core.cv2ex import *
|
||||||
from core.imagelib import sd
|
from core.imagelib import sd
|
||||||
|
from core.imagelib.color_transfer import random_lab_rotation
|
||||||
from facelib import FaceType, LandmarksProcessor
|
from facelib import FaceType, LandmarksProcessor
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ class SampleProcessor(object):
|
||||||
BGR = 1 #BGR
|
BGR = 1 #BGR
|
||||||
G = 2 #Grayscale
|
G = 2 #Grayscale
|
||||||
GGG = 3 #3xGrayscale
|
GGG = 3 #3xGrayscale
|
||||||
|
LAB_RAND_TRANSFORM = 4 # LAB random transform
|
||||||
|
|
||||||
|
|
||||||
class FaceMaskType(IntEnum):
|
class FaceMaskType(IntEnum):
|
||||||
NONE = 0
|
NONE = 0
|
||||||
|
@ -231,6 +234,8 @@ class SampleProcessor(object):
|
||||||
# Transform from BGR to desired channel_type
|
# Transform from BGR to desired channel_type
|
||||||
if channel_type == SPCT.BGR:
|
if channel_type == SPCT.BGR:
|
||||||
out_sample = img
|
out_sample = img
|
||||||
|
elif channel_type == SPCT.LAB_RAND_TRANSFORM:
|
||||||
|
out_sample = random_lab_rotation(img, sample_rnd_seed)
|
||||||
elif channel_type == SPCT.G:
|
elif channel_type == SPCT.G:
|
||||||
out_sample = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)[...,None]
|
out_sample = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)[...,None]
|
||||||
elif channel_type == SPCT.GGG:
|
elif channel_type == SPCT.GGG:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue