daddyjin commited on
Commit
9f3fa29
·
1 Parent(s): 182e18d

add all files except ckpt files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. FONT/.idea/.gitignore +8 -0
  2. FONT/.idea/EAMM-main.iml +15 -0
  3. FONT/.idea/deployment.xml +15 -0
  4. FONT/.idea/inspectionProfiles/Project_Default.xml +22 -0
  5. FONT/.idea/inspectionProfiles/profiles_settings.xml +6 -0
  6. FONT/.idea/misc.xml +4 -0
  7. FONT/.idea/modules.xml +8 -0
  8. FONT/.idea/sshConfigs.xml +8 -0
  9. FONT/3DDFA_V2/demo.py +246 -0
  10. FONT/3DDFA_V2/utils/pose.py +284 -0
  11. FONT/LICENSE +21 -0
  12. FONT/M003_template.npy +3 -0
  13. FONT/README.md +67 -0
  14. FONT/audio.py +145 -0
  15. FONT/augmentation.py +430 -0
  16. FONT/config/MEAD_emo_video_aug_delta_4_crop_random_crop.yaml +105 -0
  17. FONT/config/train_part1.yaml +83 -0
  18. FONT/config/train_part1_fine_tune.yaml +81 -0
  19. FONT/config/train_part1_fine_tune_hdtf.yaml +81 -0
  20. FONT/config/train_part1_hdtf.yaml +83 -0
  21. FONT/config/train_part2.yaml +93 -0
  22. FONT/demo.py +632 -0
  23. FONT/filter1.py +48 -0
  24. FONT/frames_dataset.py +539 -0
  25. FONT/frames_dataset_liujin.py +727 -0
  26. FONT/gradio_demo.py +560 -0
  27. FONT/hparams.py +101 -0
  28. FONT/logger.py +225 -0
  29. FONT/modules/conv.py +44 -0
  30. FONT/modules/dense_motion.py +113 -0
  31. FONT/modules/discriminator.py +95 -0
  32. FONT/modules/frames_dataset.py +451 -0
  33. FONT/modules/function.py +75 -0
  34. FONT/modules/generator.py +97 -0
  35. FONT/modules/keypoint_detector.py +260 -0
  36. FONT/modules/model.py +597 -0
  37. FONT/modules/model1.py +539 -0
  38. FONT/modules/model_delta_map.py +500 -0
  39. FONT/modules/model_gen.py +516 -0
  40. FONT/modules/ops.py +77 -0
  41. FONT/modules/stylegan2.py +923 -0
  42. FONT/modules/util.py +2008 -0
  43. FONT/ops.py +96 -0
  44. FONT/process_data.py +143 -0
  45. FONT/requirements.txt +16 -0
  46. FONT/result/all.mov +3 -0
  47. FONT/result/all_with_pose.mov +3 -0
  48. FONT/run.py +137 -0
  49. FONT/script_backup.sh +17 -0
  50. FONT/script_finetune_liujin.sh +1 -0
FONT/.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Datasource local storage ignored files
5
+ /../../../../../:\PG5\projects\EAMM-main\.idea/dataSources/
6
+ /dataSources.local.xml
7
+ # Editor-based HTTP Client requests
8
+ /httpRequests/
FONT/.idea/EAMM-main.iml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$" />
5
+ <orderEntry type="inheritedJdk" />
6
+ <orderEntry type="sourceFolder" forTests="false" />
7
+ </component>
8
+ <component name="PyDocumentationSettings">
9
+ <option name="format" value="GOOGLE" />
10
+ <option name="myDocStringFormat" value="Google" />
11
+ </component>
12
+ <component name="TestRunnerService">
13
+ <option name="PROJECT_TEST_RUNNER" value="pytest" />
14
+ </component>
15
+ </module>
FONT/.idea/deployment.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="PublishConfigData" autoUpload="Always" serverName="10.26.128.77" remoteFilesAllowedToDisappearOnAutoupload="false">
4
+ <serverData>
5
+ <paths name="10.26.128.77">
6
+ <serverdata>
7
+ <mappings>
8
+ <mapping deploy="/data/liujin/EAMM-main" local="$PROJECT_DIR$" web="/" />
9
+ </mappings>
10
+ </serverdata>
11
+ </paths>
12
+ </serverData>
13
+ <option name="myAutoUpload" value="ALWAYS" />
14
+ </component>
15
+ </project>
FONT/.idea/inspectionProfiles/Project_Default.xml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
6
+ <option name="ignoredPackages">
7
+ <value>
8
+ <list size="7">
9
+ <item index="0" class="java.lang.String" itemvalue="tensorboard" />
10
+ <item index="1" class="java.lang.String" itemvalue="opencv-python" />
11
+ <item index="2" class="java.lang.String" itemvalue="librosa" />
12
+ <item index="3" class="java.lang.String" itemvalue="torch" />
13
+ <item index="4" class="java.lang.String" itemvalue="dill" />
14
+ <item index="5" class="java.lang.String" itemvalue="torchvision" />
15
+ <item index="6" class="java.lang.String" itemvalue="dominate" />
16
+ </list>
17
+ </value>
18
+ </option>
19
+ </inspection_tool>
20
+ <inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
21
+ </profile>
22
+ </component>
FONT/.idea/inspectionProfiles/profiles_settings.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
FONT/.idea/misc.xml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (base)" project-jdk-type="Python SDK" />
4
+ </project>
FONT/.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/EAMM-main.iml" filepath="$PROJECT_DIR$/.idea/EAMM-main.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
FONT/.idea/sshConfigs.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="SshConfigs">
4
+ <configs>
5
+ <sshConfig authType="PASSWORD" host="10.26.128.77" id="e53dc234-7f07-4f76-84e5-ddf5b28db632" port="22" nameFormat="DESCRIPTIVE" username="user" useOpenSSHConfig="true" />
6
+ </configs>
7
+ </component>
8
+ </project>
FONT/3DDFA_V2/demo.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+
3
+ __author__ = 'cleardusk'
4
+
5
+ import sys
6
+ import argparse
7
+ import cv2
8
+ import yaml
9
+ import os
10
+ import time
11
+ from FaceBoxes import FaceBoxes
12
+ from TDDFA import TDDFA
13
+ from utils.render import render
14
+ #from utils.render_ctypes import render # faster
15
+ from utils.depth import depth
16
+ from utils.pncc import pncc
17
+ from utils.uv import uv_tex
18
+ from utils.pose import viz_pose, get_pose
19
+ from utils.serialization import ser_to_ply, ser_to_obj
20
+ from utils.functions import draw_landmarks, get_suffix
21
+ from utils.tddfa_util import str2bool
22
+ import numpy as np
23
+ from tqdm import tqdm
24
+ import copy
25
+
26
+ import concurrent.futures
27
+ from multiprocessing import Pool
28
+
29
+ def main(args,img, save_path, pose_path):
30
+ # begin = time.time()
31
+ cfg = yaml.load(open(args.config), Loader=yaml.SafeLoader)
32
+
33
+ # Init FaceBoxes and TDDFA, recommend using onnx flag
34
+ if args.onnx:
35
+ import os
36
+ os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
37
+ os.environ['OMP_NUM_THREADS'] = '4'
38
+
39
+ from FaceBoxes.FaceBoxes_ONNX import FaceBoxes_ONNX
40
+ from TDDFA_ONNX import TDDFA_ONNX
41
+
42
+ face_boxes = FaceBoxes_ONNX()
43
+ tddfa = TDDFA_ONNX(**cfg)
44
+ else:
45
+ gpu_mode = args.mode == 'gpu'
46
+ tddfa = TDDFA(gpu_mode=gpu_mode, **cfg)
47
+ face_boxes = FaceBoxes()
48
+
49
+ # Given a still image path and load to BGR channel
50
+ # img = cv2.imread(img_path) #args.img_fp
51
+
52
+ # Detect faces, get 3DMM params and roi boxes
53
+ boxes = face_boxes(img)
54
+ n = len(boxes)
55
+ if n == 0:
56
+ print(f'No face detected, exit')
57
+ # sys.exit(-1)
58
+ return None
59
+ print(f'Detect {n} faces')
60
+
61
+ param_lst, roi_box_lst = tddfa(img, boxes)
62
+ #detection time
63
+ # detect_time = time.time()-begin
64
+ # print('detection time: '+str(detect_time), file=open('/mnt/lustre/jixinya/Home/3DDFA_V2/pose.txt', 'a'))
65
+ # Visualization and serialization
66
+ dense_flag = args.opt in ('2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'ply', 'obj')
67
+ # old_suffix = get_suffix(img_path)
68
+ old_suffix = 'png'
69
+ new_suffix = f'.{args.opt}' if args.opt in ('ply', 'obj') else '.jpg'
70
+
71
+ wfp = f'examples/results/{args.img_fp.split("/")[-1].replace(old_suffix, "")}_{args.opt}' + new_suffix
72
+
73
+ ver_lst = tddfa.recon_vers(param_lst, roi_box_lst, dense_flag=dense_flag)
74
+
75
+ if args.opt == '2d_sparse':
76
+ draw_landmarks(img, ver_lst, show_flag=args.show_flag, dense_flag=dense_flag, wfp=wfp)
77
+ elif args.opt == '2d_dense':
78
+ draw_landmarks(img, ver_lst, show_flag=args.show_flag, dense_flag=dense_flag, wfp=wfp)
79
+ elif args.opt == '3d':
80
+ render(img, ver_lst, tddfa.tri, alpha=0.6, show_flag=args.show_flag, wfp=wfp)
81
+ elif args.opt == 'depth':
82
+
83
+ # if `with_bf_flag` is False, the background is black
84
+ depth(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp, with_bg_flag=True)
85
+ elif args.opt == 'pncc':
86
+ pncc(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp, with_bg_flag=True)
87
+ elif args.opt == 'uv_tex':
88
+ uv_tex(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp)
89
+ elif args.opt == 'pose':
90
+ all_pose = get_pose(img, param_lst, ver_lst, show_flag=args.show_flag, wfp=save_path, wnp = pose_path)
91
+ elif args.opt == 'ply':
92
+ ser_to_ply(ver_lst, tddfa.tri, height=img.shape[0], wfp=wfp)
93
+ elif args.opt == 'obj':
94
+ ser_to_obj(img, ver_lst, tddfa.tri, height=img.shape[0], wfp=wfp)
95
+ else:
96
+ raise ValueError(f'Unknown opt {args.opt}')
97
+
98
+ return all_pose
99
+
100
+
101
+
102
+ def process_word(i):
103
+ path = '/media/xinya/Backup Plus/sense_shixi_data/new_crop/MEAD_fomm_video_6/'
104
+ save = '/media/xinya/Backup Plus/sense_shixi_data/new_crop/MEAD_fomm_pose_im/'
105
+ pose = '/media/xinya/Backup Plus/sense_shixi_data/new_crop/MEAD_fomm_pose/'
106
+ start = time.time()
107
+ Dir = os.listdir(path)
108
+ Dir.sort()
109
+ word = Dir[i]
110
+ wpath = os.path.join(path, word)
111
+ print(wpath)
112
+ pathDir = os.listdir(wpath)
113
+ pose_file = os.path.join(pose,word)
114
+ if not os.path.exists(pose_file):
115
+ os.makedirs(pose_file)
116
+
117
+ for j in range(len(pathDir)):
118
+ name = pathDir[j]
119
+ # save_file = os.path.join(save,word,name)
120
+ # if not os.path.exists(save_file):
121
+ # os.makedirs(save_file)
122
+ fpath = os.path.join(wpath,name)
123
+ image_all = []
124
+ videoCapture = cv2.VideoCapture(fpath)
125
+
126
+ success, frame = videoCapture.read()
127
+
128
+ n = 0
129
+ while success :
130
+ image_all.append(frame)
131
+ n = n + 1
132
+ success, frame = videoCapture.read()
133
+
134
+ # fDir = os.listdir(fpath)
135
+ pose_all = np.zeros((len(image_all),7))
136
+ for k in range(len(image_all)):
137
+ # index = fDir[k].split('.')[0]
138
+ # img_path = os.path.join(fpath,str(k)+'.png')
139
+
140
+ # pose_all[k] = main(args,image_all[k], os.path.join(save_file,str(k)+'.jpg'), None)
141
+ pose_all[k] = main(args,image_all[k], None, None)
142
+ np.save(os.path.join(pose,word,name.split('.')[0]+'.npy'),pose_all)
143
+ st = time.time()-start
144
+ print(str(i)+' '+word+' '+str(j)+' '+name+' '+str(k)+'time: '+str(st), file=open('/media/thea/Backup Plus/sense_shixi_data/new_crop/pose_mead6.txt', 'a'))
145
+ print(i,word,j,name,k)
146
+
147
+ if __name__ == '__main__':
148
+ parser = argparse.ArgumentParser(description='The demo of still image of 3DDFA_V2')
149
+ parser.add_argument('-c', '--config', type=str, default='configs/mb1_120x120.yml')
150
+ parser.add_argument('-f', '--img_fp', type=str, default='examples/inputs/0.png')
151
+ parser.add_argument('-m', '--mode', type=str, default='cpu', help='gpu or cpu mode')
152
+ parser.add_argument('-o', '--opt', type=str, default='pose',
153
+ choices=['2d_sparse', '2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'pose', 'ply', 'obj'])
154
+ parser.add_argument('--show_flag', type=str2bool, default='False', help='whether to show the visualization result')
155
+ parser.add_argument('--onnx', action='store_true', default=False)
156
+
157
+ args = parser.parse_args()
158
+
159
+
160
+
161
+ # filepath = 'test/image/'
162
+ # pathDir = os.listdir(filepath)
163
+ # for i in range(len(pathDir)):
164
+ # image= cv2.imread(os.path.join(filepath,pathDir[i]))
165
+ # pose = main(args,image, None, None).reshape(1,7)
166
+ #
167
+ # np.save('test/pose/'+pathDir[i].split('.')[0]+'.npy',pose)
168
+ # print(i,pathDir[i])
169
+
170
+ test_image_path = "/data/liujin/dataset/LRW/lipread_frames/ABOUT/train/ABOUT_00001/000000.jpg"
171
+ image = cv2.imread(test_image_path)
172
+ pose = main(args, image, None, None).reshape(1, 7)
173
+ print(pose)
174
+
175
+
176
+
177
+
178
+ '''
179
+
180
+
181
+
182
+
183
+
184
+ def main(args):
185
+ cfg = yaml.load(open(args.config), Loader=yaml.SafeLoader)
186
+
187
+ # Init FaceBoxes and TDDFA, recommend using onnx flag
188
+ if args.onnx:
189
+ import os
190
+ os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
191
+ os.environ['OMP_NUM_THREADS'] = '4'
192
+
193
+ from FaceBoxes.FaceBoxes_ONNX import FaceBoxes_ONNX
194
+ from TDDFA_ONNX import TDDFA_ONNX
195
+
196
+ face_boxes = FaceBoxes_ONNX()
197
+ tddfa = TDDFA_ONNX(**cfg)
198
+ else:
199
+ gpu_mode = args.mode == 'gpu'
200
+ tddfa = TDDFA(gpu_mode=gpu_mode, **cfg)
201
+ face_boxes = FaceBoxes()
202
+
203
+ # Given a still image path and load to BGR channel
204
+ img = cv2.imread(args.img_fp)
205
+
206
+ # Detect faces, get 3DMM params and roi boxes
207
+ boxes = face_boxes(img)
208
+ n = len(boxes)
209
+ if n == 0:
210
+ print(f'No face detected, exit')
211
+ sys.exit(-1)
212
+ print(f'Detect {n} faces')
213
+
214
+ param_lst, roi_box_lst = tddfa(img, boxes)
215
+
216
+ # Visualization and serialization
217
+ dense_flag = args.opt in ('2d_dense', '3d', 'depth', 'pncc', 'uv_tex', 'ply', 'obj')
218
+ old_suffix = get_suffix(args.img_fp)
219
+ new_suffix = f'.{args.opt}' if args.opt in ('ply', 'obj') else '.jpg'
220
+
221
+ wfp = f'examples/results/{args.img_fp.split("/")[-1].replace(old_suffix, "")}_{args.opt}' + new_suffix
222
+
223
+ ver_lst = tddfa.recon_vers(param_lst, roi_box_lst, dense_flag=dense_flag)
224
+
225
+ if args.opt == '2d_sparse':
226
+ draw_landmarks(img, ver_lst, show_flag=args.show_flag, dense_flag=dense_flag, wfp=wfp)
227
+ elif args.opt == '2d_dense':
228
+ draw_landmarks(img, ver_lst, show_flag=args.show_flag, dense_flag=dense_flag, wfp=wfp)
229
+ elif args.opt == '3d':
230
+ render(img, ver_lst, tddfa.tri, alpha=0.6, show_flag=args.show_flag, wfp=wfp)
231
+ elif args.opt == 'depth':
232
+ # if `with_bf_flag` is False, the background is black
233
+ depth(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp, with_bg_flag=True)
234
+ elif args.opt == 'pncc':
235
+ pncc(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp, with_bg_flag=True)
236
+ elif args.opt == 'uv_tex':
237
+ uv_tex(img, ver_lst, tddfa.tri, show_flag=args.show_flag, wfp=wfp)
238
+ elif args.opt == 'pose':
239
+ viz_pose(img, param_lst, ver_lst, show_flag=args.show_flag, wfp=wfp)
240
+ elif args.opt == 'ply':
241
+ ser_to_ply(ver_lst, tddfa.tri, height=img.shape[0], wfp=wfp)
242
+ elif args.opt == 'obj':
243
+ ser_to_obj(img, ver_lst, tddfa.tri, height=img.shape[0], wfp=wfp)
244
+ else:
245
+ raise ValueError(f'Unknown opt {args.opt}')
246
+ '''
FONT/3DDFA_V2/utils/pose.py ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+
3
+ """
4
+ Reference: https://github.com/YadiraF/PRNet/blob/master/utils/estimate_pose.py
5
+
6
+ Calculating pose from the output 3DMM parameters, you can also try to use solvePnP to perform estimation
7
+ """
8
+
9
+ __author__ = 'cleardusk'
10
+
11
+ import cv2
12
+ import numpy as np
13
+ from math import cos, sin, atan2, asin, sqrt
14
+
15
+ from .functions import calc_hypotenuse, plot_image
16
+
17
+
18
+ def P2sRt(P):
19
+ """ decompositing camera matrix P.
20
+ Args:
21
+ P: (3, 4). Affine Camera Matrix.
22
+ Returns:
23
+ s: scale factor.
24
+ R: (3, 3). rotation matrix.
25
+ t2d: (2,). 2d translation.
26
+ """
27
+ t3d = P[:, 3]
28
+ R1 = P[0:1, :3]
29
+ R2 = P[1:2, :3]
30
+ s = (np.linalg.norm(R1) + np.linalg.norm(R2)) / 2.0
31
+ r1 = R1 / np.linalg.norm(R1)
32
+ r2 = R2 / np.linalg.norm(R2)
33
+ r3 = np.cross(r1, r2)
34
+
35
+ R = np.concatenate((r1, r2, r3), 0)
36
+ return s, R, t3d
37
+
38
+
39
+ def matrix2angle(R):
40
+ """ compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf
41
+ refined by: https://stackoverflow.com/questions/43364900/rotation-matrix-to-euler-angles-with-opencv
42
+ todo: check and debug
43
+ Args:
44
+ R: (3,3). rotation matrix
45
+ Returns:
46
+ x: yaw
47
+ y: pitch
48
+ z: roll
49
+ """
50
+ if R[2, 0] > 0.998:
51
+ z = 0
52
+ x = np.pi / 2
53
+ y = z + atan2(-R[0, 1], -R[0, 2])
54
+ elif R[2, 0] < -0.998:
55
+ z = 0
56
+ x = -np.pi / 2
57
+ y = -z + atan2(R[0, 1], R[0, 2])
58
+ else:
59
+ x = asin(R[2, 0])
60
+ y = atan2(R[2, 1] / cos(x), R[2, 2] / cos(x))
61
+ z = atan2(R[1, 0] / cos(x), R[0, 0] / cos(x))
62
+
63
+ return x, y, z
64
+
65
+ def angle2matrix(theta):
66
+ """ compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf
67
+ refined by: https://stackoverflow.com/questions/43364900/rotation-matrix-to-euler-angles-with-opencv
68
+ todo: check and debug
69
+ Args:
70
+ R: (3,3). rotation matrix
71
+ Returns:
72
+ x: yaw
73
+ y: pitch
74
+ z: roll
75
+ """
76
+ R_x = np.array([[1, 0, 0 ],
77
+
78
+ [0, cos(theta[1]), -sin(theta[1]) ],
79
+
80
+ [0, sin(theta[1]), cos(theta[1]) ]
81
+
82
+ ])
83
+
84
+
85
+
86
+ R_y = np.array([[cos(theta[0]), 0, sin(-theta[0]) ],
87
+
88
+ [0, 1, 0 ],
89
+
90
+ [-sin(-theta[0]), 0, cos(theta[0]) ]
91
+
92
+ ])
93
+
94
+
95
+
96
+ R_z = np.array([[cos(theta[2]), -sin(theta[2]), 0],
97
+
98
+ [sin(theta[2]), cos(theta[2]), 0],
99
+
100
+ [0, 0, 1]
101
+
102
+ ])
103
+
104
+
105
+
106
+ R = np.dot(R_z, np.dot( R_y, R_x ))
107
+
108
+
109
+
110
+ return R
111
+
112
+ def angle2matrix_3ddfa(angles):
113
+ ''' get rotation matrix from three rotation angles(radian). The same as in 3DDFA.
114
+ Args:
115
+ angles: [3,]. x, y, z angles
116
+ x: pitch.
117
+ y: yaw.
118
+ z: roll.
119
+ Returns:
120
+ R: 3x3. rotation matrix.
121
+ '''
122
+ # x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2])
123
+ x, y, z = angles[1], angles[0], angles[2]
124
+
125
+ # x
126
+ Rx=np.array([[1, 0, 0],
127
+ [0, cos(x), sin(x)],
128
+ [0, -sin(x), cos(x)]])
129
+ # y
130
+ Ry=np.array([[ cos(y), 0, -sin(y)],
131
+ [ 0, 1, 0],
132
+ [sin(y), 0, cos(y)]])
133
+ # z
134
+ Rz=np.array([[cos(z), sin(z), 0],
135
+ [-sin(z), cos(z), 0],
136
+ [ 0, 0, 1]])
137
+ R = Rx.dot(Ry).dot(Rz)
138
+ return R.astype(np.float32)
139
+
140
+ def calc_pose(param):
141
+ P = param[:12].reshape(3, -1) # camera matrix
142
+ s, R, t3d = P2sRt(P)
143
+ P = np.concatenate((R, t3d.reshape(3, -1)), axis=1) # without scale
144
+ pose = matrix2angle(R)
145
+ pose = [p * 180 / np.pi for p in pose]
146
+
147
+ return P, pose
148
+
149
+
150
+ def build_camera_box(rear_size=90):
151
+ point_3d = []
152
+ rear_depth = 0
153
+ point_3d.append((-rear_size, -rear_size, rear_depth))
154
+ point_3d.append((-rear_size, rear_size, rear_depth))
155
+ point_3d.append((rear_size, rear_size, rear_depth))
156
+ point_3d.append((rear_size, -rear_size, rear_depth))
157
+ point_3d.append((-rear_size, -rear_size, rear_depth))
158
+
159
+ front_size = int(4 / 3 * rear_size)
160
+ front_depth = int(4 / 3 * rear_size)
161
+ point_3d.append((-front_size, -front_size, front_depth))
162
+ point_3d.append((-front_size, front_size, front_depth))
163
+ point_3d.append((front_size, front_size, front_depth))
164
+ point_3d.append((front_size, -front_size, front_depth))
165
+ point_3d.append((-front_size, -front_size, front_depth))
166
+ point_3d = np.array(point_3d, dtype=np.float32).reshape(-1, 3)
167
+
168
+ return point_3d
169
+
170
+
171
+ def plot_pose_box(img, P, ver, color=(40, 255, 0), line_width=2):
172
+ """ Draw a 3D box as annotation of pose.
173
+ Ref:https://github.com/yinguobing/head-pose-estimation/blob/master/pose_estimator.py
174
+ Args:
175
+ img: the input image
176
+ P: (3, 4). Affine Camera Matrix.
177
+ kpt: (2, 68) or (3, 68)
178
+ """
179
+ llength = calc_hypotenuse(ver)
180
+ point_3d = build_camera_box(llength)
181
+ # Map to 2d image points
182
+ point_3d_homo = np.hstack((point_3d, np.ones([point_3d.shape[0], 1]))) # n x 4
183
+ point_2d = point_3d_homo.dot(P.T)[:, :2]
184
+
185
+ point_2d[:, 1] = - point_2d[:, 1]
186
+ point_2d[:, :2] = point_2d[:, :2] - np.mean(point_2d[:4, :2], 0) + np.mean(ver[:2, :27], 1)
187
+ point_2d = np.int32(point_2d.reshape(-1, 2))
188
+
189
+ # Draw all the lines
190
+ cv2.polylines(img, [point_2d], True, color, line_width, cv2.LINE_AA)
191
+ cv2.line(img, tuple(point_2d[1]), tuple(
192
+ point_2d[6]), color, line_width, cv2.LINE_AA)
193
+ cv2.line(img, tuple(point_2d[2]), tuple(
194
+ point_2d[7]), color, line_width, cv2.LINE_AA)
195
+ cv2.line(img, tuple(point_2d[3]), tuple(
196
+ point_2d[8]), color, line_width, cv2.LINE_AA)
197
+
198
+ return img
199
+
200
+
201
+ def viz_pose(img, param_lst, ver_lst, show_flag=False, wfp=None):
202
+ for param, ver in zip(param_lst, ver_lst):
203
+ P, pose = calc_pose(param)
204
+ img = plot_pose_box(img, P, ver)
205
+ # print(P[:, :3])
206
+ print(f'yaw: {pose[0]:.1f}, pitch: {pose[1]:.1f}, roll: {pose[2]:.1f}')
207
+
208
+ if wfp is not None:
209
+ cv2.imwrite(wfp, img)
210
+ print(f'Save visualization result to {wfp}')
211
+
212
+ if show_flag:
213
+ plot_image(img)
214
+
215
+ return img
216
+
217
+ def pose_6(param):
218
+ P = param[:12].reshape(3, -1) # camera matrix
219
+ s, R, t3d = P2sRt(P)
220
+ P = np.concatenate((R, t3d.reshape(3, -1)), axis=1) # without scale
221
+ pose = matrix2angle(R)
222
+ print(t3d)
223
+ R1 = angle2matrix(pose)
224
+ print(R)
225
+ print(R1)
226
+ pose = [p * 180 / np.pi for p in pose]
227
+
228
+ return s, pose, t3d, P
229
+
230
+
231
+ def smooth_pose(img, param_lst, ver_lst, pose_new, show_flag=False, wfp=None, wnp = None):
232
+ for param, ver in zip(param_lst, ver_lst):
233
+ t3d = np.array([pose_new[4],pose_new[5],pose_new[6]])
234
+
235
+ theta = np.array([pose_new[0],pose_new[1],pose_new[2]])
236
+ theta = [p * np.pi / 180 for p in theta]
237
+ R = angle2matrix(theta)
238
+ P = np.concatenate((R, t3d.reshape(3, -1)), axis=1)
239
+ img = plot_pose_box(img, P, ver)
240
+ # print(P,P.shape,t3d)
241
+ print(P,pose_new)
242
+ print(f'yaw: {theta[0]:.1f}, pitch: {theta[1]:.1f}, roll: {theta[2]:.1f}')
243
+ all_pose = [0]
244
+ all_pose = np.array(all_pose)
245
+
246
+ if wfp is not None:
247
+ cv2.imwrite(wfp, img)
248
+ print(f'Save visualization result to {wfp}')
249
+
250
+ if wnp is not None:
251
+ np.save(wnp, all_pose)
252
+ print(f'Save visualization result to {wfp}')
253
+
254
+ if show_flag:
255
+ plot_image(img)
256
+
257
+ return img
258
+
259
+
260
+
261
+
262
+
263
+ def get_pose(img, param_lst, ver_lst, show_flag=False, wfp=None, wnp = None):
264
+ for param, ver in zip(param_lst, ver_lst):
265
+ s, pose, t3d, P = pose_6(param)
266
+ img = plot_pose_box(img, P, ver)
267
+ # print(P,P.shape,t3d)
268
+ print(f'yaw: {pose[0]:.1f}, pitch: {pose[1]:.1f}, roll: {pose[2]:.1f}')
269
+ all_pose = [pose[0],pose[1],pose[2],s,t3d[0],t3d[1],t3d[2]]
270
+ all_pose = np.array(all_pose)
271
+
272
+ if wfp is not None:
273
+ cv2.imwrite(wfp, img)
274
+ print(f'Save visualization result to {wfp}')
275
+
276
+ if wnp is not None:
277
+ np.save(wnp, all_pose)
278
+ print(f'Save visualization result to {wfp}')
279
+
280
+ if show_flag:
281
+ plot_image(img)
282
+
283
+ return all_pose
284
+
FONT/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2022 jixinya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
FONT/M003_template.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f7d9af24074def1fa92e8e83c2dc2a926f7d1d40054580e84472711797b3918d
3
+ size 1216
FONT/README.md ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # EAMM: One-Shot Emotional Talking Face via Audio-Based Emotion-Aware Motion Model [SIGGRAPH 2022 Conference]
2
+
3
+ Xinya Ji, [Hang Zhou](https://hangz-nju-cuhk.github.io/), Kaisiyuan Wang, [Qianyi Wu](https://wuqianyi.top/), [Wayne Wu](http://wywu.github.io/), [Feng Xu](http://xufeng.site/), [Xun Cao](https://cite.nju.edu.cn/People/Faculty/20190621/i5054.html)
4
+
5
+ [[Project]](https://jixinya.github.io/projects/EAMM/) [[Paper]](https://arxiv.org/abs/2205.15278)
6
+
7
+ ![visualization](demo/teaser-1.png)
8
+
9
+ Given a single portrait image, we can synthesize emotional talking faces, where mouth movements match the input audio and facial emotion dynamics follow the emotion source video.
10
+
11
+ ## Installation
12
+
13
+ We train and test based on Python3.6 and Pytorch. To install the dependencies run:
14
+
15
+ ```
16
+ pip install -r requirements.txt
17
+ ```
18
+
19
+ ## Testing
20
+
21
+ - Download the pre-trained models and data under the following link: [google-drive](https://drive.google.com/file/d/1IL9LjH3JegyMqJABqMxrX3StAq_v8Gtp/view?usp=sharing) and put the file in corresponding places.
22
+
23
+ - Run the demo:
24
+
25
+ `python demo.py --source_image path/to/image --driving_video path/to/emotion_video --pose_file path/to/pose --in_file path/to/audio --emotion emotion_type`
26
+
27
+ - Prepare testing data:
28
+
29
+ prepare source_image -- crop_image in process_data.py
30
+
31
+ prepare driving_video -- crop_image_tem in process_data.py
32
+
33
+ prepare pose -- detect pose using [3DDFA_V2](https://github.com/cleardusk/3DDFA_V2)
34
+
35
+ ## Training
36
+
37
+ - Dataset process: Coming soon.
38
+
39
+ - Step 1 : Train the Audio2Facial-Dynamics Module using LRW dataset
40
+
41
+ `python run.py --config config/train_part1.yaml --mode train_part1 --checkpoint log/124_52000.pth.tar `
42
+
43
+ - Step 2 : Fine-tune the Audio2Facial-Dynamics Module after getting stable results from step1
44
+
45
+ `python run.py --config config/train_part1_fine_tune.yaml --mode train_part1_fine_tune --checkpoint log/124_52000.pth.tar --audio_chechpoint checkpoint/from/step_1`
46
+
47
+ - Setp 3 : Train the Implicit Emotion Displacement Learner
48
+
49
+ `python run.py --config config/train_part2.yaml --mode train_part2 --checkpoint log/124_52000.pth.tar --audio_chechpoint checkpoint/from/step_2`
50
+
51
+ ## Citation
52
+
53
+ ```
54
+ @inproceedings{10.1145/3528233.3530745,
55
+ author = {Ji, Xinya and Zhou, Hang and Wang, Kaisiyuan and Wu, Qianyi and Wu, Wayne and Xu, Feng and Cao, Xun},
56
+ title = {EAMM: One-Shot Emotional Talking Face via Audio-Based Emotion-Aware Motion Model},
57
+ year = {2022},
58
+ isbn = {9781450393379},
59
+ url = {https://doi.org/10.1145/3528233.3530745},
60
+ doi = {10.1145/3528233.3530745},
61
+ booktitle = {ACM SIGGRAPH 2022 Conference Proceedings},
62
+ series = {SIGGRAPH '22}
63
+ }
64
+
65
+
66
+ ```
67
+
FONT/audio.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import librosa
2
+ import librosa.filters
3
+ import numpy as np
4
+ # import tensorflow as tf
5
+ from scipy import signal
6
+ from scipy.io import wavfile
7
+ # from dataset.hparams import hparams as hp
8
+ from hparams import hparams as hp
9
+ import scipy, cv2, os, sys, argparse
10
+
11
+ def load_wav(path, sr):
12
+ return librosa.core.load(path, sr=sr)[0]
13
+
14
+ def save_wav(wav, path, sr):
15
+ wav *= 32767 / max(0.01, np.max(np.abs(wav)))
16
+ #proposed by @dsmiller
17
+ wavfile.write(path, sr, wav.astype(np.int16))
18
+
19
+ def save_wavenet_wav(wav, path, sr):
20
+ librosa.output.write_wav(path, wav, sr=sr)
21
+
22
+ def preemphasis(wav, k, preemphasize=True):
23
+ if preemphasize:
24
+ return signal.lfilter([1, -k], [1], wav)
25
+ return wav
26
+
27
+ def inv_preemphasis(wav, k, inv_preemphasize=True):
28
+ if inv_preemphasize:
29
+ return signal.lfilter([1], [1, -k], wav)
30
+ return wav
31
+
32
+ def get_hop_size():
33
+ hop_size = hp.hop_size
34
+ if hop_size is None:
35
+ assert hp.frame_shift_ms is not None
36
+ hop_size = int(hp.frame_shift_ms / 1000 * hp.sample_rate)
37
+ return hop_size
38
+
39
+ def linearspectrogram(wav):
40
+ D = _stft(preemphasis(wav, hp.preemphasis, hp.preemphasize))
41
+ S = _amp_to_db(np.abs(D)) - hp.ref_level_db
42
+
43
+ if hp.signal_normalization:
44
+ return _normalize(S)
45
+ return S
46
+
47
+ def melspectrogram(wav):
48
+ D = _stft(preemphasis(wav, hp.preemphasis, hp.preemphasize))
49
+ S = _amp_to_db(_linear_to_mel(np.abs(D))) - hp.ref_level_db
50
+
51
+ if hp.signal_normalization:
52
+ return _normalize(S)
53
+ return S
54
+
55
+ def _lws_processor():
56
+ import lws
57
+ return lws.lws(hp.n_fft, get_hop_size(), fftsize=hp.win_size, mode="speech")
58
+
59
+ def _stft(y):
60
+ if hp.use_lws:
61
+ return _lws_processor(hp).stft(y).T
62
+ else:
63
+ return librosa.stft(y=y, n_fft=hp.n_fft, hop_length=get_hop_size(), win_length=hp.win_size)
64
+
65
+ ##########################################################
66
+ #Those are only correct when using lws!!! (This was messing with Wavenet quality for a long time!)
67
+ def num_frames(length, fsize, fshift):
68
+ """Compute number of time frames of spectrogram
69
+ """
70
+ pad = (fsize - fshift)
71
+ if length % fshift == 0:
72
+ M = (length + pad * 2 - fsize) // fshift + 1
73
+ else:
74
+ M = (length + pad * 2 - fsize) // fshift + 2
75
+ return M
76
+
77
+
78
+ def pad_lr(x, fsize, fshift):
79
+ """Compute left and right padding
80
+ """
81
+ M = num_frames(len(x), fsize, fshift)
82
+ pad = (fsize - fshift)
83
+ T = len(x) + 2 * pad
84
+ r = (M - 1) * fshift + fsize - T
85
+ return pad, pad + r
86
+ ##########################################################
87
+ #Librosa correct padding
88
+ def librosa_pad_lr(x, fsize, fshift):
89
+ return 0, (x.shape[0] // fshift + 1) * fshift - x.shape[0]
90
+
91
+ # Conversions
92
+ _mel_basis = None
93
+
94
+ def _linear_to_mel(spectogram):
95
+ global _mel_basis
96
+ if _mel_basis is None:
97
+ _mel_basis = _build_mel_basis()
98
+ return np.dot(_mel_basis, spectogram)
99
+
100
+ def _build_mel_basis():
101
+ assert hp.fmax <= hp.sample_rate // 2
102
+ return librosa.filters.mel(hp.sample_rate, hp.n_fft, n_mels=hp.num_mels,
103
+ fmin=hp.fmin, fmax=hp.fmax)
104
+
105
+ def _amp_to_db(x):
106
+ min_level = np.exp(hp.min_level_db / 20 * np.log(10))
107
+ return 20 * np.log10(np.maximum(min_level, x))
108
+
109
+ def _db_to_amp(x):
110
+ return np.power(10.0, (x) * 0.05)
111
+
112
+ def _normalize(S):
113
+ if hp.allow_clipping_in_normalization:
114
+ if hp.symmetric_mels:
115
+ return np.clip((2 * hp.max_abs_value) * ((S - hp.min_level_db) / (-hp.min_level_db)) - hp.max_abs_value,
116
+ -hp.max_abs_value, hp.max_abs_value)
117
+ else:
118
+ return np.clip(hp.max_abs_value * ((S - hp.min_level_db) / (-hp.min_level_db)), 0, hp.max_abs_value)
119
+
120
+ assert S.max() <= 0 and S.min() - hp.min_level_db >= 0
121
+ if hp.symmetric_mels:
122
+ return (2 * hp.max_abs_value) * ((S - hp.min_level_db) / (-hp.min_level_db)) - hp.max_abs_value
123
+ else:
124
+ return hp.max_abs_value * ((S - hp.min_level_db) / (-hp.min_level_db))
125
+
126
+ def _denormalize(D):
127
+ if hp.allow_clipping_in_normalization:
128
+ if hp.symmetric_mels:
129
+ return (((np.clip(D, -hp.max_abs_value,
130
+ hp.max_abs_value) + hp.max_abs_value) * -hp.min_level_db / (2 * hp.max_abs_value))
131
+ + hp.min_level_db)
132
+ else:
133
+ return ((np.clip(D, 0, hp.max_abs_value) * -hp.min_level_db / hp.max_abs_value) + hp.min_level_db)
134
+
135
+ if hp.symmetric_mels:
136
+ return (((D + hp.max_abs_value) * -hp.min_level_db / (2 * hp.max_abs_value)) + hp.min_level_db)
137
+ else:
138
+ return ((D * -hp.min_level_db / hp.max_abs_value) + hp.min_level_db)
139
+
140
+
141
+ if __name__ == "__main__":
142
+ audio_path = "/data/liujin/dataset/LRW/lipread_wav/ABOUT/train/ABOUT_00001.wav"
143
+ wav = audio.load_wav(audio_path, 16000)
144
+ mel = audio.melspectrogram(wav)
145
+ print(mel.shape)
FONT/augmentation.py ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Code from https://github.com/hassony2/torch_videovision
3
+ """
4
+
5
+ import numbers
6
+ import math
7
+ import random
8
+ import numpy as np
9
+ import PIL
10
+ import cv2
11
+ from skimage.transform import resize, rotate, AffineTransform, warp
12
+ from skimage.util import pad
13
+ import torchvision
14
+
15
+ import warnings
16
+
17
+ from skimage import img_as_ubyte, img_as_float
18
+
19
+
20
+ def crop_clip(clip, min_h, min_w, h, w):
21
+ if isinstance(clip[0], np.ndarray):
22
+ cropped = [img[min_h:min_h + h, min_w:min_w + w, :] for img in clip]
23
+
24
+ elif isinstance(clip[0], PIL.Image.Image):
25
+ cropped = [
26
+ img.crop((min_w, min_h, min_w + w, min_h + h)) for img in clip
27
+ ]
28
+ else:
29
+ raise TypeError('Expected numpy.ndarray or PIL.Image' +
30
+ 'but got list of {0}'.format(type(clip[0])))
31
+ return cropped
32
+
33
+
34
+ def pad_clip(clip, h, w):
35
+ im_h, im_w = clip[0].shape[:2]
36
+ pad_h = (0, 0) if h < im_h else ((h - im_h) // 2, (h - im_h + 1) // 2)
37
+ pad_w = (0, 0) if w < im_w else ((w - im_w) // 2, (w - im_w + 1) // 2)
38
+
39
+ return pad(clip, ((0, 0), pad_h, pad_w, (0, 0)), mode='edge')
40
+
41
+
42
+ def resize_clip(clip, size, interpolation='bilinear'):
43
+ if isinstance(clip[0], np.ndarray):
44
+ if isinstance(size, numbers.Number):
45
+ im_h, im_w, im_c = clip[0].shape
46
+ # Min spatial dim already matches minimal size
47
+ if (im_w <= im_h and im_w == size) or (im_h <= im_w
48
+ and im_h == size):
49
+ return clip
50
+ new_h, new_w = get_resize_sizes(im_h, im_w, size)
51
+ size = (new_w, new_h)
52
+ else:
53
+ size = size[1], size[0]
54
+
55
+ scaled = [
56
+ resize(img, size, order=1 if interpolation == 'bilinear' else 0, preserve_range=True,
57
+ mode='constant', anti_aliasing=True) for img in clip
58
+ ]
59
+ elif isinstance(clip[0], PIL.Image.Image):
60
+ if isinstance(size, numbers.Number):
61
+ im_w, im_h = clip[0].size
62
+ # Min spatial dim already matches minimal size
63
+ if (im_w <= im_h and im_w == size) or (im_h <= im_w
64
+ and im_h == size):
65
+ return clip
66
+ new_h, new_w = get_resize_sizes(im_h, im_w, size)
67
+ size = (new_w, new_h)
68
+ else:
69
+ size = size[1], size[0]
70
+ if interpolation == 'bilinear':
71
+ pil_inter = PIL.Image.NEAREST
72
+ else:
73
+ pil_inter = PIL.Image.BILINEAR
74
+ scaled = [img.resize(size, pil_inter) for img in clip]
75
+ else:
76
+ raise TypeError('Expected numpy.ndarray or PIL.Image' +
77
+ 'but got list of {0}'.format(type(clip[0])))
78
+ return scaled
79
+
80
+
81
+ def get_resize_sizes(im_h, im_w, size):
82
+ if im_w < im_h:
83
+ ow = size
84
+ oh = int(size * im_h / im_w)
85
+ else:
86
+ oh = size
87
+ ow = int(size * im_w / im_h)
88
+ return oh, ow
89
+
90
+
91
+ class RandomFlip(object):
92
+ def __init__(self, time_flip=False, horizontal_flip=False):
93
+ self.time_flip = time_flip
94
+ self.horizontal_flip = horizontal_flip
95
+
96
+ def __call__(self, clip):
97
+ if random.random() < 0.5 and self.time_flip:
98
+ return clip[::-1]
99
+ if random.random() < 0.5 and self.horizontal_flip:
100
+ return [np.fliplr(img) for img in clip]
101
+
102
+ return clip
103
+
104
+
105
+ class RandomResize(object):
106
+ """Resizes a list of (H x W x C) numpy.ndarray to the final size
107
+ The larger the original image is, the more times it takes to
108
+ interpolate
109
+ Args:
110
+ interpolation (str): Can be one of 'nearest', 'bilinear'
111
+ defaults to nearest
112
+ size (tuple): (widht, height)
113
+ """
114
+
115
+ def __init__(self, ratio=(3. / 4., 4. / 3.), interpolation='nearest'):
116
+ self.ratio = ratio
117
+ self.interpolation = interpolation
118
+
119
+ def __call__(self, clip):
120
+ scaling_factor = random.uniform(self.ratio[0], self.ratio[1])
121
+
122
+ if isinstance(clip[0], np.ndarray):
123
+ im_h, im_w, im_c = clip[0].shape
124
+ elif isinstance(clip[0], PIL.Image.Image):
125
+ im_w, im_h = clip[0].size
126
+
127
+ new_w = int(im_w * scaling_factor)
128
+ new_h = int(im_h * scaling_factor)
129
+ new_size = (new_w, new_h)
130
+ resized = resize_clip(
131
+ clip, new_size, interpolation=self.interpolation)
132
+
133
+ return resized
134
+
135
+
136
+ class RandomCrop(object):
137
+ """Extract random crop at the same location for a list of videos
138
+ Args:
139
+ size (sequence or int): Desired output size for the
140
+ crop in format (h, w)
141
+ """
142
+
143
+ def __init__(self, size):
144
+ if isinstance(size, numbers.Number):
145
+ size = (size, size)
146
+
147
+ self.size = size
148
+
149
+ def __call__(self, clip):
150
+ """
151
+ Args:
152
+ img (PIL.Image or numpy.ndarray): List of videos to be cropped
153
+ in format (h, w, c) in numpy.ndarray
154
+ Returns:
155
+ PIL.Image or numpy.ndarray: Cropped list of videos
156
+ """
157
+ h, w = self.size
158
+ if isinstance(clip[0], np.ndarray):
159
+ im_h, im_w, im_c = clip[0].shape
160
+ elif isinstance(clip[0], PIL.Image.Image):
161
+ im_w, im_h = clip[0].size
162
+ else:
163
+ raise TypeError('Expected numpy.ndarray or PIL.Image' +
164
+ 'but got list of {0}'.format(type(clip[0])))
165
+
166
+ clip = pad_clip(clip, h, w)
167
+ im_h, im_w = clip.shape[1:3]
168
+ x1 = 0 if h == im_h else random.randint(0, im_w - w)
169
+ y1 = 0 if w == im_w else random.randint(0, im_h - h)
170
+ cropped = crop_clip(clip, y1, x1, h, w)
171
+
172
+ return cropped
173
+
174
+
175
+ class MouthCrop(object):
176
+ """Extract random crop at the same location for a list of videos
177
+ Args:
178
+ size (sequence or int): Desired output size for the
179
+ crop in format (h, w)
180
+ """
181
+
182
+ def __init__(self, center_x, center_y, mask_width, mask_height):
183
+
184
+
185
+ self.center_x = center_x
186
+ self.center_y = center_y
187
+ self.mask_width = mask_width
188
+ self.mask_height = mask_height
189
+
190
+ def __call__(self, clip):
191
+ """
192
+ Args:
193
+ img (PIL.Image or numpy.ndarray): List of videos to be cropped
194
+ in format (h, w, c) in numpy.ndarray
195
+ Returns:
196
+ PIL.Image or numpy.ndarray: Cropped list of videos
197
+ """
198
+ start_x = self.center_x - int(self.mask_width/2)
199
+ start_y = self.center_y - int(self.mask_height/2)
200
+ end_x = start_x + self.mask_width
201
+ end_y = start_y + self.mask_height
202
+ # mask is all white
203
+ # mask = 255*np.ones((mask_height, mask_width, 3), dtype=np.uint8)
204
+ # mask is uniform noise
205
+ cropped = []
206
+ for i in range(len(clip)):
207
+ mask = np.random.rand(self.mask_height, self.mask_width, 3)
208
+ img = clip[i].copy()
209
+ img[start_y:end_y, start_x:end_x, :] = mask
210
+
211
+ cropped.append(img)
212
+ cropped = np.array(cropped)
213
+ return cropped
214
+
215
+ class RandomRotation(object):
216
+ """Rotate entire clip randomly by a random angle within
217
+ given bounds
218
+ Args:
219
+ degrees (sequence or int): Range of degrees to select from
220
+ If degrees is a number instead of sequence like (min, max),
221
+ the range of degrees, will be (-degrees, +degrees).
222
+ """
223
+
224
+ def __init__(self, degrees):
225
+ if isinstance(degrees, numbers.Number):
226
+ if degrees < 0:
227
+ raise ValueError('If degrees is a single number,'
228
+ 'must be positive')
229
+ degrees = (-degrees, degrees)
230
+ else:
231
+ if len(degrees) != 2:
232
+ raise ValueError('If degrees is a sequence,'
233
+ 'it must be of len 2.')
234
+
235
+ self.degrees = degrees
236
+
237
+ def __call__(self, clip):
238
+ """
239
+ Args:
240
+ img (PIL.Image or numpy.ndarray): List of videos to be cropped
241
+ in format (h, w, c) in numpy.ndarray
242
+ Returns:
243
+ PIL.Image or numpy.ndarray: Cropped list of videos
244
+ """
245
+ angle = random.uniform(self.degrees[0], self.degrees[1])
246
+ if isinstance(clip[0], np.ndarray):
247
+ rotated = [rotate(image=img, angle=angle, preserve_range=True) for img in clip]
248
+ elif isinstance(clip[0], PIL.Image.Image):
249
+ rotated = [img.rotate(angle) for img in clip]
250
+ else:
251
+ raise TypeError('Expected numpy.ndarray or PIL.Image' +
252
+ 'but got list of {0}'.format(type(clip[0])))
253
+
254
+ return rotated
255
+
256
+ class RandomPerspective(object):
257
+ """Rotate entire clip randomly by a random angle within
258
+ given bounds
259
+ Args:
260
+ degrees (sequence or int): Range of degrees to select from
261
+ If degrees is a number instead of sequence like (min, max),
262
+ the range of degrees, will be (-degrees, +degrees).
263
+ """
264
+
265
+ def __init__(self, pers_num, enlarge_num):
266
+ self.pers_num = pers_num
267
+ self.enlarge_num = enlarge_num
268
+
269
+ def __call__(self, clip):
270
+ """
271
+ Args:
272
+ img (PIL.Image or numpy.ndarray): List of videos to be cropped
273
+ in format (h, w, c) in numpy.ndarray
274
+ Returns:
275
+ PIL.Image or numpy.ndarray: Cropped list of videos
276
+ """
277
+ out = clip
278
+ for i in range(len(clip)):
279
+ self.pers_size = np.random.randint(20, self.pers_num) * pow(-1, np.random.randint(2))
280
+ self.enlarge_size = np.random.randint(20, self.enlarge_num) * pow(-1, np.random.randint(2))
281
+ h, w, c = clip[i].shape
282
+ crop_size=256
283
+ dst = np.array([
284
+ [-self.enlarge_size, -self.enlarge_size],
285
+ [-self.enlarge_size + self.pers_size, w + self.enlarge_size],
286
+ [h + self.enlarge_size, -self.enlarge_size],
287
+ [h + self.enlarge_size - self.pers_size, w + self.enlarge_size],], dtype=np.float32)
288
+ src = np.array([[-self.enlarge_size, -self.enlarge_size], [-self.enlarge_size, w + self.enlarge_size],
289
+ [h + self.enlarge_size, -self.enlarge_size], [h + self.enlarge_size, w + self.enlarge_size]]).astype(np.float32())
290
+ M = cv2.getPerspectiveTransform(src, dst)
291
+ warped = cv2.warpPerspective(clip[i], M, (crop_size, crop_size), borderMode=cv2.BORDER_REPLICATE)
292
+ out[i] = warped
293
+
294
+ return out
295
+
296
+
297
+ class ColorJitter(object):
298
+ """Randomly change the brightness, contrast and saturation and hue of the clip
299
+ Args:
300
+ brightness (float): How much to jitter brightness. brightness_factor
301
+ is chosen uniformly from [max(0, 1 - brightness), 1 + brightness].
302
+ contrast (float): How much to jitter contrast. contrast_factor
303
+ is chosen uniformly from [max(0, 1 - contrast), 1 + contrast].
304
+ saturation (float): How much to jitter saturation. saturation_factor
305
+ is chosen uniformly from [max(0, 1 - saturation), 1 + saturation].
306
+ hue(float): How much to jitter hue. hue_factor is chosen uniformly from
307
+ [-hue, hue]. Should be >=0 and <= 0.5.
308
+ """
309
+
310
+ def __init__(self, brightness=0, contrast=0, saturation=0, hue=0):
311
+ self.brightness = brightness
312
+ self.contrast = contrast
313
+ self.saturation = saturation
314
+ self.hue = hue
315
+
316
+ def get_params(self, brightness, contrast, saturation, hue):
317
+ if brightness > 0:
318
+ brightness_factor = random.uniform(
319
+ max(0, 1 - brightness), 1 + brightness)
320
+ else:
321
+ brightness_factor = None
322
+
323
+ if contrast > 0:
324
+ contrast_factor = random.uniform(
325
+ max(0, 1 - contrast), 1 + contrast)
326
+ else:
327
+ contrast_factor = None
328
+
329
+ if saturation > 0:
330
+ saturation_factor = random.uniform(
331
+ max(0, 1 - saturation), 1 + saturation)
332
+ else:
333
+ saturation_factor = None
334
+
335
+ if hue > 0:
336
+ hue_factor = random.uniform(-hue, hue)
337
+ else:
338
+ hue_factor = None
339
+ return brightness_factor, contrast_factor, saturation_factor, hue_factor
340
+
341
+ def __call__(self, clip):
342
+ """
343
+ Args:
344
+ clip (list): list of PIL.Image
345
+ Returns:
346
+ list PIL.Image : list of transformed PIL.Image
347
+ """
348
+ if isinstance(clip[0], np.ndarray):
349
+ brightness, contrast, saturation, hue = self.get_params(
350
+ self.brightness, self.contrast, self.saturation, self.hue)
351
+
352
+ # Create img transform function sequence
353
+ img_transforms = []
354
+ if brightness is not None:
355
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_brightness(img, brightness))
356
+ if saturation is not None:
357
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_saturation(img, saturation))
358
+ if hue is not None:
359
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_hue(img, hue))
360
+ if contrast is not None:
361
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_contrast(img, contrast))
362
+ random.shuffle(img_transforms)
363
+ img_transforms = [img_as_ubyte, torchvision.transforms.ToPILImage()] + img_transforms + [np.array,
364
+ img_as_float]
365
+
366
+ with warnings.catch_warnings():
367
+ warnings.simplefilter("ignore")
368
+ jittered_clip = []
369
+ for img in clip:
370
+ jittered_img = img
371
+ for func in img_transforms:
372
+ jittered_img = func(jittered_img)
373
+ jittered_clip.append(jittered_img.astype('float32'))
374
+ elif isinstance(clip[0], PIL.Image.Image):
375
+ brightness, contrast, saturation, hue = self.get_params(
376
+ self.brightness, self.contrast, self.saturation, self.hue)
377
+
378
+ # Create img transform function sequence
379
+ img_transforms = []
380
+ if brightness is not None:
381
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_brightness(img, brightness))
382
+ if saturation is not None:
383
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_saturation(img, saturation))
384
+ if hue is not None:
385
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_hue(img, hue))
386
+ if contrast is not None:
387
+ img_transforms.append(lambda img: torchvision.transforms.functional.adjust_contrast(img, contrast))
388
+ random.shuffle(img_transforms)
389
+
390
+ # Apply to all videos
391
+ jittered_clip = []
392
+ for img in clip:
393
+ for func in img_transforms:
394
+ jittered_img = func(img)
395
+ jittered_clip.append(jittered_img)
396
+
397
+ else:
398
+ raise TypeError('Expected numpy.ndarray or PIL.Image' +
399
+ 'but got list of {0}'.format(type(clip[0])))
400
+ return jittered_clip
401
+
402
+
403
+ class AllAugmentationTransform:
404
+ def __init__(self, crop_mouth_param = None, resize_param=None, rotation_param=None, perspective_param=None, flip_param=None, crop_param=None, jitter_param=None):
405
+ self.transforms = []
406
+ if crop_mouth_param is not None:
407
+ self.transforms.append(MouthCrop(**crop_mouth_param))
408
+
409
+ if flip_param is not None:
410
+ self.transforms.append(RandomFlip(**flip_param))
411
+
412
+ if rotation_param is not None:
413
+ self.transforms.append(RandomRotation(**rotation_param))
414
+
415
+ if perspective_param is not None:
416
+ self.transforms.append(RandomPerspective(**perspective_param))
417
+
418
+ if resize_param is not None:
419
+ self.transforms.append(RandomResize(**resize_param))
420
+
421
+ if crop_param is not None:
422
+ self.transforms.append(RandomCrop(**crop_param))
423
+
424
+ if jitter_param is not None:
425
+ self.transforms.append(ColorJitter(**jitter_param))
426
+
427
+ def __call__(self, clip):
428
+ for t in self.transforms:
429
+ clip = t(clip)
430
+ return clip
FONT/config/MEAD_emo_video_aug_delta_4_crop_random_crop.yaml ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ root_dir: /mnt/lustre/share_data/jixinya/MEAD/
3
+ frame_shape: [256, 256, 3]
4
+ id_sampling: False
5
+ pairs_list: Random_choice
6
+ augmentation_params:
7
+ crop_mouth_param:
8
+ center_x: 135
9
+ center_y: 190
10
+ mask_width: 100
11
+ mask_height: 60
12
+ rotation_param:
13
+ degrees: 30
14
+ perspective_param:
15
+ pers_num: 30
16
+ enlarge_num: 40
17
+ flip_param:
18
+ horizontal_flip: True
19
+ time_flip: False
20
+ jitter_param:
21
+ brightness: 0
22
+ contrast: 0
23
+ saturation: 0
24
+ hue: 0
25
+
26
+ model_params:
27
+ common_params:
28
+ num_kp: 10
29
+ num_channels: 3
30
+ estimate_jacobian: True
31
+ audio_params:
32
+ num_kp: 10
33
+ num_channels : 3
34
+ num_channels_a : 3
35
+ estimate_jacobian: True
36
+ kp_detector_params:
37
+ temperature: 0.1
38
+ block_expansion: 32
39
+ max_features: 1024
40
+ scale_factor: 0.25
41
+ num_blocks: 5
42
+ generator_params:
43
+ block_expansion: 64
44
+ max_features: 512
45
+ num_down_blocks: 2
46
+ num_bottleneck_blocks: 6
47
+ estimate_occlusion_map: True
48
+ dense_motion_params:
49
+ block_expansion: 64
50
+ max_features: 1024
51
+ num_blocks: 5
52
+ scale_factor: 0.25
53
+ discriminator_params:
54
+ scales: [1]
55
+ block_expansion: 32
56
+ max_features: 512
57
+ num_blocks: 4
58
+ sn: True
59
+
60
+ train_params:
61
+ type: linear_4
62
+ smooth: False
63
+ jaco_net: cnn
64
+ ldmark: fake
65
+ generator: not
66
+ train_generator: False
67
+ num_epochs: 300
68
+ num_repeats: 1
69
+ epoch_milestones: [60, 90]
70
+ lr_generator: 2.0e-4
71
+ lr_discriminator: 2.0e-4
72
+ lr_kp_detector: 2.0e-4
73
+ lr_audio_feature: 2.0e-4
74
+ batch_size: 16
75
+ scales: [1, 0.5, 0.25, 0.125]
76
+ checkpoint_freq: 1
77
+ transform_params:
78
+ sigma_affine: 0.05
79
+ sigma_tps: 0.005
80
+ points_tps: 5
81
+ loss_weights:
82
+ generator_gan: 0
83
+ discriminator_gan: 1
84
+ feature_matching: [10, 10, 10, 10]
85
+ perceptual: [10, 10, 10, 10, 10]
86
+ equivariance_value: 0
87
+ equivariance_jacobian: 0
88
+ emo: 10
89
+
90
+ reconstruction_params:
91
+ num_videos: 1000
92
+ format: '.mp4'
93
+
94
+ animate_params:
95
+ num_pairs: 50
96
+ format: '.mp4'
97
+ normalization_params:
98
+ adapt_movement_scale: False
99
+ use_relative_movement: True
100
+ use_relative_jacobian: True
101
+
102
+ visualizer_params:
103
+ kp_size: 5
104
+ draw_border: True
105
+ colormap: 'gist_rainbow'
FONT/config/train_part1.yaml ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ name: Lrw
3
+ root_dir: dataset/LRW/
4
+ frame_shape: [256, 256, 3]
5
+ id_sampling: False
6
+ augmentation_params:
7
+ flip_param:
8
+ horizontal_flip: False
9
+ time_flip: False
10
+ jitter_param:
11
+ brightness: 0.1
12
+ contrast: 0.1
13
+ saturation: 0.1
14
+ hue: 0.1
15
+
16
+
17
+ model_params:
18
+ common_params:
19
+ num_kp: 10
20
+ num_channels: 3
21
+ estimate_jacobian: True
22
+ audio_params:
23
+ num_kp: 10
24
+ num_channels : 3
25
+ num_channels_a : 3
26
+ estimate_jacobian: True
27
+ kp_detector_params:
28
+ temperature: 0.1
29
+ block_expansion: 32
30
+ max_features: 1024
31
+ scale_factor: 0.25
32
+ num_blocks: 5
33
+ generator_params:
34
+ block_expansion: 64
35
+ max_features: 512
36
+ num_down_blocks: 2
37
+ num_bottleneck_blocks: 6
38
+ estimate_occlusion_map: True
39
+ dense_motion_params:
40
+ block_expansion: 64
41
+ max_features: 1024
42
+ num_blocks: 5
43
+ scale_factor: 0.25
44
+ discriminator_params:
45
+ scales: [1]
46
+ block_expansion: 32
47
+ max_features: 512
48
+ num_blocks: 4
49
+ sn: True
50
+
51
+ train_params:
52
+ jaco_net: cnn
53
+ ldmark: fake
54
+ generator: not
55
+ num_epochs: 600
56
+ num_repeats: 1
57
+ epoch_milestones: [60, 90]
58
+ lr_generator: 2.0e-4
59
+ lr_discriminator: 2.0e-4
60
+ lr_kp_detector: 2.0e-4
61
+ lr_audio_feature: 2.0e-4
62
+ batch_size: 16
63
+ scales: [1, 0.5, 0.25, 0.125]
64
+ checkpoint_freq: 1
65
+ transform_params:
66
+ sigma_affine: 0.05
67
+ sigma_tps: 0.005
68
+ points_tps: 5
69
+ loss_weights:
70
+ generator_gan: 0
71
+ discriminator_gan: 0
72
+ feature_matching: [10, 10, 10, 10]
73
+ perceptual: [10, 10, 10, 10, 10]
74
+ equivariance_value: 0
75
+ equivariance_jacobian: 0
76
+ audio: 10
77
+
78
+
79
+
80
+ visualizer_params:
81
+ kp_size: 5
82
+ draw_border: True
83
+ colormap: 'gist_rainbow'
FONT/config/train_part1_fine_tune.yaml ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ name: Lrw
3
+ root_dir: dataset/LRW/
4
+ frame_shape: [256, 256, 3]
5
+ id_sampling: False
6
+ augmentation_params:
7
+ flip_param:
8
+ horizontal_flip: False
9
+ time_flip: False
10
+ jitter_param:
11
+ brightness: 0.1
12
+ contrast: 0.1
13
+ saturation: 0.1
14
+ hue: 0.1
15
+
16
+
17
+ model_params:
18
+ common_params:
19
+ num_kp: 10
20
+ num_channels: 3
21
+ estimate_jacobian: True
22
+ audio_params:
23
+ num_kp: 10
24
+ num_channels : 3
25
+ num_channels_a : 3
26
+ estimate_jacobian: True
27
+ kp_detector_params:
28
+ temperature: 0.1
29
+ block_expansion: 32
30
+ max_features: 1024
31
+ scale_factor: 0.25
32
+ num_blocks: 5
33
+ generator_params:
34
+ block_expansion: 64
35
+ max_features: 512
36
+ num_down_blocks: 2
37
+ num_bottleneck_blocks: 6
38
+ estimate_occlusion_map: True
39
+ dense_motion_params:
40
+ block_expansion: 64
41
+ max_features: 1024
42
+ num_blocks: 5
43
+ scale_factor: 0.25
44
+ discriminator_params:
45
+ scales: [1]
46
+ block_expansion: 32
47
+ max_features: 512
48
+ num_blocks: 4
49
+ sn: True
50
+
51
+ train_params:
52
+ jaco_net: cnn
53
+ ldmark: fake
54
+ generator: audio
55
+ num_epochs: 600
56
+ num_repeats: 1
57
+ epoch_milestones: [60, 90]
58
+ lr_generator: 2.0e-4
59
+ lr_discriminator: 2.0e-4
60
+ lr_kp_detector: 2.0e-4
61
+ lr_audio_feature: 2.0e-4
62
+ batch_size: 6
63
+ scales: [1, 0.5, 0.25, 0.125]
64
+ checkpoint_freq: 1
65
+ transform_params:
66
+ sigma_affine: 0.05
67
+ sigma_tps: 0.005
68
+ points_tps: 5
69
+ loss_weights:
70
+ generator_gan: 0
71
+ discriminator_gan: 0
72
+ feature_matching: [10, 10, 10, 10]
73
+ perceptual: [0.1, 0.1, 0.1, 0.1, 0.1]
74
+ equivariance_value: 0
75
+ equivariance_jacobian: 0
76
+ audio: 10
77
+
78
+ visualizer_params:
79
+ kp_size: 5
80
+ draw_border: True
81
+ colormap: 'gist_rainbow'
FONT/config/train_part1_fine_tune_hdtf.yaml ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ name: hdtf
3
+ root_dir: dataset/LRW/
4
+ frame_shape: [256, 256, 3]
5
+ id_sampling: False
6
+ augmentation_params:
7
+ flip_param:
8
+ horizontal_flip: False
9
+ time_flip: False
10
+ jitter_param:
11
+ brightness: 0.1
12
+ contrast: 0.1
13
+ saturation: 0.1
14
+ hue: 0.1
15
+
16
+
17
+ model_params:
18
+ common_params:
19
+ num_kp: 10
20
+ num_channels: 3
21
+ estimate_jacobian: True
22
+ audio_params:
23
+ num_kp: 10
24
+ num_channels : 3
25
+ num_channels_a : 3
26
+ estimate_jacobian: True
27
+ kp_detector_params:
28
+ temperature: 0.1
29
+ block_expansion: 32
30
+ max_features: 1024
31
+ scale_factor: 0.25
32
+ num_blocks: 5
33
+ generator_params:
34
+ block_expansion: 64
35
+ max_features: 512
36
+ num_down_blocks: 2
37
+ num_bottleneck_blocks: 6
38
+ estimate_occlusion_map: True
39
+ dense_motion_params:
40
+ block_expansion: 64
41
+ max_features: 1024
42
+ num_blocks: 5
43
+ scale_factor: 0.25
44
+ discriminator_params:
45
+ scales: [1]
46
+ block_expansion: 32
47
+ max_features: 512
48
+ num_blocks: 4
49
+ sn: True
50
+
51
+ train_params:
52
+ jaco_net: cnn
53
+ ldmark: fake
54
+ generator: audio
55
+ num_epochs: 7000
56
+ num_repeats: 1
57
+ epoch_milestones: [60, 90]
58
+ lr_generator: 2.0e-4
59
+ lr_discriminator: 2.0e-4
60
+ lr_kp_detector: 2.0e-4
61
+ lr_audio_feature: 2.0e-4
62
+ batch_size: 6
63
+ scales: [1, 0.5, 0.25, 0.125]
64
+ checkpoint_freq: 1
65
+ transform_params:
66
+ sigma_affine: 0.05
67
+ sigma_tps: 0.005
68
+ points_tps: 5
69
+ loss_weights:
70
+ generator_gan: 0
71
+ discriminator_gan: 0
72
+ feature_matching: [10, 10, 10, 10]
73
+ perceptual: [0.1, 0.1, 0.1, 0.1, 0.1]
74
+ equivariance_value: 0
75
+ equivariance_jacobian: 0
76
+ audio: 10
77
+
78
+ visualizer_params:
79
+ kp_size: 5
80
+ draw_border: True
81
+ colormap: 'gist_rainbow'
FONT/config/train_part1_hdtf.yaml ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ name: hdtf
3
+ root_dir: dataset/LRW/
4
+ frame_shape: [256, 256, 3]
5
+ id_sampling: False
6
+ augmentation_params:
7
+ flip_param:
8
+ horizontal_flip: False
9
+ time_flip: False
10
+ jitter_param:
11
+ brightness: 0.1
12
+ contrast: 0.1
13
+ saturation: 0.1
14
+ hue: 0.1
15
+
16
+
17
+ model_params:
18
+ common_params:
19
+ num_kp: 10
20
+ num_channels: 3
21
+ estimate_jacobian: True
22
+ audio_params:
23
+ num_kp: 10
24
+ num_channels : 3
25
+ num_channels_a : 3
26
+ estimate_jacobian: True
27
+ kp_detector_params:
28
+ temperature: 0.1
29
+ block_expansion: 32
30
+ max_features: 1024
31
+ scale_factor: 0.25
32
+ num_blocks: 5
33
+ generator_params:
34
+ block_expansion: 64
35
+ max_features: 512
36
+ num_down_blocks: 2
37
+ num_bottleneck_blocks: 6
38
+ estimate_occlusion_map: True
39
+ dense_motion_params:
40
+ block_expansion: 64
41
+ max_features: 1024
42
+ num_blocks: 5
43
+ scale_factor: 0.25
44
+ discriminator_params:
45
+ scales: [1]
46
+ block_expansion: 32
47
+ max_features: 512
48
+ num_blocks: 4
49
+ sn: True
50
+
51
+ train_params:
52
+ jaco_net: cnn
53
+ ldmark: fake
54
+ generator: not
55
+ num_epochs: 100000
56
+ num_repeats: 1
57
+ epoch_milestones: [60, 90]
58
+ lr_generator: 2.0e-4
59
+ lr_discriminator: 2.0e-4
60
+ lr_kp_detector: 2.0e-4
61
+ lr_audio_feature: 2.0e-4
62
+ batch_size: 16
63
+ scales: [1, 0.5, 0.25, 0.125]
64
+ checkpoint_freq: 1
65
+ transform_params:
66
+ sigma_affine: 0.05
67
+ sigma_tps: 0.005
68
+ points_tps: 5
69
+ loss_weights:
70
+ generator_gan: 0
71
+ discriminator_gan: 0
72
+ feature_matching: [10, 10, 10, 10]
73
+ perceptual: [10, 10, 10, 10, 10]
74
+ equivariance_value: 0
75
+ equivariance_jacobian: 0
76
+ audio: 10
77
+
78
+
79
+
80
+ visualizer_params:
81
+ kp_size: 5
82
+ draw_border: True
83
+ colormap: 'gist_rainbow'
FONT/config/train_part2.yaml ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_params:
2
+ name: MEAD
3
+ root_dir: dataset/MEAD/
4
+ frame_shape: [256, 256, 3]
5
+ id_sampling: False
6
+ augmentation_params:
7
+ crop_mouth_param:
8
+ center_x: 135
9
+ center_y: 190
10
+ mask_width: 100
11
+ mask_height: 60
12
+ rotation_param:
13
+ degrees: 30
14
+ perspective_param:
15
+ pers_num: 30
16
+ enlarge_num: 40
17
+ flip_param:
18
+ horizontal_flip: True
19
+ time_flip: False
20
+ jitter_param:
21
+ brightness: 0
22
+ contrast: 0
23
+ saturation: 0
24
+ hue: 0
25
+
26
+ model_params:
27
+ common_params:
28
+ num_kp: 10
29
+ num_channels: 3
30
+ estimate_jacobian: True
31
+ audio_params:
32
+ num_kp: 10
33
+ num_channels : 3
34
+ num_channels_a : 3
35
+ estimate_jacobian: True
36
+ kp_detector_params:
37
+ temperature: 0.1
38
+ block_expansion: 32
39
+ max_features: 1024
40
+ scale_factor: 0.25
41
+ num_blocks: 5
42
+ generator_params:
43
+ block_expansion: 64
44
+ max_features: 512
45
+ num_down_blocks: 2
46
+ num_bottleneck_blocks: 6
47
+ estimate_occlusion_map: True
48
+ dense_motion_params:
49
+ block_expansion: 64
50
+ max_features: 1024
51
+ num_blocks: 5
52
+ scale_factor: 0.25
53
+ discriminator_params:
54
+ scales: [1]
55
+ block_expansion: 32
56
+ max_features: 512
57
+ num_blocks: 4
58
+ sn: True
59
+
60
+ train_params:
61
+ type: linear_4
62
+ smooth: False
63
+ jaco_net: cnn
64
+ ldmark: fake
65
+ generator: not
66
+ num_epochs: 300
67
+ num_repeats: 1
68
+ epoch_milestones: [60, 90]
69
+ lr_generator: 2.0e-4
70
+ lr_discriminator: 2.0e-4
71
+ lr_kp_detector: 2.0e-4
72
+ lr_audio_feature: 2.0e-4
73
+ batch_size: 16
74
+ scales: [1, 0.5, 0.25, 0.125]
75
+ checkpoint_freq: 1
76
+ transform_params:
77
+ sigma_affine: 0.05
78
+ sigma_tps: 0.005
79
+ points_tps: 5
80
+ loss_weights:
81
+ generator_gan: 0
82
+ discriminator_gan: 0
83
+ feature_matching: [10, 10, 10, 10]
84
+ perceptual: [10, 10, 10, 10, 10]
85
+ equivariance_value: 0
86
+ equivariance_jacobian: 0
87
+ emo: 10
88
+
89
+
90
+ visualizer_params:
91
+ kp_size: 5
92
+ draw_border: True
93
+ colormap: 'gist_rainbow'
FONT/demo.py ADDED
@@ -0,0 +1,632 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Wed Oct 6 20:57:27 2021
5
+
6
+ @author: thea
7
+ """
8
+
9
+ import matplotlib
10
+ matplotlib.use('Agg')
11
+ import os,sys
12
+ import yaml
13
+ from argparse import ArgumentParser
14
+ from tqdm import tqdm
15
+ from skimage import io, img_as_float32
16
+ import imageio
17
+ import numpy as np
18
+ from skimage.transform import resize
19
+ from skimage import img_as_ubyte
20
+ import torch
21
+ from filter1 import OneEuroFilter
22
+ import torch.utils
23
+
24
+ from torch.autograd import Variable
25
+ from modules.generator import OcclusionAwareGenerator
26
+ from modules.keypoint_detector import KPDetector, KPDetector_a
27
+ from modules.util import AT_net, Emotion_k, Emotion_map, AT_net2
28
+ from augmentation import AllAugmentationTransform
29
+
30
+ from scipy.spatial import ConvexHull
31
+ import audio
32
+ import random
33
+ import python_speech_features
34
+ from pathlib import Path
35
+ import dlib
36
+ import cv2
37
+ from skimage.draw import circle
38
+ import matplotlib.pyplot as plt
39
+ import librosa
40
+ from skimage import transform as tf
41
+ import torch.nn.functional as F
42
+
43
+
44
+
45
+ detector = dlib.get_frontal_face_detector()
46
+ predictor = dlib.shape_predictor('./ckpt/shape_predictor_68_face_landmarks.dat')
47
+
48
+
49
+
50
+
51
+ def load_checkpoints(opt, checkpoint_path, audio_checkpoint_path, emo_checkpoint_path, kp_checkpoint_path, cpu=False):
52
+
53
+ with open(opt.config) as f:
54
+ config = yaml.load(f, Loader=yaml.FullLoader)
55
+
56
+ generator = OcclusionAwareGenerator(**config['model_params']['generator_params'],
57
+ **config['model_params']['common_params'])
58
+ if not cpu:
59
+ generator.cuda()
60
+
61
+ kp_detector = KPDetector(**config['model_params']['kp_detector_params'],
62
+ **config['model_params']['common_params'])
63
+ if not cpu:
64
+ kp_detector.cuda()
65
+
66
+ kp_detector_a = KPDetector_a(**config['model_params']['kp_detector_params'],
67
+ **config['model_params']['audio_params'])
68
+
69
+ audio_feature = AT_net2()
70
+ # audio_feature = AT_net()
71
+ # audio_feature = AT_net_ori()
72
+ if opt.type.startswith('linear'):
73
+ emo_detector = Emotion_k(block_expansion=32, num_channels=3, max_features=1024,
74
+ num_blocks=5, scale_factor=0.25, num_classes=8)
75
+ elif opt.type.startswith('map'):
76
+ emo_detector = Emotion_map(block_expansion=32, num_channels=3, max_features=1024,
77
+ num_blocks=5, scale_factor=0.25, num_classes=8)
78
+ if not cpu:
79
+ kp_detector_a.cuda()
80
+ audio_feature.cuda()
81
+ emo_detector.cuda()
82
+
83
+
84
+
85
+
86
+ if cpu:
87
+ checkpoint = torch.load(checkpoint_path, map_location=torch.device('cpu'))
88
+ audio_checkpoint = torch.load(audio_checkpoint_path, map_location=torch.device('cpu'))
89
+ emo_checkpoint = torch.load(emo_checkpoint_path, map_location=torch.device('cpu'))
90
+ kp_checkpoint = torch.load(kp_checkpoint_path, map_location=torch.device('cpu'))
91
+ else:
92
+ checkpoint = torch.load(checkpoint_path)
93
+ audio_checkpoint = torch.load(audio_checkpoint_path)
94
+ emo_checkpoint = torch.load(emo_checkpoint_path)
95
+ kp_checkpoint = torch.load(kp_checkpoint_path)
96
+
97
+ generator.load_state_dict(checkpoint['generator'])
98
+ kp_detector.load_state_dict(kp_checkpoint['kp_detector'])
99
+ audio_feature.load_state_dict(audio_checkpoint['audio_feature'], strict=False)
100
+
101
+
102
+
103
+
104
+ kp_detector_a.load_state_dict(audio_checkpoint['kp_detector_a'])
105
+ emo_detector.load_state_dict(emo_checkpoint['emo_detector'])
106
+
107
+
108
+ if not cpu:
109
+ generator = generator.cuda()
110
+ kp_detector = kp_detector.cuda()
111
+ audio_feature = audio_feature.cuda()
112
+ kp_detector_a = kp_detector_a.cuda()
113
+ emo_detector = emo_detector.cuda()
114
+
115
+ generator.eval()
116
+ kp_detector.eval()
117
+ audio_feature.eval()
118
+ kp_detector_a.eval()
119
+ emo_detector.eval()
120
+ return generator, kp_detector, kp_detector_a, audio_feature, emo_detector
121
+
122
+ def normalize_kp(kp_source, kp_driving, kp_driving_initial, adapt_movement_scale=False,
123
+ use_relative_movement=False, use_relative_jacobian=False):
124
+ if adapt_movement_scale:
125
+ source_area = ConvexHull(kp_source['value'][0].data.cpu().numpy()).volume
126
+ driving_area = ConvexHull(kp_driving_initial['value'][0].data.cpu().numpy()).volume
127
+ adapt_movement_scale = np.sqrt(source_area) / np.sqrt(driving_area)
128
+ else:
129
+ adapt_movement_scale = 1
130
+
131
+ kp_new = {k: v for k, v in kp_driving.items()}
132
+
133
+ if use_relative_movement:
134
+ kp_value_diff = (kp_driving['value'] - kp_driving_initial['value'])
135
+ kp_value_diff *= adapt_movement_scale
136
+ kp_new['value'] = kp_value_diff + kp_source['value']
137
+
138
+ if use_relative_jacobian:
139
+ jacobian_diff = torch.matmul(kp_driving['jacobian'], torch.inverse(kp_driving_initial['jacobian']))
140
+ kp_new['jacobian'] = torch.matmul(jacobian_diff, kp_source['jacobian'])
141
+
142
+ return kp_new
143
+
144
+ def shape_to_np(shape, dtype="int"):
145
+ # initialize the list of (x, y)-coordinates
146
+ coords = np.zeros((shape.num_parts, 2), dtype=dtype)
147
+
148
+ # loop over all facial landmarks and convert them
149
+ # to a 2-tuple of (x, y)-coordinates
150
+ for i in range(0, shape.num_parts):
151
+ coords[i] = (shape.part(i).x, shape.part(i).y)
152
+
153
+ # return the list of (x, y)-coordinates
154
+ return coords
155
+
156
+ def get_aligned_image(driving_video, opt):
157
+ aligned_array = []
158
+
159
+ video_array = np.array(driving_video)
160
+ source_image=video_array[0]
161
+ # aligned_array.append(source_image)
162
+ source_image = np.array(source_image * 255, dtype=np.uint8)
163
+ gray = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
164
+ rects = detector(gray, 1) #detect human face
165
+ for (i, rect) in enumerate(rects):
166
+ template = predictor(gray, rect) #detect 68 points
167
+ template = shape_to_np(template)
168
+
169
+ if opt.emotion == 'surprised' or opt.emotion == 'fear':
170
+ template = template-[0,10]
171
+ for i in range(len(video_array)):
172
+ image=np.array(video_array[i] * 255, dtype=np.uint8)
173
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
174
+ rects = detector(gray, 1) #detect human face
175
+ for (j, rect) in enumerate(rects):
176
+ shape = predictor(gray, rect) #detect 68 points
177
+ shape = shape_to_np(shape)
178
+
179
+ pts2 = np.float32(template[:35,:])
180
+ pts1 = np.float32(shape[:35,:]) #eye and nose
181
+
182
+ # pts2 = np.float32(np.concatenate((template[:16,:],template[27:36,:]),axis = 0))
183
+ # pts1 = np.float32(np.concatenate((shape[:16,:],shape[27:36,:]),axis = 0)) #eye and nose
184
+ # pts1 = np.float32(landmark[17:35,:])
185
+ tform = tf.SimilarityTransform()
186
+ tform.estimate( pts2, pts1) #Set the transformation matrix with the explicit parameters.
187
+ dst = tf.warp(image, tform, output_shape=(256, 256))
188
+
189
+ dst = np.array(dst, dtype=np.float32)
190
+ aligned_array.append(dst)
191
+
192
+ return aligned_array
193
+
194
+ def get_transformed_image(driving_video, opt):
195
+ video_array = np.array(driving_video)
196
+ with open(opt.config) as f:
197
+ config = yaml.load(f, Loader=yaml.FullLoader)
198
+ transformations = AllAugmentationTransform(**config['dataset_params']['augmentation_params'])
199
+ transformed_array = transformations(video_array)
200
+ return transformed_array
201
+
202
+
203
+
204
+ def make_animation_smooth(source_image, driving_video, transformed_video, deco_out, kp_loss, generator, kp_detector, kp_detector_a, emo_detector, opt, relative=True, adapt_movement_scale=True, cpu=False):
205
+ with torch.no_grad():
206
+ predictions = []
207
+
208
+
209
+ source = torch.tensor(source_image[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2)
210
+ if not cpu:
211
+ source = source.cuda()
212
+
213
+
214
+ driving = torch.tensor(np.array(driving_video)[np.newaxis].astype(np.float32)).permute(0, 4, 1, 2, 3)
215
+ transformed_driving = torch.tensor(np.array(transformed_video)[np.newaxis].astype(np.float32)).permute(0, 4, 1, 2, 3)
216
+
217
+
218
+ kp_source = kp_detector(source)
219
+
220
+ save_dpi = (100, 100)
221
+ # save kp source image
222
+ # source = kp_source['value'].data.cpu().numpy()
223
+ # kp_array = source[0]
224
+ # image = np.zeros((256,256,3))
225
+ # spatial_size = np.array(image.shape[:2][::-1])[np.newaxis]
226
+ # kp_array = spatial_size * (kp_array + 1) / 2
227
+ # num_kp = kp_array.shape[0]
228
+ colormap = plt.get_cmap('gist_rainbow')
229
+ # for kp_ind, kp in enumerate(kp_array):
230
+ # rr, cc = circle(kp[1], kp[0], 5, shape=image.shape[:2])
231
+ # image[rr, cc] = np.array(colormap(kp_ind / num_kp))[:3]
232
+ # imageio.imsave('./result/kp_source.png', image)
233
+
234
+
235
+
236
+ kp_driving_initial = kp_detector_a(deco_out[:,0])
237
+
238
+
239
+ emo_driving_all = []
240
+ features = []
241
+ kp_driving_all = []
242
+ for frame_idx in tqdm(range(len(deco_out[0]))):
243
+
244
+ driving_frame = driving[:, :, frame_idx]
245
+ transformed_frame = transformed_driving[:, :, frame_idx]
246
+ if not cpu:
247
+ driving_frame = driving_frame.cuda()
248
+ transformed_frame = transformed_frame.cuda()
249
+ kp_driving = kp_detector_a(deco_out[:,frame_idx])
250
+ kp_driving_all.append(kp_driving)
251
+ if opt.add_emo:
252
+ value = kp_driving['value']
253
+ jacobian = kp_driving['jacobian']
254
+ if opt.type == 'linear_3':
255
+ emo_driving,_ = emo_detector(transformed_frame,value,jacobian)
256
+ features.append(emo_detector.feature(transformed_frame).data.cpu().numpy())
257
+
258
+ emo_driving_all.append(emo_driving)
259
+ features = np.array(features)
260
+ if opt.add_emo:
261
+ one_euro_filter_v = OneEuroFilter(mincutoff=1, beta=0.2, dcutoff=1.0, freq=100)#1 0.4
262
+ one_euro_filter_j = OneEuroFilter(mincutoff=1, beta=0.2, dcutoff=1.0, freq=100)#1 0.4
263
+
264
+ for j in range(len(emo_driving_all)):
265
+ emo_driving_all[j]['value']=one_euro_filter_v.process(emo_driving_all[j]['value'].cpu()*100)/100
266
+ emo_driving_all[j]['value'] = emo_driving_all[j]['value'].cuda()
267
+ emo_driving_all[j]['jacobian']=one_euro_filter_j.process(emo_driving_all[j]['jacobian'].cpu()*100)/100
268
+ emo_driving_all[j]['jacobian'] = emo_driving_all[j]['jacobian'].cuda()
269
+
270
+
271
+ one_euro_filter_v = OneEuroFilter(mincutoff=0.05, beta=8, dcutoff=1.0, freq=100)
272
+ one_euro_filter_j = OneEuroFilter(mincutoff=0.05, beta=8, dcutoff=1.0, freq=100)
273
+
274
+ for j in range(len(kp_driving_all)):
275
+ kp_driving_all[j]['value']=one_euro_filter_v.process(kp_driving_all[j]['value'].cpu()*10)/10
276
+ kp_driving_all[j]['value'] = kp_driving_all[j]['value'].cuda()
277
+ kp_driving_all[j]['jacobian']=one_euro_filter_j.process(kp_driving_all[j]['jacobian'].cpu()*10)/10
278
+ kp_driving_all[j]['jacobian'] = kp_driving_all[j]['jacobian'].cuda()
279
+
280
+
281
+ for frame_idx in tqdm(range(len(deco_out[0]))):
282
+
283
+ if opt.check_add:
284
+ kp_driving = kp_detector_a(deco_out[:,0])
285
+ else:
286
+ kp_driving = kp_driving_all[frame_idx]
287
+
288
+ # kp_driving_real = kp_detector(driving_frame)
289
+
290
+ # kp_driving['value'] = (1-opt.weight)*kp_driving['value'] + opt.weight*kp_driving_real['value']
291
+ # kp_driving['jacobian'] = (1-opt.weight)*kp_driving['jacobian'] + opt.weight*kp_driving_real['jacobian']
292
+
293
+ if opt.add_emo:
294
+ emo_driving = emo_driving_all[frame_idx]
295
+ if opt.type == 'linear_3':
296
+ kp_driving['value'][:,1] = kp_driving['value'][:,1] + emo_driving['value'][:,0]*0.2
297
+ kp_driving['jacobian'][:,1] = kp_driving['jacobian'][:,1] + emo_driving['jacobian'][:,0]*0.2
298
+ kp_driving['value'][:,4] = kp_driving['value'][:,4] + emo_driving['value'][:,1]
299
+ kp_driving['jacobian'][:,4] = kp_driving['jacobian'][:,4] + emo_driving['jacobian'][:,1]
300
+ kp_driving['value'][:,6] = kp_driving['value'][:,6] + emo_driving['value'][:,2]
301
+ kp_driving['jacobian'][:,6] = kp_driving['jacobian'][:,6] + emo_driving['jacobian'][:,2]
302
+ # kp_driving['value'][:,8] = kp_driving['value'][:,8] + emo_driving['value'][:,3]
303
+ # kp_driving['jacobian'][:,8] = kp_driving['jacobian'][:,8] + emo_driving['jacobian'][:,3]
304
+
305
+
306
+ kp_norm = normalize_kp(kp_source=kp_source, kp_driving=kp_driving,
307
+ kp_driving_initial=kp_driving_initial, use_relative_movement=relative,
308
+ use_relative_jacobian=relative, adapt_movement_scale=adapt_movement_scale)
309
+ out = generator(source, kp_source=kp_source, kp_driving=kp_norm)
310
+
311
+ # occlusion_map = out['occlusion_map'].data.cpu().repeat(1, 3, 1, 1)
312
+ # occlusion_map = F.interpolate(occlusion_map, size=(256,256)).numpy()
313
+ # occlusion_map = np.transpose(occlusion_map, [0, 2, 3, 1])
314
+ # print(occlusion_map.shape)
315
+ # imageio.imsave('./result/occlusion.png', occlusion_map[0], dpi=save_dpi)
316
+ #
317
+ # prediction = out['prediction'].data.cpu().numpy()
318
+ # prediction = np.transpose(prediction, [0, 2, 3, 1])
319
+ # print(prediction.shape)
320
+ # imageio.imsave('./result/prediction.png', prediction[0], dpi=save_dpi)
321
+ #
322
+ # full_mask = []
323
+ # for i in range(out['sparse_deformed'].shape[1]):
324
+ # mask = out['mask'][:, i:(i + 1)].data.cpu().repeat(1, 3, 1, 1)
325
+ # mask = F.interpolate(mask, size=(256,256))
326
+ # mask = np.transpose(mask.numpy(), (0, 2, 3, 1))
327
+ # if i != 0:
328
+ # color = np.array(colormap((i - 1) / (out['sparse_deformed'].shape[1] - 1)))[:3]
329
+ # else:
330
+ # color = np.array((0, 0, 0))
331
+ #
332
+ # color = color.reshape((1, 1, 1, 3))
333
+ #
334
+ # full_mask.append(mask * color)
335
+ # motion_flow = sum(full_mask)
336
+ # print(motion_flow.shape)
337
+ # imageio.imsave('./result/motion_flow.png', motion_flow[0], dpi=save_dpi)
338
+ # quit()
339
+
340
+
341
+
342
+ predictions.append(np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0])
343
+ return predictions, features
344
+
345
+
346
+
347
+ def test_auido(example_image, audio_feature, all_pose, opt):
348
+ with open(opt.config) as f:
349
+ para = yaml.load(f, Loader=yaml.FullLoader)
350
+
351
+ # encoder = audio_feature()
352
+ if not opt.cpu:
353
+ audio_feature = audio_feature.cuda()
354
+
355
+ audio_feature.eval()
356
+ # decoder.eval()
357
+ test_file = opt.in_file
358
+ pose = all_pose[:,:6]
359
+ if len(pose) == 1:
360
+ pose = np.repeat(pose,100,0)
361
+
362
+ elif opt.smooth_pose:
363
+ one_euro_filter = OneEuroFilter(mincutoff=0.004, beta=0.7, dcutoff=1.0, freq=100)
364
+
365
+
366
+ for j in range(len(pose)):
367
+ pose[j]=one_euro_filter.process(pose[j])
368
+ # pose[j]=pose[0]
369
+
370
+ example_image = np.array(example_image, dtype='float32').transpose((2, 0, 1))
371
+
372
+
373
+
374
+ # # get wav2lip audio feature
375
+ # wav = audio.load_wav(test_file, 16000)
376
+ # mel = audio.melspectrogram(wav)
377
+ # fps = 30
378
+ # mel_step_size = 16
379
+ # mel_chunks = []
380
+ # mel_idx_multiplier = 80. / fps
381
+ # i = 0
382
+ # while 1:
383
+ # start_idx = int(i * mel_idx_multiplier)
384
+ # if start_idx + mel_step_size > len(mel[0]):
385
+ # mel_chunks.append(mel[:, len(mel[0]) - mel_step_size:])
386
+ # break
387
+ # mel_chunks.append(mel[:, start_idx: start_idx + mel_step_size])
388
+ # i += 1
389
+ # mel_chunks = np.stack(mel_chunks, axis=0)
390
+ # input_mfcc = torch.FloatTensor(mel_chunks).cuda()
391
+
392
+
393
+ # get atvg audio feature
394
+ speech, sr = librosa.load(test_file, sr=16000)
395
+ # mfcc = python_speech_features.mfcc(speech ,16000,winstep=0.01)
396
+ speech = np.insert(speech, 0, np.zeros(1920))
397
+ speech = np.append(speech, np.zeros(1920))
398
+ mfcc = python_speech_features.mfcc(speech,16000,winstep=0.01)
399
+ ind = 3
400
+ fake_lmark = []
401
+ input_mfcc = []
402
+ while ind <= int(mfcc.shape[0] / 4) - 4:
403
+ t_mfcc = mfcc[(ind - 3) * 4: (ind + 4) * 4, 1:]
404
+ t_mfcc = torch.FloatTensor(t_mfcc).cuda()
405
+ input_mfcc.append(t_mfcc)
406
+ ind += 1
407
+ input_mfcc = torch.stack(input_mfcc, dim=0) # N,28,12
408
+
409
+
410
+ print ('=======================================')
411
+ print ('Start to generate images')
412
+
413
+
414
+ with torch.no_grad():
415
+ if (len(pose)<len(input_mfcc)):
416
+ gap = len(input_mfcc)-len(pose)
417
+ n = int((gap/len(pose)/2)) +2
418
+ pose = np.concatenate((pose,pose[::-1,:]),axis = 0)
419
+ pose = np.tile(pose, (n,1))
420
+ if(len(pose)>len(input_mfcc)):
421
+ pose = pose[:len(input_mfcc),:]
422
+
423
+
424
+ if not opt.cpu:
425
+ example_image = Variable(torch.FloatTensor(example_image.astype(float)) ).cuda()
426
+ example_image = torch.unsqueeze(example_image,0)
427
+ pose = Variable(torch.FloatTensor(pose.astype(float)) ).cuda()
428
+
429
+ pose = pose.unsqueeze(0)
430
+
431
+ input_mfcc = input_mfcc.unsqueeze(0)
432
+
433
+ deco_out = audio_feature(example_image,input_mfcc,pose,para['train_params']['jaco_net'],1.6)
434
+
435
+ # ATNET
436
+ # deco_out = audio_feature(example_image, input_mfcc, pose, para['train_params']['jaco_net'])
437
+
438
+ return deco_out
439
+
440
+
441
+ def save(path, frames, format):
442
+
443
+ if format == '.png':
444
+ if not os.path.exists(path):
445
+
446
+ os.makedirs(path)
447
+ for j, frame in enumerate(frames):
448
+ imageio.imsave(path+'/'+str(j)+'.png',frame)
449
+ # imageio.imsave(os.path.join(path, str(j) + '.png'), frames[j])
450
+ else:
451
+ print ("Unknown format %s" % format)
452
+ exit()
453
+
454
+ class VideoWriter(object):
455
+ def __init__(self, path, width, height, fps):
456
+ fourcc = cv2.VideoWriter_fourcc(*'XVID')
457
+ self.path = path
458
+ self.out = cv2.VideoWriter(self.path, fourcc, fps, (width, height))
459
+
460
+ def write_frame(self, frame):
461
+ self.out.write(frame)
462
+
463
+ def end(self):
464
+ self.out.release()
465
+
466
+ def concatenate(number, imgs, save_path):
467
+ width, height = imgs.shape[-3:-1]
468
+ imgs = imgs.reshape(number,-1,width,height,3)
469
+ if number == 2:
470
+ left = imgs[0]
471
+ right = imgs[1]
472
+
473
+ im_all = []
474
+ for i in range(len(left)):
475
+ im = np.concatenate((left[i],right[i]),axis = 1)
476
+ im_all.append(im)
477
+ if number == 3:
478
+ left = imgs[0]
479
+ middle = imgs[1]
480
+ right = imgs[2]
481
+
482
+ im_all = []
483
+ for i in range(len(left)):
484
+ im = np.concatenate((left[i],middle[i],right[i]),axis = 1)
485
+ im_all.append(im)
486
+ if number == 4:
487
+ left = imgs[0]
488
+ left2 = imgs[1]
489
+ right = imgs[2]
490
+ right2 = imgs[3]
491
+
492
+ im_all = []
493
+ for i in range(len(left)):
494
+ im = np.concatenate((left[i],left2[i],right[i],right2[i]),axis = 1)
495
+ im_all.append(im)
496
+ if number == 5:
497
+ left = imgs[0]
498
+ left2 = imgs[1]
499
+ middle = imgs[2]
500
+ right = imgs[3]
501
+ right2 = imgs[4]
502
+
503
+ im_all = []
504
+ for i in range(len(left)):
505
+ im = np.concatenate((left[i],left2[i],middle[i],right[i],right2[i]),axis = 1)
506
+ im_all.append(im)
507
+
508
+
509
+ imageio.mimsave(save_path, [img_as_ubyte(frame) for frame in im_all], fps=25)
510
+
511
+ def add_audio(video_name=None, audio_dir = None):
512
+
513
+ command = 'ffmpeg -i ' + video_name + ' -i ' + audio_dir + ' -vcodec copy -acodec copy -y ' + video_name.replace('.mp4','.mov')
514
+ print (command)
515
+ os.system(command)
516
+
517
+ def smooth_pose(pose_file, pose_long):
518
+ start = np.load(pose_file)
519
+ video_pose = np.load(pose_long)
520
+ if video_pose.shape[-1] == 6:
521
+ start = start[:, :6]
522
+
523
+
524
+ delta = video_pose - video_pose[0,:]
525
+ # print(len(delta))
526
+
527
+ pose = np.repeat(start,len(delta),axis = 0)
528
+ all_pose = pose + delta
529
+
530
+ return all_pose
531
+
532
+ def test(opt, name):
533
+ pose_dim = np.load(opt.pose_file).shape[-1]
534
+ all_pose = np.load(opt.pose_file).reshape(-1,pose_dim)
535
+ if opt.pose_long:
536
+ all_pose = smooth_pose(opt.pose_file,opt.pose_given)
537
+
538
+
539
+ source_image = img_as_float32(io.imread(opt.source_image))
540
+ source_image = resize(source_image, (256, 256))[..., :3]
541
+
542
+ reader = imageio.get_reader(opt.driving_video)
543
+ fps = reader.get_meta_data()['fps']
544
+ driving_video = []
545
+ try:
546
+ for im in reader:
547
+ driving_video.append(im)
548
+ except RuntimeError:
549
+ pass
550
+ reader.close()
551
+
552
+
553
+ driving_video = [resize(frame, (256, 256))[..., :3] for frame in driving_video]
554
+ driving_video = get_aligned_image(driving_video, opt)
555
+ transformed_video = get_transformed_image(driving_video, opt)
556
+ transformed_video = np.array(transformed_video)
557
+
558
+ generator, kp_detector,kp_detector_a, audio_feature, emo_detector = \
559
+ load_checkpoints(opt=opt, checkpoint_path=opt.checkpoint, audio_checkpoint_path=opt.audio_checkpoint, emo_checkpoint_path = opt.emo_checkpoint, kp_checkpoint_path=opt.kp_checkpoint, cpu=opt.cpu)
560
+
561
+ deco_out = test_auido(source_image, audio_feature, all_pose, opt) #1,N,32+3,64,64
562
+
563
+
564
+ if len(driving_video) < len(deco_out[0]):
565
+ driving_video = np.resize(driving_video,(len(deco_out[0]),256,256,3))
566
+ transformed_video = np.resize(transformed_video,(len(deco_out[0]),256,256,3))
567
+
568
+ else:
569
+ driving_video = driving_video[:len(deco_out[0])]
570
+ opt.add_emo = False
571
+ predictions, _ = make_animation_smooth(source_image, driving_video, transformed_video, deco_out, opt.kp_loss, generator, kp_detector, kp_detector_a, emo_detector, opt, relative=opt.relative, adapt_movement_scale=opt.adapt_scale, cpu=opt.cpu)
572
+
573
+ imageio.mimsave(os.path.join(opt.result_path,'neutral.mp4'), [img_as_ubyte(frame) for frame in predictions], fps=fps)
574
+ predictions = np.array(predictions)
575
+
576
+ opt.add_emo = True
577
+ predictions1,_ = make_animation_smooth(source_image, driving_video, transformed_video, deco_out, opt.kp_loss, generator, kp_detector, kp_detector_a, emo_detector, opt, relative=opt.relative, adapt_movement_scale=opt.adapt_scale, cpu=opt.cpu)
578
+
579
+ imageio.mimsave(os.path.join(opt.result_path,'emotion.mp4'), [img_as_ubyte(frame) for frame in predictions1], fps=fps)
580
+ add_audio(os.path.join(opt.result_path,'emotion.mp4'),opt.in_file)
581
+ predictions1 = np.array(predictions1)
582
+ all_imgs = np.concatenate((driving_video,predictions,predictions1),axis = 0)
583
+ save_path = os.path.join(opt.result_path, 'all.mp4')
584
+ concatenate(3, all_imgs, save_path)
585
+ add_audio(save_path,opt.in_file)
586
+
587
+
588
+
589
+ if __name__ == "__main__":
590
+
591
+
592
+
593
+ parser = ArgumentParser()
594
+ parser.add_argument("--config", default ='config/MEAD_emo_video_aug_delta_4_crop_random_crop.yaml', help="path to config")#required=True default ='config/vox-256.yaml'
595
+
596
+ parser.add_argument("--audio_checkpoint", default='ckpt/1-6000.pth.tar', help="path to checkpoint to restore")
597
+ parser.add_argument("--checkpoint", default='ckpt/124_52000.pth.tar', help="path to checkpoint to restore")
598
+ parser.add_argument("--kp_checkpoint", default='ckpt/124_52000.pth.tar', help="path to checkpoint to restore")
599
+ # parser.add_argument("--emo_checkpoint", default='ablation/ablation/ten/10-6000.pth.tar', help="path to checkpoint to restore")
600
+ parser.add_argument("--emo_checkpoint", default='ckpt/5-3000.pth.tar', help="path to checkpoint to restore")
601
+
602
+ parser.add_argument("--source_image", default='test/image/21.png', help="path to source image")
603
+
604
+ parser.add_argument("--driving_video", default='test/video/disgusted.mp4', help="path to driving video")#data/M030/video/M030_angry_
605
+ parser.add_argument('--in_file', type=str, default='test/audio/sample1.mov')
606
+ parser.add_argument('--pose_file', type=str, default='test/pose/60.npy')
607
+ parser.add_argument('--pose_given', type=str, default='test/pose_long/50IAfJCypFI_Alex_Kingston_50IAfJCypFI_0001.npy')
608
+
609
+ parser.add_argument("--result_path", default='result/', help="path to output")#'/media/thea/新加卷/fomm/Exp/'+emotion+'.mp4'
610
+
611
+ parser.add_argument("--relative", dest="relative", action="store_true", help="use relative or absolute keypoint coordinates")
612
+ parser.add_argument("--adapt_scale", dest="adapt_scale", action="store_true", help="adapt movement scale based on convex hull of keypoints")
613
+
614
+ parser.add_argument("--cpu", dest="cpu", action="store_true", help="cpu mode.")
615
+ parser.add_argument("--kp_loss", default=0, help="keypoint loss.")
616
+
617
+ parser.add_argument("--smooth_pose", default=True, help="cpu mode.")
618
+ parser.add_argument("--pose_long", default=False, help="use given long poses.")
619
+ parser.add_argument("--weight", default=0, help="cpu mode.")
620
+ parser.add_argument("--add_emo", default=False, help="add emotion.")
621
+ parser.add_argument("--check_add", default=False, help="check emotion displacement.")
622
+ parser.add_argument("--type", default='linear_3', help="add emotion type.")
623
+ parser.add_argument("--emotion", default='disgusted', help="emotion category, 'angry', 'contempt','disgusted','fear','happy','neutral','sad','surprised'.")
624
+ parser.set_defaults(relative=False)
625
+ parser.set_defaults(adapt_scale=False)
626
+
627
+ opt = parser.parse_args()
628
+ # opt.cpu = True
629
+
630
+ test(opt,'test')
631
+
632
+
FONT/filter1.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ #import pickle
3
+ import time
4
+ import numpy as np
5
+ import copy
6
+
7
+ from matplotlib import pyplot as plt
8
+ from tqdm import tqdm
9
+
10
+
11
+
12
+
13
+ class LowPassFilter:
14
+ def __init__(self):
15
+ self.prev_raw_value = None
16
+ self.prev_filtered_value = None
17
+
18
+ def process(self, value, alpha):
19
+ if self.prev_raw_value is None:
20
+ s = value
21
+ else:
22
+ s = alpha * value + (1.0 - alpha) * self.prev_filtered_value
23
+ self.prev_raw_value = value
24
+ self.prev_filtered_value = s
25
+ return s
26
+
27
+
28
+ class OneEuroFilter:
29
+ def __init__(self, mincutoff=1.0, beta=0.0, dcutoff=1.0, freq=30):
30
+ self.freq = freq
31
+ self.mincutoff = mincutoff
32
+ self.beta = beta
33
+ self.dcutoff = dcutoff
34
+ self.x_filter = LowPassFilter()
35
+ self.dx_filter = LowPassFilter()
36
+
37
+ def compute_alpha(self, cutoff):
38
+ te = 1.0 / self.freq
39
+ tau = 1.0 / (2 * np.pi * cutoff)
40
+ return 1.0 / (1.0 + tau / te)
41
+
42
+ def process(self, x):
43
+ prev_x = self.x_filter.prev_raw_value
44
+ dx = 0.0 if prev_x is None else (x - prev_x) * self.freq
45
+ edx = self.dx_filter.process(dx, self.compute_alpha(self.dcutoff))
46
+ cutoff = self.mincutoff + self.beta * np.abs(edx)
47
+ return self.x_filter.process(x, self.compute_alpha(cutoff))
48
+
FONT/frames_dataset.py ADDED
@@ -0,0 +1,539 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from skimage import io, img_as_float32, transform
3
+ from skimage.color import gray2rgb
4
+ from sklearn.model_selection import train_test_split
5
+ from imageio import mimread
6
+
7
+ import numpy as np
8
+ from torch.utils.data import Dataset
9
+ import pandas as pd
10
+ from augmentation import AllAugmentationTransform
11
+ import glob
12
+ import pickle
13
+ import random
14
+ from filter1 import OneEuroFilter
15
+ def read_video(name, frame_shape):
16
+ """
17
+ Read video which can be:
18
+ - an image of concatenated frames
19
+ - '.mp4' and'.gif'
20
+ - folder with videos
21
+ """
22
+
23
+ if os.path.isdir(name):
24
+ frames = sorted(os.listdir(name))
25
+ num_frames = len(frames)
26
+ video_array = np.array(
27
+ [img_as_float32(io.imread(os.path.join(name, frames[idx]))) for idx in range(num_frames)])
28
+ elif name.lower().endswith('.png') or name.lower().endswith('.jpg'):
29
+ image = io.imread(name)
30
+
31
+ if len(image.shape) == 2 or image.shape[2] == 1:
32
+ image = gray2rgb(image)
33
+
34
+ if image.shape[2] == 4:
35
+ image = image[..., :3]
36
+
37
+ image = img_as_float32(image)
38
+
39
+ video_array = np.moveaxis(image, 1, 0)
40
+
41
+ video_array = video_array.reshape((-1,) + frame_shape)
42
+ video_array = np.moveaxis(video_array, 1, 2)
43
+ elif name.lower().endswith('.gif') or name.lower().endswith('.mp4') or name.lower().endswith('.mov'):
44
+ video = np.array(mimread(name))
45
+ if len(video.shape) == 3:
46
+ video = np.array([gray2rgb(frame) for frame in video])
47
+ if video.shape[-1] == 4:
48
+ video = video[..., :3]
49
+ video_array = img_as_float32(video)
50
+ else:
51
+ raise Exception("Unknown file extensions %s" % name)
52
+
53
+ return video_array
54
+
55
+ def get_list(ipath,base_name):
56
+ #ipath = '/mnt/lustre/share/jixinya/LRW/pose/train_fo/'
57
+ ipath = os.path.join(ipath,base_name)
58
+ name_list = os.listdir(ipath)
59
+ image_path = os.path.join('/mnt/lustre/share/jixinya/LRW/Image/',base_name)
60
+ all = []
61
+ for k in range(len(name_list)):
62
+ name = name_list[k]
63
+ path_ = os.path.join(ipath,name)
64
+ Dir = os.listdir(path_)
65
+ for i in range(len(Dir)):
66
+ word = Dir[i]
67
+ path = os.path.join(path_, word)
68
+ if os.path.exists(os.path.join(image_path,name,word.split('.')[0])):
69
+ all.append(name+'/'+word.split('.')[0])
70
+ #print(k,name,i,word)
71
+ print('get list '+os.path.basename(ipath))
72
+ return all
73
+
74
+
75
+ class AudioDataset(Dataset):
76
+ """
77
+ Dataset of videos, each video can be represented as:
78
+ - an image of concatenated frames
79
+ - '.mp4' or '.gif'
80
+ - folder with all frames
81
+ """
82
+
83
+ def __init__(self, name, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
84
+ random_seed=0, augmentation_params=None):
85
+ self.root_dir = root_dir
86
+ self.audio_dir = os.path.join(root_dir,'MFCC')
87
+ self.image_dir = os.path.join(root_dir,'Image')
88
+ self.pose_dir = os.path.join(root_dir,'pose')
89
+ # assert len(os.listdir(self.audio_dir)) == len(os.listdir(self.image_dir)), 'audio and image length not equal'
90
+
91
+ # self.videos=np.load('../LRW/list/train_fo.npy')
92
+ # self.videos = os.listdir(self.landmark_dir)
93
+ self.frame_shape = tuple(frame_shape)
94
+
95
+ self.id_sampling = id_sampling
96
+
97
+ if os.path.exists(os.path.join(self.pose_dir, 'train_fo')):
98
+ assert os.path.exists(os.path.join(self.pose_dir, 'test_fo'))
99
+ print("Use predefined train-test split.")
100
+ if id_sampling:
101
+ train_videos = {os.path.basename(video).split('#')[0] for video in
102
+ os.listdir(os.path.join(self.image_dir, 'train'))}
103
+ train_videos = list(train_videos)
104
+ else:
105
+ train_videos = np.load('../LRW/list/train_fo.npy')# get_list(self.pose_dir, 'train_fo')
106
+ # df=open('../LRW/list/test_fo.txt','rb')
107
+ test_videos=np.load('../LRW/list/test_fo.npy')
108
+ # df.close()
109
+ # test_videos = np.load('../LRW/list/train_fo.npy')
110
+ #get_list(self.pose_dir, 'test_fo')
111
+ # self.root_dir = os.path.join(self.root_dir, 'train' if is_train else 'test')
112
+
113
+ self.image_dir = os.path.join(self.image_dir, 'train_fo' if is_train else 'test_fo')
114
+ self.audio_dir = os.path.join(self.audio_dir, 'train' if is_train else 'test')
115
+ self.pose_dir = os.path.join(self.pose_dir, 'train_fo' if is_train else 'test_fo')
116
+ else:
117
+ print("Use random train-test split.")
118
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
119
+
120
+ if is_train:
121
+ self.videos = train_videos
122
+ else:
123
+ self.videos = test_videos
124
+
125
+ self.is_train = is_train
126
+
127
+ if self.is_train:
128
+ self.transform = AllAugmentationTransform(**augmentation_params)
129
+ else:
130
+ self.transform = None
131
+
132
+ def __len__(self):
133
+ return len(self.videos)
134
+
135
+ def __getitem__(self, idx):
136
+ if self.is_train and self.id_sampling:
137
+ name = self.videos[idx].split('.')[0]
138
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
139
+ else:
140
+ name = self.videos[idx].split('.')[0]
141
+
142
+ audio_path = os.path.join(self.audio_dir, name)
143
+ pose_path = os.path.join(self.pose_dir,name)
144
+ path = os.path.join(self.image_dir, name)
145
+
146
+ video_name = os.path.basename(path)
147
+
148
+ if os.path.isdir(path):
149
+ # if self.is_train and os.path.isdir(path):
150
+
151
+ # mfcc loading
152
+ r = random.choice([x for x in range(3, 8)])
153
+
154
+ example_image = img_as_float32(io.imread(os.path.join(path, str(r)+'.png')))
155
+
156
+ mfccs = []
157
+ for ind in range(1, 17):
158
+ # t_mfcc = mfcc[(r + ind - 3) * 4: (r + ind + 4) * 4, 1:]
159
+ t_mfcc = np.load(os.path.join(audio_path,str(r + ind)+'.npy'),allow_pickle=True)[:, 1:]
160
+ mfccs.append(t_mfcc)
161
+ mfccs = np.array(mfccs)
162
+
163
+ poses = []
164
+ video_array = []
165
+ for ind in range(1, 17):
166
+
167
+ t_pose = np.load(os.path.join(self.pose_dir,name+'.npy'))[r+ind,:-1]
168
+
169
+ poses.append(t_pose)
170
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
171
+ video_array.append(image)
172
+ poses = np.array(poses)
173
+ video_array = np.array(video_array)
174
+
175
+ else:
176
+ print('Wrong, data path not an existing file.')
177
+
178
+ if self.transform is not None:
179
+ video_array = self.transform(video_array)
180
+
181
+ out = {}
182
+
183
+ driving = np.array(video_array, dtype='float32')
184
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
185
+ driving_pose = np.array(poses, dtype='float32')
186
+ example_image = np.array(example_image, dtype='float32')
187
+
188
+ out['example_image'] = example_image.transpose((2, 0, 1))
189
+ out['driving_pose'] = driving_pose
190
+ out['driving'] = driving.transpose((0, 3, 1, 2))
191
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
192
+ # out['name'] = video_name
193
+
194
+ return out
195
+
196
+ class VoxDataset(Dataset):
197
+ """
198
+ Dataset of videos, each video can be represented as:
199
+ - an image of concatenated frames
200
+ - '.mp4' or '.gif'
201
+ - folder with all frames
202
+ """
203
+
204
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
205
+ random_seed=0, pairs_list=None, augmentation_params=None):
206
+ self.root_dir = root_dir
207
+ self.audio_dir = os.path.join(root_dir,'MFCC')
208
+ self.image_dir = os.path.join(root_dir,'align_img')
209
+
210
+ self.pose_dir = os.path.join(root_dir,'align_pose')
211
+ # assert len(os.listdir(self.audio_dir)) == len(os.listdir(self.image_dir)), 'audio and image length not equal'
212
+
213
+
214
+ # df=open('../LRW/list/test_fo.txt','rb')
215
+ # self.videos=pickle.load(df)
216
+ # df.close()
217
+ self.videos=np.load('/mnt/lustre/share_data/jixinya/VoxCeleb1_Cut/right.npy')
218
+ # self.videos = os.listdir(self.landmark_dir)
219
+ self.frame_shape = tuple(frame_shape)
220
+ self.pairs_list = pairs_list
221
+ self.id_sampling = id_sampling
222
+
223
+ if os.path.exists(os.path.join(self.pose_dir, 'train_fo')):
224
+ assert os.path.exists(os.path.join(self.pose_dir, 'test_fo'))
225
+ print("Use predefined train-test split.")
226
+ if id_sampling:
227
+ train_videos = {os.path.basename(video).split('#')[0] for video in
228
+ os.listdir(os.path.join(self.image_dir, 'train'))}
229
+ train_videos = list(train_videos)
230
+ else:
231
+ train_videos = np.load('/mnt/lustre/share_data/jixinya/VoxCeleb1_Cut/right.npy')# get_list(self.pose_dir, 'train_fo')
232
+
233
+ self.image_dir = os.path.join(self.image_dir, 'train_fo' if is_train else 'test_fo')
234
+ self.audio_dir = os.path.join(self.audio_dir, 'train' if is_train else 'test')
235
+ self.pose_dir = os.path.join(self.pose_dir, 'train_fo' if is_train else 'test_fo')
236
+ else:
237
+ print("Use random train-test split.")
238
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
239
+
240
+ if is_train:
241
+ self.videos = train_videos
242
+ else:
243
+ self.videos = test_videos
244
+
245
+ self.is_train = is_train
246
+
247
+ if self.is_train:
248
+ self.transform = AllAugmentationTransform(**augmentation_params)
249
+ else:
250
+ self.transform = None
251
+
252
+ def __len__(self):
253
+ return len(self.videos)
254
+
255
+ def __getitem__(self, idx):
256
+ if self.is_train and self.id_sampling:
257
+ name = self.videos[idx].split('.')[0]
258
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
259
+ else:
260
+ name = self.videos[idx].split('.')[0]
261
+
262
+ audio_path = os.path.join(self.audio_dir, name+'.npy')
263
+ pose_path = os.path.join(self.pose_dir,name+'.npy')
264
+ path = os.path.join(self.image_dir, name)
265
+
266
+ video_name = os.path.basename(path)
267
+
268
+ if os.path.isdir(path):
269
+ # if self.is_train and os.path.isdir(path):
270
+ frames = os.listdir(path)
271
+ num_frames = len(frames)
272
+ frame_idx = np.sort(np.random.choice(num_frames, replace=True, size=2))
273
+ video_array = [img_as_float32(io.imread(os.path.join(path, frames[idx]))) for idx in frame_idx]
274
+ mfcc = np.load(audio_path)
275
+ pose = np.load(pose_path)
276
+
277
+ # print(audio_path,pose_path,len(mfcc))
278
+
279
+ try:
280
+ len(mfcc) > 16
281
+ except:
282
+ print('wrongmfcc len:',audio_path)
283
+ if 16 < len(mfcc) < 24 :
284
+ r = 0
285
+ else:
286
+
287
+ r = random.choice([x for x in range(3, len(mfcc)-20)])
288
+
289
+ mfccs = []
290
+ poses = []
291
+ video_array = []
292
+ for ind in range(1, 17):
293
+ t_mfcc = mfcc[r+ind][:, 1:]
294
+ mfccs.append(t_mfcc)
295
+ t_pose = pose[r+ind,:-1]
296
+ poses.append(t_pose)
297
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
298
+ video_array.append(image)
299
+ mfccs = np.array(mfccs)
300
+ poses = np.array(poses)
301
+ video_array = np.array(video_array)
302
+
303
+ example_image = img_as_float32(io.imread(os.path.join(path, str(r)+'.png')))
304
+
305
+
306
+ else:
307
+ print('Wrong, data path not an existing file.')
308
+
309
+ if self.transform is not None:
310
+ video_array = self.transform(video_array)
311
+
312
+ out = {}
313
+
314
+ driving = np.array(video_array, dtype='float32')
315
+
316
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
317
+ driving_pose = np.array(poses, dtype='float32')
318
+ example_image = np.array(example_image, dtype='float32')
319
+ out['example_image'] = example_image.transpose((2, 0, 1))
320
+ out['driving_pose'] = driving_pose
321
+ out['driving'] = driving.transpose((0, 3, 1, 2))
322
+
323
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
324
+ # out['name'] = video_name
325
+
326
+ return out
327
+
328
+ class MeadDataset(Dataset):
329
+ """
330
+ Dataset of videos, each video can be represented as:
331
+ - an image of concatenated frames
332
+ - '.mp4' or '.gif'
333
+ - folder with all frames
334
+ """
335
+
336
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
337
+ random_seed=0, augmentation_params=None):
338
+ self.root_dir = root_dir
339
+
340
+ self.audio_dir = os.path.join(root_dir,'MEAD_MFCC')
341
+ self.image_dir = os.path.join(root_dir,'MEAD_fomm_crop')
342
+
343
+ self.pose_dir = os.path.join(root_dir,'MEAD_fomm_pose_crop')
344
+
345
+ self.videos = np.load('/mnt/lustre/share_data/jixinya/MEAD/MEAD_fomm_audio_less_crop.npy')
346
+ self.dict = np.load('/mnt/lustre/share_data/jixinya/MEAD/MEAD_fomm_neu_dic_crop.npy',allow_pickle=True).item()
347
+ # self.videos = os.listdir(root_dir)
348
+ self.frame_shape = tuple(frame_shape)
349
+
350
+ self.id_sampling = id_sampling
351
+ if os.path.exists(os.path.join(root_dir, 'train')):
352
+ assert os.path.exists(os.path.join(root_dir, 'test'))
353
+ print("Use predefined train-test split.")
354
+ if id_sampling:
355
+ train_videos = {os.path.basename(video).split('#')[0] for video in
356
+ os.listdir(os.path.join(root_dir, 'train'))}
357
+ train_videos = list(train_videos)
358
+ else:
359
+ train_videos = os.listdir(os.path.join(root_dir, 'train'))
360
+ test_videos = os.listdir(os.path.join(root_dir, 'test'))
361
+ self.root_dir = os.path.join(self.root_dir, 'train' if is_train else 'test')
362
+ else:
363
+ print("Use random train-test split.")
364
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
365
+
366
+ if is_train:
367
+ self.videos = train_videos
368
+ else:
369
+ self.videos = test_videos
370
+
371
+ self.is_train = is_train
372
+
373
+ if self.is_train:
374
+ self.transform = AllAugmentationTransform(**augmentation_params)
375
+ else:
376
+ self.transform = None
377
+
378
+ def __len__(self):
379
+ return len(self.videos)
380
+
381
+ def __getitem__(self, idx):
382
+ if self.is_train and self.id_sampling:
383
+ name = self.videos[idx]
384
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
385
+ else:
386
+ name = self.videos[idx]
387
+ path = os.path.join(self.image_dir, name)
388
+
389
+ video_name = os.path.basename(path)
390
+ id_name = path.split('/')[-2]
391
+ neu_list = self.dict[id_name]
392
+ neu_path = os.path.join(self.image_dir, np.random.choice(neu_list))
393
+
394
+ audio_path = os.path.join(self.audio_dir, name+'.npy')
395
+ pose_path = os.path.join(self.pose_dir,name+'.npy')
396
+
397
+
398
+ if self.is_train and os.path.isdir(path):
399
+
400
+ mfcc = np.load(audio_path)
401
+ pose_raw = np.load(pose_path)
402
+ one_euro_filter = OneEuroFilter(mincutoff=0.01, beta=0.7, dcutoff=1.0, freq=100)
403
+ pose = np.zeros((len(pose_raw),7))
404
+
405
+ for j in range(len(pose_raw)):
406
+ pose[j]=one_euro_filter.process(pose_raw[j])
407
+ # print(audio_path,pose_path,len(mfcc))
408
+
409
+ neu_frames = os.listdir(neu_path)
410
+ num_neu_frames = len(neu_frames)
411
+ frame_idx = np.random.choice(num_neu_frames)
412
+ example_image = img_as_float32(io.imread(os.path.join(neu_path, neu_frames[frame_idx])))
413
+ try:
414
+ len(mfcc) > 16
415
+ except:
416
+ print('wrongmfcc len:',audio_path)
417
+ if 16 < len(mfcc) < 24 :
418
+ r = 0
419
+ else:
420
+
421
+ r = random.choice([x for x in range(3, len(mfcc)-20)])
422
+
423
+ mfccs = []
424
+ poses = []
425
+ video_array = []
426
+ for ind in range(1, 17):
427
+ t_mfcc = mfcc[r+ind][:, 1:]
428
+ mfccs.append(t_mfcc)
429
+ t_pose = pose[r+ind,:-1]
430
+ poses.append(t_pose)
431
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
432
+ video_array.append(image)
433
+ mfccs = np.array(mfccs)
434
+ poses = np.array(poses)
435
+ video_array = np.array(video_array)
436
+
437
+ else:
438
+ print('Wrong, data path not an existing file.')
439
+
440
+ # if self.transform is not None:
441
+ # video_array = self.transform(video_array)
442
+
443
+ out = {}
444
+ if self.is_train:
445
+
446
+ driving = np.array(video_array, dtype='float32')
447
+ driving_pose = np.array(poses, dtype='float32')
448
+ example_image = np.array(example_image, dtype='float32')
449
+
450
+
451
+ out['example_image'] = example_image.transpose((2, 0, 1))
452
+ out['driving_pose'] = driving_pose
453
+ out['driving'] = driving.transpose((0, 3, 1, 2))
454
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
455
+
456
+ # out['name'] = id_name+'/'+video_name
457
+
458
+ return out
459
+
460
+
461
+ class DatasetRepeater(Dataset):
462
+ """
463
+ Pass several times over the same dataset for better i/o performance
464
+ """
465
+
466
+ def __init__(self, dataset, num_repeats=100):
467
+ self.dataset = dataset
468
+ # self.dataset2 = dataset2
469
+ self.num_repeats = num_repeats
470
+
471
+ def __len__(self):
472
+ return self.num_repeats * self.dataset.__len__()
473
+
474
+ def __getitem__(self, idx):
475
+ # if idx % 5 == 0:
476
+ # return self.dataset2[idx % self.dataset2.__len__()]#% self.dataset.__len__()
477
+ # else:
478
+ # return self.dataset[idx % self.dataset.__len__()]
479
+ return self.dataset[idx % self.dataset.__len__()]
480
+
481
+ class TestsetRepeater(Dataset):
482
+ """
483
+ Pass several times over the same dataset for better i/o performance
484
+ """
485
+
486
+ def __init__(self, dataset, num_repeats=100):
487
+ self.dataset = dataset
488
+
489
+ self.num_repeats = num_repeats
490
+
491
+ def __len__(self):
492
+ return self.num_repeats * self.dataset.__len__()
493
+
494
+ def __getitem__(self, idx):
495
+
496
+ return self.dataset[idx % self.dataset.__len__()]#% self.dataset.__len__()
497
+
498
+
499
+ class PairedDataset(Dataset):
500
+ """
501
+ Dataset of pairs for animation.
502
+ """
503
+
504
+ def __init__(self, initial_dataset, number_of_pairs, seed=0):
505
+ self.initial_dataset = initial_dataset
506
+ pairs_list = self.initial_dataset.pairs_list
507
+
508
+ np.random.seed(seed)
509
+
510
+ if pairs_list is None:
511
+ max_idx = min(number_of_pairs, len(initial_dataset))
512
+ nx, ny = max_idx, max_idx
513
+ xy = np.mgrid[:nx, :ny].reshape(2, -1).T
514
+ number_of_pairs = min(xy.shape[0], number_of_pairs)
515
+ self.pairs = xy.take(np.random.choice(xy.shape[0], number_of_pairs, replace=False), axis=0)
516
+ else:
517
+ videos = self.initial_dataset.videos
518
+ name_to_index = {name: index for index, name in enumerate(videos)}
519
+ pairs = pd.read_csv(pairs_list)
520
+ pairs = pairs[np.logical_and(pairs['source'].isin(videos), pairs['driving'].isin(videos))]
521
+
522
+ number_of_pairs = min(pairs.shape[0], number_of_pairs)
523
+ self.pairs = []
524
+ self.start_frames = []
525
+ for ind in range(number_of_pairs):
526
+ self.pairs.append(
527
+ (name_to_index[pairs['driving'].iloc[ind]], name_to_index[pairs['source'].iloc[ind]]))
528
+
529
+ def __len__(self):
530
+ return len(self.pairs)
531
+
532
+ def __getitem__(self, idx):
533
+ pair = self.pairs[idx]
534
+ first = self.initial_dataset[pair[0]]
535
+ second = self.initial_dataset[pair[1]]
536
+ first = {'driving_' + key: value for key, value in first.items()}
537
+ second = {'source_' + key: value for key, value in second.items()}
538
+
539
+ return {**first, **second}
FONT/frames_dataset_liujin.py ADDED
@@ -0,0 +1,727 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from skimage import io, img_as_float32, transform
3
+ from skimage.color import gray2rgb
4
+ from sklearn.model_selection import train_test_split
5
+ from imageio import mimread
6
+
7
+ import numpy as np
8
+ from torch.utils.data import Dataset
9
+ import pandas as pd
10
+ from augmentation import AllAugmentationTransform
11
+ import glob
12
+ import pickle
13
+ import random
14
+ from filter1 import OneEuroFilter
15
+ import pickle
16
+ from tqdm import tqdm
17
+ from scipy.io import loadmat
18
+ import time
19
+ import random
20
+
21
+
22
+
23
+ def read_video(name, frame_shape):
24
+ """
25
+ Read video which can be:
26
+ - an image of concatenated frames
27
+ - '.mp4' and'.gif'
28
+ - folder with videos
29
+ """
30
+
31
+ if os.path.isdir(name):
32
+ frames = sorted(os.listdir(name))
33
+ num_frames = len(frames)
34
+ video_array = np.array(
35
+ [img_as_float32(io.imread(os.path.join(name, frames[idx]))) for idx in range(num_frames)])
36
+ elif name.lower().endswith('.png') or name.lower().endswith('.jpg'):
37
+ image = io.imread(name)
38
+
39
+ if len(image.shape) == 2 or image.shape[2] == 1:
40
+ image = gray2rgb(image)
41
+
42
+ if image.shape[2] == 4:
43
+ image = image[..., :3]
44
+
45
+ image = img_as_float32(image)
46
+
47
+ video_array = np.moveaxis(image, 1, 0)
48
+
49
+ video_array = video_array.reshape((-1,) + frame_shape)
50
+ video_array = np.moveaxis(video_array, 1, 2)
51
+ elif name.lower().endswith('.gif') or name.lower().endswith('.mp4') or name.lower().endswith('.mov'):
52
+ video = np.array(mimread(name))
53
+ if len(video.shape) == 3:
54
+ video = np.array([gray2rgb(frame) for frame in video])
55
+ if video.shape[-1] == 4:
56
+ video = video[..., :3]
57
+ video_array = img_as_float32(video)
58
+ else:
59
+ raise Exception("Unknown file extensions %s" % name)
60
+
61
+ return video_array
62
+
63
+ def get_list(ipath,base_name):
64
+ #ipath = '/mnt/lustre/share/jixinya/LRW/pose/train_fo/'
65
+ ipath = os.path.join(ipath,base_name)
66
+ name_list = os.listdir(ipath)
67
+ image_path = os.path.join('/mnt/lustre/share/jixinya/LRW/Image/',base_name)
68
+ all = []
69
+ for k in range(len(name_list)):
70
+ name = name_list[k]
71
+ path_ = os.path.join(ipath,name)
72
+ Dir = os.listdir(path_)
73
+ for i in range(len(Dir)):
74
+ word = Dir[i]
75
+ path = os.path.join(path_, word)
76
+ if os.path.exists(os.path.join(image_path,name,word.split('.')[0])):
77
+ all.append(name+'/'+word.split('.')[0])
78
+ #print(k,name,i,word)
79
+ print('get list '+os.path.basename(ipath))
80
+ return all
81
+
82
+
83
+ class AudioDataset(Dataset):
84
+ """
85
+ Dataset of videos, each video can be represented as:
86
+ - an image of concatenated frames
87
+ - '.mp4' or '.gif'
88
+ - folder with all frames
89
+ """
90
+
91
+ def __init__(self, name, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
92
+ random_seed=0, augmentation_params=None):
93
+
94
+ self.root_dir = "/data/liujin/dataset/LRW/"
95
+ # self.audio_dir = os.path.join(root_dir,'lipread_atvg_audio_feature')
96
+
97
+
98
+ self.frame_shape = tuple(frame_shape)
99
+
100
+ self.is_train = is_train
101
+ self.split = 'train' if is_train else 'test'
102
+
103
+ self.used_video_frames_paths = self.get_used_frames_paths()
104
+
105
+ self.videos = self.get_video_items(self.used_video_frames_paths)
106
+
107
+
108
+ print('length of LRW {} dataset is {}'.format(self.split, str(len(self.videos))) )
109
+
110
+
111
+ if self.is_train:
112
+ self.transform = AllAugmentationTransform(**augmentation_params)
113
+ else:
114
+ self.transform = None
115
+
116
+ def get_video_items(self, all_video_frames_paths):
117
+ print('total video items length is {}'.format(len(all_video_frames_paths)))
118
+ video_items = []
119
+ cur_lengh = 0
120
+ init_start_time = time.time()
121
+
122
+ for video_frames_path in tqdm(all_video_frames_paths):
123
+ video_items.append(self.construct_Video_Info(video_frames_path))
124
+ if len(video_items) - cur_lengh > 5000:
125
+ init_end_time = time.time()
126
+
127
+ print(len(video_items))
128
+ print('Cost {} seconds'.format(str(init_end_time - init_start_time)))
129
+ cur_lengh = len(video_items)
130
+ init_start_time = init_end_time
131
+ return video_items
132
+
133
+ def get_used_frames_paths(self):
134
+ used_video_frames_paths = []
135
+ # used_words = ['ABOUT', 'ABSOLUTELY', 'ABUSE', 'ACCESS', 'ACCORDING',
136
+ # 'COUNCIL', 'COUNTRIES', 'COUNTRY', 'COUPLE', 'COURSE',
137
+ # 'HISTORY', 'HOMES', 'HOSPITAL', 'HOURS', 'HOUSE',
138
+ # 'OPPOSITION', 'ORDER', 'OTHER', 'OTHERS', 'OUTSIDE',
139
+ # 'SOMETHING', 'SOUTH', 'SOUTHERN', 'SPEAKING']
140
+
141
+ lrw_word_dir = "/data/liujin/dataset/LRW/lipread_frames/"
142
+ all_words = sorted(os.listdir(lrw_word_dir))
143
+ # used_words = all_words[0:500:5]
144
+
145
+ used_words = sorted(os.listdir("/data/liujin/dataset/LRW/lipread_3DDFA_pose/"))
146
+
147
+ for word in (used_words):
148
+ cur_videos_path = os.path.join('/data/liujin/dataset/LRW/lipread_frames/', word, self.split)
149
+ length = len(os.listdir(cur_videos_path))
150
+ for video_name in sorted(os.listdir(cur_videos_path))[:int(0.05 * length)]:
151
+ used_video_frames_paths.append(os.path.join(cur_videos_path, video_name))
152
+
153
+
154
+ return used_video_frames_paths[:]
155
+
156
+ def construct_Video_Info(self, cur_frames_path):
157
+ info = {}
158
+
159
+ cor_mfcc_path = cur_frames_path.replace('lipread_frames', 'lipread_atvg_audio_feature') + '.pkl'
160
+ with open(cor_mfcc_path, 'rb') as fp:
161
+ info['mfccs'] = pickle.load(fp) #N,28,12 ATVG / N,80,16,wav2lip
162
+
163
+ # cor_pose_path = cur_frames_path.replace('lipread_frames', 'lipread_3dmm')
164
+ cor_pose_path = cur_frames_path.replace('lipread_frames', 'lipread_3DDFA_pose')
165
+ cur_video_pose = []
166
+ for pose_name in sorted(os.listdir(cor_pose_path)):
167
+ frame_pose_path = os.path.join(cor_pose_path, pose_name)
168
+ cur_pose_data = None
169
+ if frame_pose_path.endswith('npy'):
170
+ cur_pose_data = np.load(frame_pose_path)
171
+ elif frame_pose_path.endswith('mat'):
172
+ file_mat = loadmat(frame_pose_path)
173
+ coeff_3dmm = file_mat['coeff']
174
+ angles = coeff_3dmm[:, 224:227] # euler angles for pose
175
+ translation = coeff_3dmm[:, 254:257] # translation
176
+ cur_pose_data = np.concatenate([angles, translation], 1)
177
+
178
+
179
+ cur_video_pose.append(cur_pose_data)
180
+ cur_video_pose_array = np.concatenate(cur_video_pose, axis=0) #N,7
181
+ info['poses'] = cur_video_pose_array
182
+
183
+
184
+ frames = []
185
+ for frame_name in sorted(os.listdir(cur_frames_path)):
186
+ cur_frame_path = os.path.join(cur_frames_path, frame_name)
187
+ # frames.append(img_as_float32(io.imread(cur_frame_path)))
188
+ frames.append(cur_frame_path)
189
+ info['frames'] = frames
190
+
191
+ return info
192
+
193
+
194
+ def __len__(self):
195
+ return len(self.videos)
196
+
197
+ def __getitem__(self, idx):
198
+
199
+ video_info = self.videos[idx]
200
+ # mfcc loading
201
+ r = random.choice([x for x in range(3, 8)])
202
+
203
+ example_image = video_info['frames'][r]
204
+
205
+
206
+ mfccs = video_info['mfccs'][r:r+16]
207
+
208
+ poses = []
209
+ video_array = []
210
+ for ind in range(1, 17):
211
+
212
+ t_pose = video_info['poses'][r+ind,:6]
213
+ poses.append(t_pose)
214
+
215
+ image = video_info['frames'][r + ind]
216
+ image_data = img_as_float32(io.imread(image))
217
+ video_array.append(image_data)
218
+ poses = np.array(poses)
219
+ video_array = np.array(video_array)
220
+
221
+
222
+
223
+ # if self.transform is not None:
224
+ # video_array = self.transform(video_array)
225
+
226
+ out = {}
227
+
228
+ driving = np.array(video_array, dtype='float32')
229
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
230
+ driving_pose = np.array(poses, dtype='float32')
231
+
232
+ example_image_data = img_as_float32(io.imread(example_image))
233
+ example_image = np.array(example_image_data, dtype='float32')
234
+
235
+ out['example_image'] = example_image.transpose((2, 0, 1))
236
+ out['driving_pose'] = driving_pose
237
+ out['driving'] = driving.transpose((0, 3, 1, 2))
238
+ # out['driving_audio'] = np.array(mfccs, dtype='float32')
239
+ # out['driving_audio'] = np.array(mfccs, dtype='float32')
240
+ out['driving_audio'] = mfccs
241
+ # out['name'] = video_name
242
+ out['transformed_driving'] = out['driving']
243
+
244
+ return out
245
+
246
+
247
+ class HDTFDataset(Dataset):
248
+ """
249
+ Dataset of videos, each video can be represented as:
250
+ - an image of concatenated frames
251
+ - '.mp4' or '.gif'
252
+ - folder with all frames
253
+ """
254
+
255
+ def __init__(self, name, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
256
+ random_seed=0, augmentation_params=None):
257
+
258
+ self.root_dir = "/data/liujin/dataset/HDTF/"
259
+ # self.audio_dir = os.path.join(root_dir,'lipread_atvg_audio_feature')
260
+
261
+ self.frame_shape = tuple(frame_shape)
262
+
263
+ self.is_train = is_train
264
+ self.split = 'train' if is_train else 'test'
265
+
266
+ self.used_video_frames_paths = self.get_used_frames_paths()
267
+
268
+ self.videos = self.get_video_items(self.used_video_frames_paths)
269
+
270
+ print('length of HDTF {} dataset is {}'.format(self.split, str(len(self.videos))))
271
+
272
+ if self.is_train:
273
+ self.transform = AllAugmentationTransform(**augmentation_params)
274
+ else:
275
+ self.transform = None
276
+
277
+ def get_video_items(self, all_video_frames_paths):
278
+ print('total video items length is {}'.format(len(all_video_frames_paths)))
279
+ video_items = []
280
+ cur_lengh = 0
281
+ init_start_time = time.time()
282
+
283
+ for video_frames_path in tqdm(all_video_frames_paths):
284
+ video_items.append(self.construct_Video_Info(video_frames_path))
285
+ if len(video_items) - cur_lengh > 5000:
286
+ init_end_time = time.time()
287
+
288
+ print(len(video_items))
289
+ print('Cost {} seconds'.format(str(init_end_time - init_start_time)))
290
+ cur_lengh = len(video_items)
291
+ init_start_time = init_end_time
292
+ return video_items
293
+
294
+ def get_used_frames_paths(self):
295
+
296
+
297
+ video_frames_dir = os.path.join(self.root_dir, 'frames_256')
298
+ video_names = sorted(os.listdir(video_frames_dir))
299
+ length = len(video_names)
300
+ used_video_names = video_names[:int(0.9 * length)] if self.is_train else video_names[int(0.9 * length):]
301
+
302
+ used_frames_paths = [os.path.join(video_frames_dir, video_name) for video_name in used_video_names]
303
+
304
+ return used_frames_paths
305
+
306
+ def construct_Video_Info(self, cur_frames_path):
307
+ info = {}
308
+
309
+ cor_mfcc_path = cur_frames_path.replace('frames_256', 'atvg_audio_feature') + '.pkl'
310
+ with open(cor_mfcc_path, 'rb') as fp:
311
+ info['mfccs'] = pickle.load(fp) # N,28,12 ATVG / N,80,16,wav2lip
312
+
313
+ # cor_pose_path = cur_frames_path.replace('frames_256', '3dmm_256')
314
+ cor_pose_path = cur_frames_path.replace('frames_256', 'pose_3DDFA_256')
315
+ cur_video_pose = []
316
+ for pose_name in sorted(os.listdir(cor_pose_path)):
317
+ frame_pose_path = os.path.join(cor_pose_path, pose_name)
318
+ cur_pose_data = None
319
+ if frame_pose_path.endswith('npy'):
320
+ cur_pose_data = np.load(frame_pose_path)
321
+ elif frame_pose_path.endswith('mat'):
322
+ file_mat = loadmat(frame_pose_path)
323
+ coeff_3dmm = file_mat['coeff']
324
+ angles = coeff_3dmm[:, 224:227] # euler angles for pose
325
+ translation = coeff_3dmm[:, 254:257] # translation
326
+ cur_pose_data = np.concatenate([angles, translation], 1)
327
+
328
+ cur_video_pose.append(cur_pose_data)
329
+ cur_video_pose_array = np.concatenate(cur_video_pose, axis=0) # N,7
330
+ info['poses'] = cur_video_pose_array
331
+
332
+ frames = []
333
+ for frame_name in sorted(os.listdir(cur_frames_path)):
334
+ cur_frame_path = os.path.join(cur_frames_path, frame_name)
335
+ # frames.append(img_as_float32(io.imread(cur_frame_path)))
336
+ frames.append(cur_frame_path)
337
+ info['frames'] = frames
338
+
339
+ return info
340
+
341
+ def __len__(self):
342
+ return len(self.videos)
343
+
344
+ def __getitem__(self, idx):
345
+
346
+ video_info = self.videos[idx]
347
+ # mfcc loading
348
+ r = random.choice([x for x in range(3, 8)])
349
+
350
+ example_image = video_info['frames'][r]
351
+
352
+ mfccs = video_info['mfccs'][r:r + 16]
353
+
354
+ poses = []
355
+ video_array = []
356
+ for ind in range(1, 17):
357
+ t_pose = video_info['poses'][r + ind, :6]
358
+ poses.append(t_pose)
359
+
360
+ image = video_info['frames'][r + ind]
361
+ image_data = img_as_float32(io.imread(image))
362
+ video_array.append(image_data)
363
+ poses = np.array(poses)
364
+ video_array = np.array(video_array)
365
+
366
+ # if self.transform is not None:
367
+ # video_array = self.transform(video_array)
368
+
369
+ out = {}
370
+
371
+ driving = np.array(video_array, dtype='float32')
372
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
373
+ driving_pose = np.array(poses, dtype='float32')
374
+
375
+ example_image_data = img_as_float32(io.imread(example_image))
376
+ example_image = np.array(example_image_data, dtype='float32')
377
+
378
+ out['example_image'] = example_image.transpose((2, 0, 1))
379
+ out['driving_pose'] = driving_pose
380
+ out['driving'] = driving.transpose((0, 3, 1, 2))
381
+ # out['driving_audio'] = np.array(mfccs, dtype='float32')
382
+ # out['driving_audio'] = np.array(mfccs, dtype='float32')
383
+ out['driving_audio'] = mfccs
384
+ # out['name'] = video_name
385
+ out['transformed_driving'] = out['driving']
386
+
387
+ return out
388
+
389
+ class VoxDataset(Dataset):
390
+ """
391
+ Dataset of videos, each video can be represented as:
392
+ - an image of concatenated frames
393
+ - '.mp4' or '.gif'
394
+ - folder with all frames
395
+ """
396
+
397
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
398
+ random_seed=0, pairs_list=None, augmentation_params=None):
399
+ self.root_dir = root_dir
400
+ self.audio_dir = os.path.join(root_dir,'MFCC')
401
+ self.image_dir = os.path.join(root_dir,'align_img')
402
+
403
+ self.pose_dir = os.path.join(root_dir,'align_pose')
404
+ # assert len(os.listdir(self.audio_dir)) == len(os.listdir(self.image_dir)), 'audio and image length not equal'
405
+
406
+
407
+ self.frame_shape = tuple(frame_shape)
408
+ self.pairs_list = pairs_list
409
+ self.id_sampling = id_sampling
410
+
411
+ if os.path.exists(os.path.join(self.pose_dir, 'train_fo')):
412
+ assert os.path.exists(os.path.join(self.pose_dir, 'test_fo'))
413
+ print("Use predefined train-test split.")
414
+ if id_sampling:
415
+ train_videos = {os.path.basename(video).split('#')[0] for video in
416
+ os.listdir(os.path.join(self.image_dir, 'train'))}
417
+ train_videos = list(train_videos)
418
+ else:
419
+ train_videos = np.load('/mnt/lustre/share_data/jixinya/VoxCeleb1_Cut/right.npy')# get_list(self.pose_dir, 'train_fo')
420
+
421
+ self.image_dir = os.path.join(self.image_dir, 'train_fo' if is_train else 'test_fo')
422
+ self.audio_dir = os.path.join(self.audio_dir, 'train' if is_train else 'test')
423
+ self.pose_dir = os.path.join(self.pose_dir, 'train_fo' if is_train else 'test_fo')
424
+ else:
425
+ print("Use random train-test split.")
426
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
427
+
428
+ if is_train:
429
+ self.videos = train_videos
430
+ else:
431
+ self.videos = test_videos
432
+
433
+ self.is_train = is_train
434
+
435
+ if self.is_train:
436
+ self.transform = AllAugmentationTransform(**augmentation_params)
437
+ else:
438
+ self.transform = None
439
+
440
+ def __len__(self):
441
+ return len(self.videos)
442
+
443
+ def __getitem__(self, idx):
444
+ if self.is_train and self.id_sampling:
445
+ name = self.videos[idx].split('.')[0]
446
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
447
+ else:
448
+ name = self.videos[idx].split('.')[0]
449
+
450
+ audio_path = os.path.join(self.audio_dir, name+'.npy')
451
+ pose_path = os.path.join(self.pose_dir,name+'.npy')
452
+ path = os.path.join(self.image_dir, name)
453
+
454
+ video_name = os.path.basename(path)
455
+
456
+ if os.path.isdir(path):
457
+ # if self.is_train and os.path.isdir(path):
458
+ frames = os.listdir(path)
459
+ num_frames = len(frames)
460
+ frame_idx = np.sort(np.random.choice(num_frames, replace=True, size=2))
461
+ video_array = [img_as_float32(io.imread(os.path.join(path, frames[idx]))) for idx in frame_idx]
462
+ mfcc = np.load(audio_path)
463
+ pose = np.load(pose_path)
464
+
465
+ # print(audio_path,pose_path,len(mfcc))
466
+
467
+ try:
468
+ len(mfcc) > 16
469
+ except:
470
+ print('wrongmfcc len:',audio_path)
471
+ if 16 < len(mfcc) < 24 :
472
+ r = 0
473
+ else:
474
+
475
+ r = random.choice([x for x in range(3, len(mfcc)-20)])
476
+
477
+ mfccs = []
478
+ poses = []
479
+ video_array = []
480
+ for ind in range(1, 17):
481
+ t_mfcc = mfcc[r+ind][:, 1:]
482
+ mfccs.append(t_mfcc)
483
+ t_pose = pose[r+ind,:-1]
484
+ poses.append(t_pose)
485
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
486
+ video_array.append(image)
487
+ mfccs = np.array(mfccs)
488
+ poses = np.array(poses)
489
+ video_array = np.array(video_array)
490
+
491
+ example_image = img_as_float32(io.imread(os.path.join(path, str(r)+'.png')))
492
+
493
+
494
+ else:
495
+ print('Wrong, data path not an existing file.')
496
+
497
+ if self.transform is not None:
498
+ video_array = self.transform(video_array)
499
+
500
+ out = {}
501
+
502
+ driving = np.array(video_array, dtype='float32')
503
+
504
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
505
+ driving_pose = np.array(poses, dtype='float32')
506
+ example_image = np.array(example_image, dtype='float32')
507
+ out['example_image'] = example_image.transpose((2, 0, 1))
508
+ out['driving_pose'] = driving_pose
509
+ out['driving'] = driving.transpose((0, 3, 1, 2))
510
+
511
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
512
+ # out['name'] = video_name
513
+
514
+ return out
515
+
516
+ class MeadDataset(Dataset):
517
+ """
518
+ Dataset of videos, each video can be represented as:
519
+ - an image of concatenated frames
520
+ - '.mp4' or '.gif'
521
+ - folder with all frames
522
+ """
523
+
524
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
525
+ random_seed=0, augmentation_params=None):
526
+ self.root_dir = root_dir
527
+
528
+ self.audio_dir = os.path.join(root_dir,'MEAD_MFCC')
529
+ self.image_dir = os.path.join(root_dir,'MEAD_fomm_crop')
530
+
531
+ self.pose_dir = os.path.join(root_dir,'MEAD_fomm_pose_crop')
532
+
533
+ self.videos = np.load('/mnt/lustre/share_data/jixinya/MEAD/MEAD_fomm_audio_less_crop.npy')
534
+ self.dict = np.load('/mnt/lustre/share_data/jixinya/MEAD/MEAD_fomm_neu_dic_crop.npy',allow_pickle=True).item()
535
+ # self.videos = os.listdir(root_dir)
536
+ self.frame_shape = tuple(frame_shape)
537
+
538
+ self.id_sampling = id_sampling
539
+ if os.path.exists(os.path.join(root_dir, 'train')):
540
+ assert os.path.exists(os.path.join(root_dir, 'test'))
541
+ print("Use predefined train-test split.")
542
+ if id_sampling:
543
+ train_videos = {os.path.basename(video).split('#')[0] for video in
544
+ os.listdir(os.path.join(root_dir, 'train'))}
545
+ train_videos = list(train_videos)
546
+ else:
547
+ train_videos = os.listdir(os.path.join(root_dir, 'train'))
548
+ test_videos = os.listdir(os.path.join(root_dir, 'test'))
549
+ self.root_dir = os.path.join(self.root_dir, 'train' if is_train else 'test')
550
+ else:
551
+ print("Use random train-test split.")
552
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
553
+
554
+ if is_train:
555
+ self.videos = train_videos
556
+ else:
557
+ self.videos = test_videos
558
+
559
+ self.is_train = is_train
560
+
561
+ if self.is_train:
562
+ self.transform = AllAugmentationTransform(**augmentation_params)
563
+ else:
564
+ self.transform = None
565
+
566
+ def __len__(self):
567
+ return len(self.videos)
568
+
569
+ def __getitem__(self, idx):
570
+ if self.is_train and self.id_sampling:
571
+ name = self.videos[idx]
572
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
573
+ else:
574
+ name = self.videos[idx]
575
+ path = os.path.join(self.image_dir, name)
576
+
577
+ video_name = os.path.basename(path)
578
+ id_name = path.split('/')[-2]
579
+ neu_list = self.dict[id_name]
580
+ neu_path = os.path.join(self.image_dir, np.random.choice(neu_list))
581
+
582
+ audio_path = os.path.join(self.audio_dir, name+'.npy')
583
+ pose_path = os.path.join(self.pose_dir,name+'.npy')
584
+
585
+
586
+ if self.is_train and os.path.isdir(path):
587
+
588
+ mfcc = np.load(audio_path)
589
+ pose_raw = np.load(pose_path)
590
+ one_euro_filter = OneEuroFilter(mincutoff=0.01, beta=0.7, dcutoff=1.0, freq=100)
591
+ pose = np.zeros((len(pose_raw),7))
592
+
593
+ for j in range(len(pose_raw)):
594
+ pose[j]=one_euro_filter.process(pose_raw[j])
595
+ # print(audio_path,pose_path,len(mfcc))
596
+
597
+ neu_frames = os.listdir(neu_path)
598
+ num_neu_frames = len(neu_frames)
599
+ frame_idx = np.random.choice(num_neu_frames)
600
+ example_image = img_as_float32(io.imread(os.path.join(neu_path, neu_frames[frame_idx])))
601
+ try:
602
+ len(mfcc) > 16
603
+ except:
604
+ print('wrongmfcc len:',audio_path)
605
+ if 16 < len(mfcc) < 24 :
606
+ r = 0
607
+ else:
608
+
609
+ r = random.choice([x for x in range(3, len(mfcc)-20)])
610
+
611
+ mfccs = []
612
+ poses = []
613
+ video_array = []
614
+ for ind in range(1, 17):
615
+ t_mfcc = mfcc[r+ind][:, 1:]
616
+ mfccs.append(t_mfcc)
617
+ t_pose = pose[r+ind,:-1]
618
+ poses.append(t_pose)
619
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
620
+ video_array.append(image)
621
+ mfccs = np.array(mfccs)
622
+ poses = np.array(poses)
623
+ video_array = np.array(video_array)
624
+
625
+ else:
626
+ print('Wrong, data path not an existing file.')
627
+
628
+ if self.transform is not None:
629
+ video_array = self.transform(video_array)
630
+
631
+ out = {}
632
+ if self.is_train:
633
+
634
+ driving = np.array(video_array, dtype='float32')
635
+ driving_pose = np.array(poses, dtype='float32')
636
+ example_image = np.array(example_image, dtype='float32')
637
+
638
+
639
+ out['example_image'] = example_image.transpose((2, 0, 1))
640
+ out['driving_pose'] = driving_pose
641
+ out['driving'] = driving.transpose((0, 3, 1, 2))
642
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
643
+
644
+ # out['name'] = id_name+'/'+video_name
645
+
646
+ return out
647
+
648
+
649
+ class DatasetRepeater(Dataset):
650
+ """
651
+ Pass several times over the same dataset for better i/o performance
652
+ """
653
+
654
+ def __init__(self, dataset, num_repeats=100):
655
+ self.dataset = dataset
656
+ # self.dataset2 = dataset2
657
+ self.num_repeats = num_repeats
658
+
659
+ def __len__(self):
660
+ return self.num_repeats * self.dataset.__len__()
661
+
662
+ def __getitem__(self, idx):
663
+ # if idx % 5 == 0:
664
+ # return self.dataset2[idx % self.dataset2.__len__()]#% self.dataset.__len__()
665
+ # else:
666
+ # return self.dataset[idx % self.dataset.__len__()]
667
+ return self.dataset[idx % self.dataset.__len__()]
668
+
669
+ class TestsetRepeater(Dataset):
670
+ """
671
+ Pass several times over the same dataset for better i/o performance
672
+ """
673
+
674
+ def __init__(self, dataset, num_repeats=100):
675
+ self.dataset = dataset
676
+
677
+ self.num_repeats = num_repeats
678
+
679
+ def __len__(self):
680
+ return self.num_repeats * self.dataset.__len__()
681
+
682
+ def __getitem__(self, idx):
683
+
684
+ return self.dataset[idx % self.dataset.__len__()]#% self.dataset.__len__()
685
+
686
+
687
+ class PairedDataset(Dataset):
688
+ """
689
+ Dataset of pairs for animation.
690
+ """
691
+
692
+ def __init__(self, initial_dataset, number_of_pairs, seed=0):
693
+ self.initial_dataset = initial_dataset
694
+ pairs_list = self.initial_dataset.pairs_list
695
+
696
+ np.random.seed(seed)
697
+
698
+ if pairs_list is None:
699
+ max_idx = min(number_of_pairs, len(initial_dataset))
700
+ nx, ny = max_idx, max_idx
701
+ xy = np.mgrid[:nx, :ny].reshape(2, -1).T
702
+ number_of_pairs = min(xy.shape[0], number_of_pairs)
703
+ self.pairs = xy.take(np.random.choice(xy.shape[0], number_of_pairs, replace=False), axis=0)
704
+ else:
705
+ videos = self.initial_dataset.videos
706
+ name_to_index = {name: index for index, name in enumerate(videos)}
707
+ pairs = pd.read_csv(pairs_list)
708
+ pairs = pairs[np.logical_and(pairs['source'].isin(videos), pairs['driving'].isin(videos))]
709
+
710
+ number_of_pairs = min(pairs.shape[0], number_of_pairs)
711
+ self.pairs = []
712
+ self.start_frames = []
713
+ for ind in range(number_of_pairs):
714
+ self.pairs.append(
715
+ (name_to_index[pairs['driving'].iloc[ind]], name_to_index[pairs['source'].iloc[ind]]))
716
+
717
+ def __len__(self):
718
+ return len(self.pairs)
719
+
720
+ def __getitem__(self, idx):
721
+ pair = self.pairs[idx]
722
+ first = self.initial_dataset[pair[0]]
723
+ second = self.initial_dataset[pair[1]]
724
+ first = {'driving_' + key: value for key, value in first.items()}
725
+ second = {'source_' + key: value for key, value in second.items()}
726
+
727
+ return {**first, **second}
FONT/gradio_demo.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib
2
+ matplotlib.use('Agg')
3
+ import os,sys
4
+ import yaml
5
+ from argparse import ArgumentParser
6
+ from tqdm import tqdm
7
+ from skimage import io, img_as_float32
8
+ import imageio
9
+ import numpy as np
10
+ from skimage.transform import resize
11
+ from skimage import img_as_ubyte
12
+ import torch
13
+ from FONT.filter1 import OneEuroFilter
14
+ import torch.utils
15
+
16
+ from torch.autograd import Variable
17
+ from FONT.modules.generator import OcclusionAwareGenerator
18
+ from FONT.modules.keypoint_detector import KPDetector, KPDetector_a
19
+ from FONT.modules.util import AT_net, Emotion_k, Emotion_map, AT_net2
20
+ from . import augmentation
21
+
22
+ from scipy.spatial import ConvexHull
23
+ import random
24
+ import python_speech_features
25
+ from pathlib import Path
26
+ import dlib
27
+ import cv2
28
+ from skimage.draw import circle
29
+ import matplotlib.pyplot as plt
30
+ import librosa
31
+ from skimage import transform as tf
32
+ import torch.nn.functional as F
33
+
34
+ detector = dlib.get_frontal_face_detector()
35
+ predictor = dlib.shape_predictor('./FONT/ckpt/shape_predictor_68_face_landmarks.dat')
36
+
37
+
38
+
39
+ class FONT():
40
+
41
+ def __init__(self, checkpoint_path='./FONT/ckpt', config_path='./FONT/config/MEAD_emo_video_aug_delta_4_crop_random_crop.yaml'):
42
+
43
+ if torch.cuda.is_available():
44
+ device = "cuda"
45
+ else:
46
+ device = "cpu"
47
+
48
+ self.device = device
49
+
50
+ os.environ['TORCH_HOME'] = checkpoint_path
51
+
52
+ self.checkpoint_path = checkpoint_path
53
+ self.config_path = config_path
54
+ self.result_path = './results'
55
+
56
+ def load_checkpoints(self, checkpoint_path, audio_checkpoint_path, emo_checkpoint_path, kp_checkpoint_path):
57
+
58
+ with open(self.config_path) as f:
59
+ config = yaml.load(f, Loader=yaml.FullLoader)
60
+
61
+ generator = OcclusionAwareGenerator(**config['model_params']['generator_params'],
62
+ **config['model_params']['common_params'])
63
+
64
+ generator.to(self.device)
65
+
66
+ kp_detector = KPDetector(**config['model_params']['kp_detector_params'],
67
+ **config['model_params']['common_params'])
68
+
69
+ kp_detector.to(self.device)
70
+
71
+ kp_detector_a = KPDetector_a(**config['model_params']['kp_detector_params'],
72
+ **config['model_params']['audio_params'])
73
+
74
+ audio_feature = AT_net2()
75
+
76
+ emo_detector = Emotion_k(block_expansion=32, num_channels=3, max_features=1024,
77
+ num_blocks=5, scale_factor=0.25, num_classes=8)
78
+
79
+
80
+ kp_detector_a.to(self.device)
81
+ audio_feature.to(self.device)
82
+ emo_detector.to(self.device)
83
+
84
+ if self.device == 'cpu':
85
+ checkpoint = torch.load(checkpoint_path, map_location=torch.device('cpu'))
86
+ audio_checkpoint = torch.load(audio_checkpoint_path, map_location=torch.device('cpu'))
87
+ emo_checkpoint = torch.load(emo_checkpoint_path, map_location=torch.device('cpu'))
88
+ kp_checkpoint = torch.load(kp_checkpoint_path, map_location=torch.device('cpu'))
89
+ else:
90
+ checkpoint = torch.load(checkpoint_path)
91
+ audio_checkpoint = torch.load(audio_checkpoint_path)
92
+ emo_checkpoint = torch.load(emo_checkpoint_path)
93
+ kp_checkpoint = torch.load(kp_checkpoint_path)
94
+
95
+ generator.load_state_dict(checkpoint['generator'])
96
+ kp_detector.load_state_dict(kp_checkpoint['kp_detector'])
97
+ audio_feature.load_state_dict(audio_checkpoint['audio_feature'], strict=False)
98
+
99
+ kp_detector_a.load_state_dict(audio_checkpoint['kp_detector_a'])
100
+ emo_detector.load_state_dict(emo_checkpoint['emo_detector'])
101
+
102
+
103
+ generator.eval()
104
+ kp_detector.eval()
105
+ audio_feature.eval()
106
+ kp_detector_a.eval()
107
+ emo_detector.eval()
108
+ return generator, kp_detector, kp_detector_a, audio_feature, emo_detector
109
+
110
+ def normalize_kp(self, kp_source, kp_driving, kp_driving_initial, adapt_movement_scale=False,
111
+ use_relative_movement=False, use_relative_jacobian=False):
112
+ if adapt_movement_scale:
113
+ source_area = ConvexHull(kp_source['value'][0].data.cpu().numpy()).volume
114
+ driving_area = ConvexHull(kp_driving_initial['value'][0].data.cpu().numpy()).volume
115
+ adapt_movement_scale = np.sqrt(source_area) / np.sqrt(driving_area)
116
+ else:
117
+ adapt_movement_scale = 1
118
+
119
+ kp_new = {k: v for k, v in kp_driving.items()}
120
+
121
+ if use_relative_movement:
122
+ kp_value_diff = (kp_driving['value'] - kp_driving_initial['value'])
123
+ kp_value_diff *= adapt_movement_scale
124
+ kp_new['value'] = kp_value_diff + kp_source['value']
125
+
126
+ if use_relative_jacobian:
127
+ jacobian_diff = torch.matmul(kp_driving['jacobian'], torch.inverse(kp_driving_initial['jacobian']))
128
+ kp_new['jacobian'] = torch.matmul(jacobian_diff, kp_source['jacobian'])
129
+
130
+ return kp_new
131
+
132
+ def shape_to_np(self, shape, dtype="int"):
133
+ # initialize the list of (x, y)-coordinates
134
+ coords = np.zeros((shape.num_parts, 2), dtype=dtype)
135
+
136
+ # loop over all facial landmarks and convert them
137
+ # to a 2-tuple of (x, y)-coordinates
138
+ for i in range(0, shape.num_parts):
139
+ coords[i] = (shape.part(i).x, shape.part(i).y)
140
+
141
+ # return the list of (x, y)-coordinates
142
+ return coords
143
+
144
+ def get_aligned_image(self, driving_video):
145
+ aligned_array = []
146
+
147
+ video_array = np.array(driving_video)
148
+ source_image = video_array[0]
149
+ # aligned_array.append(source_image)
150
+ source_image = np.array(source_image * 255, dtype=np.uint8)
151
+ gray = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
152
+ rects = detector(gray, 1) # detect human face
153
+ for (i, rect) in enumerate(rects):
154
+ template = predictor(gray, rect) # detect 68 points
155
+ template = shape_to_np(template)
156
+
157
+ # if opt.emotion == 'surprised' or opt.emotion == 'fear':
158
+ # template = template - [0, 10]
159
+ for i in range(len(video_array)):
160
+ image = np.array(video_array[i] * 255, dtype=np.uint8)
161
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
162
+ rects = detector(gray, 1) # detect human face
163
+ for (j, rect) in enumerate(rects):
164
+ shape = predictor(gray, rect) # detect 68 points
165
+ shape = shape_to_np(shape)
166
+
167
+ pts2 = np.float32(template[:35, :])
168
+ pts1 = np.float32(shape[:35, :]) # eye and nose
169
+
170
+ # pts2 = np.float32(np.concatenate((template[:16,:],template[27:36,:]),axis = 0))
171
+ # pts1 = np.float32(np.concatenate((shape[:16,:],shape[27:36,:]),axis = 0)) #eye and nose
172
+ # pts1 = np.float32(landmark[17:35,:])
173
+ tform = tf.SimilarityTransform()
174
+ tform.estimate(pts2, pts1) # Set the transformation matrix with the explicit parameters.
175
+ dst = tf.warp(image, tform, output_shape=(256, 256))
176
+
177
+ dst = np.array(dst, dtype=np.float32)
178
+ aligned_array.append(dst)
179
+
180
+ return aligned_array
181
+
182
+ def get_transformed_image(self, driving_video):
183
+ video_array = np.array(driving_video)
184
+ with open(self.config_path) as f:
185
+ config = yaml.load(f, Loader=yaml.FullLoader)
186
+ transformations = AllAugmentationTransform(**config['dataset_params']['augmentation_params'])
187
+ transformed_array = transformations(video_array)
188
+ return transformed_array
189
+
190
+ def make_animation_smooth(self, source_image, deco_out, kp_loss, generator, kp_detector,
191
+ kp_detector_a, emo_detector, relative=True, adapt_movement_scale=True):
192
+ with torch.no_grad():
193
+ predictions = []
194
+
195
+ source = torch.tensor(source_image[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2)
196
+ if self.device == 'cuda':
197
+ source = source.cuda()
198
+
199
+
200
+ kp_source = kp_detector(source)
201
+
202
+ save_dpi = (100, 100)
203
+ # save kp source image
204
+ # source = kp_source['value'].data.cpu().numpy()
205
+ # kp_array = source[0]
206
+ # image = np.zeros((256,256,3))
207
+ # spatial_size = np.array(image.shape[:2][::-1])[np.newaxis]
208
+ # kp_array = spatial_size * (kp_array + 1) / 2
209
+ # num_kp = kp_array.shape[0]
210
+ colormap = plt.get_cmap('gist_rainbow')
211
+ # for kp_ind, kp in enumerate(kp_array):
212
+ # rr, cc = circle(kp[1], kp[0], 5, shape=image.shape[:2])
213
+ # image[rr, cc] = np.array(colormap(kp_ind / num_kp))[:3]
214
+ # imageio.imsave('./result/kp_source.png', image)
215
+
216
+ kp_driving_initial = kp_detector_a(deco_out[:, 0])
217
+
218
+ emo_driving_all = []
219
+ features = []
220
+ kp_driving_all = []
221
+ for frame_idx in tqdm(range(len(deco_out[0]))):
222
+
223
+
224
+ kp_driving = kp_detector_a(deco_out[:, frame_idx])
225
+ kp_driving_all.append(kp_driving)
226
+ # if opt.add_emo:
227
+ # value = kp_driving['value']
228
+ # jacobian = kp_driving['jacobian']
229
+ # if opt.type == 'linear_3':
230
+ # emo_driving, _ = emo_detector(transformed_frame, value, jacobian)
231
+ # features.append(emo_detector.feature(transformed_frame).data.cpu().numpy())
232
+ #
233
+ # emo_driving_all.append(emo_driving)
234
+ features = np.array(features)
235
+ # if opt.add_emo:
236
+ # one_euro_filter_v = OneEuroFilter(mincutoff=1, beta=0.2, dcutoff=1.0, freq=100) # 1 0.4
237
+ # one_euro_filter_j = OneEuroFilter(mincutoff=1, beta=0.2, dcutoff=1.0, freq=100) # 1 0.4
238
+ #
239
+ # for j in range(len(emo_driving_all)):
240
+ # emo_driving_all[j]['value'] = one_euro_filter_v.process(
241
+ # emo_driving_all[j]['value'].cpu() * 100) / 100
242
+ # emo_driving_all[j]['value'] = emo_driving_all[j]['value'].cuda()
243
+ # emo_driving_all[j]['jacobian'] = one_euro_filter_j.process(
244
+ # emo_driving_all[j]['jacobian'].cpu() * 100) / 100
245
+ # emo_driving_all[j]['jacobian'] = emo_driving_all[j]['jacobian'].cuda()
246
+
247
+ one_euro_filter_v = OneEuroFilter(mincutoff=0.05, beta=8, dcutoff=1.0, freq=100)
248
+ one_euro_filter_j = OneEuroFilter(mincutoff=0.05, beta=8, dcutoff=1.0, freq=100)
249
+
250
+ for j in range(len(kp_driving_all)):
251
+ kp_driving_all[j]['value'] = one_euro_filter_v.process(kp_driving_all[j]['value'].cpu() * 10) / 10
252
+ kp_driving_all[j]['value'] = kp_driving_all[j]['value'].cuda()
253
+ kp_driving_all[j]['jacobian'] = one_euro_filter_j.process(kp_driving_all[j]['jacobian'].cpu() * 10) / 10
254
+ kp_driving_all[j]['jacobian'] = kp_driving_all[j]['jacobian'].cuda()
255
+
256
+ for frame_idx in tqdm(range(len(deco_out[0]))):
257
+
258
+
259
+ kp_driving = kp_driving_all[frame_idx]
260
+
261
+ # kp_driving_real = kp_detector(driving_frame)
262
+
263
+ # kp_driving['value'] = (1-opt.weight)*kp_driving['value'] + opt.weight*kp_driving_real['value']
264
+ # kp_driving['jacobian'] = (1-opt.weight)*kp_driving['jacobian'] + opt.weight*kp_driving_real['jacobian']
265
+
266
+ # if opt.add_emo:
267
+ # emo_driving = emo_driving_all[frame_idx]
268
+ # if opt.type == 'linear_3':
269
+ # kp_driving['value'][:, 1] = kp_driving['value'][:, 1] + emo_driving['value'][:, 0] * 0.2
270
+ # kp_driving['jacobian'][:, 1] = kp_driving['jacobian'][:, 1] + emo_driving['jacobian'][:,
271
+ # 0] * 0.2
272
+ # kp_driving['value'][:, 4] = kp_driving['value'][:, 4] + emo_driving['value'][:, 1]
273
+ # kp_driving['jacobian'][:, 4] = kp_driving['jacobian'][:, 4] + emo_driving['jacobian'][:, 1]
274
+ # kp_driving['value'][:, 6] = kp_driving['value'][:, 6] + emo_driving['value'][:, 2]
275
+ # kp_driving['jacobian'][:, 6] = kp_driving['jacobian'][:, 6] + emo_driving['jacobian'][:, 2]
276
+ # # kp_driving['value'][:,8] = kp_driving['value'][:,8] + emo_driving['value'][:,3]
277
+ # # kp_driving['jacobian'][:,8] = kp_driving['jacobian'][:,8] + emo_driving['jacobian'][:,3]
278
+
279
+ kp_norm = self.normalize_kp(kp_source=kp_source, kp_driving=kp_driving,
280
+ kp_driving_initial=kp_driving_initial, use_relative_movement=relative,
281
+ use_relative_jacobian=relative, adapt_movement_scale=adapt_movement_scale)
282
+ out = generator(source, kp_source=kp_source, kp_driving=kp_norm)
283
+
284
+ # occlusion_map = out['occlusion_map'].data.cpu().repeat(1, 3, 1, 1)
285
+ # occlusion_map = F.interpolate(occlusion_map, size=(256,256)).numpy()
286
+ # occlusion_map = np.transpose(occlusion_map, [0, 2, 3, 1])
287
+ # print(occlusion_map.shape)
288
+ # imageio.imsave('./result/occlusion.png', occlusion_map[0], dpi=save_dpi)
289
+ #
290
+ # prediction = out['prediction'].data.cpu().numpy()
291
+ # prediction = np.transpose(prediction, [0, 2, 3, 1])
292
+ # print(prediction.shape)
293
+ # imageio.imsave('./result/prediction.png', prediction[0], dpi=save_dpi)
294
+ #
295
+ # full_mask = []
296
+ # for i in range(out['sparse_deformed'].shape[1]):
297
+ # mask = out['mask'][:, i:(i + 1)].data.cpu().repeat(1, 3, 1, 1)
298
+ # mask = F.interpolate(mask, size=(256,256))
299
+ # mask = np.transpose(mask.numpy(), (0, 2, 3, 1))
300
+ # if i != 0:
301
+ # color = np.array(colormap((i - 1) / (out['sparse_deformed'].shape[1] - 1)))[:3]
302
+ # else:
303
+ # color = np.array((0, 0, 0))
304
+ #
305
+ # color = color.reshape((1, 1, 1, 3))
306
+ #
307
+ # full_mask.append(mask * color)
308
+ # motion_flow = sum(full_mask)
309
+ # print(motion_flow.shape)
310
+ # imageio.imsave('./result/motion_flow.png', motion_flow[0], dpi=save_dpi)
311
+ # quit()
312
+
313
+ predictions.append(np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0])
314
+ return predictions, features
315
+
316
+ def test_auido(self, example_image, audio_feature, all_pose, driving_audio_path):
317
+ with open(self.config_path) as f:
318
+ para = yaml.load(f, Loader=yaml.FullLoader)
319
+
320
+ # encoder = audio_feature()
321
+
322
+ audio_feature = audio_feature.to(self.device)
323
+ audio_feature.eval()
324
+ # decoder.eval()
325
+ test_file = driving_audio_path
326
+ pose = all_pose[:, :6]
327
+
328
+ one_euro_filter = OneEuroFilter(mincutoff=0.004, beta=0.7, dcutoff=1.0, freq=100)
329
+
330
+ for j in range(len(pose)):
331
+ pose[j] = one_euro_filter.process(pose[j])
332
+ # pose[j]=pose[0]
333
+
334
+ example_image = np.array(example_image, dtype='float32').transpose((2, 0, 1))
335
+
336
+
337
+
338
+ # get atvg audio feature
339
+ speech, sr = librosa.load(test_file, sr=16000)
340
+ # mfcc = python_speech_features.mfcc(speech ,16000,winstep=0.01)
341
+ speech = np.insert(speech, 0, np.zeros(1920))
342
+ speech = np.append(speech, np.zeros(1920))
343
+ mfcc = python_speech_features.mfcc(speech, 16000, winstep=0.01)
344
+ ind = 3
345
+ fake_lmark = []
346
+ input_mfcc = []
347
+ while ind <= int(mfcc.shape[0] / 4) - 4:
348
+ t_mfcc = mfcc[(ind - 3) * 4: (ind + 4) * 4, 1:]
349
+ t_mfcc = torch.FloatTensor(t_mfcc).cuda()
350
+ input_mfcc.append(t_mfcc)
351
+ ind += 1
352
+ input_mfcc = torch.stack(input_mfcc, dim=0) # N,28,12
353
+
354
+ print('=======================================')
355
+ print('Start to generate images')
356
+
357
+ with torch.no_grad():
358
+ if (len(pose) < len(input_mfcc)):
359
+ gap = len(input_mfcc) - len(pose)
360
+ n = int((gap / len(pose) / 2)) + 2
361
+ pose = np.concatenate((pose, pose[::-1, :]), axis=0)
362
+ pose = np.tile(pose, (n, 1))
363
+ if (len(pose) > len(input_mfcc)):
364
+ pose = pose[:len(input_mfcc), :]
365
+
366
+ pose = Variable(torch.FloatTensor(pose.astype(float)))
367
+ example_image = Variable(torch.FloatTensor(example_image.astype(float)))
368
+
369
+ if self.device == 'cuda':
370
+ pose = pose.cuda()
371
+ example_image = example_image.cuda()
372
+ input_mfcc = input_mfcc.cuda()
373
+
374
+ pose = pose.unsqueeze(0)
375
+ example_image = example_image.unsqueeze(0)
376
+ input_mfcc = input_mfcc.unsqueeze(0)
377
+
378
+ deco_out = audio_feature(example_image, input_mfcc, pose, para['train_params']['jaco_net'], 1.6)
379
+
380
+ # ATNET
381
+ # deco_out = audio_feature(example_image, input_mfcc, pose, para['train_params']['jaco_net'])
382
+
383
+ return deco_out
384
+
385
+ def save(self, path, frames, format):
386
+
387
+ if format == '.png':
388
+ if not os.path.exists(path):
389
+ os.makedirs(path)
390
+ for j, frame in enumerate(frames):
391
+ imageio.imsave(path + '/' + str(j) + '.png', frame)
392
+ # imageio.imsave(os.path.join(path, str(j) + '.png'), frames[j])
393
+ else:
394
+ print("Unknown format %s" % format)
395
+ exit()
396
+
397
+ class VideoWriter(object):
398
+ def __init__(self, path, width, height, fps):
399
+ fourcc = cv2.VideoWriter_fourcc(*'XVID')
400
+ self.path = path
401
+ self.out = cv2.VideoWriter(self.path, fourcc, fps, (width, height))
402
+
403
+ def write_frame(self, frame):
404
+ self.out.write(frame)
405
+
406
+ def end(self):
407
+ self.out.release()
408
+
409
+ def get_pose_from_audio(self, driving_audio):
410
+ pose = './FONT/test/pose/7.npy'
411
+ pose_long = './FONT/test/pose_long/0zn70Ak8lRc_Daniel_Auteuil_0zn70Ak8lRc_0002.npy'
412
+ return pose, pose_long
413
+
414
+ def concatenate(self, number, imgs, save_path):
415
+ width, height = imgs.shape[-3:-1]
416
+ imgs = imgs.reshape(number, -1, width, height, 3)
417
+ if number == 2:
418
+ left = imgs[0]
419
+ right = imgs[1]
420
+
421
+ im_all = []
422
+ for i in range(len(left)):
423
+ im = np.concatenate((left[i], right[i]), axis=1)
424
+ im_all.append(im)
425
+ if number == 3:
426
+ left = imgs[0]
427
+ middle = imgs[1]
428
+ right = imgs[2]
429
+
430
+ im_all = []
431
+ for i in range(len(left)):
432
+ im = np.concatenate((left[i], middle[i], right[i]), axis=1)
433
+ im_all.append(im)
434
+ if number == 4:
435
+ left = imgs[0]
436
+ left2 = imgs[1]
437
+ right = imgs[2]
438
+ right2 = imgs[3]
439
+
440
+ im_all = []
441
+ for i in range(len(left)):
442
+ im = np.concatenate((left[i], left2[i], right[i], right2[i]), axis=1)
443
+ im_all.append(im)
444
+ if number == 5:
445
+ left = imgs[0]
446
+ left2 = imgs[1]
447
+ middle = imgs[2]
448
+ right = imgs[3]
449
+ right2 = imgs[4]
450
+
451
+ im_all = []
452
+ for i in range(len(left)):
453
+ im = np.concatenate((left[i], left2[i], middle[i], right[i], right2[i]), axis=1)
454
+ im_all.append(im)
455
+
456
+ imageio.mimsave(save_path, [img_as_ubyte(frame) for frame in im_all], fps=25)
457
+
458
+ def add_audio(self, video_name=None, audio_dir=None):
459
+
460
+ command = 'ffmpeg -i ' + video_name + ' -i ' + audio_dir + ' -vcodec copy -acodec copy -y ' + video_name.replace(
461
+ '.mp4', '.mov')
462
+ print(command)
463
+ os.system(command)
464
+
465
+ def smooth_pose(self, pose_file, pose_long):
466
+ start = np.load(pose_file)
467
+ video_pose = np.load(pose_long)
468
+ if video_pose.shape[-1] == 6:
469
+ start = start[:, :6]
470
+
471
+ delta = video_pose - video_pose[0, :]
472
+ # print(len(delta))
473
+
474
+ pose = np.repeat(start, len(delta), axis=0)
475
+ all_pose = pose + delta
476
+
477
+ return all_pose
478
+
479
+
480
+
481
+ def test(self, source_image_path, driving_audio_path, result_dir='./results/'):
482
+
483
+ pose_file, pose_given = self.get_pose_from_audio(driving_audio_path)
484
+
485
+
486
+ pose_dim = np.load(pose_file).shape[-1]
487
+ all_pose = np.load(pose_file).reshape(-1, pose_dim)
488
+ all_pose = self.smooth_pose(pose_file, pose_given)
489
+
490
+ source_image = img_as_float32(io.imread(source_image_path))
491
+ source_image = resize(source_image, (256, 256))[..., :3]
492
+
493
+ # reader = imageio.get_reader(driving_video)
494
+ # fps = reader.get_meta_data()['fps']
495
+ # driving_video = []
496
+ # try:
497
+ # for im in reader:
498
+ # driving_video.append(im)
499
+ # except RuntimeError:
500
+ # pass
501
+ # reader.close()
502
+
503
+ # driving_video = [resize(frame, (256, 256))[..., :3] for frame in driving_video]
504
+ # driving_video = self.get_aligned_image(driving_video)
505
+ # transformed_video = self.get_transformed_image(driving_video)
506
+ # transformed_video = np.array(transformed_video)
507
+
508
+ checkpoint = os.path.join(self.checkpoint_path, "124_52000.pth.tar")
509
+ audio_checkpoint = os.path.join(self.checkpoint_path, "1-6000.pth.tar")
510
+ emo_checkpoint = os.path.join(self.checkpoint_path, "5-3000.pth.tar")
511
+
512
+ generator, kp_detector, kp_detector_a, audio_feature, emo_detector = \
513
+ self.load_checkpoints(checkpoint_path=checkpoint, audio_checkpoint_path=audio_checkpoint,
514
+ emo_checkpoint_path=emo_checkpoint, kp_checkpoint_path=checkpoint)
515
+
516
+ deco_out = self.test_auido(source_image, audio_feature, all_pose, driving_audio_path) # 1,N,32+3,64,64
517
+
518
+ # if len(driving_video) < len(deco_out[0]):
519
+ # driving_video = np.resize(driving_video, (len(deco_out[0]), 256, 256, 3))
520
+ # transformed_video = np.resize(transformed_video, (len(deco_out[0]), 256, 256, 3))
521
+ #
522
+ # else:
523
+ # driving_video = driving_video[:len(deco_out[0])]
524
+ predictions, _ = self.make_animation_smooth(source_image, deco_out, 0,
525
+ generator, kp_detector, kp_detector_a, emo_detector)
526
+
527
+ imageio.mimsave(os.path.join(self.result_path, 'neutral.mp4'), [img_as_ubyte(frame) for frame in predictions],
528
+ fps=30)
529
+ predictions = np.array(predictions)
530
+
531
+ # opt.add_emo = True
532
+ # predictions1, _ = make_animation_smooth(source_image, driving_video, transformed_video, deco_out, opt.kp_loss,
533
+ # generator, kp_detector, kp_detector_a, emo_detector, opt,
534
+ # relative=opt.relative, adapt_movement_scale=opt.adapt_scale,
535
+ # cpu=opt.cpu)
536
+
537
+ # imageio.mimsave(os.path.join(self.result_path, 'emotion.mp4'), [img_as_ubyte(frame) for frame in predictions1],
538
+ # fps=fps)
539
+ # add_audio(os.path.join(self.result_path, 'emotion.mp4'), opt.in_file)
540
+ # predictions1 = np.array(predictions1)
541
+ # all_imgs = np.concatenate((driving_video, predictions, predictions1), axis=0)
542
+ save_path = os.path.join(self.result_path, 'neutral.mp4')
543
+ # concatenate(3, all_imgs, save_path)
544
+ self.add_audio(save_path, driving_audio_path)
545
+
546
+
547
+
548
+ # del self.preprocess_model
549
+ # del self.audio_to_coeff
550
+ # del self.animate_from_coeff
551
+
552
+ if torch.cuda.is_available():
553
+ torch.cuda.empty_cache()
554
+ torch.cuda.synchronize()
555
+
556
+ import gc;
557
+ gc.collect()
558
+
559
+ return save_path
560
+
FONT/hparams.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from glob import glob
2
+ import os
3
+
4
+ def get_image_list(data_root, split):
5
+ filelist = []
6
+
7
+ with open('filelists/{}.txt'.format(split)) as f:
8
+ for line in f:
9
+ line = line.strip()
10
+ if ' ' in line: line = line.split()[0]
11
+ filelist.append(os.path.join(data_root, line))
12
+
13
+ return filelist
14
+
15
+ class HParams:
16
+ def __init__(self, **kwargs):
17
+ self.data = {}
18
+
19
+ for key, value in kwargs.items():
20
+ self.data[key] = value
21
+
22
+ def __getattr__(self, key):
23
+ if key not in self.data:
24
+ raise AttributeError("'HParams' object has no attribute %s" % key)
25
+ return self.data[key]
26
+
27
+ def set_hparam(self, key, value):
28
+ self.data[key] = value
29
+
30
+
31
+ # Default hyperparameters
32
+ hparams = HParams(
33
+ num_mels=80, # Number of mel-spectrogram channels and local conditioning dimensionality
34
+ # network
35
+ rescale=True, # Whether to rescale audio prior to preprocessing
36
+ rescaling_max=0.9, # Rescaling value
37
+
38
+ # Use LWS (https://github.com/Jonathan-LeRoux/lws) for STFT and phase reconstruction
39
+ # It"s preferred to set True to use with https://github.com/r9y9/wavenet_vocoder
40
+ # Does not work if n_ffit is not multiple of hop_size!!
41
+ use_lws=False,
42
+
43
+ n_fft=800, # Extra window size is filled with 0 paddings to match this parameter
44
+ hop_size=200, # For 16000Hz, 200 = 12.5 ms (0.0125 * sample_rate)
45
+ win_size=800, # For 16000Hz, 800 = 50 ms (If None, win_size = n_fft) (0.05 * sample_rate)
46
+ sample_rate=16000, # 16000Hz (corresponding to librispeech) (sox --i <filename>)
47
+
48
+ frame_shift_ms=None, # Can replace hop_size parameter. (Recommended: 12.5)
49
+
50
+ # Mel and Linear spectrograms normalization/scaling and clipping
51
+ signal_normalization=True,
52
+ # Whether to normalize mel spectrograms to some predefined range (following below parameters)
53
+ allow_clipping_in_normalization=True, # Only relevant if mel_normalization = True
54
+ symmetric_mels=True,
55
+ # Whether to scale the data to be symmetric around 0. (Also multiplies the output range by 2,
56
+ # faster and cleaner convergence)
57
+ max_abs_value=4.,
58
+ # max absolute value of data. If symmetric, data will be [-max, max] else [0, max] (Must not
59
+ # be too big to avoid gradient explosion,
60
+ # not too small for fast convergence)
61
+ # Contribution by @begeekmyfriend
62
+ # Spectrogram Pre-Emphasis (Lfilter: Reduce spectrogram noise and helps model certitude
63
+ # levels. Also allows for better G&L phase reconstruction)
64
+ preemphasize=True, # whether to apply filter
65
+ preemphasis=0.97, # filter coefficient.
66
+
67
+ # Limits
68
+ min_level_db=-100,
69
+ ref_level_db=20,
70
+ fmin=55,
71
+ # Set this to 55 if your speaker is male! if female, 95 should help taking off noise. (To
72
+ # test depending on dataset. Pitch info: male~[65, 260], female~[100, 525])
73
+ fmax=7600, # To be increased/reduced depending on data.
74
+
75
+ ###################### Our training parameters #################################
76
+ img_size=96,
77
+ fps=25,
78
+
79
+ batch_size=16,
80
+ initial_learning_rate=1e-4,
81
+ nepochs=200000000000000000, ### ctrl + c, stop whenever eval loss is consistently greater than train loss for ~10 epochs
82
+ num_workers=16,
83
+ checkpoint_interval=3000,
84
+ eval_interval=3000,
85
+ save_optimizer_state=True,
86
+
87
+ syncnet_wt=0.0, # is initially zero, will be set automatically to 0.03 later. Leads to faster convergence.
88
+ syncnet_batch_size=64,
89
+ syncnet_lr=1e-4,
90
+ syncnet_eval_interval=10000,
91
+ syncnet_checkpoint_interval=10000,
92
+
93
+ disc_wt=0.07,
94
+ disc_initial_learning_rate=1e-4,
95
+ )
96
+
97
+
98
+ def hparams_debug_string():
99
+ values = hparams.values()
100
+ hp = [" %s: %s" % (name, values[name]) for name in sorted(values) if name != "sentences"]
101
+ return "Hyperparameters:\n" + "\n".join(hp)
FONT/logger.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import torch.nn.functional as F
4
+ import imageio
5
+
6
+ import os
7
+ from skimage.draw import circle
8
+
9
+ import matplotlib.pyplot as plt
10
+ import collections
11
+
12
+
13
+ class Logger:
14
+ def __init__(self, log_dir, checkpoint_freq=50, visualizer_params=None, zfill_num=8, log_file_name='log.txt'):
15
+
16
+ self.loss_list = []
17
+ self.cpk_dir = log_dir
18
+ self.visualizations_dir = os.path.join(log_dir, 'train-vis')
19
+ if not os.path.exists(self.visualizations_dir):
20
+ os.makedirs(self.visualizations_dir)
21
+ self.log_file = open(os.path.join(log_dir, log_file_name), 'a')
22
+ self.zfill_num = zfill_num
23
+ self.visualizer = Visualizer(**visualizer_params)
24
+ self.checkpoint_freq = checkpoint_freq
25
+ self.epoch = 0
26
+ self.best_loss = float('inf')
27
+ self.names = None
28
+
29
+ def log_scores(self, loss_names):
30
+ loss_mean = np.array(self.loss_list).mean(axis=0)
31
+
32
+ loss_string = "; ".join(["%s - %.5f" % (name, value) for name, value in zip(loss_names, loss_mean)])
33
+ loss_string = str(str(self.epoch)+str(self.step).zfill(self.zfill_num)) + ") " + loss_string
34
+
35
+ print(loss_string, file=self.log_file)
36
+ self.loss_list = []
37
+ self.log_file.flush()
38
+
39
+ def visualize_rec(self, inp, out):
40
+ # image = self.visualizer.visualize(inp['driving'], inp['source'], out)
41
+ image = self.visualizer.visualize(inp['driving'][:,-1], inp['transformed_driving'][:,-1], inp['example_image'], out)
42
+ imageio.imsave(os.path.join(self.visualizations_dir, "%s-%s-rec.png" % (str(self.epoch),str(self.step).zfill(self.zfill_num))), image)
43
+
44
+ def save_cpk(self, emergent=False):
45
+ cpk = {k: v.state_dict() for k, v in self.models.items()}
46
+ cpk['epoch'] = self.epoch
47
+ cpk['step'] = self.step
48
+ cpk_path = os.path.join(self.cpk_dir, '%s-%s-checkpoint.pth.tar' % (str(self.epoch),str(self.step).zfill(self.zfill_num)))
49
+ if not (os.path.exists(cpk_path) and emergent):
50
+ torch.save(cpk, cpk_path)
51
+
52
+ @staticmethod
53
+ def load_cpk(checkpoint_path, generator=None, discriminator=None, kp_detector=None, audio_feature=None,
54
+ optimizer_generator=None, optimizer_discriminator=None, optimizer_kp_detector=None, optimizer_audio_feature = None):
55
+ checkpoint = torch.load(checkpoint_path)
56
+ if generator is not None:
57
+ generator.load_state_dict(checkpoint['generator'])
58
+ if kp_detector is not None:
59
+ kp_detector.load_state_dict(checkpoint['kp_detector'])
60
+ if discriminator is not None:
61
+ try:
62
+ discriminator.load_state_dict(checkpoint['discriminator'])
63
+ except:
64
+ print ('No discriminator in the state-dict. Dicriminator will be randomly initialized')
65
+ # if audio_feature is not None:
66
+ # audio_feature.load_state_dict(checkpoint['audio_feature'])
67
+ if optimizer_generator is not None:
68
+ optimizer_generator.load_state_dict(checkpoint['optimizer_generator'])
69
+ if optimizer_discriminator is not None:
70
+ try:
71
+ optimizer_discriminator.load_state_dict(checkpoint['optimizer_discriminator'])
72
+ except RuntimeError as e:
73
+ print ('No discriminator optimizer in the state-dict. Optimizer will be not initialized')
74
+ if optimizer_kp_detector is not None:
75
+ optimizer_kp_detector.load_state_dict(checkpoint['optimizer_kp_detector'])
76
+ # if optimizer_audio_feature is not None:
77
+ # a = checkpoint['optimizer_kp_detector']['param_groups']
78
+ # a[0].pop('params')
79
+ # optimizer_audio_feature.load_state_dict(checkpoint['optimizer_audio_feature'])
80
+
81
+ return checkpoint['epoch']
82
+
83
+ def __enter__(self):
84
+ return self
85
+
86
+ def __exit__(self, exc_type, exc_val, exc_tb):
87
+ if 'models' in self.__dict__:
88
+ self.save_cpk()
89
+ self.log_file.close()
90
+
91
+ def log_iter(self, losses):
92
+ losses = collections.OrderedDict(losses.items())
93
+ if self.names is None:
94
+ self.names = list(losses.keys())
95
+ self.loss_list.append(list(losses.values()))
96
+
97
+ def log_epoch(self, epoch, step, models, inp, out):
98
+ self.epoch = epoch
99
+ self.step = step
100
+ self.models = models
101
+ if (self.epoch + 1) % self.checkpoint_freq == 0:
102
+ self.save_cpk()
103
+ self.log_scores(self.names)
104
+ self.visualize_rec(inp, out)
105
+
106
+
107
+ class Visualizer:
108
+ def __init__(self, kp_size=5, draw_border=False, colormap='gist_rainbow'):
109
+ self.kp_size = kp_size
110
+ self.draw_border = draw_border
111
+ self.colormap = plt.get_cmap(colormap)
112
+
113
+ def draw_image_with_kp(self, image, kp_array):
114
+ image = np.copy(image)
115
+ spatial_size = np.array(image.shape[:2][::-1])[np.newaxis]
116
+ kp_array = spatial_size * (kp_array + 1) / 2
117
+ num_kp = kp_array.shape[0]
118
+ for kp_ind, kp in enumerate(kp_array):
119
+ rr, cc = circle(kp[1], kp[0], self.kp_size, shape=image.shape[:2])
120
+ image[rr, cc] = np.array(self.colormap(kp_ind / num_kp))[:3]
121
+ return image
122
+
123
+ def create_image_column_with_kp(self, images, kp):
124
+ image_array = np.array([self.draw_image_with_kp(v, k) for v, k in zip(images, kp)])
125
+ return self.create_image_column(image_array)
126
+
127
+ def create_image_column(self, images):
128
+ if self.draw_border:
129
+ images = np.copy(images)
130
+ images[:, :, [0, -1]] = (1, 1, 1)
131
+ images[:, :, [0, -1]] = (1, 1, 1)
132
+ return np.concatenate(list(images), axis=0)
133
+
134
+ def create_image_grid(self, *args):
135
+ out = []
136
+ for arg in args:
137
+ if type(arg) == tuple:
138
+ out.append(self.create_image_column_with_kp(arg[0], arg[1]))
139
+ else:
140
+ out.append(self.create_image_column(arg))
141
+ return np.concatenate(out, axis=1)
142
+
143
+ def visualize(self, driving, transformed_driving, source, out):
144
+ images = []
145
+
146
+
147
+ # Source image with keypoints
148
+ source = source.data.cpu()
149
+ kp_source = out['kp_source']['value'].data.cpu().numpy()
150
+ source = np.transpose(source, [0, 2, 3, 1])
151
+ images.append((source, kp_source))
152
+
153
+ # Equivariance visualization
154
+ if 'transformed_frame' in out:
155
+ transformed = out['transformed_frame'].data.cpu().numpy()
156
+ transformed = np.transpose(transformed, [0, 2, 3, 1])
157
+ transformed_kp = out['transformed_kp']['value'].data.cpu().numpy()
158
+ images.append((transformed, transformed_kp))
159
+
160
+ # Equivariance visualization
161
+ transformed_driving = transformed_driving.data.cpu().numpy()
162
+ transformed_driving = np.transpose(transformed_driving, [0, 2, 3, 1])
163
+ images.append(transformed_driving)
164
+
165
+ # Driving image with keypoints
166
+ kp_driving = out['kp_driving'][-1]['value'].data.cpu().numpy() #[-1]['value']
167
+ driving = driving.data.cpu().numpy()
168
+ driving = np.transpose(driving, [0, 2, 3, 1])
169
+ images.append((driving, kp_driving))
170
+
171
+
172
+
173
+ # Deformed image
174
+ if 'deformed' in out:
175
+ deformed = out['deformed'].data.cpu().numpy()
176
+ deformed = np.transpose(deformed, [0, 2, 3, 1])
177
+ images.append(deformed)
178
+
179
+ # Result with and without keypoints
180
+ prediction = out['prediction'].data.cpu().numpy()
181
+ prediction = np.transpose(prediction, [0, 2, 3, 1])
182
+ if 'kp_norm' in out:
183
+ kp_norm = out['kp_norm']['value'].data.cpu().numpy()
184
+ images.append((prediction, kp_norm))
185
+ images.append(prediction)
186
+
187
+
188
+ ## Occlusion map
189
+ if 'occlusion_map' in out:
190
+ occlusion_map = out['occlusion_map'].data.cpu().repeat(1, 3, 1, 1)
191
+ occlusion_map = F.interpolate(occlusion_map, size=source.shape[1:3]).numpy()
192
+ occlusion_map = np.transpose(occlusion_map, [0, 2, 3, 1])
193
+ images.append(occlusion_map)
194
+
195
+ # Deformed images according to each individual transform
196
+ if 'sparse_deformed' in out:
197
+ full_mask = []
198
+ for i in range(out['sparse_deformed'].shape[1]):
199
+ image = out['sparse_deformed'][:, i].data.cpu()
200
+ image = F.interpolate(image, size=source.shape[1:3])
201
+ mask = out['mask'][:, i:(i+1)].data.cpu().repeat(1, 3, 1, 1)
202
+ mask = F.interpolate(mask, size=source.shape[1:3])
203
+ image = np.transpose(image.numpy(), (0, 2, 3, 1))
204
+ mask = np.transpose(mask.numpy(), (0, 2, 3, 1))
205
+
206
+ if i != 0:
207
+ color = np.array(self.colormap((i - 1) / (out['sparse_deformed'].shape[1] - 1)))[:3]
208
+ else:
209
+ color = np.array((0, 0, 0))
210
+
211
+ color = color.reshape((1, 1, 1, 3))
212
+
213
+ images.append(image)
214
+ if i != 0:
215
+ images.append(mask * color)
216
+ else:
217
+ images.append(mask)
218
+
219
+ full_mask.append(mask * color)
220
+
221
+ images.append(sum(full_mask))
222
+
223
+ image = self.create_image_grid(*images)
224
+ image = (255 * image).astype(np.uint8)
225
+ return image
FONT/modules/conv.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+
5
+ class Conv2d(nn.Module):
6
+ def __init__(self, cin, cout, kernel_size, stride, padding, residual=False, *args, **kwargs):
7
+ super().__init__(*args, **kwargs)
8
+ self.conv_block = nn.Sequential(
9
+ nn.Conv2d(cin, cout, kernel_size, stride, padding),
10
+ nn.BatchNorm2d(cout)
11
+ )
12
+ self.act = nn.ReLU()
13
+ self.residual = residual
14
+
15
+ def forward(self, x):
16
+ out = self.conv_block(x)
17
+ if self.residual:
18
+ out += x
19
+ return self.act(out)
20
+
21
+ class nonorm_Conv2d(nn.Module):
22
+ def __init__(self, cin, cout, kernel_size, stride, padding, residual=False, *args, **kwargs):
23
+ super().__init__(*args, **kwargs)
24
+ self.conv_block = nn.Sequential(
25
+ nn.Conv2d(cin, cout, kernel_size, stride, padding),
26
+ )
27
+ self.act = nn.LeakyReLU(0.01, inplace=True)
28
+
29
+ def forward(self, x):
30
+ out = self.conv_block(x)
31
+ return self.act(out)
32
+
33
+ class Conv2dTranspose(nn.Module):
34
+ def __init__(self, cin, cout, kernel_size, stride, padding, output_padding=0, *args, **kwargs):
35
+ super().__init__(*args, **kwargs)
36
+ self.conv_block = nn.Sequential(
37
+ nn.ConvTranspose2d(cin, cout, kernel_size, stride, padding, output_padding),
38
+ nn.BatchNorm2d(cout)
39
+ )
40
+ self.act = nn.ReLU()
41
+
42
+ def forward(self, x):
43
+ out = self.conv_block(x)
44
+ return self.act(out)
FONT/modules/dense_motion.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch.nn.functional as F
3
+ import torch
4
+ from .util import Hourglass, AntiAliasInterpolation2d, make_coordinate_grid, kp2gaussian
5
+
6
+
7
+ class DenseMotionNetwork(nn.Module):
8
+ """
9
+ Module that predicting a dense motion from sparse motion representation given by kp_source and kp_driving
10
+ """
11
+
12
+ def __init__(self, block_expansion, num_blocks, max_features, num_kp, num_channels, estimate_occlusion_map=False,
13
+ scale_factor=1, kp_variance=0.01):
14
+ super(DenseMotionNetwork, self).__init__()
15
+ self.hourglass = Hourglass(block_expansion=block_expansion, in_features=(num_kp + 1) * (num_channels + 1),
16
+ max_features=max_features, num_blocks=num_blocks)
17
+
18
+ self.mask = nn.Conv2d(self.hourglass.out_filters, num_kp + 1, kernel_size=(7, 7), padding=(3, 3))
19
+
20
+ if estimate_occlusion_map:
21
+ self.occlusion = nn.Conv2d(self.hourglass.out_filters, 1, kernel_size=(7, 7), padding=(3, 3))
22
+ else:
23
+ self.occlusion = None
24
+
25
+ self.num_kp = num_kp
26
+ self.scale_factor = scale_factor
27
+ self.kp_variance = kp_variance
28
+
29
+ if self.scale_factor != 1:
30
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
31
+
32
+ def create_heatmap_representations(self, source_image, kp_driving, kp_source):
33
+ """
34
+ Eq 6. in the paper H_k(z)
35
+ """
36
+ spatial_size = source_image.shape[2:]
37
+ gaussian_driving = kp2gaussian(kp_driving, spatial_size=spatial_size, kp_variance=self.kp_variance)
38
+ gaussian_source = kp2gaussian(kp_source, spatial_size=spatial_size, kp_variance=self.kp_variance)
39
+ heatmap = gaussian_driving - gaussian_source #[4,10,H,W]
40
+
41
+ #adding background feature
42
+ zeros = torch.zeros(heatmap.shape[0], 1, spatial_size[0], spatial_size[1]).type(heatmap.type())
43
+ heatmap = torch.cat([zeros, heatmap], dim=1)
44
+ heatmap = heatmap.unsqueeze(2) #[4,11,1,h,w]
45
+ return heatmap
46
+
47
+ def create_sparse_motions(self, source_image, kp_driving, kp_source):
48
+ """
49
+ Eq 4. in the paper T_{s<-d}(z)
50
+ """
51
+ bs, _, h, w = source_image.shape
52
+ identity_grid = make_coordinate_grid((h, w), type=kp_source['value'].type())
53
+ identity_grid = identity_grid.view(1, 1, h, w, 2)
54
+ coordinate_grid = identity_grid - kp_driving['value'].view(bs, self.num_kp, 1, 1, 2) #[4,10,64,64,2]
55
+ if 'jacobian' in kp_driving:
56
+ jacobian = torch.matmul(kp_source['jacobian'], torch.inverse(kp_driving['jacobian']))
57
+ jacobian = jacobian.unsqueeze(-3).unsqueeze(-3)
58
+ jacobian = jacobian.repeat(1, 1, h, w, 1, 1)
59
+ coordinate_grid = torch.matmul(jacobian, coordinate_grid.unsqueeze(-1))
60
+ coordinate_grid = coordinate_grid.squeeze(-1)
61
+
62
+ driving_to_source = coordinate_grid + kp_source['value'].view(bs, self.num_kp, 1, 1, 2)
63
+
64
+ #adding background feature
65
+ identity_grid = identity_grid.repeat(bs, 1, 1, 1, 1)
66
+ sparse_motions = torch.cat([identity_grid, driving_to_source], dim=1)
67
+ return sparse_motions
68
+
69
+ def create_deformed_source_image(self, source_image, sparse_motions):
70
+ """
71
+ Eq 7. in the paper \hat{T}_{s<-d}(z)
72
+ """
73
+ bs, _, h, w = source_image.shape
74
+ source_repeat = source_image.unsqueeze(1).unsqueeze(1).repeat(1, self.num_kp + 1, 1, 1, 1, 1)
75
+ source_repeat = source_repeat.view(bs * (self.num_kp + 1), -1, h, w)
76
+ sparse_motions = sparse_motions.view((bs * (self.num_kp + 1), h, w, -1))
77
+ sparse_deformed = F.grid_sample(source_repeat, sparse_motions)
78
+ sparse_deformed = sparse_deformed.view((bs, self.num_kp + 1, -1, h, w))
79
+ return sparse_deformed
80
+
81
+ def forward(self, source_image, kp_driving, kp_source):
82
+ if self.scale_factor != 1:
83
+ source_image = self.down(source_image) #[4,3,H*scale,W*scale]
84
+
85
+ bs, _, h, w = source_image.shape
86
+
87
+ out_dict = dict()
88
+ heatmap_representation = self.create_heatmap_representations(source_image, kp_driving, kp_source) #[4,11,1,64,64]
89
+ sparse_motion = self.create_sparse_motions(source_image, kp_driving, kp_source) #[4,11,64,64,2]
90
+ deformed_source = self.create_deformed_source_image(source_image, sparse_motion) #[4,11,3,64,64]
91
+ out_dict['sparse_deformed'] = deformed_source
92
+
93
+ input = torch.cat([heatmap_representation, deformed_source], dim=2)
94
+ input = input.view(bs, -1, h, w) #[4,11*4,64,64]
95
+
96
+ prediction = self.hourglass(input) #[4,108,64,64]
97
+
98
+ mask = self.mask(prediction)
99
+ mask = F.softmax(mask, dim=1) #[4,11,64,64]
100
+ out_dict['mask'] = mask
101
+ mask = mask.unsqueeze(2)
102
+ sparse_motion = sparse_motion.permute(0, 1, 4, 2, 3)
103
+ deformation = (sparse_motion * mask).sum(dim=1)
104
+ deformation = deformation.permute(0, 2, 3, 1) #[4,64,64,2]
105
+
106
+ out_dict['deformation'] = deformation
107
+
108
+ # Sec. 3.2 in the paper
109
+ if self.occlusion:
110
+ occlusion_map = torch.sigmoid(self.occlusion(prediction))
111
+ out_dict['occlusion_map'] = occlusion_map #[4,1,64,64]
112
+
113
+ return out_dict
FONT/modules/discriminator.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch.nn.functional as F
3
+ from modules.util import kp2gaussian
4
+ import torch
5
+
6
+
7
+ class DownBlock2d(nn.Module):
8
+ """
9
+ Simple block for processing video (encoder).
10
+ """
11
+
12
+ def __init__(self, in_features, out_features, norm=False, kernel_size=4, pool=False, sn=False):
13
+ super(DownBlock2d, self).__init__()
14
+ self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size)
15
+
16
+ if sn:
17
+ self.conv = nn.utils.spectral_norm(self.conv)
18
+
19
+ if norm:
20
+ self.norm = nn.InstanceNorm2d(out_features, affine=True)
21
+ else:
22
+ self.norm = None
23
+ self.pool = pool
24
+
25
+ def forward(self, x):
26
+ out = x
27
+ out = self.conv(out)
28
+ if self.norm:
29
+ out = self.norm(out)
30
+ out = F.leaky_relu(out, 0.2)
31
+ if self.pool:
32
+ out = F.avg_pool2d(out, (2, 2))
33
+ return out
34
+
35
+
36
+ class Discriminator(nn.Module):
37
+ """
38
+ Discriminator similar to Pix2Pix
39
+ """
40
+
41
+ def __init__(self, num_channels=3, block_expansion=64, num_blocks=4, max_features=512,
42
+ sn=False, use_kp=False, num_kp=10, kp_variance=0.01, **kwargs):
43
+ super(Discriminator, self).__init__()
44
+
45
+ down_blocks = []
46
+ for i in range(num_blocks):
47
+ down_blocks.append(
48
+ DownBlock2d(num_channels + num_kp * use_kp if i == 0 else min(max_features, block_expansion * (2 ** i)),
49
+ min(max_features, block_expansion * (2 ** (i + 1))),
50
+ norm=(i != 0), kernel_size=4, pool=(i != num_blocks - 1), sn=sn))
51
+
52
+ self.down_blocks = nn.ModuleList(down_blocks)
53
+ self.conv = nn.Conv2d(self.down_blocks[-1].conv.out_channels, out_channels=1, kernel_size=1)
54
+ if sn:
55
+ self.conv = nn.utils.spectral_norm(self.conv)
56
+ self.use_kp = use_kp
57
+ self.kp_variance = kp_variance
58
+
59
+ def forward(self, x, kp=None):
60
+ feature_maps = []
61
+ out = x
62
+ if self.use_kp:
63
+ heatmap = kp2gaussian(kp, x.shape[2:], self.kp_variance)
64
+ out = torch.cat([out, heatmap], dim=1)
65
+
66
+ for down_block in self.down_blocks:
67
+ feature_maps.append(down_block(out))
68
+ out = feature_maps[-1]
69
+ prediction_map = self.conv(out)
70
+
71
+ return feature_maps, prediction_map
72
+
73
+
74
+ class MultiScaleDiscriminator(nn.Module):
75
+ """
76
+ Multi-scale (scale) discriminator
77
+ """
78
+
79
+ def __init__(self, scales=(), **kwargs):
80
+ super(MultiScaleDiscriminator, self).__init__()
81
+ self.scales = scales
82
+ discs = {}
83
+ for scale in scales:
84
+ discs[str(scale).replace('.', '-')] = Discriminator(**kwargs)
85
+ self.discs = nn.ModuleDict(discs)
86
+
87
+ def forward(self, x, kp=None):
88
+ out_dict = {}
89
+ for scale, disc in self.discs.items():
90
+ scale = str(scale).replace('-', '.')
91
+ key = 'prediction_' + scale
92
+ feature_maps, prediction_map = disc(x[key], kp)
93
+ out_dict['feature_maps_' + scale] = feature_maps
94
+ out_dict['prediction_map_' + scale] = prediction_map
95
+ return out_dict
FONT/modules/frames_dataset.py ADDED
@@ -0,0 +1,451 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from skimage import io, img_as_float32, transform
3
+ from skimage.color import gray2rgb
4
+ from sklearn.model_selection import train_test_split
5
+ from imageio import mimread
6
+
7
+ import numpy as np
8
+ from torch.utils.data import Dataset
9
+ import pandas as pd
10
+ from augmentation import AllAugmentationTransform
11
+ import glob
12
+ import pickle
13
+ import random
14
+ def read_video(name, frame_shape):
15
+ """
16
+ Read video which can be:
17
+ - an image of concatenated frames
18
+ - '.mp4' and'.gif'
19
+ - folder with videos
20
+ """
21
+
22
+ if os.path.isdir(name):
23
+ frames = sorted(os.listdir(name))
24
+ num_frames = len(frames)
25
+ video_array = np.array(
26
+ [img_as_float32(io.imread(os.path.join(name, frames[idx]))) for idx in range(num_frames)])
27
+ elif name.lower().endswith('.png') or name.lower().endswith('.jpg'):
28
+ image = io.imread(name)
29
+
30
+ if len(image.shape) == 2 or image.shape[2] == 1:
31
+ image = gray2rgb(image)
32
+
33
+ if image.shape[2] == 4:
34
+ image = image[..., :3]
35
+
36
+ image = img_as_float32(image)
37
+
38
+ video_array = np.moveaxis(image, 1, 0)
39
+
40
+ video_array = video_array.reshape((-1,) + frame_shape)
41
+ video_array = np.moveaxis(video_array, 1, 2)
42
+ elif name.lower().endswith('.gif') or name.lower().endswith('.mp4') or name.lower().endswith('.mov'):
43
+ video = np.array(mimread(name))
44
+ if len(video.shape) == 3:
45
+ video = np.array([gray2rgb(frame) for frame in video])
46
+ if video.shape[-1] == 4:
47
+ video = video[..., :3]
48
+ video_array = img_as_float32(video)
49
+ else:
50
+ raise Exception("Unknown file extensions %s" % name)
51
+
52
+ return video_array
53
+
54
+ def get_list(ipath,base_name):
55
+ #ipath = '/mnt/lustre/share/jixinya/LRW/pose/train_fo/'
56
+ ipath = os.path.join(ipath,base_name)
57
+ name_list = os.listdir(ipath)
58
+ image_path = os.path.join('/mnt/lustre/share/jixinya/LRW/Image/',base_name)
59
+ all = []
60
+ for k in range(len(name_list)):
61
+ name = name_list[k]
62
+ path_ = os.path.join(ipath,name)
63
+ Dir = os.listdir(path_)
64
+ for i in range(len(Dir)):
65
+ word = Dir[i]
66
+ path = os.path.join(path_, word)
67
+ if os.path.exists(os.path.join(image_path,name,word.split('.')[0])):
68
+ all.append(name+'/'+word.split('.')[0])
69
+ #print(k,name,i,word)
70
+ print('get list '+os.path.basename(ipath))
71
+ return all
72
+
73
+
74
+ class AudioDataset(Dataset):
75
+ """
76
+ Dataset of videos, each video can be represented as:
77
+ - an image of concatenated frames
78
+ - '.mp4' or '.gif'
79
+ - folder with all frames
80
+ """
81
+
82
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
83
+ random_seed=0, pairs_list=None, augmentation_params=None):
84
+ self.root_dir = root_dir
85
+ self.audio_dir = os.path.join(root_dir,'MFCC')
86
+ self.image_dir = os.path.join(root_dir,'Image')
87
+ self.landmark_dir = os.path.join(root_dir,'Landmark')
88
+ self.pose_dir = os.path.join(root_dir,'pose')
89
+ # assert len(os.listdir(self.audio_dir)) == len(os.listdir(self.image_dir)), 'audio and image length not equal'
90
+
91
+
92
+ df=open('../LRW/list/test_fo.txt','rb')
93
+ self.videos=pickle.load(df)
94
+ df.close()
95
+ # self.videos=np.load('../LRW/list/train_fo.npy')
96
+ # self.videos = os.listdir(self.landmark_dir)
97
+ self.frame_shape = tuple(frame_shape)
98
+ self.pairs_list = pairs_list
99
+ self.id_sampling = id_sampling
100
+ self.pca = np.load('../LRW/list/U_106.npy')[:, :16]
101
+ self.mean = np.load('../LRW/list/mean_106.npy')
102
+
103
+ if os.path.exists(os.path.join(self.pose_dir, 'train_fo')):
104
+ assert os.path.exists(os.path.join(self.pose_dir, 'test_fo'))
105
+ print("Use predefined train-test split.")
106
+ if id_sampling:
107
+ train_videos = {os.path.basename(video).split('#')[0] for video in
108
+ os.listdir(os.path.join(self.image_dir, 'train'))}
109
+ train_videos = list(train_videos)
110
+ else:
111
+ train_videos = np.load('../LRW/list/train_fo.npy')# get_list(self.pose_dir, 'train_fo')
112
+ df=open('../LRW/list/test_fo.txt','rb')
113
+ test_videos=pickle.load(df)
114
+ df.close()
115
+ # test_videos = np.load('../LRW/list/train_fo.npy')
116
+ #get_list(self.pose_dir, 'test_fo')
117
+ # self.root_dir = os.path.join(self.root_dir, 'train' if is_train else 'test')
118
+ self.landmark_dir = os.path.join(self.landmark_dir, 'train_fo' if is_train else 'test_fo')
119
+ self.image_dir = os.path.join(self.image_dir, 'train_fo' if is_train else 'test_fo')
120
+ self.audio_dir = os.path.join(self.audio_dir, 'train' if is_train else 'test')
121
+ self.pose_dir = os.path.join(self.pose_dir, 'train_fo' if is_train else 'test_fo')
122
+ else:
123
+ print("Use random train-test split.")
124
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
125
+
126
+ if is_train:
127
+ self.videos = train_videos
128
+ else:
129
+ self.videos = test_videos
130
+
131
+ self.is_train = is_train
132
+
133
+ if self.is_train:
134
+ self.transform = AllAugmentationTransform(**augmentation_params)
135
+ else:
136
+ self.transform = None
137
+
138
+ def __len__(self):
139
+ return len(self.videos)
140
+
141
+ def __getitem__(self, idx):
142
+ if self.is_train and self.id_sampling:
143
+ name = self.videos[idx].split('.')[0]
144
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
145
+ else:
146
+ name = self.videos[idx].split('.')[0]
147
+ landmark_path = os.path.join(self.landmark_dir, name+'.npy')
148
+
149
+ audio_path = os.path.join(self.audio_dir, name)
150
+ pose_path = os.path.join(self.pose_dir,name)
151
+ path = os.path.join(self.image_dir, name)
152
+
153
+ video_name = os.path.basename(path)
154
+
155
+ if os.path.isdir(path):
156
+ # if self.is_train and os.path.isdir(path):
157
+
158
+ lmark = np.load(landmark_path).reshape(-1,212)/255
159
+ if np.isnan(lmark).sum() or np.isinf(lmark).sum():
160
+ print('Wrong lmark '+ video_name, file=open('log/wrong.txt', 'a'))
161
+ lmark = np.zeros((29,212))
162
+ lmark = lmark - self.mean
163
+ lmark = np.dot(lmark, self.pca)
164
+
165
+ # mfcc loading
166
+
167
+ r = random.choice([x for x in range(3, 8)])
168
+ example_landmark = lmark[r, :]
169
+ example_image = img_as_float32(io.imread(os.path.join(path, str(r)+'.png')))
170
+ # example_mfcc = mfcc[(r - 3) * 4: (r + 4) * 4, 1:]
171
+
172
+ mfccs = []
173
+ for ind in range(1, 17):
174
+ # t_mfcc = mfcc[(r + ind - 3) * 4: (r + ind + 4) * 4, 1:]
175
+ try:
176
+ t_mfcc = np.load(os.path.join(audio_path,str(r + ind)+'.npy'),allow_pickle=True)[:, 1:]
177
+ if np.isnan(t_mfcc).sum() or np.isinf(t_mfcc).sum():
178
+ print('Wrong mfcc '+ video_name+str(r+ind), file=open('log/wrong.txt', 'a'))
179
+ t_mfcc = np.zeros((28,13))[:,1:]
180
+ except:
181
+ t_mfcc = np.zeros((28,13))[:,1:]
182
+ mfccs.append(t_mfcc)
183
+ mfccs = np.array(mfccs)
184
+ if not self.is_train:
185
+ poses = []
186
+ video_array = []
187
+ for ind in range(1, 17):
188
+ # t_mfcc = mfcc[(r + ind - 3) * 4: (r + ind + 4) * 4, 1:]
189
+ t_pose = np.load(os.path.join(pose_path,str(r + ind)+'.npy'))[:-1]
190
+ poses.append(t_pose)
191
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
192
+ video_array.append(image)
193
+ poses = np.array(poses)
194
+ video_array = np.array(video_array)
195
+ else:
196
+ poses = []
197
+ video_array = []
198
+ for ind in range(1, 17):
199
+ # t_mfcc = mfcc[(r + ind - 3) * 4: (r + ind + 4) * 4, 1:]
200
+ t_pose = np.load(os.path.join(self.pose_dir,name+'.npy'))[r+ind,:-1]
201
+ if np.isnan(t_pose).sum() or np.isinf(t_pose).sum():
202
+ print('Wrong pose '+ video_name, file=open('log/wrong.txt', 'a'))
203
+ t_pose = np.zeros((6,))
204
+ poses.append(t_pose)
205
+ image = img_as_float32(io.imread(os.path.join(path, str(r + ind)+'.png')))
206
+ video_array.append(image)
207
+ poses = np.array(poses)
208
+ video_array = np.array(video_array)
209
+
210
+ #mfccs = torch.FloatTensor(mfccs)
211
+ landmark = lmark[r + 1: r + 17, :]
212
+ index_32 = [0,4,8,12,16,20,24,28,32,33,35,67,68,40,42,52,55,72,73,58,61,75,76,46,47,51,84,87,90,93,98,102]
213
+ driving_landmark = np.load(landmark_path)[r + 1: r + 17, :][:,index_32]
214
+ source_landmark = np.load(landmark_path)[r, :][index_32]
215
+ else:
216
+ video_array = read_video(path, frame_shape=self.frame_shape)
217
+ num_frames = len(video_array)
218
+ frame_idx = np.sort(np.random.choice(num_frames, replace=True, size=2)) if self.is_train else range(
219
+ num_frames)
220
+ video_array = video_array[frame_idx]
221
+
222
+ if self.transform is not None:
223
+ video_array = self.transform(video_array)
224
+
225
+ out = {}
226
+ if True:#self.is_train:
227
+ # a = img_as_float32(io.imread('/media/thea/Data/first-order-model/images_512/102.jpg'))
228
+ # source = np.array(a, dtype='float32')
229
+
230
+ driving = np.array(video_array, dtype='float32')
231
+
232
+ spatial_size = np.array(driving.shape[1:3][::-1])[np.newaxis]
233
+ # example_landmark = np.array(2*example_landmark / spatial_size -1, dtype='float32')
234
+ driving_landmark = np.array(2*driving_landmark / spatial_size -1, dtype='float32')
235
+ source_landmark = np.array(2*source_landmark / spatial_size -1, dtype='float32')
236
+ driving_pose = np.array(poses, dtype='float32')
237
+ example_landmark = np.array(example_landmark, dtype='float32')
238
+ example_image = np.array(example_image, dtype='float32')
239
+ # source_cube = np.array(transform.resize(cube_array[0], (64,64)), dtype='float32')
240
+ # driving_cube = np.array(transform.resize(cube_array[1], (64,64)), dtype='float32')
241
+ # source_heatmap = np.array(heatmap_array[0] , dtype='float32')
242
+ # driving_heatmap = np.array(heatmap_array[1] , dtype='float32')
243
+ # out['source_cube'] = source_cube
244
+ # out['driving_cube'] = driving_cube
245
+ out['example_landmark'] = example_landmark
246
+ out['example_image'] = example_image.transpose((2, 0, 1))
247
+ out['driving_landmark'] = driving_landmark
248
+ out['source_landmark'] = source_landmark
249
+ out['driving_pose'] = driving_pose
250
+ # out['source_heatmap'] = source_heatmap
251
+ # out['driving_heatmap'] = driving_heatmap
252
+ out['driving'] = driving.transpose((0, 3, 1, 2))
253
+ # out['source'] = source.transpose((2, 0, 1))
254
+
255
+ # out['source_audio'] = np.array(audio_array[0], dtype='float32')
256
+ out['driving_audio'] = np.array(mfccs, dtype='float32')
257
+ out['gt_landmark'] = np.array(landmark, dtype='float32')
258
+ out['pca'] = np.array(self.pca, dtype='float32')
259
+ out['mean'] = np.array(self.mean, dtype='float32')
260
+
261
+
262
+ out['name'] = video_name
263
+
264
+ return out
265
+
266
+ class FramesDataset(Dataset):
267
+ """
268
+ Dataset of videos, each video can be represented as:
269
+ - an image of concatenated frames
270
+ - '.mp4' or '.gif'
271
+ - folder with all frames
272
+ """
273
+
274
+ def __init__(self, root_dir, frame_shape=(256, 256, 3), id_sampling=False, is_train=True,
275
+ random_seed=0, pairs_list=None, augmentation_params=None):
276
+ self.root_dir = root_dir
277
+ self.audio_dir = os.path.join(root_dir,'audio/')
278
+ self.image_dir = os.path.join(root_dir,'image/')
279
+ self.landmark_dir = os.path.join(root_dir,'cube/')
280
+ # assert len(os.listdir(self.audio_dir)) == len(os.listdir(self.image_dir)), 'audio and image length not equal'
281
+
282
+
283
+ df=open('/media/thea/新加卷/MEAD/neutral/train.txt','rb')
284
+ self.videos=pickle.load(df)
285
+ df.close()
286
+ # self.videos = os.listdir(self.landmark_dir)
287
+ self.frame_shape = tuple(frame_shape)
288
+ self.pairs_list = pairs_list
289
+ self.id_sampling = id_sampling
290
+ if os.path.exists(os.path.join(self.image_dir, 'train')):
291
+ assert os.path.exists(os.path.join(self.image_dir, 'test'))
292
+ print("Use predefined train-test split.")
293
+ if id_sampling:
294
+ train_videos = {os.path.basename(video).split('#')[0] for video in
295
+ os.listdir(os.path.join(self.image_dir, 'train'))}
296
+ train_videos = list(train_videos)
297
+ else:
298
+ train_videos = os.listdir(os.path.join(self.image_dir, 'train'))
299
+ test_videos = os.listdir(os.path.join(self.image_dir, 'test'))
300
+ self.root_dir = os.path.join(self.root_dir, 'train' if is_train else 'test')
301
+ self.landmark_dir = os.path.join(self.landmark_dir, 'train' if is_train else 'test')
302
+ self.image_dir = os.path.join(self.image_dir, 'train' if is_train else 'test')
303
+ self.audio_dir = os.path.join(self.audio_dir, 'train' if is_train else 'test')
304
+
305
+ else:
306
+ print("Use random train-test split.")
307
+ train_videos, test_videos = train_test_split(self.videos, random_state=random_seed, test_size=0.2)
308
+
309
+ if is_train:
310
+ self.videos = train_videos
311
+ else:
312
+ self.videos = test_videos
313
+
314
+ self.is_train = is_train
315
+
316
+ if self.is_train:
317
+ self.transform = AllAugmentationTransform(**augmentation_params)
318
+ else:
319
+ self.transform = None
320
+
321
+ def __len__(self):
322
+ return len(self.videos)
323
+
324
+ def __getitem__(self, idx):
325
+ if self.is_train and self.id_sampling:
326
+ name = self.videos[idx].split('.')[0]
327
+ path = np.random.choice(glob.glob(os.path.join(self.root_dir, name + '*.mp4')))
328
+ else:
329
+ name = self.videos[idx].split('.')[0]
330
+ landmark_path = os.path.join(self.landmark_dir, name)
331
+
332
+ audio_path = os.path.join(self.audio_dir, name)
333
+ path = os.path.join(self.image_dir, name)
334
+
335
+ video_name = os.path.basename(path)
336
+
337
+ if self.is_train and os.path.isdir(path):
338
+ frames = os.listdir(audio_path)
339
+ num_frames = len(frames)
340
+ frame_idx = np.sort(np.random.choice(num_frames-1, replace=True, size=2))
341
+ # landmark = np.load(landmark_path)#+'.npy'
342
+ # assert len(os.listdir(path)) == len(landmark), video_name+' length not equal'
343
+ video_array = [img_as_float32(io.imread(os.path.join(path, str(idx)+'.png'))) for idx in frame_idx]
344
+ cube_array = [img_as_float32(io.imread(os.path.join(landmark_path, str(idx)+'.jpg'))) for idx in frame_idx]
345
+ audio_array = [np.load(os.path.join(audio_path, str(idx)+'.npy'))[:,1:] for idx in frame_idx]
346
+ index_20 = [0,16,32,35,40,52,55,58,61,46,72,73,75,76,84,87,90,93,98,102]
347
+ index_32 = [0,4,8,12,16,20,24,28,32,33,35,67,68,40,42,52,55,72,73,58,61,75,76,46,47,51,84,87,90,93,98,102]
348
+ # landmark_array = [landmark[idx] for idx in frame_idx]
349
+ # landmark_array = [landmark[idx][index_32] for idx in frame_idx]
350
+ else:
351
+ video_array = read_video(path, frame_shape=self.frame_shape)
352
+ num_frames = len(video_array)
353
+ frame_idx = np.sort(np.random.choice(num_frames, replace=True, size=2)) if self.is_train else range(
354
+ num_frames)
355
+ video_array = video_array[frame_idx]
356
+
357
+ if self.transform is not None:
358
+ video_array = self.transform(video_array)
359
+
360
+ out = {}
361
+ if self.is_train:
362
+ # a = img_as_float32(io.imread('/media/thea/Data/first-order-model/images_512/102.jpg'))
363
+ # source = np.array(a, dtype='float32')
364
+ source = np.array(video_array[0], dtype='float32')
365
+ driving = np.array(video_array[1], dtype='float32')
366
+
367
+ spatial_size = np.array(source.shape[:2][::-1])[np.newaxis]
368
+ # source_landmark = np.array(2*landmark_array[0] / spatial_size -1, dtype='float32')
369
+ # driving_landmark = np.array(2*landmark_array[1] / spatial_size -1, dtype='float32')
370
+ source_cube = np.array(transform.resize(cube_array[0], (64,64)), dtype='float32')
371
+ driving_cube = np.array(transform.resize(cube_array[1], (64,64)), dtype='float32')
372
+ # source_heatmap = np.array(heatmap_array[0] , dtype='float32')
373
+ # driving_heatmap = np.array(heatmap_array[1] , dtype='float32')
374
+ out['source_cube'] = source_cube
375
+ out['driving_cube'] = driving_cube
376
+ # out['source_landmark'] = source_landmark
377
+ # out['driving_landmark'] = driving_landmark
378
+ # out['source_heatmap'] = source_heatmap
379
+ # out['driving_heatmap'] = driving_heatmap
380
+ out['driving'] = driving.transpose((2, 0, 1))
381
+ out['source'] = source.transpose((2, 0, 1))
382
+
383
+ out['source_audio'] = np.array(audio_array[0], dtype='float32')
384
+ out['driving_audio'] = np.array(audio_array[1], dtype='float32')
385
+
386
+ else:
387
+ video = np.array(video_array, dtype='float32')
388
+ out['video'] = video.transpose((3, 0, 1, 2))
389
+
390
+ out['name'] = video_name
391
+
392
+ return out
393
+
394
+
395
+ class DatasetRepeater(Dataset):
396
+ """
397
+ Pass several times over the same dataset for better i/o performance
398
+ """
399
+
400
+ def __init__(self, dataset, num_repeats=100):
401
+ self.dataset = dataset
402
+ self.num_repeats = num_repeats
403
+
404
+ def __len__(self):
405
+ return self.num_repeats * self.dataset.__len__()
406
+
407
+ def __getitem__(self, idx):
408
+ return self.dataset[idx % self.dataset.__len__()]#% self.dataset.__len__()
409
+
410
+
411
+ class PairedDataset(Dataset):
412
+ """
413
+ Dataset of pairs for animation.
414
+ """
415
+
416
+ def __init__(self, initial_dataset, number_of_pairs, seed=0):
417
+ self.initial_dataset = initial_dataset
418
+ pairs_list = self.initial_dataset.pairs_list
419
+
420
+ np.random.seed(seed)
421
+
422
+ if pairs_list is None:
423
+ max_idx = min(number_of_pairs, len(initial_dataset))
424
+ nx, ny = max_idx, max_idx
425
+ xy = np.mgrid[:nx, :ny].reshape(2, -1).T
426
+ number_of_pairs = min(xy.shape[0], number_of_pairs)
427
+ self.pairs = xy.take(np.random.choice(xy.shape[0], number_of_pairs, replace=False), axis=0)
428
+ else:
429
+ videos = self.initial_dataset.videos
430
+ name_to_index = {name: index for index, name in enumerate(videos)}
431
+ pairs = pd.read_csv(pairs_list)
432
+ pairs = pairs[np.logical_and(pairs['source'].isin(videos), pairs['driving'].isin(videos))]
433
+
434
+ number_of_pairs = min(pairs.shape[0], number_of_pairs)
435
+ self.pairs = []
436
+ self.start_frames = []
437
+ for ind in range(number_of_pairs):
438
+ self.pairs.append(
439
+ (name_to_index[pairs['driving'].iloc[ind]], name_to_index[pairs['source'].iloc[ind]]))
440
+
441
+ def __len__(self):
442
+ return len(self.pairs)
443
+
444
+ def __getitem__(self, idx):
445
+ pair = self.pairs[idx]
446
+ first = self.initial_dataset[pair[0]]
447
+ second = self.initial_dataset[pair[1]]
448
+ first = {'driving_' + key: value for key, value in first.items()}
449
+ second = {'source_' + key: value for key, value in second.items()}
450
+
451
+ return {**first, **second}
FONT/modules/function.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Sep 30 17:45:24 2021
5
+
6
+ @author: SENSETIME\jixinya1
7
+ """
8
+
9
+ import torch
10
+
11
+
12
+ def calc_mean_std(feat, eps=1e-5):
13
+ # eps is a small value added to the variance to avoid divide-by-zero.
14
+ size = feat.size()
15
+ assert (len(size) == 4)
16
+ N, C = size[:2]
17
+ feat_var = feat.view(N, C, -1).var(dim=2) + eps
18
+ feat_std = feat_var.sqrt().view(N, C, 1, 1)
19
+ feat_mean = feat.view(N, C, -1).mean(dim=2).view(N, C, 1, 1)
20
+ return feat_mean, feat_std
21
+
22
+
23
+ def adaptive_instance_normalization(content_feat, style_feat):
24
+ assert (content_feat.size()[:2] == style_feat.size()[:2])
25
+ size = content_feat.size()
26
+ style_mean, style_std = calc_mean_std(style_feat)
27
+ content_mean, content_std = calc_mean_std(content_feat)
28
+
29
+ normalized_feat = (content_feat - content_mean.expand(
30
+ size)) / content_std.expand(size)
31
+ return normalized_feat * style_std.expand(size) + style_mean.expand(size)
32
+
33
+
34
+ def _calc_feat_flatten_mean_std(feat):
35
+ # takes 3D feat (C, H, W), return mean and std of array within channels
36
+ assert (feat.size()[0] == 3)
37
+ assert (isinstance(feat, torch.FloatTensor))
38
+ feat_flatten = feat.view(3, -1)
39
+ mean = feat_flatten.mean(dim=-1, keepdim=True)
40
+ std = feat_flatten.std(dim=-1, keepdim=True)
41
+ return feat_flatten, mean, std
42
+
43
+
44
+ def _mat_sqrt(x):
45
+ U, D, V = torch.svd(x)
46
+ return torch.mm(torch.mm(U, D.pow(0.5).diag()), V.t())
47
+
48
+
49
+ def coral(source, target):
50
+ # assume both source and target are 3D array (C, H, W)
51
+ # Note: flatten -> f
52
+
53
+ source_f, source_f_mean, source_f_std = _calc_feat_flatten_mean_std(source)
54
+ source_f_norm = (source_f - source_f_mean.expand_as(
55
+ source_f)) / source_f_std.expand_as(source_f)
56
+ source_f_cov_eye = \
57
+ torch.mm(source_f_norm, source_f_norm.t()) + torch.eye(3)
58
+
59
+ target_f, target_f_mean, target_f_std = _calc_feat_flatten_mean_std(target)
60
+ target_f_norm = (target_f - target_f_mean.expand_as(
61
+ target_f)) / target_f_std.expand_as(target_f)
62
+ target_f_cov_eye = \
63
+ torch.mm(target_f_norm, target_f_norm.t()) + torch.eye(3)
64
+
65
+ source_f_norm_transfer = torch.mm(
66
+ _mat_sqrt(target_f_cov_eye),
67
+ torch.mm(torch.inverse(_mat_sqrt(source_f_cov_eye)),
68
+ source_f_norm)
69
+ )
70
+
71
+ source_f_transfer = source_f_norm_transfer * \
72
+ target_f_std.expand_as(source_f_norm) + \
73
+ target_f_mean.expand_as(source_f_norm)
74
+
75
+ return source_f_transfer.view(source.size())
FONT/modules/generator.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ import torch.nn.functional as F
4
+ from .util import ResBlock2d, SameBlock2d, UpBlock2d, DownBlock2d
5
+ from .dense_motion import DenseMotionNetwork
6
+
7
+
8
+ class OcclusionAwareGenerator(nn.Module):
9
+ """
10
+ Generator that given source image and and keypoints try to transform image according to movement trajectories
11
+ induced by keypoints. Generator follows Johnson architecture.
12
+ """
13
+
14
+ def __init__(self, num_channels, num_kp, block_expansion, max_features, num_down_blocks,
15
+ num_bottleneck_blocks, estimate_occlusion_map=False, dense_motion_params=None, estimate_jacobian=False):
16
+ super(OcclusionAwareGenerator, self).__init__()
17
+
18
+ if dense_motion_params is not None:
19
+ self.dense_motion_network = DenseMotionNetwork(num_kp=num_kp, num_channels=num_channels,
20
+ estimate_occlusion_map=estimate_occlusion_map,
21
+ **dense_motion_params)
22
+ else:
23
+ self.dense_motion_network = None
24
+
25
+ self.first = SameBlock2d(num_channels, block_expansion, kernel_size=(7, 7), padding=(3, 3))
26
+
27
+ down_blocks = []
28
+ for i in range(num_down_blocks):
29
+ in_features = min(max_features, block_expansion * (2 ** i))
30
+ out_features = min(max_features, block_expansion * (2 ** (i + 1)))
31
+ down_blocks.append(DownBlock2d(in_features, out_features, kernel_size=(3, 3), padding=(1, 1)))
32
+ self.down_blocks = nn.ModuleList(down_blocks)
33
+
34
+ up_blocks = []
35
+ for i in range(num_down_blocks):
36
+ in_features = min(max_features, block_expansion * (2 ** (num_down_blocks - i)))
37
+ out_features = min(max_features, block_expansion * (2 ** (num_down_blocks - i - 1)))
38
+ up_blocks.append(UpBlock2d(in_features, out_features, kernel_size=(3, 3), padding=(1, 1)))
39
+ self.up_blocks = nn.ModuleList(up_blocks)
40
+
41
+ self.bottleneck = torch.nn.Sequential()
42
+ in_features = min(max_features, block_expansion * (2 ** num_down_blocks))
43
+ for i in range(num_bottleneck_blocks):
44
+ self.bottleneck.add_module('r' + str(i), ResBlock2d(in_features, kernel_size=(3, 3), padding=(1, 1)))
45
+
46
+ self.final = nn.Conv2d(block_expansion, num_channels, kernel_size=(7, 7), padding=(3, 3))
47
+ self.estimate_occlusion_map = estimate_occlusion_map
48
+ self.num_channels = num_channels
49
+
50
+ def deform_input(self, inp, deformation):
51
+ _, h_old, w_old, _ = deformation.shape
52
+ _, _, h, w = inp.shape
53
+ if h_old != h or w_old != w:
54
+ deformation = deformation.permute(0, 3, 1, 2)
55
+ deformation = F.interpolate(deformation, size=(h, w), mode='bilinear')
56
+ deformation = deformation.permute(0, 2, 3, 1)
57
+ return F.grid_sample(inp, deformation)
58
+
59
+ def forward(self, source_image, kp_driving, kp_source):
60
+ # Encoding (downsampling) part
61
+ out = self.first(source_image) #[4,64,H,W]
62
+ for i in range(len(self.down_blocks)):
63
+ out = self.down_blocks[i](out) #[4,256,H/4,W/4]
64
+
65
+ # Transforming feature representation according to deformation and occlusion
66
+ output_dict = {}
67
+ if self.dense_motion_network is not None:
68
+ dense_motion = self.dense_motion_network(source_image=source_image, kp_driving=kp_driving,
69
+ kp_source=kp_source)
70
+ output_dict['mask'] = dense_motion['mask']
71
+ output_dict['sparse_deformed'] = dense_motion['sparse_deformed']
72
+
73
+ if 'occlusion_map' in dense_motion:
74
+ occlusion_map = dense_motion['occlusion_map']
75
+ output_dict['occlusion_map'] = occlusion_map
76
+ else:
77
+ occlusion_map = None
78
+ deformation = dense_motion['deformation']
79
+ out = self.deform_input(out, deformation)
80
+
81
+ if occlusion_map is not None:
82
+ if out.shape[2] != occlusion_map.shape[2] or out.shape[3] != occlusion_map.shape[3]:
83
+ occlusion_map = F.interpolate(occlusion_map, size=out.shape[2:], mode='bilinear')
84
+ out = out * occlusion_map
85
+
86
+ output_dict["deformed"] = self.deform_input(source_image, deformation)
87
+
88
+ # Decoding part
89
+ out = self.bottleneck(out) #[4,256,64,64]
90
+ for i in range(len(self.up_blocks)):
91
+ out = self.up_blocks[i](out)
92
+ out = self.final(out)
93
+ out = torch.sigmoid(out) #[4,3,256,256]
94
+
95
+ output_dict["prediction"] = out
96
+
97
+ return output_dict
FONT/modules/keypoint_detector.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from .util import Hourglass, make_coordinate_grid, AntiAliasInterpolation2d, Ct_encoder, EmotionNet, AF2F, AF2F_s, draw_heatmap
5
+
6
+
7
+ class KPDetector(nn.Module):
8
+ """
9
+ Detecting a keypoints. Return keypoint position and jacobian near each keypoint.
10
+ """
11
+
12
+ def __init__(self, block_expansion, num_kp, num_channels, max_features,
13
+ num_blocks, temperature, estimate_jacobian=False, scale_factor=1,
14
+ single_jacobian_map=False, pad=0):
15
+ super(KPDetector, self).__init__()
16
+
17
+ self.predictor = Hourglass(block_expansion, in_features=num_channels,
18
+ max_features=max_features, num_blocks=num_blocks)
19
+
20
+ self.kp = nn.Conv2d(in_channels=self.predictor.out_filters, out_channels=num_kp, kernel_size=(7, 7),
21
+ padding=pad)
22
+
23
+ if estimate_jacobian:
24
+ self.num_jacobian_maps = 1 if single_jacobian_map else num_kp
25
+ self.jacobian = nn.Conv2d(in_channels=self.predictor.out_filters,
26
+ out_channels=4 * self.num_jacobian_maps, kernel_size=(7, 7), padding=pad)
27
+ self.jacobian.weight.data.zero_()
28
+ self.jacobian.bias.data.copy_(torch.tensor([1, 0, 0, 1] * self.num_jacobian_maps, dtype=torch.float))
29
+ else:
30
+ self.jacobian = None
31
+
32
+ self.temperature = temperature
33
+ self.scale_factor = scale_factor
34
+ if self.scale_factor != 1:
35
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
36
+
37
+
38
+
39
+
40
+ def gaussian2kp(self, heatmap):
41
+ """
42
+ Extract the mean and from a heatmap
43
+ """
44
+ shape = heatmap.shape
45
+ heatmap = heatmap.unsqueeze(-1) #[4,10,58,58,1]
46
+ grid = make_coordinate_grid(shape[2:], heatmap.type()).unsqueeze_(0).unsqueeze_(0) #[1,1,58,58,2]
47
+ value = (heatmap * grid).sum(dim=(2, 3)) #[4,10,2]
48
+ kp = {'value': value}
49
+
50
+ return kp
51
+
52
+ def audio_feature(self, x, heatmap):
53
+
54
+ # prediction = self.kp(x) #[4,10,H/4-6, W/4-6]
55
+
56
+ # final_shape = prediction.shape
57
+ # heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
58
+ # heatmap = F.softmax(heatmap / self.temperature, dim=2)
59
+ # heatmap = heatmap.view(*final_shape) #[4,10,58,58]
60
+
61
+ # out = self.gaussian2kp(heatmap)
62
+ final_shape = heatmap.squeeze(2).shape
63
+
64
+ if self.jacobian is not None:
65
+ jacobian_map = self.jacobian(x) ##[4,40,H/4-6, W/4-6]
66
+ jacobian_map = jacobian_map.reshape(final_shape[0], self.num_jacobian_maps, 4, final_shape[2],
67
+ final_shape[3])
68
+ heatmap = heatmap.unsqueeze(2)
69
+
70
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
71
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
72
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
73
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
74
+
75
+ return jacobian
76
+
77
+ def forward(self, x): #torch.Size([4, 3, H, W])
78
+ if self.scale_factor != 1:
79
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
80
+
81
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
82
+ prediction = self.kp(feature_map) #[4,10,H/4-6, W/4-6]
83
+
84
+ final_shape = prediction.shape
85
+
86
+ heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
87
+ heatmap = F.softmax(heatmap / self.temperature, dim=2)
88
+ heatmap = heatmap.view(*final_shape) #[4,10,58,58]
89
+
90
+ out = self.gaussian2kp(heatmap)
91
+ out['heatmap'] = heatmap
92
+
93
+ if self.jacobian is not None:
94
+ jacobian_map = self.jacobian(feature_map) ##[4,40,H/4-6, W/4-6]
95
+ jacobian_map = jacobian_map.reshape(final_shape[0], self.num_jacobian_maps, 4, final_shape[2],
96
+ final_shape[3])
97
+ heatmap = heatmap.unsqueeze(2)
98
+
99
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
100
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
101
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
102
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
103
+ out['jacobian'] = jacobian
104
+
105
+ return out
106
+
107
+
108
+
109
+
110
+ class KPDetector_a(nn.Module):
111
+ """
112
+ Detecting a keypoints. Return keypoint position and jacobian near each keypoint.
113
+ """
114
+
115
+ def __init__(self, block_expansion, num_kp, num_channels,num_channels_a, max_features,
116
+ num_blocks, temperature, estimate_jacobian=False, scale_factor=1,
117
+ single_jacobian_map=False, pad=0):
118
+ super(KPDetector_a, self).__init__()
119
+
120
+ self.predictor = Hourglass(block_expansion, in_features=num_channels_a,
121
+ max_features=max_features, num_blocks=num_blocks)
122
+
123
+ self.kp = nn.Conv2d(in_channels=self.predictor.out_filters, out_channels=num_kp, kernel_size=(7, 7),
124
+ padding=pad)
125
+
126
+ if estimate_jacobian:
127
+ self.num_jacobian_maps = 1 if single_jacobian_map else num_kp
128
+ self.jacobian = nn.Conv2d(in_channels=self.predictor.out_filters,
129
+ out_channels=4 * self.num_jacobian_maps, kernel_size=(7, 7), padding=pad)
130
+ self.jacobian.weight.data.zero_()
131
+ self.jacobian.bias.data.copy_(torch.tensor([1, 0, 0, 1] * self.num_jacobian_maps, dtype=torch.float))
132
+ else:
133
+ self.jacobian = None
134
+
135
+ self.temperature = temperature
136
+ self.scale_factor = scale_factor
137
+ if self.scale_factor != 1:
138
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
139
+
140
+
141
+
142
+
143
+ def gaussian2kp(self, heatmap):
144
+ """
145
+ Extract the mean and from a heatmap
146
+ """
147
+ shape = heatmap.shape
148
+ heatmap = heatmap.unsqueeze(-1) #[4,10,58,58,1]
149
+ grid = make_coordinate_grid(shape[2:], heatmap.type()).unsqueeze_(0).unsqueeze_(0) #[1,1,58,58,2]
150
+ value = (heatmap * grid).sum(dim=(2, 3)) #[4,10,2]
151
+ kp = {'value': value}
152
+
153
+ return kp
154
+
155
+ def audio_feature(self, x, heatmap):
156
+
157
+ # prediction = self.kp(x) #[4,10,H/4-6, W/4-6]
158
+
159
+ # final_shape = prediction.shape
160
+ # heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
161
+ # heatmap = F.softmax(heatmap / self.temperature, dim=2)
162
+ # heatmap = heatmap.view(*final_shape) #[4,10,58,58]
163
+
164
+ # out = self.gaussian2kp(heatmap)
165
+ final_shape = heatmap.squeeze(2).shape
166
+
167
+ if self.jacobian is not None:
168
+ jacobian_map = self.jacobian(x) ##[4,40,H/4-6, W/4-6]
169
+ jacobian_map = jacobian_map.reshape(final_shape[0], self.num_jacobian_maps, 4, final_shape[2],
170
+ final_shape[3])
171
+ heatmap = heatmap.unsqueeze(2)
172
+
173
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
174
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
175
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
176
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
177
+
178
+ return jacobian
179
+
180
+ def forward(self, feature_map): #torch.Size([4, 3, H, W])
181
+
182
+
183
+ prediction = self.kp(feature_map) #[4,10,H/4-6, W/4-6]
184
+
185
+ final_shape = prediction.shape
186
+
187
+ heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
188
+ heatmap = F.softmax(heatmap / self.temperature, dim=2)
189
+ heatmap = heatmap.view(*final_shape) #[4,10,58,58]
190
+
191
+ out = self.gaussian2kp(heatmap)
192
+ out['heatmap'] = heatmap #B,10,58,58
193
+
194
+ if self.jacobian is not None:
195
+ jacobian_map = self.jacobian(feature_map) ##[4,40,H/4-6, W/4-6]
196
+ jacobian_map = jacobian_map.reshape(final_shape[0], self.num_jacobian_maps, 4, final_shape[2],
197
+ final_shape[3])
198
+ heatmap = heatmap.unsqueeze(2)
199
+
200
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
201
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
202
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
203
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
204
+ out['jacobian'] = jacobian #B,10,2,2
205
+
206
+ return out
207
+
208
+
209
+ class Audio_Feature(nn.Module):
210
+ def __init__(self):
211
+ super(Audio_Feature, self).__init__()
212
+
213
+ self.con_encoder = Ct_encoder()
214
+ self.emo_encoder = EmotionNet()
215
+ self.decoder = AF2F_s()
216
+
217
+
218
+
219
+ def forward(self, x):
220
+ x = x.unsqueeze(1)
221
+
222
+ c = self.con_encoder(x)
223
+ e = self.emo_encoder(x)
224
+
225
+ # d = torch.cat([c, e], dim=1)
226
+ d = self.decoder(c)
227
+
228
+
229
+ return d
230
+ '''
231
+ def forward(self, x, cube, audio): #torch.Size([4, 3, H, W])
232
+ if self.scale_factor != 1:
233
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
234
+
235
+ cube = cube.unsqueeze(1)
236
+ feature = torch.cat([x,cube,audio],dim=1)
237
+ feature_map = self.predictor(feature) #[4,3+32,H/4, W/4]
238
+ prediction = self.kp(feature_map) #[4,10,H/4-6, W/4-6]
239
+
240
+ final_shape = prediction.shape
241
+ heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
242
+ heatmap = F.softmax(heatmap / self.temperature, dim=2)
243
+ heatmap = heatmap.view(*final_shape) #[4,10,58,58]
244
+
245
+ out = self.gaussian2kp(heatmap)
246
+ out['heatmap'] = heatmap
247
+ if self.jacobian is not None:
248
+ jacobian_map = self.jacobian(feature_map) ##[4,40,H/4-6, W/4-6]
249
+ jacobian_map = jacobian_map.reshape(final_shape[0], self.num_jacobian_maps, 4, final_shape[2],
250
+ final_shape[3])
251
+ heatmap = heatmap.unsqueeze(2)
252
+
253
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
254
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
255
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
256
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
257
+ out['jacobian'] = jacobian
258
+
259
+ return out
260
+ '''
FONT/modules/model.py ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from modules.util import AntiAliasInterpolation2d, make_coordinate_grid
5
+ from torchvision import models
6
+ import numpy as np
7
+ from torch.autograd import grad
8
+
9
+
10
+ class Vgg19(torch.nn.Module):
11
+ """
12
+ Vgg19 network for perceptual loss. See Sec 3.3.
13
+ """
14
+ def __init__(self, requires_grad=False):
15
+ super(Vgg19, self).__init__()
16
+ vgg_pretrained_features = models.vgg19(pretrained=True).features
17
+ self.slice1 = torch.nn.Sequential()
18
+ self.slice2 = torch.nn.Sequential()
19
+ self.slice3 = torch.nn.Sequential()
20
+ self.slice4 = torch.nn.Sequential()
21
+ self.slice5 = torch.nn.Sequential()
22
+ for x in range(2):
23
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
24
+ for x in range(2, 7):
25
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
26
+ for x in range(7, 12):
27
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
28
+ for x in range(12, 21):
29
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
30
+ for x in range(21, 30):
31
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
32
+
33
+ self.mean = torch.nn.Parameter(data=torch.Tensor(np.array([0.485, 0.456, 0.406]).reshape((1, 3, 1, 1))),
34
+ requires_grad=False)
35
+ self.std = torch.nn.Parameter(data=torch.Tensor(np.array([0.229, 0.224, 0.225]).reshape((1, 3, 1, 1))),
36
+ requires_grad=False)
37
+
38
+ if not requires_grad:
39
+ for param in self.parameters():
40
+ param.requires_grad = False
41
+
42
+ def forward(self, X):
43
+ X = (X - self.mean) / self.std
44
+ h_relu1 = self.slice1(X)
45
+ h_relu2 = self.slice2(h_relu1)
46
+ h_relu3 = self.slice3(h_relu2)
47
+ h_relu4 = self.slice4(h_relu3)
48
+ h_relu5 = self.slice5(h_relu4)
49
+ out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
50
+ return out
51
+
52
+
53
+ class ImagePyramide(torch.nn.Module):
54
+ """
55
+ Create image pyramide for computing pyramide perceptual loss. See Sec 3.3
56
+ """
57
+ def __init__(self, scales, num_channels):
58
+ super(ImagePyramide, self).__init__()
59
+ downs = {}
60
+ for scale in scales:
61
+ downs[str(scale).replace('.', '-')] = AntiAliasInterpolation2d(num_channels, scale)
62
+ self.downs = nn.ModuleDict(downs)
63
+
64
+ def forward(self, x):
65
+ out_dict = {}
66
+ for scale, down_module in self.downs.items():
67
+ out_dict['prediction_' + str(scale).replace('-', '.')] = down_module(x)
68
+ return out_dict
69
+
70
+
71
+ class Transform:
72
+ """
73
+ Random tps transformation for equivariance constraints. See Sec 3.3
74
+ """
75
+ def __init__(self, bs, **kwargs):
76
+ noise = torch.normal(mean=0, std=kwargs['sigma_affine'] * torch.ones([bs, 2, 3]))
77
+ self.theta = noise + torch.eye(2, 3).view(1, 2, 3)
78
+ self.bs = bs
79
+
80
+ if ('sigma_tps' in kwargs) and ('points_tps' in kwargs):
81
+ self.tps = True
82
+ self.control_points = make_coordinate_grid((kwargs['points_tps'], kwargs['points_tps']), type=noise.type())
83
+ self.control_points = self.control_points.unsqueeze(0)
84
+ self.control_params = torch.normal(mean=0,
85
+ std=kwargs['sigma_tps'] * torch.ones([bs, 1, kwargs['points_tps'] ** 2]))
86
+ else:
87
+ self.tps = False
88
+
89
+ def transform_frame(self, frame):
90
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
91
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
92
+ grid = self.warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
93
+ return F.grid_sample(frame, grid, padding_mode="reflection")
94
+
95
+ def inverse_transform_frame(self, frame):
96
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
97
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
98
+ grid = self.inverse_warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
99
+ return F.grid_sample(frame, grid, padding_mode="reflection")
100
+
101
+ def warp_coordinates(self, coordinates):
102
+ theta = self.theta.type(coordinates.type())
103
+ theta = theta.unsqueeze(1)
104
+ transformed = torch.matmul(theta[:, :, :, :2], coordinates.unsqueeze(-1)) + theta[:, :, :, 2:]
105
+ transformed = transformed.squeeze(-1)
106
+
107
+ if self.tps:
108
+ control_points = self.control_points.type(coordinates.type())
109
+ control_params = self.control_params.type(coordinates.type())
110
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
111
+ distances = torch.abs(distances).sum(-1)
112
+
113
+ result = distances ** 2
114
+ result = result * torch.log(distances + 1e-6)
115
+ result = result * control_params
116
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
117
+ transformed = transformed + result
118
+
119
+ return transformed
120
+
121
+ def inverse_warp_coordinates(self, coordinates):
122
+ theta = self.theta.type(coordinates.type())
123
+ theta = theta.unsqueeze(1)
124
+ a = torch.FloatTensor([[[[0,0,1]]]]).repeat([self.bs,1,1,1]).cuda()
125
+ c = torch.cat((theta,a),2)
126
+ d = c.inverse()[:,:,:2,:]
127
+ d = d.type(coordinates.type())
128
+ transformed = torch.matmul(d[:, :, :, :2], coordinates.unsqueeze(-1)) + d[:, :, :, 2:]
129
+ transformed = transformed.squeeze(-1)
130
+
131
+ if self.tps:
132
+ control_points = self.control_points.type(coordinates.type())
133
+ control_params = self.control_params.type(coordinates.type())
134
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
135
+ distances = torch.abs(distances).sum(-1)
136
+
137
+ result = distances ** 2
138
+ result = result * torch.log(distances + 1e-6)
139
+ result = result * control_params
140
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
141
+ transformed = transformed + result
142
+
143
+
144
+ return transformed
145
+
146
+ def jacobian(self, coordinates):
147
+ coordinates.requires_grad=True
148
+ new_coordinates = self.warp_coordinates(coordinates)#[4,10,2]
149
+ grad_x = grad(new_coordinates[..., 0].sum(), coordinates, create_graph=True)
150
+ grad_y = grad(new_coordinates[..., 1].sum(), coordinates, create_graph=True)
151
+ jacobian = torch.cat([grad_x[0].unsqueeze(-2), grad_y[0].unsqueeze(-2)], dim=-2)
152
+ return jacobian
153
+
154
+
155
+ def detach_kp(kp):
156
+ return {key: value.detach() for key, value in kp.items()}
157
+
158
+ class TrainPart1Model(torch.nn.Module):
159
+ """
160
+ Merge all generator related updates into single model for better multi-gpu usage
161
+ """
162
+
163
+ def __init__(self, kp_extractor, kp_extractor_a, audio_feature, generator, discriminator, train_params, device_ids):
164
+ super(TrainPart1Model, self).__init__()
165
+ self.kp_extractor = kp_extractor
166
+ self.kp_extractor_a = kp_extractor_a
167
+
168
+ self.audio_feature = audio_feature
169
+ self.generator = generator
170
+ self.discriminator = discriminator
171
+ self.train_params = train_params
172
+ self.scales = train_params['scales']
173
+ self.disc_scales = self.discriminator.scales
174
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
175
+ if torch.cuda.is_available():
176
+ self.pyramid = self.pyramid.cuda()
177
+
178
+ self.loss_weights = train_params['loss_weights']
179
+
180
+ if sum(self.loss_weights['perceptual']) != 0:
181
+ self.vgg = Vgg19()
182
+ if torch.cuda.is_available():
183
+ self.vgg = self.vgg.cuda()
184
+
185
+
186
+ self.mse_loss_fn = nn.MSELoss().cuda()
187
+ def forward(self, x):
188
+
189
+ kp_source = self.kp_extractor(x['example_image'])
190
+
191
+
192
+ kp_driving = []
193
+ for i in range(16):
194
+ kp_driving.append(self.kp_extractor(x['driving'][:,i]))
195
+
196
+
197
+
198
+ kp_driving_a = [] #x['example_image'],
199
+
200
+
201
+ # print(x['example_image'].shape, x['driving_audio'].shape, x['driving_pose'].shape)
202
+ deco_out = self.audio_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
203
+ loss_values = {}
204
+
205
+ if self.loss_weights['audio'] != 0:
206
+
207
+ kp_driving_a = []
208
+ for i in range(16):
209
+ kp_driving_a.append(self.kp_extractor_a(deco_out[:,i]))#
210
+
211
+
212
+ loss_value = 0
213
+ loss_heatmap = 0
214
+ loss_jacobian = 0
215
+ loss_perceptual = 0
216
+ for i in range(len(kp_driving)):
217
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian']).mean())*self.loss_weights['audio']
218
+
219
+ # loss_jacobian = loss_jacobian*self.loss_weights['audio']
220
+ loss_heatmap += (torch.abs(kp_driving[i]['heatmap'] - kp_driving_a[i]['heatmap']).mean())*self.loss_weights['audio']*100
221
+
222
+
223
+ loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value']).mean())*self.loss_weights['audio']
224
+
225
+ loss_values['loss_value'] = loss_value/len(kp_driving)
226
+ loss_values['loss_heatmap'] = loss_heatmap/len(kp_driving)
227
+ loss_values['loss_jacobian'] = loss_jacobian/len(kp_driving)
228
+
229
+
230
+ if self.train_params['generator'] == 'not':
231
+ # loss_values['perceptual'] = self.mse_loss_fn(deco_out,deco_out)
232
+ for i in range(1): #0,len(kp_driving),4
233
+
234
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving_a[i])
235
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving_a})
236
+
237
+
238
+ elif self.train_params['generator'] == 'visual':
239
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
240
+
241
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving[i])
242
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
243
+
244
+ pyramide_real = self.pyramid(x['driving'][:,i])
245
+ pyramide_generated = self.pyramid(generated['prediction'])
246
+
247
+ if sum(self.loss_weights['perceptual']) != 0:
248
+ value_total = 0
249
+ for scale in self.scales:
250
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
251
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
252
+
253
+ for i, weight in enumerate(self.loss_weights['perceptual']):
254
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
255
+ value_total += self.loss_weights['perceptual'][i] * value
256
+ loss_perceptual += value_total
257
+
258
+ length = int((len(kp_driving)-1)/4)+1
259
+ loss_values['perceptual'] = loss_perceptual/length
260
+ elif self.train_params['generator'] == 'audio':
261
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
262
+
263
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving_a[i])
264
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving_a})
265
+
266
+ pyramide_real = self.pyramid(x['driving'][:,i])
267
+ pyramide_generated = self.pyramid(generated['prediction'])
268
+
269
+ if sum(self.loss_weights['perceptual']) != 0:
270
+ value_total = 0
271
+ for scale in self.scales:
272
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
273
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
274
+
275
+ for i, weight in enumerate(self.loss_weights['perceptual']):
276
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
277
+ value_total += self.loss_weights['perceptual'][i] * value
278
+ loss_perceptual += value_total
279
+
280
+ length = int((len(kp_driving)-1)/4)+1
281
+ loss_values['perceptual'] = loss_perceptual/length
282
+ else:
283
+ print('wrong train_params: ', self.train_params['generator'])
284
+
285
+ return loss_values,generated
286
+
287
+
288
+ class TrainPart2Model(torch.nn.Module):
289
+ """
290
+ Merge all generator related updates into single model for better multi-gpu usage
291
+ """
292
+
293
+ def __init__(self, kp_extractor, emo_feature, kp_extractor_a, audio_feature, generator, discriminator, train_params, device_ids):
294
+ super(TrainPart2Model, self).__init__()
295
+ self.kp_extractor = kp_extractor
296
+ self.kp_extractor_a = kp_extractor_a
297
+
298
+ self.audio_feature = audio_feature
299
+ self.emo_feature = emo_feature
300
+ self.generator = generator
301
+ self.discriminator = discriminator
302
+ self.train_params = train_params
303
+ self.scales = train_params['scales']
304
+ self.disc_scales = self.discriminator.scales
305
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
306
+ if torch.cuda.is_available():
307
+ self.pyramid = self.pyramid.cuda()
308
+
309
+ self.loss_weights = train_params['loss_weights']
310
+
311
+ if sum(self.loss_weights['perceptual']) != 0:
312
+ self.vgg = Vgg19()
313
+ if torch.cuda.is_available():
314
+ self.vgg = self.vgg.cuda()
315
+
316
+ self.mse_loss_fn = nn.MSELoss().cuda()
317
+ self.CroEn_loss = nn.CrossEntropyLoss().cuda()
318
+ def forward(self, x):
319
+
320
+ kp_source = self.kp_extractor(x['example_image'])
321
+
322
+ kp_driving = []
323
+ kp_emo = []
324
+ for i in range(16):
325
+ kp_driving.append(self.kp_extractor(x['driving'][:,i]))
326
+ # kp_emo.append(self.emo_detector(x['driving'][:,i]))
327
+
328
+ kp_driving_a = [] #x['example_image'],
329
+ deco_out = self.audio_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
330
+ # emo_out = self.emo_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
331
+ loss_values = {}
332
+
333
+ if self.loss_weights['emo'] != 0:
334
+
335
+ kp_driving_a = []
336
+ fakes = []
337
+ for i in range(16):
338
+ kp_driving_a.append(self.kp_extractor_a(deco_out[:,i]))#
339
+ value = self.kp_extractor_a(deco_out[:,i])['value']
340
+ jacobian = self.kp_extractor_a(deco_out[:,i])['jacobian']
341
+ if self.train_params['type'] == 'linear_4' :
342
+ out, fake = self.emo_feature(x['transformed_driving'][:,i],value,jacobian)
343
+ kp_emo.append(out)
344
+ fakes.append(fake)
345
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
346
+ elif self.train_params['type'] == 'linear_10':
347
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
348
+
349
+ out, fake = self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian)
350
+ kp_emo.append(out)
351
+ fakes.append(fake)
352
+ elif self.train_params['type'] == 'linear_4_new':
353
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
354
+
355
+ out, fake = self.emo_feature.linear_4(x['transformed_driving'][:,i],value,jacobian)
356
+ kp_emo.append(out)
357
+ fakes.append(fake)
358
+ elif self.train_params['type'] == 'linear_np_4':
359
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
360
+
361
+ out, fake = self.emo_feature.linear_np_4(x['transformed_driving'][:,i],value,jacobian)
362
+ kp_emo.append(out)
363
+ fakes.append(fake)
364
+ elif self.train_params['type'] == 'linear_np_10':
365
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
366
+
367
+ out, fake = self.emo_feature.linear_np_10(x['transformed_driving'][:,i],value,jacobian)
368
+ kp_emo.append(out)
369
+ fakes.append(fake)
370
+
371
+ loss_value = 0
372
+
373
+ loss_jacobian = 0
374
+
375
+ loss_classify = 0
376
+ kp_all = kp_driving_a
377
+
378
+ for i in range(len(kp_driving)):
379
+
380
+ if self.train_params['type'] == 'linear_4' or self.train_params['type'] == 'linear_4_new' or self.train_params['type'] == 'linear_np_4':
381
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,1] - kp_driving_a[i]['jacobian'][:,1] -kp_emo[i]['jacobian'][:,0]).mean())*self.loss_weights['emo']
382
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,4] - kp_driving_a[i]['jacobian'][:,4] -kp_emo[i]['jacobian'][:,1]).mean())*self.loss_weights['emo']
383
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,6] - kp_driving_a[i]['jacobian'][:,6] -kp_emo[i]['jacobian'][:,2]).mean())*self.loss_weights['emo']
384
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,8] - kp_driving_a[i]['jacobian'][:,8] -kp_emo[i]['jacobian'][:,3]).mean())*self.loss_weights['emo']
385
+
386
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
387
+ loss_value += (torch.abs(kp_driving[i]['value'][:,1] .detach() - kp_driving_a[i]['value'][:,1] - kp_emo[i]['value'][:,0] ).mean())*self.loss_weights['emo']
388
+ loss_value += (torch.abs(kp_driving[i]['value'][:,4] .detach() - kp_driving_a[i]['value'][:,4] - kp_emo[i]['value'][:,1] ).mean())*self.loss_weights['emo']
389
+ loss_value += (torch.abs(kp_driving[i]['value'][:,6] .detach() - kp_driving_a[i]['value'][:,6] - kp_emo[i]['value'][:,2] ).mean())*self.loss_weights['emo']
390
+ loss_value += (torch.abs(kp_driving[i]['value'][:,8] .detach() - kp_driving_a[i]['value'][:,8] - kp_emo[i]['value'][:,3] ).mean())*self.loss_weights['emo']
391
+ kp_all[i]['jacobian'][:,1] = kp_emo[i]['jacobian'][:,0] + kp_driving_a[i]['jacobian'][:,1]
392
+ kp_all[i]['jacobian'][:,4] = kp_emo[i]['jacobian'][:,1] + kp_driving_a[i]['jacobian'][:,4]
393
+ kp_all[i]['jacobian'][:,6] = kp_emo[i]['jacobian'][:,2] + kp_driving_a[i]['jacobian'][:,6]
394
+ kp_all[i]['jacobian'][:,8] = kp_emo[i]['jacobian'][:,3] + kp_driving_a[i]['jacobian'][:,8]
395
+ kp_all[i]['value'][:,1] = kp_emo[i]['value'][:,0] + kp_driving_a[i]['value'][:,1]
396
+ kp_all[i]['value'][:,4] = kp_emo[i]['value'][:,1] + kp_driving_a[i]['value'][:,4]
397
+ kp_all[i]['value'][:,6] = kp_emo[i]['value'][:,2] + kp_driving_a[i]['value'][:,6]
398
+ kp_all[i]['value'][:,8] = kp_emo[i]['value'][:,3] + kp_driving_a[i]['value'][:,8]
399
+ elif self.train_params['type'] == 'linear_10' or self.train_params['type'] == 'linear_np_10':
400
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian'] -kp_emo[i]['jacobian']).mean())*self.loss_weights['emo']
401
+
402
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
403
+ loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value'] - kp_emo[i]['value'] ).mean())*self.loss_weights['emo']
404
+
405
+ # kp_all[i]['value'] = kp_emo[i]['value'] + kp_driving_a[i]['value']
406
+
407
+ loss_values['loss_value'] = loss_value/len(kp_driving)
408
+ # loss_values['loss_heatmap'] = loss_heatmap/len(kp_driving)
409
+ loss_values['loss_jacobian'] = loss_jacobian/len(kp_driving)
410
+ if self.train_params['classify'] == True:
411
+ loss_values['loss_classify'] = loss_classify/len(kp_driving)
412
+ else:
413
+ loss_values['loss_classify'] = torch.tensor(0, device = loss_values['loss_value'].device)
414
+
415
+
416
+
417
+
418
+
419
+ return loss_values,generated
420
+
421
+
422
+ class GeneratorFullModel(torch.nn.Module):
423
+ """
424
+ Merge all generator related updates into single model for better multi-gpu usage
425
+ """
426
+
427
+ def __init__(self, kp_extractor, kp_extractor_a, audio_feature, generator, discriminator, train_params):
428
+ super(GeneratorFullModel, self).__init__()
429
+ self.kp_extractor = kp_extractor
430
+ self.kp_extractor_a = kp_extractor_a
431
+ # self.content_encoder = content_encoder
432
+ # self.emotion_encoder = emotion_encoder
433
+ self.audio_feature = audio_feature
434
+ self.generator = generator
435
+ self.discriminator = discriminator
436
+ self.train_params = train_params
437
+ self.scales = train_params['scales']
438
+ self.disc_scales = self.discriminator.scales
439
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
440
+ if torch.cuda.is_available():
441
+ self.pyramid = self.pyramid.cuda()
442
+
443
+ self.loss_weights = train_params['loss_weights']
444
+
445
+ if sum(self.loss_weights['perceptual']) != 0:
446
+ self.vgg = Vgg19()
447
+ if torch.cuda.is_available():
448
+ self.vgg = self.vgg.cuda()
449
+
450
+ self.pca = torch.FloatTensor(np.load('.../LRW/list/U_106.npy'))[:, :16].cuda()
451
+ self.mean = torch.FloatTensor(np.load('.../LRW/list/mean_106.npy')).cuda()
452
+
453
+ def forward(self, x):
454
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
455
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
456
+ # kp_source = self.kp_extractor(x['source'])
457
+ # kp_source_a = self.kp_extractor_a(x['source'], x['source_cube'], source_a_f)
458
+ # driving_a_f = self.audio_feature(self.content_encoder(x['driving_audio'].unsqueeze(1)), self.emotion_encoder(x['driving_audio'].unsqueeze(1)))
459
+ # driving_a_f = self.audio_feature(x['driving_audio'])
460
+ # kp_driving = self.kp_extractor(x['driving'])
461
+ # kp_driving_a = self.kp_extractor_a(x['driving'], x['driving_cube'], driving_a_f)
462
+
463
+ kp_driving = []
464
+ for i in range(16):
465
+ kp_driving.append(self.kp_extractor(x['driving'][:,i],x['driving_landmark'][:,i],self.loss_weights['equivariance_value']))
466
+
467
+ kp_driving_a = []
468
+ fc_out, deco_out = self.audio_feature(x['example_landmark'], x['driving_audio'], x['driving_pose'])
469
+ fake_lmark=fc_out + x['example_landmark'].expand_as(fc_out)
470
+
471
+
472
+ fake_lmark = torch.mm( fake_lmark, self.pca.t() )
473
+ fake_lmark = fake_lmark + self.mean.expand_as(fake_lmark)
474
+
475
+
476
+ fake_lmark = fake_lmark.unsqueeze(0)
477
+
478
+ # for i in range(16):
479
+ # kp_driving_a.append()
480
+
481
+ # generated = self.generator(x['source'], kp_source=kp_source, kp_driving=kp_driving)
482
+ # generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
483
+
484
+ loss_values = {}
485
+
486
+ pyramide_real = self.pyramid(x['driving'])
487
+ pyramide_generated = self.pyramid(generated['prediction'])
488
+
489
+ if self.loss_weights['audio'] != 0:
490
+ value = torch.abs(kp_source['jacobian'].detach() - kp_source_a['jacobian'].detach()).mean() + torch.abs(kp_driving['jacobian'].detach() - kp_driving_a['jacobian']).mean()
491
+ value = value/2
492
+ loss_values['jacobian'] = value*self.loss_weights['audio']
493
+ value = torch.abs(kp_source['heatmap'].detach() - kp_source_a['heatmap'].detach()).mean() + torch.abs(kp_driving['heatmap'].detach() - kp_driving_a['heatmap']).mean()
494
+ value = value/2
495
+ loss_values['heatmap'] = value*self.loss_weights['audio']
496
+ value = torch.abs(kp_source['value'].detach() - kp_source_a['value'].detach()).mean() + torch.abs(kp_driving['value'].detach() - kp_driving_a['value']).mean()
497
+ value = value/2
498
+ loss_values['value'] = value*self.loss_weights['audio']
499
+
500
+ if sum(self.loss_weights['perceptual']) != 0:
501
+ value_total = 0
502
+ for scale in self.scales:
503
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
504
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
505
+
506
+ for i, weight in enumerate(self.loss_weights['perceptual']):
507
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
508
+ value_total += self.loss_weights['perceptual'][i] * value
509
+ loss_values['perceptual'] = value_total
510
+
511
+ if self.loss_weights['generator_gan'] != 0:
512
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
513
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
514
+ value_total = 0
515
+ for scale in self.disc_scales:
516
+ key = 'prediction_map_%s' % scale
517
+ value = ((1 - discriminator_maps_generated[key]) ** 2).mean()
518
+ value_total += self.loss_weights['generator_gan'] * value
519
+ loss_values['gen_gan'] = value_total
520
+
521
+ if sum(self.loss_weights['feature_matching']) != 0:
522
+ value_total = 0
523
+ for scale in self.disc_scales:
524
+ key = 'feature_maps_%s' % scale
525
+ for i, (a, b) in enumerate(zip(discriminator_maps_real[key], discriminator_maps_generated[key])):
526
+ if self.loss_weights['feature_matching'][i] == 0:
527
+ continue
528
+ value = torch.abs(a - b).mean()
529
+ value_total += self.loss_weights['feature_matching'][i] * value
530
+ loss_values['feature_matching'] = value_total
531
+
532
+ if (self.loss_weights['equivariance_value'] + self.loss_weights['equivariance_jacobian']) != 0:
533
+ transform = Transform(x['driving'].shape[0], **self.train_params['transform_params'])
534
+ transformed_frame = transform.transform_frame(x['driving'])
535
+ transformed_landmark = transform.inverse_warp_coordinates(x['driving_landmark'])
536
+ transformed_kp = self.kp_extractor(transformed_frame)
537
+
538
+ generated['transformed_frame'] = transformed_frame
539
+ generated['transformed_kp'] = transformed_kp
540
+
541
+ ## Value loss part
542
+ if self.loss_weights['equivariance_value'] != 0:
543
+ value = torch.abs(kp_driving['value'] - transform.warp_coordinates(transformed_kp['value'])).mean()
544
+ loss_values['equivariance_value'] = self.loss_weights['equivariance_value'] * value
545
+
546
+ ## jacobian loss part
547
+ if self.loss_weights['equivariance_jacobian'] != 0:
548
+ jacobian_transformed = torch.matmul(transform.jacobian(transformed_kp['value']),
549
+ transformed_kp['jacobian'])
550
+
551
+ normed_driving = torch.inverse(kp_driving['jacobian'])
552
+ normed_transformed = jacobian_transformed
553
+ value = torch.matmul(normed_driving, normed_transformed)
554
+
555
+ eye = torch.eye(2).view(1, 1, 2, 2).type(value.type())
556
+
557
+ value = torch.abs(eye - value).mean()
558
+ loss_values['equivariance_jacobian'] = self.loss_weights['equivariance_jacobian'] * value
559
+
560
+ return loss_values, generated
561
+
562
+
563
+ class DiscriminatorFullModel(torch.nn.Module):
564
+ """
565
+ Merge all discriminator related updates into single model for better multi-gpu usage
566
+ """
567
+
568
+ def __init__(self, kp_extractor, generator, discriminator, train_params):
569
+ super(DiscriminatorFullModel, self).__init__()
570
+ self.kp_extractor = kp_extractor
571
+ self.generator = generator
572
+ self.discriminator = discriminator
573
+ self.train_params = train_params
574
+ self.scales = self.discriminator.scales
575
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
576
+ if torch.cuda.is_available():
577
+ self.pyramid = self.pyramid.cuda()
578
+
579
+ self.loss_weights = train_params['loss_weights']
580
+
581
+ def forward(self, x, generated):
582
+ pyramide_real = self.pyramid(x['driving'])
583
+ pyramide_generated = self.pyramid(generated['prediction'].detach())
584
+
585
+ kp_driving = generated['kp_driving']
586
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
587
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
588
+
589
+ loss_values = {}
590
+ value_total = 0
591
+ for scale in self.scales:
592
+ key = 'prediction_map_%s' % scale
593
+ value = (1 - discriminator_maps_real[key]) ** 2 + discriminator_maps_generated[key] ** 2
594
+ value_total += self.loss_weights['discriminator_gan'] * value.mean()
595
+ loss_values['disc_gan'] = value_total
596
+
597
+ return loss_values
FONT/modules/model1.py ADDED
@@ -0,0 +1,539 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from modules.util import AntiAliasInterpolation2d, make_coordinate_grid
5
+ from torchvision import models
6
+ import numpy as np
7
+ from torch.autograd import grad
8
+
9
+
10
+ class Vgg19(torch.nn.Module):
11
+ """
12
+ Vgg19 network for perceptual loss. See Sec 3.3.
13
+ """
14
+ def __init__(self, requires_grad=False):
15
+ super(Vgg19, self).__init__()
16
+ vgg_pretrained_features = models.vgg19(pretrained=True).features
17
+ self.slice1 = torch.nn.Sequential()
18
+ self.slice2 = torch.nn.Sequential()
19
+ self.slice3 = torch.nn.Sequential()
20
+ self.slice4 = torch.nn.Sequential()
21
+ self.slice5 = torch.nn.Sequential()
22
+ for x in range(2):
23
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
24
+ for x in range(2, 7):
25
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
26
+ for x in range(7, 12):
27
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
28
+ for x in range(12, 21):
29
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
30
+ for x in range(21, 30):
31
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
32
+
33
+ self.mean = torch.nn.Parameter(data=torch.Tensor(np.array([0.485, 0.456, 0.406]).reshape((1, 3, 1, 1))),
34
+ requires_grad=False)
35
+ self.std = torch.nn.Parameter(data=torch.Tensor(np.array([0.229, 0.224, 0.225]).reshape((1, 3, 1, 1))),
36
+ requires_grad=False)
37
+
38
+ if not requires_grad:
39
+ for param in self.parameters():
40
+ param.requires_grad = False
41
+
42
+ def forward(self, X):
43
+ X = (X - self.mean) / self.std
44
+ h_relu1 = self.slice1(X)
45
+ h_relu2 = self.slice2(h_relu1)
46
+ h_relu3 = self.slice3(h_relu2)
47
+ h_relu4 = self.slice4(h_relu3)
48
+ h_relu5 = self.slice5(h_relu4)
49
+ out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
50
+ return out
51
+
52
+
53
+ class ImagePyramide(torch.nn.Module):
54
+ """
55
+ Create image pyramide for computing pyramide perceptual loss. See Sec 3.3
56
+ """
57
+ def __init__(self, scales, num_channels):
58
+ super(ImagePyramide, self).__init__()
59
+ downs = {}
60
+ for scale in scales:
61
+ downs[str(scale).replace('.', '-')] = AntiAliasInterpolation2d(num_channels, scale)
62
+ self.downs = nn.ModuleDict(downs)
63
+
64
+ def forward(self, x):
65
+ out_dict = {}
66
+ for scale, down_module in self.downs.items():
67
+ out_dict['prediction_' + str(scale).replace('-', '.')] = down_module(x)
68
+ return out_dict
69
+
70
+
71
+ class Transform:
72
+ """
73
+ Random tps transformation for equivariance constraints. See Sec 3.3
74
+ """
75
+ def __init__(self, bs, **kwargs):
76
+ noise = torch.normal(mean=0, std=kwargs['sigma_affine'] * torch.ones([bs, 2, 3]))
77
+ self.theta = noise + torch.eye(2, 3).view(1, 2, 3)
78
+ self.bs = bs
79
+
80
+ if ('sigma_tps' in kwargs) and ('points_tps' in kwargs):
81
+ self.tps = True
82
+ self.control_points = make_coordinate_grid((kwargs['points_tps'], kwargs['points_tps']), type=noise.type())
83
+ self.control_points = self.control_points.unsqueeze(0)
84
+ self.control_params = torch.normal(mean=0,
85
+ std=kwargs['sigma_tps'] * torch.ones([bs, 1, kwargs['points_tps'] ** 2]))
86
+ else:
87
+ self.tps = False
88
+
89
+ def transform_frame(self, frame):
90
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
91
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
92
+ grid = self.warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
93
+ return F.grid_sample(frame, grid, padding_mode="reflection")
94
+
95
+ def inverse_transform_frame(self, frame):
96
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
97
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
98
+ grid = self.inverse_warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
99
+ return F.grid_sample(frame, grid, padding_mode="reflection")
100
+
101
+ def warp_coordinates(self, coordinates):
102
+ theta = self.theta.type(coordinates.type())
103
+ theta = theta.unsqueeze(1)
104
+ transformed = torch.matmul(theta[:, :, :, :2], coordinates.unsqueeze(-1)) + theta[:, :, :, 2:]
105
+ transformed = transformed.squeeze(-1)
106
+
107
+ if self.tps:
108
+ control_points = self.control_points.type(coordinates.type())
109
+ control_params = self.control_params.type(coordinates.type())
110
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
111
+ distances = torch.abs(distances).sum(-1)
112
+
113
+ result = distances ** 2
114
+ result = result * torch.log(distances + 1e-6)
115
+ result = result * control_params
116
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
117
+ transformed = transformed + result
118
+
119
+ return transformed
120
+
121
+ def inverse_warp_coordinates(self, coordinates):
122
+ theta = self.theta.type(coordinates.type())
123
+ theta = theta.unsqueeze(1)
124
+ a = torch.FloatTensor([[[[0,0,1]]]]).repeat([self.bs,1,1,1]).cuda()
125
+ c = torch.cat((theta,a),2)
126
+ d = c.inverse()[:,:,:2,:]
127
+ d = d.type(coordinates.type())
128
+ transformed = torch.matmul(d[:, :, :, :2], coordinates.unsqueeze(-1)) + d[:, :, :, 2:]
129
+ transformed = transformed.squeeze(-1)
130
+
131
+ if self.tps:
132
+ control_points = self.control_points.type(coordinates.type())
133
+ control_params = self.control_params.type(coordinates.type())
134
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
135
+ distances = torch.abs(distances).sum(-1)
136
+
137
+ result = distances ** 2
138
+ result = result * torch.log(distances + 1e-6)
139
+ result = result * control_params
140
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
141
+ transformed = transformed + result
142
+
143
+
144
+ return transformed
145
+
146
+ def jacobian(self, coordinates):
147
+ coordinates.requires_grad=True
148
+ new_coordinates = self.warp_coordinates(coordinates)#[4,10,2]
149
+ grad_x = grad(new_coordinates[..., 0].sum(), coordinates, create_graph=True)
150
+ grad_y = grad(new_coordinates[..., 1].sum(), coordinates, create_graph=True)
151
+ jacobian = torch.cat([grad_x[0].unsqueeze(-2), grad_y[0].unsqueeze(-2)], dim=-2)
152
+ return jacobian
153
+
154
+
155
+ def detach_kp(kp):
156
+ return {key: value.detach() for key, value in kp.items()}
157
+
158
+ class TrainFullModel(torch.nn.Module):
159
+ """
160
+ Merge all generator related updates into single model for better multi-gpu usage
161
+ """
162
+
163
+ def __init__(self, kp_extractor, emo_feature, kp_extractor_a, audio_feature, generator, discriminator, train_params, device_ids):
164
+ super(TrainFullModel, self).__init__()
165
+ self.kp_extractor = kp_extractor
166
+ self.kp_extractor_a = kp_extractor_a
167
+ # self.emo_detector = emo_detector
168
+ # self.content_encoder = content_encoder
169
+ # self.emotion_encoder = emotion_encoder
170
+ self.audio_feature = audio_feature
171
+ self.emo_feature = emo_feature
172
+ self.generator = generator
173
+ self.discriminator = discriminator
174
+ self.train_params = train_params
175
+ self.scales = train_params['scales']
176
+ self.disc_scales = self.discriminator.scales
177
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
178
+ if torch.cuda.is_available():
179
+ self.pyramid = self.pyramid.cuda()
180
+
181
+ self.loss_weights = train_params['loss_weights']
182
+
183
+ if sum(self.loss_weights['perceptual']) != 0:
184
+ self.vgg = Vgg19()
185
+ if torch.cuda.is_available():
186
+ self.vgg = self.vgg.cuda()
187
+
188
+ # self.pca = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/U_106.npy'))[:, :16].to(device_ids[0])
189
+ # self.mean = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/mean_106.npy')).to(device_ids[0])
190
+ self.mse_loss_fn = nn.MSELoss().cuda()
191
+ self.CroEn_loss = nn.CrossEntropyLoss().cuda()
192
+ def forward(self, x):
193
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
194
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
195
+ kp_source = self.kp_extractor(x['example_image'])
196
+ # print(x['name'],len(x['name']))
197
+ kp_driving = []
198
+ kp_emo = []
199
+ for i in range(16):
200
+ kp_driving.append(self.kp_extractor(x['driving'][:,i]))
201
+ # kp_emo.append(self.emo_detector(x['driving'][:,i]))
202
+ # print('KP_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
203
+ kp_driving_a = [] #x['example_image'],
204
+ deco_out = self.audio_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
205
+ # emo_out = self.emo_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
206
+ loss_values = {}
207
+
208
+ if self.loss_weights['emo'] != 0:
209
+
210
+ kp_driving_a = []
211
+ fakes = []
212
+ for i in range(16):
213
+ kp_driving_a.append(self.kp_extractor_a(deco_out[:,i]))#
214
+ value = self.kp_extractor_a(deco_out[:,i])['value']
215
+ jacobian = self.kp_extractor_a(deco_out[:,i])['jacobian']
216
+ if self.train_params['type'] == 'linear_4' :
217
+ out, fake = self.emo_feature(x['transformed_driving'][:,i],value,jacobian)
218
+ kp_emo.append(out)
219
+ fakes.append(fake)
220
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
221
+ elif self.train_params['type'] == 'linear_10':
222
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
223
+
224
+ out, fake = self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian)
225
+ kp_emo.append(out)
226
+ fakes.append(fake)
227
+ elif self.train_params['type'] == 'linear_4_new':
228
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
229
+
230
+ out, fake = self.emo_feature.linear_4(x['transformed_driving'][:,i],value,jacobian)
231
+ kp_emo.append(out)
232
+ fakes.append(fake)
233
+ elif self.train_params['type'] == 'linear_np_4':
234
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
235
+
236
+ out, fake = self.emo_feature.linear_np_4(x['transformed_driving'][:,i],value,jacobian)
237
+ kp_emo.append(out)
238
+ fakes.append(fake)
239
+ elif self.train_params['type'] == 'linear_np_10':
240
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
241
+
242
+ out, fake = self.emo_feature.linear_np_10(x['transformed_driving'][:,i],value,jacobian)
243
+ kp_emo.append(out)
244
+ fakes.append(fake)
245
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
246
+ # print('Kp_audio_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
247
+ loss_value = 0
248
+ # loss_heatmap = 0
249
+ loss_jacobian = 0
250
+ loss_perceptual = 0
251
+ loss_classify = 0
252
+ kp_all = kp_driving_a
253
+ if self.train_params['smooth'] == True:
254
+ value_all = torch.randn(len(kp_driving),out['value'].shape[0],out['value'].shape[1],out['value'].shape[2]).cuda()
255
+ jacobian_all = torch.randn(len(kp_driving),out['jacobian'].shape[0],out['jacobian'].shape[1],2,2).cuda()
256
+ print(len(kp_driving))
257
+ for i in range(len(kp_driving)):
258
+ # if x['name'][i] == 'LRW':
259
+ # loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian']).mean())*self.loss_weights['emo']
260
+
261
+ # loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value']).mean())*self.loss_weights['emo']
262
+ # loss_classify += self.mse_loss_fn(deco_out,deco_out)
263
+ if self.train_params['type'] == 'linear_4' or self.train_params['type'] == 'linear_4_new' or self.train_params['type'] == 'linear_np_4':
264
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,1] - kp_driving_a[i]['jacobian'][:,1] -kp_emo[i]['jacobian'][:,0]).mean())*self.loss_weights['emo']
265
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,4] - kp_driving_a[i]['jacobian'][:,4] -kp_emo[i]['jacobian'][:,1]).mean())*self.loss_weights['emo']
266
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,6] - kp_driving_a[i]['jacobian'][:,6] -kp_emo[i]['jacobian'][:,2]).mean())*self.loss_weights['emo']
267
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,8] - kp_driving_a[i]['jacobian'][:,8] -kp_emo[i]['jacobian'][:,3]).mean())*self.loss_weights['emo']
268
+
269
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
270
+ loss_value += (torch.abs(kp_driving[i]['value'][:,1] .detach() - kp_driving_a[i]['value'][:,1] - kp_emo[i]['value'][:,0] ).mean())*self.loss_weights['emo']
271
+ loss_value += (torch.abs(kp_driving[i]['value'][:,4] .detach() - kp_driving_a[i]['value'][:,4] - kp_emo[i]['value'][:,1] ).mean())*self.loss_weights['emo']
272
+ loss_value += (torch.abs(kp_driving[i]['value'][:,6] .detach() - kp_driving_a[i]['value'][:,6] - kp_emo[i]['value'][:,2] ).mean())*self.loss_weights['emo']
273
+ loss_value += (torch.abs(kp_driving[i]['value'][:,8] .detach() - kp_driving_a[i]['value'][:,8] - kp_emo[i]['value'][:,3] ).mean())*self.loss_weights['emo']
274
+ kp_all[i]['jacobian'][:,1] = kp_emo[i]['jacobian'][:,0] + kp_driving_a[i]['jacobian'][:,1]
275
+ kp_all[i]['jacobian'][:,4] = kp_emo[i]['jacobian'][:,1] + kp_driving_a[i]['jacobian'][:,4]
276
+ kp_all[i]['jacobian'][:,6] = kp_emo[i]['jacobian'][:,2] + kp_driving_a[i]['jacobian'][:,6]
277
+ kp_all[i]['jacobian'][:,8] = kp_emo[i]['jacobian'][:,3] + kp_driving_a[i]['jacobian'][:,8]
278
+ kp_all[i]['value'][:,1] = kp_emo[i]['value'][:,0] + kp_driving_a[i]['value'][:,1]
279
+ kp_all[i]['value'][:,4] = kp_emo[i]['value'][:,1] + kp_driving_a[i]['value'][:,4]
280
+ kp_all[i]['value'][:,6] = kp_emo[i]['value'][:,2] + kp_driving_a[i]['value'][:,6]
281
+ kp_all[i]['value'][:,8] = kp_emo[i]['value'][:,3] + kp_driving_a[i]['value'][:,8]
282
+ elif self.train_params['type'] == 'linear_10' or self.train_params['type'] == 'linear_np_10':
283
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian'] -kp_emo[i]['jacobian']).mean())*self.loss_weights['emo']
284
+
285
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
286
+ loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value'] - kp_emo[i]['value'] ).mean())*self.loss_weights['emo']
287
+ if self.train_params['smooth'] == True:
288
+ value_all[i]=kp_emo[i]['value']
289
+ jacobian_all[i] = kp_emo[i]['jacobian']
290
+
291
+ # kp_all[i]['value'] = kp_emo[i]['value'] + kp_driving_a[i]['value']
292
+
293
+ loss_values['loss_value'] = loss_value/len(kp_driving)
294
+ # loss_values['loss_heatmap'] = loss_heatmap/len(kp_driving)
295
+ loss_values['loss_jacobian'] = loss_jacobian/len(kp_driving)
296
+ if self.train_params['classify'] == True:
297
+ loss_values['loss_classify'] = loss_classify/len(kp_driving)
298
+ else:
299
+ loss_values['loss_classify'] = self.mse_loss_fn(deco_out,deco_out)
300
+ if self.train_params['smooth'] == True:
301
+ loss_smooth = 0
302
+ loss_smooth += (torch.abs(value_all[2:,:,:,:] + value_all[:-2,:,:,:].detach() -2*value_all[1:-1,:,:,:].detach()).mean())*self.loss_weights['emo'] *100
303
+ loss_smooth += (torch.abs(jacobian_all[2:,:,:,:] + jacobian_all[:-2,:,:,:].detach() -2*jacobian_all[1:-1,:,:,:].detach()).mean())*self.loss_weights['emo'] *100
304
+ loss_values['loss_smooth'] = loss_smooth/len(kp_driving)
305
+ else:
306
+ loss_values['loss_smooth'] = self.mse_loss_fn(deco_out,deco_out)
307
+ if self.train_params['generator'] == 'not':
308
+ loss_values['perceptual'] = self.mse_loss_fn(deco_out,deco_out)
309
+ for i in range(1): #0,len(kp_driving),4
310
+
311
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_all[i])
312
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_all})
313
+ elif self.train_params['generator'] == 'visual':
314
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
315
+
316
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving[i])
317
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
318
+
319
+ pyramide_real = self.pyramid(x['driving'][:,i])
320
+ pyramide_generated = self.pyramid(generated['prediction'])
321
+
322
+ if sum(self.loss_weights['perceptual']) != 0:
323
+ value_total = 0
324
+ for scale in self.scales:
325
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
326
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
327
+
328
+ for i, weight in enumerate(self.loss_weights['perceptual']):
329
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
330
+ value_total += self.loss_weights['perceptual'][i] * value
331
+ loss_perceptual += value_total
332
+
333
+ length = int((len(kp_driving)-1)/4)+1
334
+ loss_values['perceptual'] = loss_perceptual/length
335
+ elif self.train_params['generator'] == 'audio':
336
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
337
+
338
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_all[i])
339
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_all})
340
+
341
+ pyramide_real = self.pyramid(x['driving'][:,i])
342
+ pyramide_generated = self.pyramid(generated['prediction'])
343
+
344
+ if sum(self.loss_weights['perceptual']) != 0:
345
+ value_total = 0
346
+ for scale in self.scales:
347
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
348
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
349
+
350
+ for i, weight in enumerate(self.loss_weights['perceptual']):
351
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
352
+ value_total += self.loss_weights['perceptual'][i] * value
353
+ loss_perceptual += value_total
354
+
355
+ length = int((len(kp_driving)-1)/4)+1
356
+ loss_values['perceptual'] = loss_perceptual/length
357
+ else:
358
+ print('wrong train_params: ', self.train_params['generator'])
359
+
360
+
361
+
362
+ return loss_values,generated
363
+
364
+ class GeneratorFullModel(torch.nn.Module):
365
+ """
366
+ Merge all generator related updates into single model for better multi-gpu usage
367
+ """
368
+
369
+ def __init__(self, kp_extractor, kp_extractor_a, audio_feature, generator, discriminator, train_params):
370
+ super(GeneratorFullModel, self).__init__()
371
+ self.kp_extractor = kp_extractor
372
+ self.kp_extractor_a = kp_extractor_a
373
+ # self.content_encoder = content_encoder
374
+ # self.emotion_encoder = emotion_encoder
375
+ self.audio_feature = audio_feature
376
+ self.generator = generator
377
+ self.discriminator = discriminator
378
+ self.train_params = train_params
379
+ self.scales = train_params['scales']
380
+ self.disc_scales = self.discriminator.scales
381
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
382
+ if torch.cuda.is_available():
383
+ self.pyramid = self.pyramid.cuda()
384
+
385
+ self.loss_weights = train_params['loss_weights']
386
+
387
+ if sum(self.loss_weights['perceptual']) != 0:
388
+ self.vgg = Vgg19()
389
+ if torch.cuda.is_available():
390
+ self.vgg = self.vgg.cuda()
391
+
392
+ self.pca = torch.FloatTensor(np.load('.../LRW/list/U_106.npy'))[:, :16].cuda()
393
+ self.mean = torch.FloatTensor(np.load('.../LRW/list/mean_106.npy')).cuda()
394
+
395
+ def forward(self, x):
396
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
397
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
398
+ # kp_source = self.kp_extractor(x['source'])
399
+ # kp_source_a = self.kp_extractor_a(x['source'], x['source_cube'], source_a_f)
400
+ # driving_a_f = self.audio_feature(self.content_encoder(x['driving_audio'].unsqueeze(1)), self.emotion_encoder(x['driving_audio'].unsqueeze(1)))
401
+ # driving_a_f = self.audio_feature(x['driving_audio'])
402
+ # kp_driving = self.kp_extractor(x['driving'])
403
+ # kp_driving_a = self.kp_extractor_a(x['driving'], x['driving_cube'], driving_a_f)
404
+
405
+ kp_driving = []
406
+ for i in range(16):
407
+ kp_driving.append(self.kp_extractor(x['driving'][:,i],x['driving_landmark'][:,i],self.loss_weights['equivariance_value']))
408
+
409
+ kp_driving_a = []
410
+ fc_out, deco_out = self.audio_feature(x['example_landmark'], x['driving_audio'], x['driving_pose'])
411
+ fake_lmark=fc_out + x['example_landmark'].expand_as(fc_out)
412
+
413
+
414
+ fake_lmark = torch.mm( fake_lmark, self.pca.t() )
415
+ fake_lmark = fake_lmark + self.mean.expand_as(fake_lmark)
416
+
417
+
418
+ fake_lmark = fake_lmark.unsqueeze(0)
419
+
420
+ # for i in range(16):
421
+ # kp_driving_a.append()
422
+
423
+ # generated = self.generator(x['source'], kp_source=kp_source, kp_driving=kp_driving)
424
+ # generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
425
+
426
+ loss_values = {}
427
+
428
+ pyramide_real = self.pyramid(x['driving'])
429
+ pyramide_generated = self.pyramid(generated['prediction'])
430
+
431
+ if self.loss_weights['audio'] != 0:
432
+ value = torch.abs(kp_source['jacobian'].detach() - kp_source_a['jacobian'].detach()).mean() + torch.abs(kp_driving['jacobian'].detach() - kp_driving_a['jacobian']).mean()
433
+ value = value/2
434
+ loss_values['jacobian'] = value*self.loss_weights['audio']
435
+ value = torch.abs(kp_source['heatmap'].detach() - kp_source_a['heatmap'].detach()).mean() + torch.abs(kp_driving['heatmap'].detach() - kp_driving_a['heatmap']).mean()
436
+ value = value/2
437
+ loss_values['heatmap'] = value*self.loss_weights['audio']
438
+ value = torch.abs(kp_source['value'].detach() - kp_source_a['value'].detach()).mean() + torch.abs(kp_driving['value'].detach() - kp_driving_a['value']).mean()
439
+ value = value/2
440
+ loss_values['value'] = value*self.loss_weights['audio']
441
+
442
+ if sum(self.loss_weights['perceptual']) != 0:
443
+ value_total = 0
444
+ for scale in self.scales:
445
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
446
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
447
+
448
+ for i, weight in enumerate(self.loss_weights['perceptual']):
449
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
450
+ value_total += self.loss_weights['perceptual'][i] * value
451
+ loss_values['perceptual'] = value_total
452
+
453
+ if self.loss_weights['generator_gan'] != 0:
454
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
455
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
456
+ value_total = 0
457
+ for scale in self.disc_scales:
458
+ key = 'prediction_map_%s' % scale
459
+ value = ((1 - discriminator_maps_generated[key]) ** 2).mean()
460
+ value_total += self.loss_weights['generator_gan'] * value
461
+ loss_values['gen_gan'] = value_total
462
+
463
+ if sum(self.loss_weights['feature_matching']) != 0:
464
+ value_total = 0
465
+ for scale in self.disc_scales:
466
+ key = 'feature_maps_%s' % scale
467
+ for i, (a, b) in enumerate(zip(discriminator_maps_real[key], discriminator_maps_generated[key])):
468
+ if self.loss_weights['feature_matching'][i] == 0:
469
+ continue
470
+ value = torch.abs(a - b).mean()
471
+ value_total += self.loss_weights['feature_matching'][i] * value
472
+ loss_values['feature_matching'] = value_total
473
+
474
+ if (self.loss_weights['equivariance_value'] + self.loss_weights['equivariance_jacobian']) != 0:
475
+ transform = Transform(x['driving'].shape[0], **self.train_params['transform_params'])
476
+ transformed_frame = transform.transform_frame(x['driving'])
477
+ transformed_landmark = transform.inverse_warp_coordinates(x['driving_landmark'])
478
+ transformed_kp = self.kp_extractor(transformed_frame)
479
+
480
+ generated['transformed_frame'] = transformed_frame
481
+ generated['transformed_kp'] = transformed_kp
482
+
483
+ ## Value loss part
484
+ if self.loss_weights['equivariance_value'] != 0:
485
+ value = torch.abs(kp_driving['value'] - transform.warp_coordinates(transformed_kp['value'])).mean()
486
+ loss_values['equivariance_value'] = self.loss_weights['equivariance_value'] * value
487
+
488
+ ## jacobian loss part
489
+ if self.loss_weights['equivariance_jacobian'] != 0:
490
+ jacobian_transformed = torch.matmul(transform.jacobian(transformed_kp['value']),
491
+ transformed_kp['jacobian'])
492
+
493
+ normed_driving = torch.inverse(kp_driving['jacobian'])
494
+ normed_transformed = jacobian_transformed
495
+ value = torch.matmul(normed_driving, normed_transformed)
496
+
497
+ eye = torch.eye(2).view(1, 1, 2, 2).type(value.type())
498
+
499
+ value = torch.abs(eye - value).mean()
500
+ loss_values['equivariance_jacobian'] = self.loss_weights['equivariance_jacobian'] * value
501
+
502
+ return loss_values, generated
503
+
504
+
505
+ class DiscriminatorFullModel(torch.nn.Module):
506
+ """
507
+ Merge all discriminator related updates into single model for better multi-gpu usage
508
+ """
509
+
510
+ def __init__(self, kp_extractor, generator, discriminator, train_params):
511
+ super(DiscriminatorFullModel, self).__init__()
512
+ self.kp_extractor = kp_extractor
513
+ self.generator = generator
514
+ self.discriminator = discriminator
515
+ self.train_params = train_params
516
+ self.scales = self.discriminator.scales
517
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
518
+ if torch.cuda.is_available():
519
+ self.pyramid = self.pyramid.cuda()
520
+
521
+ self.loss_weights = train_params['loss_weights']
522
+
523
+ def forward(self, x, generated):
524
+ pyramide_real = self.pyramid(x['driving'])
525
+ pyramide_generated = self.pyramid(generated['prediction'].detach())
526
+
527
+ kp_driving = generated['kp_driving']
528
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
529
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
530
+
531
+ loss_values = {}
532
+ value_total = 0
533
+ for scale in self.scales:
534
+ key = 'prediction_map_%s' % scale
535
+ value = (1 - discriminator_maps_real[key]) ** 2 + discriminator_maps_generated[key] ** 2
536
+ value_total += self.loss_weights['discriminator_gan'] * value.mean()
537
+ loss_values['disc_gan'] = value_total
538
+
539
+ return loss_values
FONT/modules/model_delta_map.py ADDED
@@ -0,0 +1,500 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from modules.util import AntiAliasInterpolation2d, make_coordinate_grid
5
+ from torchvision import models
6
+ import numpy as np
7
+ from torch.autograd import grad
8
+
9
+
10
+ class Vgg19(torch.nn.Module):
11
+ """
12
+ Vgg19 network for perceptual loss. See Sec 3.3.
13
+ """
14
+ def __init__(self, requires_grad=False):
15
+ super(Vgg19, self).__init__()
16
+ vgg_pretrained_features = models.vgg19(pretrained=True).features
17
+ self.slice1 = torch.nn.Sequential()
18
+ self.slice2 = torch.nn.Sequential()
19
+ self.slice3 = torch.nn.Sequential()
20
+ self.slice4 = torch.nn.Sequential()
21
+ self.slice5 = torch.nn.Sequential()
22
+ for x in range(2):
23
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
24
+ for x in range(2, 7):
25
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
26
+ for x in range(7, 12):
27
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
28
+ for x in range(12, 21):
29
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
30
+ for x in range(21, 30):
31
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
32
+
33
+ self.mean = torch.nn.Parameter(data=torch.Tensor(np.array([0.485, 0.456, 0.406]).reshape((1, 3, 1, 1))),
34
+ requires_grad=False)
35
+ self.std = torch.nn.Parameter(data=torch.Tensor(np.array([0.229, 0.224, 0.225]).reshape((1, 3, 1, 1))),
36
+ requires_grad=False)
37
+
38
+ if not requires_grad:
39
+ for param in self.parameters():
40
+ param.requires_grad = False
41
+
42
+ def forward(self, X):
43
+ X = (X - self.mean) / self.std
44
+ h_relu1 = self.slice1(X)
45
+ h_relu2 = self.slice2(h_relu1)
46
+ h_relu3 = self.slice3(h_relu2)
47
+ h_relu4 = self.slice4(h_relu3)
48
+ h_relu5 = self.slice5(h_relu4)
49
+ out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
50
+ return out
51
+
52
+
53
+ class ImagePyramide(torch.nn.Module):
54
+ """
55
+ Create image pyramide for computing pyramide perceptual loss. See Sec 3.3
56
+ """
57
+ def __init__(self, scales, num_channels):
58
+ super(ImagePyramide, self).__init__()
59
+ downs = {}
60
+ for scale in scales:
61
+ downs[str(scale).replace('.', '-')] = AntiAliasInterpolation2d(num_channels, scale)
62
+ self.downs = nn.ModuleDict(downs)
63
+
64
+ def forward(self, x):
65
+ out_dict = {}
66
+ for scale, down_module in self.downs.items():
67
+ out_dict['prediction_' + str(scale).replace('-', '.')] = down_module(x)
68
+ return out_dict
69
+
70
+
71
+ class Transform:
72
+ """
73
+ Random tps transformation for equivariance constraints. See Sec 3.3
74
+ """
75
+ def __init__(self, bs, **kwargs):
76
+ noise = torch.normal(mean=0, std=kwargs['sigma_affine'] * torch.ones([bs, 2, 3]))
77
+ self.theta = noise + torch.eye(2, 3).view(1, 2, 3)
78
+ self.bs = bs
79
+
80
+ if ('sigma_tps' in kwargs) and ('points_tps' in kwargs):
81
+ self.tps = True
82
+ self.control_points = make_coordinate_grid((kwargs['points_tps'], kwargs['points_tps']), type=noise.type())
83
+ self.control_points = self.control_points.unsqueeze(0)
84
+ self.control_params = torch.normal(mean=0,
85
+ std=kwargs['sigma_tps'] * torch.ones([bs, 1, kwargs['points_tps'] ** 2]))
86
+ else:
87
+ self.tps = False
88
+
89
+ def transform_frame(self, frame):
90
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
91
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
92
+ grid = self.warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
93
+ return F.grid_sample(frame, grid, padding_mode="reflection")
94
+
95
+ def inverse_transform_frame(self, frame):
96
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
97
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
98
+ grid = self.inverse_warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
99
+ return F.grid_sample(frame, grid, padding_mode="reflection")
100
+
101
+ def warp_coordinates(self, coordinates):
102
+ theta = self.theta.type(coordinates.type())
103
+ theta = theta.unsqueeze(1)
104
+ transformed = torch.matmul(theta[:, :, :, :2], coordinates.unsqueeze(-1)) + theta[:, :, :, 2:]
105
+ transformed = transformed.squeeze(-1)
106
+
107
+ if self.tps:
108
+ control_points = self.control_points.type(coordinates.type())
109
+ control_params = self.control_params.type(coordinates.type())
110
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
111
+ distances = torch.abs(distances).sum(-1)
112
+
113
+ result = distances ** 2
114
+ result = result * torch.log(distances + 1e-6)
115
+ result = result * control_params
116
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
117
+ transformed = transformed + result
118
+
119
+ return transformed
120
+
121
+ def inverse_warp_coordinates(self, coordinates):
122
+ theta = self.theta.type(coordinates.type())
123
+ theta = theta.unsqueeze(1)
124
+ a = torch.FloatTensor([[[[0,0,1]]]]).repeat([self.bs,1,1,1]).cuda()
125
+ c = torch.cat((theta,a),2)
126
+ d = c.inverse()[:,:,:2,:]
127
+ d = d.type(coordinates.type())
128
+ transformed = torch.matmul(d[:, :, :, :2], coordinates.unsqueeze(-1)) + d[:, :, :, 2:]
129
+ transformed = transformed.squeeze(-1)
130
+
131
+ if self.tps:
132
+ control_points = self.control_points.type(coordinates.type())
133
+ control_params = self.control_params.type(coordinates.type())
134
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
135
+ distances = torch.abs(distances).sum(-1)
136
+
137
+ result = distances ** 2
138
+ result = result * torch.log(distances + 1e-6)
139
+ result = result * control_params
140
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
141
+ transformed = transformed + result
142
+
143
+
144
+ return transformed
145
+
146
+ def jacobian(self, coordinates):
147
+ coordinates.requires_grad=True
148
+ new_coordinates = self.warp_coordinates(coordinates)#[4,10,2]
149
+ grad_x = grad(new_coordinates[..., 0].sum(), coordinates, create_graph=True)
150
+ grad_y = grad(new_coordinates[..., 1].sum(), coordinates, create_graph=True)
151
+ jacobian = torch.cat([grad_x[0].unsqueeze(-2), grad_y[0].unsqueeze(-2)], dim=-2)
152
+ return jacobian
153
+
154
+
155
+ def detach_kp(kp):
156
+ return {key: value.detach() for key, value in kp.items()}
157
+
158
+ class TrainFullModel(torch.nn.Module):
159
+ """
160
+ Merge all generator related updates into single model for better multi-gpu usage
161
+ """
162
+
163
+ def __init__(self, kp_extractor, emo_feature, kp_extractor_a, audio_feature, generator, discriminator, train_params, device_ids):
164
+ super(TrainFullModel, self).__init__()
165
+ self.kp_extractor = kp_extractor
166
+ self.kp_extractor_a = kp_extractor_a
167
+ # self.emo_detector = emo_detector
168
+ # self.content_encoder = content_encoder
169
+ # self.emotion_encoder = emotion_encoder
170
+ self.audio_feature = audio_feature
171
+ self.emo_feature = emo_feature
172
+ self.generator = generator
173
+ self.discriminator = discriminator
174
+ self.train_params = train_params
175
+ self.scales = train_params['scales']
176
+ self.disc_scales = self.discriminator.scales
177
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
178
+ if torch.cuda.is_available():
179
+ self.pyramid = self.pyramid.cuda()
180
+
181
+ self.loss_weights = train_params['loss_weights']
182
+
183
+ if sum(self.loss_weights['perceptual']) != 0:
184
+ self.vgg = Vgg19()
185
+ if torch.cuda.is_available():
186
+ self.vgg = self.vgg.cuda()
187
+
188
+ # self.pca = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/U_106.npy'))[:, :16].to(device_ids[0])
189
+ # self.mean = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/mean_106.npy')).to(device_ids[0])
190
+ self.mse_loss_fn = nn.MSELoss().cuda()
191
+ self.CroEn_loss = nn.CrossEntropyLoss().cuda()
192
+ def forward(self, x):
193
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
194
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
195
+ kp_source = self.kp_extractor(x['example_image'])
196
+
197
+ kp_driving = []
198
+ kp_emo = []
199
+ for i in range(16):
200
+ kp_driving.append(self.kp_extractor(x['driving'][:,i]))
201
+ # kp_emo.append(self.emo_detector(x['driving'][:,i]))
202
+ # print('KP_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
203
+ kp_driving_a = [] #x['example_image'],
204
+ deco_out = self.audio_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
205
+ # emo_out = self.emo_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
206
+ loss_values = {}
207
+
208
+ if self.loss_weights['emo'] != 0:
209
+
210
+ kp_driving_a = []
211
+ fakes = []
212
+ for i in range(16):
213
+ kp_driving_a.append(self.kp_extractor_a(deco_out[:,i]))#
214
+ value = self.kp_extractor_a(deco_out[:,i])['value']
215
+ jacobian = self.kp_extractor_a(deco_out[:,i])['jacobian']
216
+ if self.train_params['type'] == 'map_4':
217
+ out, fake = self.emo_feature.map_4(x['transformed_driving'][:,i],value,jacobian)
218
+ kp_emo.append(out)
219
+ fakes.append(fake)
220
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
221
+ elif self.train_params['type'] == 'map_10':
222
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
223
+
224
+ out, fake = self.emo_feature(x['transformed_driving'][:,i],value,jacobian)
225
+ kp_emo.append(out)
226
+ fakes.append(fake)
227
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
228
+ # print('Kp_audio_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
229
+ loss_value = 0
230
+ # loss_heatmap = 0
231
+ loss_jacobian = 0
232
+ loss_perceptual = 0
233
+ loss_classify = 0
234
+ kp_all = kp_driving_a
235
+ for i in range(len(kp_driving)):
236
+ if self.train_params['type'] == 'map_4':
237
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,1] - kp_driving_a[i]['jacobian'][:,1] -kp_emo[i]['jacobian'][:,0]).mean())*self.loss_weights['emo']
238
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,4] - kp_driving_a[i]['jacobian'][:,4] -kp_emo[i]['jacobian'][:,1]).mean())*self.loss_weights['emo']
239
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,6] - kp_driving_a[i]['jacobian'][:,6] -kp_emo[i]['jacobian'][:,2]).mean())*self.loss_weights['emo']
240
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'][:,8] - kp_driving_a[i]['jacobian'][:,8] -kp_emo[i]['jacobian'][:,3]).mean())*self.loss_weights['emo']
241
+
242
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
243
+ loss_value += (torch.abs(kp_driving[i]['value'][:,1] .detach() - kp_driving_a[i]['value'][:,1] - kp_emo[i]['value'][:,0] ).mean())*self.loss_weights['emo']
244
+ loss_value += (torch.abs(kp_driving[i]['value'][:,4] .detach() - kp_driving_a[i]['value'][:,4] - kp_emo[i]['value'][:,1] ).mean())*self.loss_weights['emo']
245
+ loss_value += (torch.abs(kp_driving[i]['value'][:,6] .detach() - kp_driving_a[i]['value'][:,6] - kp_emo[i]['value'][:,2] ).mean())*self.loss_weights['emo']
246
+ loss_value += (torch.abs(kp_driving[i]['value'][:,8] .detach() - kp_driving_a[i]['value'][:,8] - kp_emo[i]['value'][:,3] ).mean())*self.loss_weights['emo']
247
+ kp_all[i]['jacobian'][:,1] = kp_emo[i]['jacobian'][:,0] + kp_driving_a[i]['jacobian'][:,1]
248
+ kp_all[i]['jacobian'][:,4] = kp_emo[i]['jacobian'][:,1] + kp_driving_a[i]['jacobian'][:,4]
249
+ kp_all[i]['jacobian'][:,6] = kp_emo[i]['jacobian'][:,2] + kp_driving_a[i]['jacobian'][:,6]
250
+ kp_all[i]['jacobian'][:,8] = kp_emo[i]['jacobian'][:,3] + kp_driving_a[i]['jacobian'][:,8]
251
+ kp_all[i]['value'][:,1] = kp_emo[i]['value'][:,0] + kp_driving_a[i]['value'][:,1]
252
+ kp_all[i]['value'][:,4] = kp_emo[i]['value'][:,1] + kp_driving_a[i]['value'][:,4]
253
+ kp_all[i]['value'][:,6] = kp_emo[i]['value'][:,2] + kp_driving_a[i]['value'][:,6]
254
+ kp_all[i]['value'][:,8] = kp_emo[i]['value'][:,3] + kp_driving_a[i]['value'][:,8]
255
+ elif self.train_params['type'] == 'map_10':
256
+ loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian'] -kp_emo[i]['jacobian']).mean())*self.loss_weights['emo']
257
+
258
+ loss_classify += self.CroEn_loss(fakes[i],x['emotion'])
259
+ loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value'] - kp_emo[i]['value'] ).mean())*self.loss_weights['emo']
260
+
261
+ # kp_all[i]['value'] = kp_emo[i]['value'] + kp_driving_a[i]['value']
262
+
263
+ loss_values['loss_value'] = loss_value/len(kp_driving)
264
+ # loss_values['loss_heatmap'] = loss_heatmap/len(kp_driving)
265
+ loss_values['loss_jacobian'] = loss_jacobian/len(kp_driving)
266
+ loss_values['loss_classify'] = loss_classify/len(kp_driving)
267
+
268
+ if self.train_params['generator'] == 'not':
269
+ loss_values['perceptual'] = self.mse_loss_fn(deco_out,deco_out)
270
+ for i in range(1): #0,len(kp_driving),4
271
+
272
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_all[i])
273
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_all})
274
+ elif self.train_params['generator'] == 'visual':
275
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
276
+
277
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving[i])
278
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
279
+
280
+ pyramide_real = self.pyramid(x['driving'][:,i])
281
+ pyramide_generated = self.pyramid(generated['prediction'])
282
+
283
+ if sum(self.loss_weights['perceptual']) != 0:
284
+ value_total = 0
285
+ for scale in self.scales:
286
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
287
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
288
+
289
+ for i, weight in enumerate(self.loss_weights['perceptual']):
290
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
291
+ value_total += self.loss_weights['perceptual'][i] * value
292
+ loss_perceptual += value_total
293
+
294
+ length = int((len(kp_driving)-1)/4)+1
295
+ loss_values['perceptual'] = loss_perceptual/length
296
+ elif self.train_params['generator'] == 'audio':
297
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
298
+
299
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving_a[i])
300
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving_a})
301
+
302
+ pyramide_real = self.pyramid(x['driving'][:,i])
303
+ pyramide_generated = self.pyramid(generated['prediction'])
304
+
305
+ if sum(self.loss_weights['perceptual']) != 0:
306
+ value_total = 0
307
+ for scale in self.scales:
308
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
309
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
310
+
311
+ for i, weight in enumerate(self.loss_weights['perceptual']):
312
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
313
+ value_total += self.loss_weights['perceptual'][i] * value
314
+ loss_perceptual += value_total
315
+
316
+ length = int((len(kp_driving)-1)/4)+1
317
+ loss_values['perceptual'] = loss_perceptual/length
318
+ else:
319
+ print('wrong train_params: ', self.train_params['generator'])
320
+
321
+
322
+
323
+ return loss_values,generated
324
+
325
+ class GeneratorFullModel(torch.nn.Module):
326
+ """
327
+ Merge all generator related updates into single model for better multi-gpu usage
328
+ """
329
+
330
+ def __init__(self, kp_extractor, kp_extractor_a, audio_feature, generator, discriminator, train_params):
331
+ super(GeneratorFullModel, self).__init__()
332
+ self.kp_extractor = kp_extractor
333
+ self.kp_extractor_a = kp_extractor_a
334
+ # self.content_encoder = content_encoder
335
+ # self.emotion_encoder = emotion_encoder
336
+ self.audio_feature = audio_feature
337
+ self.generator = generator
338
+ self.discriminator = discriminator
339
+ self.train_params = train_params
340
+ self.scales = train_params['scales']
341
+ self.disc_scales = self.discriminator.scales
342
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
343
+ if torch.cuda.is_available():
344
+ self.pyramid = self.pyramid.cuda()
345
+
346
+ self.loss_weights = train_params['loss_weights']
347
+
348
+ if sum(self.loss_weights['perceptual']) != 0:
349
+ self.vgg = Vgg19()
350
+ if torch.cuda.is_available():
351
+ self.vgg = self.vgg.cuda()
352
+
353
+ self.pca = torch.FloatTensor(np.load('.../LRW/list/U_106.npy'))[:, :16].cuda()
354
+ self.mean = torch.FloatTensor(np.load('.../LRW/list/mean_106.npy')).cuda()
355
+
356
+ def forward(self, x):
357
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
358
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
359
+ # kp_source = self.kp_extractor(x['source'])
360
+ # kp_source_a = self.kp_extractor_a(x['source'], x['source_cube'], source_a_f)
361
+ # driving_a_f = self.audio_feature(self.content_encoder(x['driving_audio'].unsqueeze(1)), self.emotion_encoder(x['driving_audio'].unsqueeze(1)))
362
+ # driving_a_f = self.audio_feature(x['driving_audio'])
363
+ # kp_driving = self.kp_extractor(x['driving'])
364
+ # kp_driving_a = self.kp_extractor_a(x['driving'], x['driving_cube'], driving_a_f)
365
+
366
+ kp_driving = []
367
+ for i in range(16):
368
+ kp_driving.append(self.kp_extractor(x['driving'][:,i],x['driving_landmark'][:,i],self.loss_weights['equivariance_value']))
369
+
370
+ kp_driving_a = []
371
+ fc_out, deco_out = self.audio_feature(x['example_landmark'], x['driving_audio'], x['driving_pose'])
372
+ fake_lmark=fc_out + x['example_landmark'].expand_as(fc_out)
373
+
374
+
375
+ fake_lmark = torch.mm( fake_lmark, self.pca.t() )
376
+ fake_lmark = fake_lmark + self.mean.expand_as(fake_lmark)
377
+
378
+
379
+ fake_lmark = fake_lmark.unsqueeze(0)
380
+
381
+ # for i in range(16):
382
+ # kp_driving_a.append()
383
+
384
+ # generated = self.generator(x['source'], kp_source=kp_source, kp_driving=kp_driving)
385
+ # generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
386
+
387
+ loss_values = {}
388
+
389
+ pyramide_real = self.pyramid(x['driving'])
390
+ pyramide_generated = self.pyramid(generated['prediction'])
391
+
392
+ if self.loss_weights['audio'] != 0:
393
+ value = torch.abs(kp_source['jacobian'].detach() - kp_source_a['jacobian'].detach()).mean() + torch.abs(kp_driving['jacobian'].detach() - kp_driving_a['jacobian']).mean()
394
+ value = value/2
395
+ loss_values['jacobian'] = value*self.loss_weights['audio']
396
+ value = torch.abs(kp_source['heatmap'].detach() - kp_source_a['heatmap'].detach()).mean() + torch.abs(kp_driving['heatmap'].detach() - kp_driving_a['heatmap']).mean()
397
+ value = value/2
398
+ loss_values['heatmap'] = value*self.loss_weights['audio']
399
+ value = torch.abs(kp_source['value'].detach() - kp_source_a['value'].detach()).mean() + torch.abs(kp_driving['value'].detach() - kp_driving_a['value']).mean()
400
+ value = value/2
401
+ loss_values['value'] = value*self.loss_weights['audio']
402
+
403
+ if sum(self.loss_weights['perceptual']) != 0:
404
+ value_total = 0
405
+ for scale in self.scales:
406
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
407
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
408
+
409
+ for i, weight in enumerate(self.loss_weights['perceptual']):
410
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
411
+ value_total += self.loss_weights['perceptual'][i] * value
412
+ loss_values['perceptual'] = value_total
413
+
414
+ if self.loss_weights['generator_gan'] != 0:
415
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
416
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
417
+ value_total = 0
418
+ for scale in self.disc_scales:
419
+ key = 'prediction_map_%s' % scale
420
+ value = ((1 - discriminator_maps_generated[key]) ** 2).mean()
421
+ value_total += self.loss_weights['generator_gan'] * value
422
+ loss_values['gen_gan'] = value_total
423
+
424
+ if sum(self.loss_weights['feature_matching']) != 0:
425
+ value_total = 0
426
+ for scale in self.disc_scales:
427
+ key = 'feature_maps_%s' % scale
428
+ for i, (a, b) in enumerate(zip(discriminator_maps_real[key], discriminator_maps_generated[key])):
429
+ if self.loss_weights['feature_matching'][i] == 0:
430
+ continue
431
+ value = torch.abs(a - b).mean()
432
+ value_total += self.loss_weights['feature_matching'][i] * value
433
+ loss_values['feature_matching'] = value_total
434
+
435
+ if (self.loss_weights['equivariance_value'] + self.loss_weights['equivariance_jacobian']) != 0:
436
+ transform = Transform(x['driving'].shape[0], **self.train_params['transform_params'])
437
+ transformed_frame = transform.transform_frame(x['driving'])
438
+ transformed_landmark = transform.inverse_warp_coordinates(x['driving_landmark'])
439
+ transformed_kp = self.kp_extractor(transformed_frame)
440
+
441
+ generated['transformed_frame'] = transformed_frame
442
+ generated['transformed_kp'] = transformed_kp
443
+
444
+ ## Value loss part
445
+ if self.loss_weights['equivariance_value'] != 0:
446
+ value = torch.abs(kp_driving['value'] - transform.warp_coordinates(transformed_kp['value'])).mean()
447
+ loss_values['equivariance_value'] = self.loss_weights['equivariance_value'] * value
448
+
449
+ ## jacobian loss part
450
+ if self.loss_weights['equivariance_jacobian'] != 0:
451
+ jacobian_transformed = torch.matmul(transform.jacobian(transformed_kp['value']),
452
+ transformed_kp['jacobian'])
453
+
454
+ normed_driving = torch.inverse(kp_driving['jacobian'])
455
+ normed_transformed = jacobian_transformed
456
+ value = torch.matmul(normed_driving, normed_transformed)
457
+
458
+ eye = torch.eye(2).view(1, 1, 2, 2).type(value.type())
459
+
460
+ value = torch.abs(eye - value).mean()
461
+ loss_values['equivariance_jacobian'] = self.loss_weights['equivariance_jacobian'] * value
462
+
463
+ return loss_values, generated
464
+
465
+
466
+ class DiscriminatorFullModel(torch.nn.Module):
467
+ """
468
+ Merge all discriminator related updates into single model for better multi-gpu usage
469
+ """
470
+
471
+ def __init__(self, kp_extractor, generator, discriminator, train_params):
472
+ super(DiscriminatorFullModel, self).__init__()
473
+ self.kp_extractor = kp_extractor
474
+ self.generator = generator
475
+ self.discriminator = discriminator
476
+ self.train_params = train_params
477
+ self.scales = self.discriminator.scales
478
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
479
+ if torch.cuda.is_available():
480
+ self.pyramid = self.pyramid.cuda()
481
+
482
+ self.loss_weights = train_params['loss_weights']
483
+
484
+ def forward(self, x, generated):
485
+ pyramide_real = self.pyramid(x['driving'])
486
+ pyramide_generated = self.pyramid(generated['prediction'].detach())
487
+
488
+ kp_driving = generated['kp_driving']
489
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
490
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
491
+
492
+ loss_values = {}
493
+ value_total = 0
494
+ for scale in self.scales:
495
+ key = 'prediction_map_%s' % scale
496
+ value = (1 - discriminator_maps_real[key]) ** 2 + discriminator_maps_generated[key] ** 2
497
+ value_total += self.loss_weights['discriminator_gan'] * value.mean()
498
+ loss_values['disc_gan'] = value_total
499
+
500
+ return loss_values
FONT/modules/model_gen.py ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from modules.util import AntiAliasInterpolation2d, make_coordinate_grid
5
+ from torchvision import models
6
+ import numpy as np
7
+ from torch.autograd import grad
8
+
9
+
10
+ class Vgg19(torch.nn.Module):
11
+ """
12
+ Vgg19 network for perceptual loss. See Sec 3.3.
13
+ """
14
+ def __init__(self, requires_grad=False):
15
+ super(Vgg19, self).__init__()
16
+ vgg_pretrained_features = models.vgg19(pretrained=True).features
17
+ self.slice1 = torch.nn.Sequential()
18
+ self.slice2 = torch.nn.Sequential()
19
+ self.slice3 = torch.nn.Sequential()
20
+ self.slice4 = torch.nn.Sequential()
21
+ self.slice5 = torch.nn.Sequential()
22
+ for x in range(2):
23
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
24
+ for x in range(2, 7):
25
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
26
+ for x in range(7, 12):
27
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
28
+ for x in range(12, 21):
29
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
30
+ for x in range(21, 30):
31
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
32
+
33
+ self.mean = torch.nn.Parameter(data=torch.Tensor(np.array([0.485, 0.456, 0.406]).reshape((1, 3, 1, 1))),
34
+ requires_grad=False)
35
+ self.std = torch.nn.Parameter(data=torch.Tensor(np.array([0.229, 0.224, 0.225]).reshape((1, 3, 1, 1))),
36
+ requires_grad=False)
37
+
38
+ if not requires_grad:
39
+ for param in self.parameters():
40
+ param.requires_grad = False
41
+
42
+ def forward(self, X):
43
+ X = (X - self.mean) / self.std
44
+ h_relu1 = self.slice1(X)
45
+ h_relu2 = self.slice2(h_relu1)
46
+ h_relu3 = self.slice3(h_relu2)
47
+ h_relu4 = self.slice4(h_relu3)
48
+ h_relu5 = self.slice5(h_relu4)
49
+ out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
50
+ return out
51
+
52
+
53
+ class ImagePyramide(torch.nn.Module):
54
+ """
55
+ Create image pyramide for computing pyramide perceptual loss. See Sec 3.3
56
+ """
57
+ def __init__(self, scales, num_channels):
58
+ super(ImagePyramide, self).__init__()
59
+ downs = {}
60
+ for scale in scales:
61
+ downs[str(scale).replace('.', '-')] = AntiAliasInterpolation2d(num_channels, scale)
62
+ self.downs = nn.ModuleDict(downs)
63
+
64
+ def forward(self, x):
65
+ out_dict = {}
66
+ for scale, down_module in self.downs.items():
67
+ out_dict['prediction_' + str(scale).replace('-', '.')] = down_module(x)
68
+ return out_dict
69
+
70
+
71
+ class Transform:
72
+ """
73
+ Random tps transformation for equivariance constraints. See Sec 3.3
74
+ """
75
+ def __init__(self, bs, **kwargs):
76
+ noise = torch.normal(mean=0, std=kwargs['sigma_affine'] * torch.ones([bs, 2, 3]))
77
+ self.theta = noise + torch.eye(2, 3).view(1, 2, 3)
78
+ self.bs = bs
79
+
80
+ if ('sigma_tps' in kwargs) and ('points_tps' in kwargs):
81
+ self.tps = True
82
+ self.control_points = make_coordinate_grid((kwargs['points_tps'], kwargs['points_tps']), type=noise.type())
83
+ self.control_points = self.control_points.unsqueeze(0)
84
+ self.control_params = torch.normal(mean=0,
85
+ std=kwargs['sigma_tps'] * torch.ones([bs, 1, kwargs['points_tps'] ** 2]))
86
+ else:
87
+ self.tps = False
88
+
89
+ def transform_frame(self, frame):
90
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
91
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
92
+ grid = self.warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
93
+ return F.grid_sample(frame, grid, padding_mode="reflection")
94
+
95
+ def inverse_transform_frame(self, frame):
96
+ grid = make_coordinate_grid(frame.shape[2:], type=frame.type()).unsqueeze(0) #[1,256,256,2]
97
+ grid = grid.view(1, frame.shape[2] * frame.shape[3], 2)
98
+ grid = self.inverse_warp_coordinates(grid).view(self.bs, frame.shape[2], frame.shape[3], 2)
99
+ return F.grid_sample(frame, grid, padding_mode="reflection")
100
+
101
+ def warp_coordinates(self, coordinates):
102
+ theta = self.theta.type(coordinates.type())
103
+ theta = theta.unsqueeze(1)
104
+ transformed = torch.matmul(theta[:, :, :, :2], coordinates.unsqueeze(-1)) + theta[:, :, :, 2:]
105
+ transformed = transformed.squeeze(-1)
106
+
107
+ if self.tps:
108
+ control_points = self.control_points.type(coordinates.type())
109
+ control_params = self.control_params.type(coordinates.type())
110
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
111
+ distances = torch.abs(distances).sum(-1)
112
+
113
+ result = distances ** 2
114
+ result = result * torch.log(distances + 1e-6)
115
+ result = result * control_params
116
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
117
+ transformed = transformed + result
118
+
119
+ return transformed
120
+
121
+ def inverse_warp_coordinates(self, coordinates):
122
+ theta = self.theta.type(coordinates.type())
123
+ theta = theta.unsqueeze(1)
124
+ a = torch.FloatTensor([[[[0,0,1]]]]).repeat([self.bs,1,1,1]).cuda()
125
+ c = torch.cat((theta,a),2)
126
+ d = c.inverse()[:,:,:2,:]
127
+ d = d.type(coordinates.type())
128
+ transformed = torch.matmul(d[:, :, :, :2], coordinates.unsqueeze(-1)) + d[:, :, :, 2:]
129
+ transformed = transformed.squeeze(-1)
130
+
131
+ if self.tps:
132
+ control_points = self.control_points.type(coordinates.type())
133
+ control_params = self.control_params.type(coordinates.type())
134
+ distances = coordinates.view(coordinates.shape[0], -1, 1, 2) - control_points.view(1, 1, -1, 2)
135
+ distances = torch.abs(distances).sum(-1)
136
+
137
+ result = distances ** 2
138
+ result = result * torch.log(distances + 1e-6)
139
+ result = result * control_params
140
+ result = result.sum(dim=2).view(self.bs, coordinates.shape[1], 1)
141
+ transformed = transformed + result
142
+
143
+
144
+ return transformed
145
+
146
+ def jacobian(self, coordinates):
147
+ coordinates.requires_grad=True
148
+ new_coordinates = self.warp_coordinates(coordinates)#[4,10,2]
149
+ grad_x = grad(new_coordinates[..., 0].sum(), coordinates, create_graph=True)
150
+ grad_y = grad(new_coordinates[..., 1].sum(), coordinates, create_graph=True)
151
+ jacobian = torch.cat([grad_x[0].unsqueeze(-2), grad_y[0].unsqueeze(-2)], dim=-2)
152
+ return jacobian
153
+
154
+
155
+ def detach_kp(kp):
156
+ return {key: value.detach() for key, value in kp.items()}
157
+
158
+ class TrainFullModel(torch.nn.Module):
159
+ """
160
+ Merge all generator related updates into single model for better multi-gpu usage
161
+ """
162
+
163
+ def __init__(self, kp_extractor, emo_feature, kp_extractor_a, audio_feature, generator, discriminator, train_params, device_ids):
164
+ super(TrainFullModel, self).__init__()
165
+ self.kp_extractor = kp_extractor
166
+ self.kp_extractor_a = kp_extractor_a
167
+ # self.emo_detector = emo_detector
168
+ # self.content_encoder = content_encoder
169
+ # self.emotion_encoder = emotion_encoder
170
+ self.audio_feature = audio_feature
171
+ self.emo_feature = emo_feature
172
+ self.generator = generator
173
+ self.discriminator = discriminator
174
+ self.train_params = train_params
175
+ self.scales = train_params['scales']
176
+ self.disc_scales = self.discriminator.scales
177
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
178
+ if torch.cuda.is_available():
179
+ self.pyramid = self.pyramid.cuda()
180
+
181
+ self.loss_weights = train_params['loss_weights']
182
+
183
+ if sum(self.loss_weights['perceptual']) != 0:
184
+ self.vgg = Vgg19()
185
+ if torch.cuda.is_available():
186
+ self.vgg = self.vgg.cuda()
187
+
188
+ # self.pca = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/U_106.npy'))[:, :16].to(device_ids[0])
189
+ # self.mean = torch.FloatTensor(np.load('/mnt/lustre/jixinya/Home/LRW/list/mean_106.npy')).to(device_ids[0])
190
+ self.mse_loss_fn = nn.MSELoss().cuda()
191
+ self.CroEn_loss = nn.CrossEntropyLoss().cuda()
192
+ def forward(self, x):
193
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
194
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
195
+ kp_source = self.kp_extractor(x['example_image'])
196
+ # print(x['name'],len(x['name']))
197
+ kp_driving = []
198
+ kp_emo = []
199
+ for i in range(16):
200
+ kp_driving.append(self.kp_extractor(x['driving'][:,i]))
201
+ # kp_emo.append(self.emo_detector(x['driving'][:,i]))
202
+ # print('KP_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
203
+ kp_driving_a = [] #x['example_image'],
204
+ deco_out = self.audio_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
205
+ # emo_out = self.emo_feature(x['example_image'], x['driving_audio'], x['driving_pose'], self.train_params['jaco_net'])
206
+ loss_values = {}
207
+
208
+ if self.loss_weights['emo'] != 0:
209
+
210
+ kp_driving_a = []
211
+ fakes = []
212
+ for i in range(16):
213
+ kp_driving_a.append(self.kp_extractor_a(deco_out[:,i]))#
214
+ value = self.kp_extractor_a(deco_out[:,i])['value']
215
+ jacobian = self.kp_extractor_a(deco_out[:,i])['jacobian']
216
+ if self.train_params['type'] == 'linear_4' and x['name'][0] == 0:
217
+ out, fake = self.emo_feature(x['transformed_driving'][:,i],value,jacobian)
218
+ kp_emo.append(out)
219
+ fakes.append(fake)
220
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
221
+ elif self.train_params['type'] == 'linear_10' and x['name'][0] == 0:
222
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
223
+
224
+ out, fake = self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian)
225
+ kp_emo.append(out)
226
+ fakes.append(fake)
227
+ elif self.train_params['type'] == 'linear_4_new' and x['name'][0] == 0:
228
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
229
+
230
+ out, fake = self.emo_feature.linear_4(x['transformed_driving'][:,i],value,jacobian)
231
+ kp_emo.append(out)
232
+ fakes.append(fake)
233
+ elif self.train_params['type'] == 'linear_np_4':
234
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
235
+
236
+ out, fake = self.emo_feature.linear_np_4(x['transformed_driving'][:,i],value,jacobian)
237
+ kp_emo.append(out)
238
+ fakes.append(fake)
239
+ elif self.train_params['type'] == 'linear_np_10':
240
+ # kp_emo.append(self.emo_feature.linear_10(x['transformed_driving'][:,i],value,jacobian))
241
+
242
+ out, fake = self.emo_feature.linear_np_10(x['transformed_driving'][:,i],value,jacobian)
243
+ kp_emo.append(out)
244
+ fakes.append(fake)
245
+ # kp_emo.append(self.emo_feature(x['transformed_driving'][:,i],value,jacobian))
246
+ # print('Kp_audio_driving ', file=open('/mnt/lustre/jixinya/Home/fomm_audio/log/LRW_test.txt', 'a'))
247
+
248
+ loss_perceptual = 0
249
+
250
+ kp_all = kp_driving_a
251
+ if self.train_params['smooth'] == True:
252
+ value_all = torch.randn(len(kp_driving),out['value'].shape[0],out['value'].shape[1],out['value'].shape[2]).cuda()
253
+ jacobian_all = torch.randn(len(kp_driving),out['jacobian'].shape[0],out['jacobian'].shape[1],2,2).cuda()
254
+ print(len(kp_driving))
255
+ for i in range(len(kp_driving)):
256
+ # if x['name'][i] == 'LRW':
257
+ # loss_jacobian += (torch.abs(kp_driving[i]['jacobian'] - kp_driving_a[i]['jacobian']).mean())*self.loss_weights['emo']
258
+
259
+ # loss_value += (torch.abs(kp_driving[i]['value'].detach() - kp_driving_a[i]['value']).mean())*self.loss_weights['emo']
260
+ # loss_classify += self.mse_loss_fn(deco_out,deco_out)
261
+ if self.train_params['type'] == 'linear_4' and x['name'][0] == 0:
262
+
263
+ kp_all[i]['jacobian'][:,1] = kp_emo[i]['jacobian'][:,0] + kp_driving_a[i]['jacobian'][:,1]
264
+ kp_all[i]['jacobian'][:,4] = kp_emo[i]['jacobian'][:,1] + kp_driving_a[i]['jacobian'][:,4]
265
+ kp_all[i]['jacobian'][:,6] = kp_emo[i]['jacobian'][:,2] + kp_driving_a[i]['jacobian'][:,6]
266
+ kp_all[i]['jacobian'][:,8] = kp_emo[i]['jacobian'][:,3] + kp_driving_a[i]['jacobian'][:,8]
267
+ kp_all[i]['value'][:,1] = kp_emo[i]['value'][:,0] + kp_driving_a[i]['value'][:,1]
268
+ kp_all[i]['value'][:,4] = kp_emo[i]['value'][:,1] + kp_driving_a[i]['value'][:,4]
269
+ kp_all[i]['value'][:,6] = kp_emo[i]['value'][:,2] + kp_driving_a[i]['value'][:,6]
270
+ kp_all[i]['value'][:,8] = kp_emo[i]['value'][:,3] + kp_driving_a[i]['value'][:,8]
271
+
272
+ # kp_all[i]['value'] = kp_emo[i]['value'] + kp_driving_a[i]['value']
273
+
274
+
275
+ if self.train_params['smooth'] == True:
276
+ loss_smooth = 0
277
+ loss_smooth += (torch.abs(value_all[2:,:,:,:] + value_all[:-2,:,:,:].detach() -2*value_all[1:-1,:,:,:].detach()).mean())*self.loss_weights['emo'] *100
278
+ loss_smooth += (torch.abs(jacobian_all[2:,:,:,:] + jacobian_all[:-2,:,:,:].detach() -2*jacobian_all[1:-1,:,:,:].detach()).mean())*self.loss_weights['emo'] *100
279
+ loss_values['loss_smooth'] = loss_smooth/len(kp_driving)
280
+ else:
281
+ loss_values['loss_smooth'] = self.mse_loss_fn(deco_out,deco_out)
282
+ if self.train_params['generator'] == 'not':
283
+ loss_values['perceptual'] = self.mse_loss_fn(deco_out,deco_out)
284
+ for i in range(1): #0,len(kp_driving),4
285
+
286
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_all[i])
287
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_all})
288
+ elif self.train_params['generator'] == 'visual':
289
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
290
+
291
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_driving[i])
292
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
293
+
294
+ pyramide_real = self.pyramid(x['driving'][:,i])
295
+ pyramide_generated = self.pyramid(generated['prediction'])
296
+
297
+ if sum(self.loss_weights['perceptual']) != 0:
298
+ value_total = 0
299
+ for scale in self.scales:
300
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
301
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
302
+
303
+ for i, weight in enumerate(self.loss_weights['perceptual']):
304
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
305
+ value_total += self.loss_weights['perceptual'][i] * value
306
+ loss_perceptual += value_total
307
+
308
+ length = int((len(kp_driving)-1)/4)+1
309
+ loss_values['perceptual'] = loss_perceptual/length
310
+ elif self.train_params['generator'] == 'audio':
311
+ for i in range(0,len(kp_driving),4): #0,len(kp_driving),4
312
+
313
+ generated = self.generator(x['example_image'], kp_source=kp_source, kp_driving=kp_all[i])
314
+ generated.update({'kp_source': kp_source, 'kp_driving': kp_all})
315
+
316
+ pyramide_real = self.pyramid(x['driving'][:,i])
317
+ pyramide_generated = self.pyramid(generated['prediction'])
318
+ # loss_mse = nn.MSELoss(generated['prediction'],x['driving'][:,i])
319
+ if sum(self.loss_weights['perceptual']) != 0:
320
+ value_total = 0
321
+ for scale in self.scales:
322
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
323
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
324
+
325
+ for i, weight in enumerate(self.loss_weights['perceptual']):
326
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
327
+ value_total += self.loss_weights['perceptual'][i] * value
328
+ loss_perceptual += value_total
329
+
330
+ length = int((len(kp_driving)-1)/4)+1
331
+ loss_values['perceptual'] = loss_perceptual/length
332
+ # loss_values['mse'] = loss_mse/length
333
+
334
+ else:
335
+ print('wrong train_params: ', self.train_params['generator'])
336
+
337
+
338
+
339
+ return loss_values,generated
340
+
341
+ class GeneratorFullModel(torch.nn.Module):
342
+ """
343
+ Merge all generator related updates into single model for better multi-gpu usage
344
+ """
345
+
346
+ def __init__(self, kp_extractor, kp_extractor_a, audio_feature, generator, discriminator, train_params):
347
+ super(GeneratorFullModel, self).__init__()
348
+ self.kp_extractor = kp_extractor
349
+ self.kp_extractor_a = kp_extractor_a
350
+ # self.content_encoder = content_encoder
351
+ # self.emotion_encoder = emotion_encoder
352
+ self.audio_feature = audio_feature
353
+ self.generator = generator
354
+ self.discriminator = discriminator
355
+ self.train_params = train_params
356
+ self.scales = train_params['scales']
357
+ self.disc_scales = self.discriminator.scales
358
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
359
+ if torch.cuda.is_available():
360
+ self.pyramid = self.pyramid.cuda()
361
+
362
+ self.loss_weights = train_params['loss_weights']
363
+
364
+ if sum(self.loss_weights['perceptual']) != 0:
365
+ self.vgg = Vgg19()
366
+ if torch.cuda.is_available():
367
+ self.vgg = self.vgg.cuda()
368
+
369
+ self.pca = torch.FloatTensor(np.load('.../LRW/list/U_106.npy'))[:, :16].cuda()
370
+ self.mean = torch.FloatTensor(np.load('.../LRW/list/mean_106.npy')).cuda()
371
+
372
+ def forward(self, x):
373
+ # source_a_f = self.audio_feature(x['source_audio'],x['source_lm'],x[])
374
+ # source_a_f = self.audio_feature(self.content_encoder(x['source_audio'].unsqueeze(1)), self.emotion_encoder(x['source_audio'].unsqueeze(1)))
375
+ # kp_source = self.kp_extractor(x['source'])
376
+ # kp_source_a = self.kp_extractor_a(x['source'], x['source_cube'], source_a_f)
377
+ # driving_a_f = self.audio_feature(self.content_encoder(x['driving_audio'].unsqueeze(1)), self.emotion_encoder(x['driving_audio'].unsqueeze(1)))
378
+ # driving_a_f = self.audio_feature(x['driving_audio'])
379
+ # kp_driving = self.kp_extractor(x['driving'])
380
+ # kp_driving_a = self.kp_extractor_a(x['driving'], x['driving_cube'], driving_a_f)
381
+
382
+ kp_driving = []
383
+ for i in range(16):
384
+ kp_driving.append(self.kp_extractor(x['driving'][:,i],x['driving_landmark'][:,i],self.loss_weights['equivariance_value']))
385
+
386
+ kp_driving_a = []
387
+ fc_out, deco_out = self.audio_feature(x['example_landmark'], x['driving_audio'], x['driving_pose'])
388
+ fake_lmark=fc_out + x['example_landmark'].expand_as(fc_out)
389
+
390
+
391
+ fake_lmark = torch.mm( fake_lmark, self.pca.t() )
392
+ fake_lmark = fake_lmark + self.mean.expand_as(fake_lmark)
393
+
394
+
395
+ fake_lmark = fake_lmark.unsqueeze(0)
396
+
397
+ # for i in range(16):
398
+ # kp_driving_a.append()
399
+
400
+ # generated = self.generator(x['source'], kp_source=kp_source, kp_driving=kp_driving)
401
+ # generated.update({'kp_source': kp_source, 'kp_driving': kp_driving})
402
+
403
+ loss_values = {}
404
+
405
+ pyramide_real = self.pyramid(x['driving'])
406
+ pyramide_generated = self.pyramid(generated['prediction'])
407
+
408
+ if self.loss_weights['audio'] != 0:
409
+ value = torch.abs(kp_source['jacobian'].detach() - kp_source_a['jacobian'].detach()).mean() + torch.abs(kp_driving['jacobian'].detach() - kp_driving_a['jacobian']).mean()
410
+ value = value/2
411
+ loss_values['jacobian'] = value*self.loss_weights['audio']
412
+ value = torch.abs(kp_source['heatmap'].detach() - kp_source_a['heatmap'].detach()).mean() + torch.abs(kp_driving['heatmap'].detach() - kp_driving_a['heatmap']).mean()
413
+ value = value/2
414
+ loss_values['heatmap'] = value*self.loss_weights['audio']
415
+ value = torch.abs(kp_source['value'].detach() - kp_source_a['value'].detach()).mean() + torch.abs(kp_driving['value'].detach() - kp_driving_a['value']).mean()
416
+ value = value/2
417
+ loss_values['value'] = value*self.loss_weights['audio']
418
+
419
+ if sum(self.loss_weights['perceptual']) != 0:
420
+ value_total = 0
421
+ for scale in self.scales:
422
+ x_vgg = self.vgg(pyramide_generated['prediction_' + str(scale)])
423
+ y_vgg = self.vgg(pyramide_real['prediction_' + str(scale)])
424
+
425
+ for i, weight in enumerate(self.loss_weights['perceptual']):
426
+ value = torch.abs(x_vgg[i] - y_vgg[i].detach()).mean()
427
+ value_total += self.loss_weights['perceptual'][i] * value
428
+ loss_values['perceptual'] = value_total
429
+
430
+ if self.loss_weights['generator_gan'] != 0:
431
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
432
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
433
+ value_total = 0
434
+ for scale in self.disc_scales:
435
+ key = 'prediction_map_%s' % scale
436
+ value = ((1 - discriminator_maps_generated[key]) ** 2).mean()
437
+ value_total += self.loss_weights['generator_gan'] * value
438
+ loss_values['gen_gan'] = value_total
439
+
440
+ if sum(self.loss_weights['feature_matching']) != 0:
441
+ value_total = 0
442
+ for scale in self.disc_scales:
443
+ key = 'feature_maps_%s' % scale
444
+ for i, (a, b) in enumerate(zip(discriminator_maps_real[key], discriminator_maps_generated[key])):
445
+ if self.loss_weights['feature_matching'][i] == 0:
446
+ continue
447
+ value = torch.abs(a - b).mean()
448
+ value_total += self.loss_weights['feature_matching'][i] * value
449
+ loss_values['feature_matching'] = value_total
450
+
451
+ if (self.loss_weights['equivariance_value'] + self.loss_weights['equivariance_jacobian']) != 0:
452
+ transform = Transform(x['driving'].shape[0], **self.train_params['transform_params'])
453
+ transformed_frame = transform.transform_frame(x['driving'])
454
+ transformed_landmark = transform.inverse_warp_coordinates(x['driving_landmark'])
455
+ transformed_kp = self.kp_extractor(transformed_frame)
456
+
457
+ generated['transformed_frame'] = transformed_frame
458
+ generated['transformed_kp'] = transformed_kp
459
+
460
+ ## Value loss part
461
+ if self.loss_weights['equivariance_value'] != 0:
462
+ value = torch.abs(kp_driving['value'] - transform.warp_coordinates(transformed_kp['value'])).mean()
463
+ loss_values['equivariance_value'] = self.loss_weights['equivariance_value'] * value
464
+
465
+ ## jacobian loss part
466
+ if self.loss_weights['equivariance_jacobian'] != 0:
467
+ jacobian_transformed = torch.matmul(transform.jacobian(transformed_kp['value']),
468
+ transformed_kp['jacobian'])
469
+
470
+ normed_driving = torch.inverse(kp_driving['jacobian'])
471
+ normed_transformed = jacobian_transformed
472
+ value = torch.matmul(normed_driving, normed_transformed)
473
+
474
+ eye = torch.eye(2).view(1, 1, 2, 2).type(value.type())
475
+
476
+ value = torch.abs(eye - value).mean()
477
+ loss_values['equivariance_jacobian'] = self.loss_weights['equivariance_jacobian'] * value
478
+
479
+ return loss_values, generated
480
+
481
+
482
+ class DiscriminatorFullModel(torch.nn.Module):
483
+ """
484
+ Merge all discriminator related updates into single model for better multi-gpu usage
485
+ """
486
+
487
+ def __init__(self, kp_extractor, generator, discriminator, train_params):
488
+ super(DiscriminatorFullModel, self).__init__()
489
+ self.kp_extractor = kp_extractor
490
+ self.generator = generator
491
+ self.discriminator = discriminator
492
+ self.train_params = train_params
493
+ self.scales = self.discriminator.scales
494
+ self.pyramid = ImagePyramide(self.scales, generator.num_channels)
495
+ if torch.cuda.is_available():
496
+ self.pyramid = self.pyramid.cuda()
497
+
498
+ self.loss_weights = train_params['loss_weights']
499
+
500
+ def forward(self, x, generated):
501
+ pyramide_real = self.pyramid(x['driving'])
502
+ pyramide_generated = self.pyramid(generated['prediction'].detach())
503
+
504
+ kp_driving = generated['kp_driving']
505
+ discriminator_maps_generated = self.discriminator(pyramide_generated, kp=detach_kp(kp_driving))
506
+ discriminator_maps_real = self.discriminator(pyramide_real, kp=detach_kp(kp_driving))
507
+
508
+ loss_values = {}
509
+ value_total = 0
510
+ for scale in self.scales:
511
+ key = 'prediction_map_%s' % scale
512
+ value = (1 - discriminator_maps_real[key]) ** 2 + discriminator_maps_generated[key] ** 2
513
+ value_total += self.loss_weights['discriminator_gan'] * value.mean()
514
+ loss_values['disc_gan'] = value_total
515
+
516
+ return loss_values
FONT/modules/ops.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+ import torch.nn as nn
4
+ import torch.nn.init as init
5
+ from torch.autograd import Variable
6
+
7
+
8
+ def linear(channel_in, channel_out,
9
+ activation=nn.ReLU,
10
+ normalizer=nn.BatchNorm1d):
11
+ layer = list()
12
+ bias = True if not normalizer else False
13
+
14
+ layer.append(nn.Linear(channel_in, channel_out, bias=bias))
15
+ _apply(layer, activation, normalizer, channel_out)
16
+ # init.kaiming_normal(layer[0].weight)
17
+
18
+ return nn.Sequential(*layer)
19
+
20
+
21
+ def conv2d(channel_in, channel_out,
22
+ ksize=3, stride=1, padding=1,
23
+ activation=nn.ReLU,
24
+ normalizer=nn.BatchNorm2d):
25
+ layer = list()
26
+ bias = True if not normalizer else False
27
+
28
+ layer.append(nn.Conv2d(channel_in, channel_out,
29
+ ksize, stride, padding,
30
+ bias=bias))
31
+ _apply(layer, activation, normalizer, channel_out)
32
+ # init.kaiming_normal(layer[0].weight)
33
+
34
+ return nn.Sequential(*layer)
35
+
36
+
37
+ def conv_transpose2d(channel_in, channel_out,
38
+ ksize=4, stride=2, padding=1,
39
+ activation=nn.ReLU,
40
+ normalizer=nn.BatchNorm2d):
41
+ layer = list()
42
+ bias = True if not normalizer else False
43
+
44
+ layer.append(nn.ConvTranspose2d(channel_in, channel_out,
45
+ ksize, stride, padding,
46
+ bias=bias))
47
+ _apply(layer, activation, normalizer, channel_out)
48
+ # init.kaiming_normal(layer[0].weight)
49
+
50
+ return nn.Sequential(*layer)
51
+
52
+
53
+ def nn_conv2d(channel_in, channel_out,
54
+ ksize=3, stride=1, padding=1,
55
+ scale_factor=2,
56
+ activation=nn.ReLU,
57
+ normalizer=nn.BatchNorm2d):
58
+ layer = list()
59
+ bias = True if not normalizer else False
60
+
61
+ layer.append(nn.UpsamplingNearest2d(scale_factor=scale_factor))
62
+ layer.append(nn.Conv2d(channel_in, channel_out,
63
+ ksize, stride, padding,
64
+ bias=bias))
65
+ _apply(layer, activation, normalizer, channel_out)
66
+ # init.kaiming_normal(layer[1].weight)
67
+
68
+ return nn.Sequential(*layer)
69
+
70
+
71
+ def _apply(layer, activation, normalizer, channel_out=None):
72
+ if normalizer:
73
+ layer.append(normalizer(channel_out))
74
+ if activation:
75
+ layer.append(activation())
76
+ return layer
77
+
FONT/modules/stylegan2.py ADDED
@@ -0,0 +1,923 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Thu Jul 8 01:03:50 2021
5
+
6
+ @author: thea
7
+ """
8
+
9
+ """
10
+ The network architectures is based on PyTorch implemenation of StyleGAN2Encoder.
11
+ Original PyTorch repo: https://github.com/rosinality/style-based-gan-pytorch
12
+ Origianl StyelGAN2 paper: https://github.com/NVlabs/stylegan2
13
+ We use the network architeture for our single-image traning setting.
14
+ """
15
+
16
+ import math
17
+ import numpy as np
18
+ import random
19
+
20
+ import torch
21
+ from torch import nn
22
+ from torch.nn import functional as F
23
+
24
+
25
+ def fused_leaky_relu(input, bias, negative_slope=0.2, scale=2 ** 0.5):
26
+ return F.leaky_relu(input + bias, negative_slope) * scale
27
+
28
+
29
+ class FusedLeakyReLU(nn.Module):
30
+ def __init__(self, channel, negative_slope=0.2, scale=2 ** 0.5):
31
+ super().__init__()
32
+ self.bias = nn.Parameter(torch.zeros(1, channel, 1, 1))
33
+ self.negative_slope = negative_slope
34
+ self.scale = scale
35
+
36
+ def forward(self, input):
37
+ # print("FusedLeakyReLU: ", input.abs().mean())
38
+ out = fused_leaky_relu(input, self.bias,
39
+ self.negative_slope,
40
+ self.scale)
41
+ # print("FusedLeakyReLU: ", out.abs().mean())
42
+ return out
43
+
44
+
45
+ def upfirdn2d_native(
46
+ input, kernel, up_x, up_y, down_x, down_y, pad_x0, pad_x1, pad_y0, pad_y1
47
+ ):
48
+ _, minor, in_h, in_w = input.shape
49
+ kernel_h, kernel_w = kernel.shape
50
+
51
+ out = input.view(-1, minor, in_h, 1, in_w, 1)
52
+ out = F.pad(out, [0, up_x - 1, 0, 0, 0, up_y - 1, 0, 0])
53
+ out = out.view(-1, minor, in_h * up_y, in_w * up_x)
54
+
55
+ out = F.pad(
56
+ out, [max(pad_x0, 0), max(pad_x1, 0), max(pad_y0, 0), max(pad_y1, 0)]
57
+ )
58
+ out = out[
59
+ :,
60
+ :,
61
+ max(-pad_y0, 0): out.shape[2] - max(-pad_y1, 0),
62
+ max(-pad_x0, 0): out.shape[3] - max(-pad_x1, 0),
63
+ ]
64
+
65
+ # out = out.permute(0, 3, 1, 2)
66
+ out = out.reshape(
67
+ [-1, 1, in_h * up_y + pad_y0 + pad_y1, in_w * up_x + pad_x0 + pad_x1]
68
+ )
69
+ w = torch.flip(kernel, [0, 1]).view(1, 1, kernel_h, kernel_w)
70
+ out = F.conv2d(out, w)
71
+ out = out.reshape(
72
+ -1,
73
+ minor,
74
+ in_h * up_y + pad_y0 + pad_y1 - kernel_h + 1,
75
+ in_w * up_x + pad_x0 + pad_x1 - kernel_w + 1,
76
+ )
77
+ # out = out.permute(0, 2, 3, 1)
78
+
79
+ return out[:, :, ::down_y, ::down_x]
80
+
81
+
82
+ def upfirdn2d(input, kernel, up=1, down=1, pad=(0, 0)):
83
+ return upfirdn2d_native(input, kernel, up, up, down, down, pad[0], pad[1], pad[0], pad[1])
84
+
85
+
86
+ class PixelNorm(nn.Module):
87
+ def __init__(self):
88
+ super().__init__()
89
+
90
+ def forward(self, input):
91
+ return input * torch.rsqrt(torch.mean(input ** 2, dim=1, keepdim=True) + 1e-8)
92
+
93
+
94
+ def make_kernel(k):
95
+ k = torch.tensor(k, dtype=torch.float32)
96
+
97
+ if len(k.shape) == 1:
98
+ k = k[None, :] * k[:, None]
99
+
100
+ k /= k.sum()
101
+
102
+ return k
103
+
104
+
105
+ class Upsample(nn.Module):
106
+ def __init__(self, kernel, factor=2):
107
+ super().__init__()
108
+
109
+ self.factor = factor
110
+ kernel = make_kernel(kernel) * (factor ** 2)
111
+ self.register_buffer('kernel', kernel)
112
+
113
+ p = kernel.shape[0] - factor
114
+
115
+ pad0 = (p + 1) // 2 + factor - 1
116
+ pad1 = p // 2
117
+
118
+ self.pad = (pad0, pad1)
119
+
120
+ def forward(self, input):
121
+ out = upfirdn2d(input, self.kernel, up=self.factor, down=1, pad=self.pad)
122
+
123
+ return out
124
+
125
+
126
+ class Downsample(nn.Module):
127
+ def __init__(self, kernel, factor=2):
128
+ super().__init__()
129
+
130
+ self.factor = factor
131
+ kernel = make_kernel(kernel)
132
+ self.register_buffer('kernel', kernel)
133
+
134
+ p = kernel.shape[0] - factor
135
+
136
+ pad0 = (p + 1) // 2
137
+ pad1 = p // 2
138
+
139
+ self.pad = (pad0, pad1)
140
+
141
+ def forward(self, input):
142
+ out = upfirdn2d(input, self.kernel, up=1, down=self.factor, pad=self.pad)
143
+
144
+ return out
145
+
146
+
147
+ class Blur(nn.Module):
148
+ def __init__(self, kernel, pad, upsample_factor=1):
149
+ super().__init__()
150
+
151
+ kernel = make_kernel(kernel)
152
+
153
+ if upsample_factor > 1:
154
+ kernel = kernel * (upsample_factor ** 2)
155
+
156
+ self.register_buffer('kernel', kernel)
157
+
158
+ self.pad = pad
159
+
160
+ def forward(self, input):
161
+ out = upfirdn2d(input, self.kernel, pad=self.pad)
162
+
163
+ return out
164
+
165
+
166
+ class EqualConv2d(nn.Module):
167
+ def __init__(
168
+ self, in_channel, out_channel, kernel_size, stride=1, padding=0, bias=True
169
+ ):
170
+ super().__init__()
171
+
172
+ self.weight = nn.Parameter(
173
+ torch.randn(out_channel, in_channel, kernel_size, kernel_size)
174
+ )
175
+ self.scale = math.sqrt(1) / math.sqrt(in_channel * (kernel_size ** 2))
176
+
177
+ self.stride = stride
178
+ self.padding = padding
179
+
180
+ if bias:
181
+ self.bias = nn.Parameter(torch.zeros(out_channel))
182
+
183
+ else:
184
+ self.bias = None
185
+
186
+ def forward(self, input):
187
+ # print("Before EqualConv2d: ", input.abs().mean())
188
+ out = F.conv2d(
189
+ input,
190
+ self.weight * self.scale,
191
+ bias=self.bias,
192
+ stride=self.stride,
193
+ padding=self.padding,
194
+ )
195
+ # print("After EqualConv2d: ", out.abs().mean(), (self.weight * self.scale).abs().mean())
196
+
197
+ return out
198
+
199
+ def __repr__(self):
200
+ return (
201
+ f'{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]},'
202
+ f' {self.weight.shape[2]}, stride={self.stride}, padding={self.padding})'
203
+ )
204
+
205
+
206
+ class EqualLinear(nn.Module):
207
+ def __init__(
208
+ self, in_dim, out_dim, bias=True, bias_init=0, lr_mul=1, activation=None
209
+ ):
210
+ super().__init__()
211
+
212
+ self.weight = nn.Parameter(torch.randn(out_dim, in_dim).div_(lr_mul))
213
+
214
+ if bias:
215
+ self.bias = nn.Parameter(torch.zeros(out_dim).fill_(bias_init))
216
+
217
+ else:
218
+ self.bias = None
219
+
220
+ self.activation = activation
221
+
222
+ self.scale = (math.sqrt(1) / math.sqrt(in_dim)) * lr_mul
223
+ self.lr_mul = lr_mul
224
+
225
+ def forward(self, input):
226
+ if self.activation:
227
+ out = F.linear(input, self.weight * self.scale)
228
+ out = fused_leaky_relu(out, self.bias * self.lr_mul)
229
+
230
+ else:
231
+ out = F.linear(
232
+ input, self.weight * self.scale, bias=self.bias * self.lr_mul
233
+ )
234
+
235
+ return out
236
+
237
+ def __repr__(self):
238
+ return (
239
+ f'{self.__class__.__name__}({self.weight.shape[1]}, {self.weight.shape[0]})'
240
+ )
241
+
242
+
243
+ class ScaledLeakyReLU(nn.Module):
244
+ def __init__(self, negative_slope=0.2):
245
+ super().__init__()
246
+
247
+ self.negative_slope = negative_slope
248
+
249
+ def forward(self, input):
250
+ out = F.leaky_relu(input, negative_slope=self.negative_slope)
251
+
252
+ return out * math.sqrt(2)
253
+
254
+
255
+ class ModulatedConv2d(nn.Module):
256
+ def __init__(
257
+ self,
258
+ in_channel,
259
+ out_channel,
260
+ kernel_size,
261
+ style_dim,
262
+ demodulate=True,
263
+ upsample=False,
264
+ downsample=False,
265
+ blur_kernel=[1, 3, 3, 1],
266
+ ):
267
+ super().__init__()
268
+
269
+ self.eps = 1e-8
270
+ self.kernel_size = kernel_size
271
+ self.in_channel = in_channel
272
+ self.out_channel = out_channel
273
+ self.upsample = upsample
274
+ self.downsample = downsample
275
+
276
+ if upsample:
277
+ factor = 2
278
+ p = (len(blur_kernel) - factor) - (kernel_size - 1)
279
+ pad0 = (p + 1) // 2 + factor - 1
280
+ pad1 = p // 2 + 1
281
+
282
+ self.blur = Blur(blur_kernel, pad=(pad0, pad1), upsample_factor=factor)
283
+
284
+ if downsample:
285
+ factor = 2
286
+ p = (len(blur_kernel) - factor) + (kernel_size - 1)
287
+ pad0 = (p + 1) // 2
288
+ pad1 = p // 2
289
+
290
+ self.blur = Blur(blur_kernel, pad=(pad0, pad1))
291
+
292
+ fan_in = in_channel * kernel_size ** 2
293
+ self.scale = math.sqrt(1) / math.sqrt(fan_in)
294
+ self.padding = kernel_size // 2
295
+
296
+ self.weight = nn.Parameter(
297
+ torch.randn(1, out_channel, in_channel, kernel_size, kernel_size)
298
+ )
299
+
300
+ if style_dim is not None and style_dim > 0:
301
+ self.modulation = EqualLinear(style_dim, in_channel, bias_init=1)
302
+
303
+ self.demodulate = demodulate
304
+
305
+ def __repr__(self):
306
+ return (
307
+ f'{self.__class__.__name__}({self.in_channel}, {self.out_channel}, {self.kernel_size}, '
308
+ f'upsample={self.upsample}, downsample={self.downsample})'
309
+ )
310
+
311
+ def forward(self, input, style):
312
+ batch, in_channel, height, width = input.shape
313
+
314
+ if style is not None:
315
+ style = self.modulation(style).view(batch, 1, in_channel, 1, 1)
316
+ else:
317
+ style = torch.ones(batch, 1, in_channel, 1, 1).cuda()
318
+ weight = self.scale * self.weight * style
319
+
320
+ if self.demodulate:
321
+ demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + 1e-8)
322
+ weight = weight * demod.view(batch, self.out_channel, 1, 1, 1)
323
+
324
+ weight = weight.view(
325
+ batch * self.out_channel, in_channel, self.kernel_size, self.kernel_size
326
+ )
327
+
328
+ if self.upsample:
329
+ input = input.view(1, batch * in_channel, height, width)
330
+ weight = weight.view(
331
+ batch, self.out_channel, in_channel, self.kernel_size, self.kernel_size
332
+ )
333
+ weight = weight.transpose(1, 2).reshape(
334
+ batch * in_channel, self.out_channel, self.kernel_size, self.kernel_size
335
+ )
336
+ out = F.conv_transpose2d(input, weight, padding=0, stride=2, groups=batch)
337
+ _, _, height, width = out.shape
338
+ out = out.view(batch, self.out_channel, height, width)
339
+ out = self.blur(out)
340
+
341
+ elif self.downsample:
342
+ input = self.blur(input)
343
+ _, _, height, width = input.shape
344
+ input = input.view(1, batch * in_channel, height, width)
345
+ out = F.conv2d(input, weight, padding=0, stride=2, groups=batch)
346
+ _, _, height, width = out.shape
347
+ out = out.view(batch, self.out_channel, height, width)
348
+
349
+ else:
350
+ input = input.view(1, batch * in_channel, height, width)
351
+ out = F.conv2d(input, weight, padding=self.padding, groups=batch)
352
+ _, _, height, width = out.shape
353
+ out = out.view(batch, self.out_channel, height, width)
354
+
355
+ return out
356
+
357
+
358
+ class NoiseInjection(nn.Module):
359
+ def __init__(self):
360
+ super().__init__()
361
+
362
+ self.weight = nn.Parameter(torch.zeros(1))
363
+
364
+ def forward(self, image, noise=None):
365
+ if noise is None:
366
+ batch, _, height, width = image.shape
367
+ noise = image.new_empty(batch, 1, height, width).normal_()
368
+
369
+ return image + self.weight * noise
370
+
371
+
372
+ class ConstantInput(nn.Module):
373
+ def __init__(self, channel, size=4):
374
+ super().__init__()
375
+
376
+ self.input = nn.Parameter(torch.randn(1, channel, size, size))
377
+
378
+ def forward(self, input):
379
+ batch = input.shape[0]
380
+ out = self.input.repeat(batch, 1, 1, 1)
381
+
382
+ return out
383
+
384
+
385
+ class StyledConv(nn.Module):
386
+ def __init__(
387
+ self,
388
+ in_channel,
389
+ out_channel,
390
+ kernel_size,
391
+ style_dim=None,
392
+ upsample=False,
393
+ blur_kernel=[1, 3, 3, 1],
394
+ demodulate=True,
395
+ inject_noise=False, #True
396
+ ):
397
+ super().__init__()
398
+
399
+ self.inject_noise = inject_noise
400
+ self.conv = ModulatedConv2d(
401
+ in_channel,
402
+ out_channel,
403
+ kernel_size,
404
+ style_dim,
405
+ upsample=upsample,
406
+ blur_kernel=blur_kernel,
407
+ demodulate=demodulate,
408
+ )
409
+
410
+ self.noise = NoiseInjection()
411
+ # self.bias = nn.Parameter(torch.zeros(1, out_channel, 1, 1))
412
+ # self.activate = ScaledLeakyReLU(0.2)
413
+ self.activate = FusedLeakyReLU(out_channel)
414
+
415
+ def forward(self, input, style=None, noise=None):
416
+ out = self.conv(input, style)
417
+ if self.inject_noise:
418
+ out = self.noise(out, noise=noise)
419
+ # out = out + self.bias
420
+ out = self.activate(out)
421
+
422
+ return out
423
+
424
+
425
+ class ToRGB(nn.Module):
426
+ def __init__(self, in_channel, style_dim, upsample=True, blur_kernel=[1, 3, 3, 1]):
427
+ super().__init__()
428
+
429
+ if upsample:
430
+ self.upsample = Upsample(blur_kernel)
431
+
432
+ self.conv = ModulatedConv2d(in_channel, 3+32, 1, style_dim, demodulate=False)
433
+ self.bias = nn.Parameter(torch.zeros(1, 3+32, 1, 1))
434
+
435
+ def forward(self, input, style, skip=None):
436
+ out = self.conv(input, style)
437
+ out = out + self.bias
438
+
439
+ if skip is not None:
440
+ skip = self.upsample(skip)
441
+
442
+ out = out + skip
443
+
444
+ return out
445
+
446
+
447
+ class Generator(nn.Module):
448
+ def __init__(
449
+ self,
450
+ size,
451
+ style_dim,
452
+ n_mlp,
453
+ channel_multiplier=1,
454
+ blur_kernel=[1, 3, 3, 1],
455
+ lr_mlp=0.01,
456
+ ):
457
+ super().__init__()
458
+
459
+ self.size = size
460
+
461
+ self.style_dim = style_dim
462
+
463
+ layers = [PixelNorm()]
464
+
465
+ for i in range(n_mlp):
466
+ layers.append(
467
+ EqualLinear(
468
+ style_dim, style_dim, lr_mul=lr_mlp, activation='fused_lrelu'
469
+ )
470
+ )
471
+
472
+ self.style = nn.Sequential(*layers)
473
+
474
+ self.channels = {
475
+ 4: 256,
476
+ 8: 256,
477
+ 16: 128,
478
+ 32: 64,
479
+ 64: 32 * channel_multiplier,
480
+ 128: 16 * channel_multiplier,
481
+ 256: 8 * channel_multiplier,
482
+ 512: 4 * channel_multiplier,
483
+ 1024: 2 * channel_multiplier,
484
+ }
485
+
486
+ self.input = ConstantInput(self.channels[4])
487
+ self.conv1 = StyledConv(
488
+ self.channels[4], self.channels[4], 3, style_dim, blur_kernel=blur_kernel
489
+ )
490
+ self.to_rgb1 = ToRGB(self.channels[4], style_dim, upsample=False)
491
+
492
+ self.log_size = int(math.log(size, 2))
493
+ self.num_layers = (self.log_size - 2) * 2 + 1
494
+
495
+ self.convs = nn.ModuleList()
496
+ self.upsamples = nn.ModuleList()
497
+ self.to_rgbs = nn.ModuleList()
498
+ self.noises = nn.Module()
499
+
500
+ in_channel = self.channels[4]
501
+
502
+ for layer_idx in range(self.num_layers):
503
+ res = (layer_idx + 5) // 2
504
+ shape = [1, 1, 2 ** res, 2 ** res]
505
+ self.noises.register_buffer(f'noise_{layer_idx}', torch.randn(*shape))
506
+
507
+ for i in range(3, self.log_size + 1):
508
+ out_channel = self.channels[2 ** i]
509
+
510
+ self.convs.append(
511
+ StyledConv(
512
+ in_channel,
513
+ out_channel,
514
+ 3,
515
+ style_dim,
516
+ upsample=True,
517
+ blur_kernel=blur_kernel,
518
+ )
519
+ )
520
+
521
+ self.convs.append(
522
+ StyledConv(
523
+ out_channel, out_channel, 3, style_dim, blur_kernel=blur_kernel
524
+ )
525
+ )
526
+
527
+ self.to_rgbs.append(ToRGB(out_channel, style_dim))
528
+
529
+ in_channel = out_channel
530
+
531
+ self.n_latent = self.log_size * 2 - 2
532
+
533
+ def make_noise(self):
534
+ device = self.input.input.device
535
+
536
+ noises = [torch.randn(1, 1, 2 ** 2, 2 ** 2, device=device)]
537
+
538
+ for i in range(3, self.log_size + 1):
539
+ for _ in range(2):
540
+ noises.append(torch.randn(1, 1, 2 ** i, 2 ** i, device=device))
541
+
542
+ return noises
543
+
544
+ def mean_latent(self, n_latent):
545
+ latent_in = torch.randn(
546
+ n_latent, self.style_dim, device=self.input.input.device
547
+ )
548
+ latent = self.style(latent_in).mean(0, keepdim=True)
549
+
550
+ return latent
551
+
552
+ def get_latent(self, input):
553
+ return self.style(input)
554
+
555
+ def forward(
556
+ self,
557
+ styles,
558
+ return_latents=False,
559
+ inject_index=None,
560
+ truncation=1,
561
+ truncation_latent=None,
562
+ input_is_latent=False,
563
+ noise=None,
564
+ randomize_noise=True,
565
+ ):
566
+ if not input_is_latent:
567
+ styles = [self.style(s) for s in styles]
568
+
569
+ if noise is None:
570
+ if randomize_noise:
571
+ noise = [None] * self.num_layers
572
+ else:
573
+ noise = [
574
+ getattr(self.noises, f'noise_{i}') for i in range(self.num_layers)
575
+ ]
576
+
577
+ if truncation < 1:
578
+ style_t = []
579
+
580
+ for style in styles:
581
+ style_t.append(
582
+ truncation_latent + truncation * (style - truncation_latent)
583
+ )
584
+
585
+ styles = style_t
586
+
587
+ if len(styles) < 2:
588
+ inject_index = self.n_latent
589
+
590
+ if len(styles[0].shape) < 3:
591
+ latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
592
+
593
+ else:
594
+ latent = styles[0]
595
+
596
+ else:
597
+ if inject_index is None:
598
+ inject_index = random.randint(1, self.n_latent - 1)
599
+
600
+ latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
601
+ latent2 = styles[1].unsqueeze(1).repeat(1, self.n_latent - inject_index, 1)
602
+
603
+ latent = torch.cat([latent, latent2], 1)
604
+
605
+ # out = self.input(latent)
606
+ out = styles[0].unsqueeze(-1).unsqueeze(-1).repeat(1,1,4,4)
607
+ out = self.conv1(out, latent[:, 0], noise=noise[0])
608
+
609
+ skip = self.to_rgb1(out, latent[:, 1])
610
+
611
+ i = 1
612
+ for conv1, conv2, noise1, noise2, to_rgb in zip(
613
+ self.convs[::2], self.convs[1::2], noise[1::2], noise[2::2], self.to_rgbs
614
+ ):
615
+ out = conv1(out, latent[:, i], noise=noise1)
616
+ out = conv2(out, latent[:, i + 1], noise=noise2)
617
+ skip = to_rgb(out, latent[:, i + 2], skip)
618
+
619
+ i += 2
620
+
621
+ image = skip
622
+
623
+ if return_latents:
624
+ return image, latent
625
+
626
+ else:
627
+ return image, None
628
+
629
+
630
+ class ConvLayer(nn.Sequential):
631
+ def __init__(
632
+ self,
633
+ in_channel,
634
+ out_channel,
635
+ kernel_size,
636
+ downsample=False,
637
+ blur_kernel=[1, 3, 3, 1],
638
+ bias=True,
639
+ activate=True,
640
+ ):
641
+ layers = []
642
+
643
+ if downsample:
644
+ factor = 2
645
+ p = (len(blur_kernel) - factor) + (kernel_size - 1)
646
+ pad0 = (p + 1) // 2
647
+ pad1 = p // 2
648
+
649
+ layers.append(Blur(blur_kernel, pad=(pad0, pad1)))
650
+
651
+ stride = 2
652
+ self.padding = 0
653
+
654
+ else:
655
+ stride = 1
656
+ self.padding = kernel_size // 2
657
+
658
+ layers.append(
659
+ EqualConv2d(
660
+ in_channel,
661
+ out_channel,
662
+ kernel_size,
663
+ padding=self.padding,
664
+ stride=stride,
665
+ bias=bias and not activate,
666
+ )
667
+ )
668
+
669
+ if activate:
670
+ if bias:
671
+ layers.append(FusedLeakyReLU(out_channel))
672
+
673
+ else:
674
+ layers.append(ScaledLeakyReLU(0.2))
675
+
676
+ super().__init__(*layers)
677
+
678
+
679
+ class ResBlock(nn.Module):
680
+ def __init__(self, in_channel, out_channel, blur_kernel=[1, 3, 3, 1], downsample=True, skip_gain=1.0):
681
+ super().__init__()
682
+
683
+ self.skip_gain = skip_gain
684
+ self.conv1 = ConvLayer(in_channel, in_channel, 3)
685
+ self.conv2 = ConvLayer(in_channel, out_channel, 3, downsample=downsample, blur_kernel=blur_kernel)
686
+
687
+ if in_channel != out_channel or downsample:
688
+ self.skip = ConvLayer(
689
+ in_channel, out_channel, 1, downsample=downsample, activate=False, bias=False
690
+ )
691
+ else:
692
+ self.skip = nn.Identity()
693
+
694
+ def forward(self, input):
695
+ out = self.conv1(input)
696
+ out = self.conv2(out)
697
+
698
+ skip = self.skip(input)
699
+ out = (out * self.skip_gain + skip) / math.sqrt(self.skip_gain ** 2 + 1.0)
700
+
701
+ return out
702
+
703
+
704
+ class StyleGAN2Discriminator(nn.Module):
705
+ def __init__(self, input_nc, ndf=64, n_layers=3, no_antialias=False, size=None, opt=None):
706
+ super().__init__()
707
+ self.opt = opt
708
+ self.stddev_group = 16
709
+ if size is None:
710
+ size = 2 ** int((np.rint(np.log2(min(opt.load_size, opt.crop_size)))))
711
+ if "patch" in self.opt.netD and self.opt.D_patch_size is not None:
712
+ size = 2 ** int(np.log2(self.opt.D_patch_size))
713
+
714
+ blur_kernel = [1, 3, 3, 1]
715
+ channel_multiplier = ndf / 64
716
+ channels = {
717
+ 4: min(384, int(4096 * channel_multiplier)),
718
+ 8: min(384, int(2048 * channel_multiplier)),
719
+ 16: min(384, int(1024 * channel_multiplier)),
720
+ 32: min(384, int(512 * channel_multiplier)),
721
+ 64: int(256 * channel_multiplier),
722
+ 128: int(128 * channel_multiplier),
723
+ 256: int(64 * channel_multiplier),
724
+ 512: int(32 * channel_multiplier),
725
+ 1024: int(16 * channel_multiplier),
726
+ }
727
+
728
+ convs = [ConvLayer(3, channels[size], 1)]
729
+
730
+ log_size = int(math.log(size, 2))
731
+
732
+ in_channel = channels[size]
733
+
734
+ if "smallpatch" in self.opt.netD:
735
+ final_res_log2 = 4
736
+ elif "patch" in self.opt.netD:
737
+ final_res_log2 = 3
738
+ else:
739
+ final_res_log2 = 2
740
+
741
+ for i in range(log_size, final_res_log2, -1):
742
+ out_channel = channels[2 ** (i - 1)]
743
+
744
+ convs.append(ResBlock(in_channel, out_channel, blur_kernel))
745
+
746
+ in_channel = out_channel
747
+
748
+ self.convs = nn.Sequential(*convs)
749
+
750
+ if False and "tile" in self.opt.netD:
751
+ in_channel += 1
752
+ self.final_conv = ConvLayer(in_channel, channels[4], 3)
753
+ if "patch" in self.opt.netD:
754
+ self.final_linear = ConvLayer(channels[4], 1, 3, bias=False, activate=False)
755
+ else:
756
+ self.final_linear = nn.Sequential(
757
+ EqualLinear(channels[4] * 4 * 4, channels[4], activation='fused_lrelu'),
758
+ EqualLinear(channels[4], 1),
759
+ )
760
+
761
+ def forward(self, input, get_minibatch_features=False):
762
+ if "patch" in self.opt.netD and self.opt.D_patch_size is not None:
763
+ h, w = input.size(2), input.size(3)
764
+ y = torch.randint(h - self.opt.D_patch_size, ())
765
+ x = torch.randint(w - self.opt.D_patch_size, ())
766
+ input = input[:, :, y:y + self.opt.D_patch_size, x:x + self.opt.D_patch_size]
767
+ out = input
768
+ for i, conv in enumerate(self.convs):
769
+ out = conv(out)
770
+ # print(i, out.abs().mean())
771
+ # out = self.convs(input)
772
+
773
+ batch, channel, height, width = out.shape
774
+
775
+ if False and "tile" in self.opt.netD:
776
+ group = min(batch, self.stddev_group)
777
+ stddev = out.view(
778
+ group, -1, 1, channel // 1, height, width
779
+ )
780
+ stddev = torch.sqrt(stddev.var(0, unbiased=False) + 1e-8)
781
+ stddev = stddev.mean([2, 3, 4], keepdim=True).squeeze(2)
782
+ stddev = stddev.repeat(group, 1, height, width)
783
+ out = torch.cat([out, stddev], 1)
784
+
785
+ out = self.final_conv(out)
786
+ # print(out.abs().mean())
787
+
788
+ if "patch" not in self.opt.netD:
789
+ out = out.view(batch, -1)
790
+ out = self.final_linear(out)
791
+
792
+ return out
793
+
794
+
795
+ class TileStyleGAN2Discriminator(StyleGAN2Discriminator):
796
+ def forward(self, input):
797
+ B, C, H, W = input.size(0), input.size(1), input.size(2), input.size(3)
798
+ size = self.opt.D_patch_size
799
+ Y = H // size
800
+ X = W // size
801
+ input = input.view(B, C, Y, size, X, size)
802
+ input = input.permute(0, 2, 4, 1, 3, 5).contiguous().view(B * Y * X, C, size, size)
803
+ return super().forward(input)
804
+
805
+
806
+ class StyleGAN2Encoder(nn.Module):
807
+ def __init__(self, input_nc, output_nc, ngf=64, use_dropout=False, n_blocks=6, padding_type='reflect', no_antialias=False, opt=None):
808
+ super().__init__()
809
+ assert opt is not None
810
+ self.opt = opt
811
+ channel_multiplier = ngf / 32
812
+ channels = {
813
+ 4: min(512, int(round(4096 * channel_multiplier))),
814
+ 8: min(512, int(round(2048 * channel_multiplier))),
815
+ 16: min(512, int(round(1024 * channel_multiplier))),
816
+ 32: min(512, int(round(512 * channel_multiplier))),
817
+ 64: int(round(256 * channel_multiplier)),
818
+ 128: int(round(128 * channel_multiplier)),
819
+ 256: int(round(64 * channel_multiplier)),
820
+ 512: int(round(32 * channel_multiplier)),
821
+ 1024: int(round(16 * channel_multiplier)),
822
+ }
823
+
824
+ blur_kernel = [1, 3, 3, 1]
825
+
826
+ cur_res = 2 ** int((np.rint(np.log2(min(opt.load_size, opt.crop_size)))))
827
+ convs = [nn.Identity(),
828
+ ConvLayer(3, channels[cur_res], 1)]
829
+
830
+ num_downsampling = self.opt.stylegan2_G_num_downsampling
831
+ for i in range(num_downsampling):
832
+ in_channel = channels[cur_res]
833
+ out_channel = channels[cur_res // 2]
834
+ convs.append(ResBlock(in_channel, out_channel, blur_kernel, downsample=True))
835
+ cur_res = cur_res // 2
836
+
837
+ for i in range(n_blocks // 2):
838
+ n_channel = channels[cur_res]
839
+ convs.append(ResBlock(n_channel, n_channel, downsample=False))
840
+
841
+ self.convs = nn.Sequential(*convs)
842
+
843
+ def forward(self, input, layers=[], get_features=False):
844
+ feat = input
845
+ feats = []
846
+ if -1 in layers:
847
+ layers.append(len(self.convs) - 1)
848
+ for layer_id, layer in enumerate(self.convs):
849
+ feat = layer(feat)
850
+ # print(layer_id, " features ", feat.abs().mean())
851
+ if layer_id in layers:
852
+ feats.append(feat)
853
+
854
+ if get_features:
855
+ return feat, feats
856
+ else:
857
+ return feat
858
+
859
+
860
+ class StyleGAN2Decoder(nn.Module):
861
+ def __init__(self, input_nc, output_nc, ngf=64, use_dropout=False, n_blocks=6, padding_type='reflect', no_antialias=False, opt=None):
862
+ super().__init__()
863
+ assert opt is not None
864
+ self.opt = opt
865
+
866
+ blur_kernel = [1, 3, 3, 1]
867
+
868
+ channel_multiplier = ngf / 32
869
+ channels = {
870
+ 4: min(512, int(round(4096 * channel_multiplier))),
871
+ 8: min(512, int(round(2048 * channel_multiplier))),
872
+ 16: min(512, int(round(1024 * channel_multiplier))),
873
+ 32: min(512, int(round(512 * channel_multiplier))),
874
+ 64: int(round(256 * channel_multiplier)),
875
+ 128: int(round(128 * channel_multiplier)),
876
+ 256: int(round(64 * channel_multiplier)),
877
+ 512: int(round(32 * channel_multiplier)),
878
+ 1024: int(round(16 * channel_multiplier)),
879
+ }
880
+
881
+ num_downsampling = self.opt.stylegan2_G_num_downsampling
882
+ cur_res = 2 ** int((np.rint(np.log2(min(opt.load_size, opt.crop_size))))) // (2 ** num_downsampling)
883
+ convs = []
884
+
885
+ for i in range(n_blocks // 2):
886
+ n_channel = channels[cur_res]
887
+ convs.append(ResBlock(n_channel, n_channel, downsample=False))
888
+
889
+ for i in range(num_downsampling):
890
+ in_channel = channels[cur_res]
891
+ out_channel = channels[cur_res * 2]
892
+ inject_noise = "small" not in self.opt.netG
893
+ convs.append(
894
+ StyledConv(in_channel, out_channel, 3, upsample=True, blur_kernel=blur_kernel, inject_noise=inject_noise)
895
+ )
896
+ cur_res = cur_res * 2
897
+
898
+ convs.append(ConvLayer(channels[cur_res], 3, 1))
899
+
900
+ self.convs = nn.Sequential(*convs)
901
+
902
+ def forward(self, input):
903
+ return self.convs(input)
904
+
905
+
906
+ class StyleGAN2Generator(nn.Module):
907
+ def __init__(self, input_nc, output_nc, ngf=64, use_dropout=False, n_blocks=6, padding_type='reflect', no_antialias=False, opt=None):
908
+ super().__init__()
909
+ self.opt = opt
910
+ self.encoder = StyleGAN2Encoder(input_nc, output_nc, ngf, use_dropout, n_blocks, padding_type, no_antialias, opt)
911
+ self.decoder = StyleGAN2Decoder(input_nc, output_nc, ngf, use_dropout, n_blocks, padding_type, no_antialias, opt)
912
+
913
+ def forward(self, input, layers=[], encode_only=False):
914
+ feat, feats = self.encoder(input, layers, True)
915
+ if encode_only:
916
+ return feats
917
+ else:
918
+ fake = self.decoder(feat)
919
+
920
+ if len(layers) > 0:
921
+ return fake, feats
922
+ else:
923
+ return fake
FONT/modules/util.py ADDED
@@ -0,0 +1,2008 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+
3
+ import torch.nn.functional as F
4
+ import torch
5
+ import numpy as np
6
+ import cv2
7
+ from FONT.sync_batchnorm import SynchronizedBatchNorm2d as BatchNorm2d
8
+
9
+ from .stylegan2 import Generator
10
+
11
+ import torch.nn as nn
12
+ import math
13
+ import torch.utils.model_zoo as model_zoo
14
+ from .function import adaptive_instance_normalization as adain
15
+
16
+ import pdb
17
+ from .conv import Conv2dTranspose, Conv2d, nonorm_Conv2d
18
+
19
+
20
+
21
+ # Misc
22
+ img2mse = lambda x, y : torch.mean((x - y) ** 2)
23
+ mse2psnr = lambda x : -10. * torch.log(x) / torch.log(torch.Tensor([10.]))
24
+ to8b = lambda x : (255*np.clip(x,0,1)).astype(np.uint8)
25
+
26
+
27
+ class InstanceNorm(nn.Module):
28
+ def __init__(self, epsilon=1e-8):
29
+ """
30
+ @notice: avoid in-place ops.
31
+ https://discuss.pytorch.org/t/encounter-the-runtimeerror-one-of-the-variables-needed-for-gradient-computation-has-been-modified-by-an-inplace-operation/836/3
32
+ """
33
+ super(InstanceNorm, self).__init__()
34
+ self.epsilon = epsilon
35
+
36
+ def forward(self, x):
37
+ x = x - torch.mean(x, (2, 3), True)
38
+ tmp = torch.mul(x, x) # or x ** 2
39
+ tmp = torch.rsqrt(torch.mean(tmp, (2, 3), True) + self.epsilon)
40
+ return x * tmp
41
+
42
+ class ApplyStyle(nn.Module):
43
+ """
44
+ @ref: https://github.com/lernapparat/lernapparat/blob/master/style_gan/pytorch_style_gan.ipynb
45
+ """
46
+ def __init__(self, latent_size, channels, use_wscale):
47
+ super(ApplyStyle, self).__init__()
48
+ self.linear = FC(latent_size,
49
+ channels * 2,
50
+ gain=1.0,
51
+ use_wscale=use_wscale)
52
+
53
+ def forward(self, x, latent):
54
+ style = self.linear(latent) # style => [batch_size, n_channels*2]
55
+ shape = [-1, 2, x.size(1), 1, 1]
56
+ style = style.view(shape) # [batch_size, 2, n_channels, ...]
57
+ x = x * (style[:, 0] + 1.) + style[:, 1]
58
+ return x
59
+
60
+
61
+ class FC(nn.Module):
62
+ def __init__(self,
63
+ in_channels,
64
+ out_channels,
65
+ gain=2**(0.5),
66
+ use_wscale=False,
67
+ lrmul=1.0,
68
+ bias=True):
69
+ """
70
+ The complete conversion of Dense/FC/Linear Layer of original Tensorflow version.
71
+ """
72
+ super(FC, self).__init__()
73
+ he_std = gain * in_channels ** (-0.5) # He init
74
+ if use_wscale:
75
+ init_std = 1.0 / lrmul
76
+ self.w_lrmul = he_std * lrmul
77
+ else:
78
+ init_std = he_std / lrmul
79
+ self.w_lrmul = lrmul
80
+
81
+ self.weight = torch.nn.Parameter(torch.randn(out_channels, in_channels) * init_std)
82
+ if bias:
83
+ self.bias = torch.nn.Parameter(torch.zeros(out_channels))
84
+ self.b_lrmul = lrmul
85
+ else:
86
+ self.bias = None
87
+
88
+ def forward(self, x):
89
+ if self.bias is not None:
90
+ out = F.linear(x, self.weight * self.w_lrmul, self.bias * self.b_lrmul)
91
+ else:
92
+ out = F.linear(x, self.weight * self.w_lrmul)
93
+ out = F.leaky_relu(out, 0.2, inplace=True)
94
+ return out
95
+
96
+
97
+ # Positional encoding (section 5.1)
98
+ class Embedder:
99
+ def __init__(self, **kwargs):
100
+ self.kwargs = kwargs
101
+ self.create_embedding_fn()
102
+
103
+ def create_embedding_fn(self):
104
+ embed_fns = []
105
+ d = self.kwargs['input_dims']
106
+ out_dim = 0
107
+ if self.kwargs['include_input']:
108
+ embed_fns.append(lambda x : x)
109
+ out_dim += d
110
+
111
+ max_freq = self.kwargs['max_freq_log2']
112
+ N_freqs = self.kwargs['num_freqs']
113
+
114
+ if self.kwargs['log_sampling']:
115
+ freq_bands = 2.**torch.linspace(0., max_freq, steps=N_freqs)
116
+ else:
117
+ freq_bands = torch.linspace(2.**0., 2.**max_freq, steps=N_freqs)
118
+
119
+ for freq in freq_bands:
120
+ for p_fn in self.kwargs['periodic_fns']:
121
+ embed_fns.append(lambda x, p_fn=p_fn, freq=freq : p_fn(x * freq))
122
+ out_dim += d
123
+
124
+ self.embed_fns = embed_fns
125
+ self.out_dim = out_dim
126
+
127
+ def embed(self, inputs):
128
+ return torch.cat([fn(inputs) for fn in self.embed_fns], -1)
129
+
130
+
131
+ def get_embedder(multires, i=0):
132
+ if i == -1:
133
+ return nn.Identity(), 6
134
+
135
+ embed_kwargs = {
136
+ 'include_input' : True,
137
+ 'input_dims' : 6,
138
+ 'max_freq_log2' : multires-1,
139
+ 'num_freqs' : multires,
140
+ 'log_sampling' : True,
141
+ 'periodic_fns' : [torch.sin, torch.cos],
142
+ }
143
+
144
+ embedder_obj = Embedder(**embed_kwargs)
145
+ embed = lambda x, eo=embedder_obj : eo.embed(x)
146
+ return embed, embedder_obj.out_dim
147
+
148
+
149
+ def draw_heatmap(landmark, width, height):
150
+ batch = landmark.shape[0]
151
+ number = landmark.shape[1]
152
+ heatmap = np.zeros((batch, number,width, height), dtype=np.float32)
153
+ # draw mouth from mouth landmarks, landmarks: mouth landmark points, format: x1, y1, x2, y2, ..., x20,
154
+
155
+
156
+ landmark = (landmark+1)*29
157
+ for i in range(batch):
158
+ for pts_idx in range(number):
159
+ if int(landmark[i,pts_idx,0])<0:
160
+ landmark[i,pts_idx,0] = 0
161
+ if int(landmark[i,pts_idx,1])<0:
162
+ landmark[i,pts_idx,1] = 0
163
+ if int(landmark[i,pts_idx,0])>57:
164
+ landmark[i,pts_idx,0] = 57
165
+ if int(landmark[i,pts_idx,1])>57:
166
+ landmark[i,pts_idx,1] = 57
167
+ heatmap[i,pts_idx, int(landmark[i,pts_idx,1]), int(landmark[i,pts_idx,0])]=1
168
+ if heatmap[i,pts_idx].sum()== 1 :
169
+
170
+ heatmap[i,pts_idx] = cv2.GaussianBlur(heatmap[i,pts_idx], ksize=(3, 3), sigmaX=1, sigmaY=1)
171
+
172
+
173
+ heatmap = torch.tensor(heatmap).cuda()
174
+ return heatmap
175
+
176
+ class NA_net(nn.Module):
177
+ def __init__(self):
178
+ super(NA_net, self).__init__()
179
+
180
+
181
+
182
+ self.decon = nn.Sequential(
183
+ nn.ConvTranspose2d(1, 16, kernel_size=(2,3), stride=2, padding=(2,1), bias=True),#16,16
184
+ nn.BatchNorm2d(16),
185
+ nn.ReLU(True),
186
+ nn.ConvTranspose2d(16, 32, kernel_size=4, stride=2, padding=1, bias=True),#8,8
187
+ nn.BatchNorm2d(32),
188
+ nn.ReLU(True),
189
+ nn.ConvTranspose2d(32, 32+3, kernel_size=4, stride=2, padding=1, bias=True)#16,16
190
+
191
+
192
+ )
193
+
194
+
195
+
196
+ def forward(self, neutral):
197
+
198
+ feature = neutral.unsqueeze(1)
199
+ current_feature = self.decon(feature)
200
+
201
+
202
+ return current_feature
203
+
204
+ class AT_net(nn.Module):
205
+ def __init__(self):
206
+ super(AT_net, self).__init__()
207
+
208
+ down_blocks = []
209
+ for i in range(8):
210
+ down_blocks.append(DownBlock2d(3 if i == 0 else 2 * (2 ** i),
211
+ 2 * (2 ** (i + 1)),
212
+ kernel_size=3, padding=1))
213
+ self.down_blocks = nn.ModuleList(down_blocks)
214
+
215
+
216
+ # self.lmark_encoder = nn.Sequential(
217
+ # nn.Linear(16,256),
218
+ # nn.ReLU(True),
219
+ # nn.Linear(256,512),
220
+ # nn.ReLU(True),
221
+ # )
222
+ self.pose_encoder = nn.Sequential(
223
+ nn.Linear(6,128),
224
+ nn.ReLU(True),
225
+ nn.Linear(128,256),
226
+ nn.ReLU(True),
227
+
228
+ )
229
+ self.audio_eocder = nn.Sequential(
230
+ conv2d(1,64,3,1,1),
231
+ conv2d(64,128,3,1,1),
232
+ nn.MaxPool2d(3, stride=(1,2)),
233
+ conv2d(128,256,3,1,1),
234
+ conv2d(256,256,3,1,1),
235
+ conv2d(256,512,3,1,1),
236
+ nn.MaxPool2d(3, stride=(2,2))
237
+ )
238
+ self.audio_eocder_fc = nn.Sequential(
239
+ nn.Linear(1024 *12,2048),
240
+ nn.ReLU(True),
241
+ nn.Linear(2048,256),
242
+ nn.ReLU(True),
243
+
244
+ )
245
+ self.lstm = nn.LSTM(256*4,256,3,batch_first = True)
246
+ # self.lstm_fc = nn.Sequential(
247
+ # nn.Linear(256,16),
248
+ # )
249
+ self.decon = nn.Sequential(
250
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
251
+ nn.BatchNorm2d(256),
252
+ nn.ReLU(True),
253
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
254
+ nn.BatchNorm2d(128),
255
+ nn.ReLU(True),
256
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True), #16,16
257
+ nn.BatchNorm2d(128),
258
+ nn.ReLU(True),
259
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#32,32
260
+ nn.BatchNorm2d(128),
261
+ nn.ReLU(True),
262
+ nn.ConvTranspose2d(128, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
263
+ # nn.ConvTranspose2d(128, 32*4, kernel_size=2, stride=2, padding=3, bias=True),#64,64
264
+
265
+
266
+ )
267
+ self.generator = Generator(64,256,8)
268
+
269
+
270
+
271
+ def forward(self, example_image, audio, pose, jaco_net):
272
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
273
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
274
+ outs = example_image
275
+ for down_block in self.down_blocks:
276
+ outs = down_block(outs)
277
+ image_feature = outs
278
+ image_feature = image_feature.view(image_feature.shape[0], -1)
279
+ lstm_input = []
280
+ for step_t in range(audio.size(1)):
281
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
282
+ current_feature = self.audio_eocder(current_audio)
283
+ current_feature = current_feature.view(current_feature.size(0), -1)
284
+ current_feature = self.audio_eocder_fc(current_feature)
285
+ pose_f = self.pose_encoder(pose[:,step_t])
286
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
287
+ lstm_input.append(features)
288
+ lstm_input = torch.stack(lstm_input, dim = 1)
289
+ lstm_out, _ = self.lstm(lstm_input, hidden)
290
+ fc_out = []
291
+ deco_out = []
292
+ for step_t in range(audio.size(1)):
293
+ fc_in = lstm_out[:,step_t,:]
294
+ # fc_out.append(self.lstm_fc(fc_in))
295
+ if jaco_net == 'cnn':
296
+ fc_feature = torch.unsqueeze(fc_in,2)
297
+ fc_feature = torch.unsqueeze(fc_feature,3)
298
+ deco_out.append(self.decon(fc_feature))
299
+ elif jaco_net == 'gan':
300
+ result,_ = self.generator([fc_in])
301
+ deco_out.append(result)
302
+ else:
303
+ raise Exception("jaco_net type wrong")
304
+
305
+ return torch.stack(deco_out,dim=1)
306
+
307
+
308
+ class AT_net2(nn.Module):
309
+ def __init__(self):
310
+ super(AT_net2, self).__init__()
311
+
312
+ down_blocks = []
313
+ for i in range(8):
314
+ down_blocks.append(DownBlock2d(3 if i == 0 else 2 * (2 ** i),
315
+ 2 * (2 ** (i + 1)),
316
+ kernel_size=3, padding=1))
317
+ self.down_blocks = nn.ModuleList(down_blocks)
318
+
319
+
320
+ # self.lmark_encoder = nn.Sequential(
321
+ # nn.Linear(16,256),
322
+ # nn.ReLU(True),
323
+ # nn.Linear(256,512),
324
+ # nn.ReLU(True),
325
+ # )
326
+ self.pose_encoder = nn.Sequential(
327
+ nn.Linear(6,128),
328
+ nn.ReLU(True),
329
+ nn.Linear(128,256),
330
+ nn.ReLU(True),
331
+
332
+ )
333
+ self.audio_eocder = nn.Sequential(
334
+ conv2d(1,64,3,1,1),
335
+ conv2d(64,128,3,1,1),
336
+ nn.MaxPool2d(3, stride=(1,2)),
337
+ conv2d(128,256,3,1,1),
338
+ conv2d(256,256,3,1,1),
339
+ conv2d(256,512,3,1,1),
340
+ nn.MaxPool2d(3, stride=(2,2))
341
+ )
342
+ self.audio_eocder_fc = nn.Sequential(
343
+ nn.Linear(1024 *12,2048),
344
+ nn.ReLU(True),
345
+ nn.Linear(2048,256),
346
+ nn.ReLU(True),
347
+
348
+ )
349
+ self.lstm = nn.LSTM(256*4,256,3,batch_first = True)
350
+ # self.lstm_fc = nn.Sequential(
351
+ # nn.Linear(256,16),
352
+ # )
353
+ self.decon = nn.Sequential(
354
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
355
+ nn.BatchNorm2d(256),
356
+ nn.ReLU(True),
357
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
358
+ nn.BatchNorm2d(128),
359
+ nn.ReLU(True),
360
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True), #16,16
361
+ nn.BatchNorm2d(128),
362
+ nn.ReLU(True),
363
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#32,32
364
+ nn.BatchNorm2d(128),
365
+ nn.ReLU(True),
366
+ nn.ConvTranspose2d(128, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
367
+ # nn.ConvTranspose2d(128, 32*4, kernel_size=2, stride=2, padding=3, bias=True),#64,64
368
+
369
+
370
+ )
371
+ self.generator = Generator(64,256,8)
372
+
373
+
374
+ def forward(self, example_image, audio, pose, jaco_net, weight):
375
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
376
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
377
+ outs = example_image
378
+ for down_block in self.down_blocks:
379
+ outs = down_block(outs)
380
+ image_feature = outs
381
+ image_feature = image_feature.view(image_feature.shape[0], -1)
382
+ lstm_input = []
383
+ for step_t in range(audio.size(1)):
384
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
385
+ current_feature = self.audio_eocder(current_audio)
386
+ current_feature = current_feature.view(current_feature.size(0), -1)
387
+ current_feature = self.audio_eocder_fc(current_feature)*weight
388
+ pose_f = self.pose_encoder(pose[:,step_t])
389
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
390
+ lstm_input.append(features)
391
+ lstm_input = torch.stack(lstm_input, dim = 1)
392
+ lstm_out, _ = self.lstm(lstm_input, hidden)
393
+ fc_out = []
394
+ deco_out = []
395
+ for step_t in range(audio.size(1)):
396
+ fc_in = lstm_out[:,step_t,:]
397
+ # fc_out.append(self.lstm_fc(fc_in))
398
+ if jaco_net == 'cnn':
399
+ fc_feature = torch.unsqueeze(fc_in,2)
400
+ fc_feature = torch.unsqueeze(fc_feature,3)
401
+ deco_out.append(self.decon(fc_feature))
402
+ elif jaco_net == 'gan':
403
+ result,_ = self.generator([fc_in])
404
+ deco_out.append(result)
405
+ else:
406
+ raise Exception("jaco_net type wrong")
407
+
408
+ return torch.stack(deco_out,dim=1)
409
+
410
+
411
+ class AT_net_liujin(nn.Module):
412
+ def __init__(self):
413
+ super(AT_net_liujin, self).__init__()
414
+
415
+ down_blocks = []
416
+ for i in range(8):
417
+ down_blocks.append(DownBlock2d(3 if i == 0 else 2 * (2 ** i),
418
+ 2 * (2 ** (i + 1)),
419
+ kernel_size=3, padding=1))
420
+ self.down_blocks = nn.ModuleList(down_blocks)
421
+
422
+
423
+ # self.lmark_encoder = nn.Sequential(
424
+ # nn.Linear(16,256),
425
+ # nn.ReLU(True),
426
+ # nn.Linear(256,512),
427
+ # nn.ReLU(True),
428
+ # )
429
+ self.pose_encoder = nn.Sequential(
430
+ nn.Linear(6,128),
431
+ nn.ReLU(True),
432
+ nn.Linear(128,256),
433
+ nn.ReLU(True),
434
+
435
+ )
436
+ self.audio_eocder = nn.Sequential(
437
+ conv2d(1,64,3,1,1),
438
+ conv2d(64,128,3,1,1),
439
+ nn.MaxPool2d(3, stride=(1,2)),
440
+ conv2d(128,256,3,1,1),
441
+ conv2d(256,256,3,1,1),
442
+ conv2d(256,512,3,1,1),
443
+ nn.MaxPool2d(3, stride=(2,2))
444
+ )
445
+ self.audio_eocder_fc = nn.Sequential(
446
+ nn.Linear(1024 *12,2048),
447
+ nn.ReLU(True),
448
+ nn.Linear(2048,256),
449
+ nn.ReLU(True),
450
+ )
451
+
452
+ self.audio_encoder_liujin = nn.Sequential(
453
+ Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
454
+ Conv2d(32, 32, kernel_size=3, stride=1, padding=1, residual=True),
455
+ Conv2d(32, 32, kernel_size=3, stride=1, padding=1, residual=True),
456
+
457
+ Conv2d(32, 64, kernel_size=3, stride=(3, 1), padding=1),
458
+ Conv2d(64, 64, kernel_size=3, stride=1, padding=1, residual=True),
459
+ Conv2d(64, 64, kernel_size=3, stride=1, padding=1, residual=True),
460
+
461
+ Conv2d(64, 128, kernel_size=3, stride=3, padding=1),
462
+ Conv2d(128, 128, kernel_size=3, stride=1, padding=1, residual=True),
463
+ Conv2d(128, 128, kernel_size=3, stride=1, padding=1, residual=True),
464
+
465
+ Conv2d(128, 256, kernel_size=3, stride=(3, 2), padding=1),
466
+ Conv2d(256, 256, kernel_size=3, stride=1, padding=1, residual=True),
467
+
468
+ Conv2d(256, 512, kernel_size=3, stride=1, padding=0),
469
+ Conv2d(512, 512, kernel_size=1, stride=1, padding=0), )
470
+
471
+ for child in self.audio_encoder_liujin.children():
472
+ for param in child.parameters():
473
+ param.requires_grad = False
474
+
475
+ # self.lstm = nn.LSTM(256*4,256,3,batch_first = True)
476
+
477
+ self.lstm_liujin = nn.LSTM(256 * 5, 256, 3, batch_first=True)
478
+
479
+ # self.lstm_fc = nn.Sequential(
480
+ # nn.Linear(256,16),
481
+ # )
482
+ self.decon = nn.Sequential(
483
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
484
+ nn.BatchNorm2d(256),
485
+ nn.ReLU(True),
486
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
487
+ nn.BatchNorm2d(128),
488
+ nn.ReLU(True),
489
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True), #16,16
490
+ nn.BatchNorm2d(128),
491
+ nn.ReLU(True),
492
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#32,32
493
+ nn.BatchNorm2d(128),
494
+ nn.ReLU(True),
495
+ nn.ConvTranspose2d(128, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
496
+ # nn.ConvTranspose2d(128, 32*4, kernel_size=2, stride=2, padding=3, bias=True),#64,64
497
+
498
+
499
+ )
500
+ self.generator = Generator(64,256,8)
501
+
502
+
503
+
504
+ def forward(self, example_image, audio, pose, jaco_net):
505
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
506
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
507
+ outs = example_image
508
+ for down_block in self.down_blocks:
509
+ outs = down_block(outs)
510
+ image_feature = outs
511
+ image_feature = image_feature.view(image_feature.shape[0], -1)
512
+ lstm_input = []
513
+ for step_t in range(audio.size(1)):
514
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
515
+ # current_feature = self.audio_eocder(current_audio)
516
+ # current_feature = current_feature.view(current_feature.size(0), -1)
517
+ # current_feature = self.audio_eocder_fc(current_feature)
518
+
519
+ current_feature = self.audio_encoder_liujin(current_audio)
520
+ current_feature = current_feature.reshape(current_audio.shape[0], -1)
521
+
522
+ pose_f = self.pose_encoder(pose[:,step_t])
523
+
524
+
525
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
526
+ lstm_input.append(features)
527
+ lstm_input = torch.stack(lstm_input, dim = 1)
528
+ # lstm_out, _ = self.lstm(lstm_input, hidden)
529
+ lstm_out, _ = self.lstm_liujin(lstm_input, hidden)
530
+ fc_out = []
531
+ deco_out = []
532
+ for step_t in range(audio.size(1)):
533
+ fc_in = lstm_out[:,step_t,:]
534
+ # fc_out.append(self.lstm_fc(fc_in))
535
+ if jaco_net == 'cnn':
536
+ fc_feature = torch.unsqueeze(fc_in,2)
537
+ fc_feature = torch.unsqueeze(fc_feature,3)
538
+ deco_out.append(self.decon(fc_feature))
539
+ elif jaco_net == 'gan':
540
+ result,_ = self.generator([fc_in])
541
+ deco_out.append(result)
542
+ else:
543
+ raise Exception("jaco_net type wrong")
544
+
545
+ return torch.stack(deco_out,dim=1)
546
+
547
+ class Classify(nn.Module):
548
+ def __init__(self):
549
+ super(Classify, self).__init__()
550
+
551
+
552
+
553
+ self.last_fc = nn.Linear(512,8)
554
+
555
+ def forward(self, feature):
556
+ # mfcc= torch.unsqueeze(mfcc, 1)
557
+
558
+ x = self.last_fc(feature)
559
+
560
+ return x
561
+
562
+ class TF_net(nn.Module):
563
+ def __init__(self):
564
+ super(TF_net, self).__init__()
565
+
566
+ down_blocks = []
567
+ for i in range(8):
568
+ down_blocks.append(DownBlock2d(3 if i == 0 else 2 * (2 ** i),
569
+ 2 * (2 ** (i + 1)),
570
+ kernel_size=3, padding=1))
571
+ self.down_blocks = nn.ModuleList(down_blocks)
572
+
573
+
574
+ # self.lmark_encoder = nn.Sequential(
575
+ # nn.Linear(16,256),
576
+ # nn.ReLU(True),
577
+ # nn.Linear(256,512),
578
+ # nn.ReLU(True),
579
+ # )
580
+ self.pose_encoder = nn.Sequential(
581
+ nn.Linear(6,128),
582
+ nn.ReLU(True),
583
+ nn.Linear(128,256),
584
+ nn.ReLU(True),
585
+
586
+ )
587
+ self.audio_eocder = nn.Sequential(
588
+ conv2d(1,64,3,1,1),
589
+ conv2d(64,128,3,1,1),
590
+ nn.MaxPool2d(3, stride=(1,2)),
591
+ conv2d(128,256,3,1,1),
592
+ conv2d(256,256,3,1,1),
593
+ conv2d(256,512,3,1,1),
594
+ nn.MaxPool2d(3, stride=(2,2))
595
+ )
596
+ self.audio_eocder_fc = nn.Sequential(
597
+ nn.Linear(1024 *12,2048),
598
+ nn.ReLU(True),
599
+ nn.Linear(2048,256),
600
+ nn.ReLU(True),
601
+
602
+ )
603
+ self.lstm = nn.LSTM(256*4,256,3,batch_first = True)
604
+ self.lstm_two = nn.LSTM(256*6,256,3,batch_first = True)
605
+ # self.lstm_fc = nn.Sequential(
606
+ # nn.Linear(256,16),
607
+ # )
608
+ self.decon = nn.Sequential(
609
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
610
+ nn.BatchNorm2d(256),
611
+ nn.ReLU(True),
612
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
613
+ nn.BatchNorm2d(128),
614
+ nn.ReLU(True),
615
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True), #16,16
616
+ nn.BatchNorm2d(128),
617
+ nn.ReLU(True),
618
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#32,32
619
+ nn.BatchNorm2d(128),
620
+ nn.ReLU(True),
621
+ nn.ConvTranspose2d(128, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
622
+ # nn.ConvTranspose2d(128, 32*4, kernel_size=2, stride=2, padding=3, bias=True),#64,64
623
+
624
+
625
+ )
626
+ self.generator = Generator(64,256,8)
627
+ self.instance_norm = InstanceNorm()
628
+ self.style_mod = ApplyStyle(512, 1024, use_wscale=True)
629
+ self.style_mod1 = ApplyStyle(512, 35, use_wscale=True)
630
+
631
+
632
+ def adain_forward(self, example_image, audio, pose, jaco_net, emo_features):
633
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
634
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
635
+ outs = example_image
636
+ for down_block in self.down_blocks:
637
+ outs = down_block(outs)
638
+ image_feature = outs
639
+ image_feature = image_feature.view(image_feature.shape[0], -1)
640
+ lstm_input = []
641
+ for step_t in range(audio.size(1)):
642
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
643
+ current_feature = self.audio_eocder(current_audio)
644
+ current_feature = current_feature.view(current_feature.size(0), -1)
645
+ current_feature = self.audio_eocder_fc(current_feature) #256
646
+ pose_f = self.pose_encoder(pose[:,step_t]) #256
647
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
648
+ features = torch.unsqueeze(torch.unsqueeze(features,-1),-1)
649
+ features = self.instance_norm(features)
650
+ x = self.style_mod(features, emo_features[step_t])
651
+ # t = adain(torch.unsqueeze(torch.unsqueeze(features,-1),-1), torch.unsqueeze(torch.unsqueeze(emo_features[step_t],1),2))
652
+
653
+ lstm_input.append(torch.squeeze(torch.squeeze(x,-1),-1))
654
+ lstm_input = torch.stack(lstm_input, dim = 1)
655
+ lstm_out, _ = self.lstm(lstm_input, hidden)
656
+ # fc_out = []
657
+ deco_out = []
658
+ for step_t in range(audio.size(1)):
659
+ fc_in = lstm_out[:,step_t,:]
660
+ # fc_out.append(self.lstm_fc(fc_in))
661
+ if jaco_net == 'cnn':
662
+ fc_feature = torch.unsqueeze(fc_in,2)
663
+ fc_feature = torch.unsqueeze(fc_feature,3)
664
+ deco_out.append(self.decon(fc_feature))
665
+ elif jaco_net == 'gan':
666
+ result,_ = self.generator([fc_in])
667
+ deco_out.append(result)
668
+ else:
669
+ raise Exception("jaco_net type wrong")
670
+
671
+ return torch.stack(deco_out,dim=1)
672
+
673
+
674
+
675
+ def adain_feature2(self, example_image, audio, pose, jaco_net, emo_features):
676
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
677
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
678
+ outs = example_image
679
+ for down_block in self.down_blocks:
680
+ outs = down_block(outs)
681
+ image_feature = outs
682
+ image_feature = image_feature.view(image_feature.shape[0], -1)
683
+ lstm_input = []
684
+ for step_t in range(audio.size(1)):
685
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
686
+ current_feature = self.audio_eocder(current_audio)
687
+ current_feature = current_feature.view(current_feature.size(0), -1)
688
+ current_feature = self.audio_eocder_fc(current_feature) #256
689
+ pose_f = self.pose_encoder(pose[:,step_t]) #256
690
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
691
+
692
+ lstm_input.append(features)
693
+ lstm_input = torch.stack(lstm_input, dim = 1)
694
+ lstm_out, _ = self.lstm(lstm_input, hidden)
695
+ # fc_out = []
696
+ deco_out = []
697
+ for step_t in range(audio.size(1)):
698
+ fc_in = lstm_out[:,step_t,:]
699
+ # fc_out.append(self.lstm_fc(fc_in))
700
+ if jaco_net == 'cnn':
701
+ fc_feature = torch.unsqueeze(fc_in,2)
702
+ fc_feature = torch.unsqueeze(fc_feature,3)
703
+ fc_feature = self.decon(fc_feature)
704
+ fc_feature = self.instance_norm(fc_feature)
705
+ t = self.style_mod1(fc_feature, emo_features[step_t])
706
+ # emo_feature = torch.unsqueeze(torch.unsqueeze(emo_features[step_t],-1),-1)
707
+ # emo_feature = emo_feature.repeat(1,fc_feature.shape[1],1,1)
708
+ # t = adain(fc_feature, emo_feature)
709
+ deco_out.append(t)
710
+ elif jaco_net == 'gan':
711
+ result,_ = self.generator([fc_in])
712
+ deco_out.append(result)
713
+ else:
714
+ raise Exception("jaco_net type wrong")
715
+
716
+ return torch.stack(deco_out,dim=1)
717
+
718
+ def forward(self, example_image, audio, pose, jaco_net, emo_features):
719
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
720
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
721
+ outs = example_image
722
+ for down_block in self.down_blocks:
723
+ outs = down_block(outs)
724
+ image_feature = outs
725
+ image_feature = image_feature.view(image_feature.shape[0], -1)
726
+ lstm_input = []
727
+ for step_t in range(audio.size(1)):
728
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
729
+ current_feature = self.audio_eocder(current_audio)
730
+ current_feature = current_feature.view(current_feature.size(0), -1)
731
+ current_feature = self.audio_eocder_fc(current_feature) #256
732
+ pose_f = self.pose_encoder(pose[:,step_t]) #256
733
+ features = torch.cat([image_feature, current_feature, pose_f, emo_features[step_t]], 1)
734
+ lstm_input.append(features)
735
+ lstm_input = torch.stack(lstm_input, dim = 1)
736
+ lstm_out, _ = self.lstm_two(lstm_input, hidden)
737
+ fc_out = []
738
+ deco_out = []
739
+ for step_t in range(audio.size(1)):
740
+ fc_in = lstm_out[:,step_t,:]
741
+ # fc_out.append(self.lstm_fc(fc_in))
742
+ if jaco_net == 'cnn':
743
+ fc_feature = torch.unsqueeze(fc_in,2)
744
+ fc_feature = torch.unsqueeze(fc_feature,3)
745
+ deco_out.append(self.decon(fc_feature))
746
+ elif jaco_net == 'gan':
747
+ result,_ = self.generator([fc_in])
748
+ deco_out.append(result)
749
+ else:
750
+ raise Exception("jaco_net type wrong")
751
+
752
+ return torch.stack(deco_out,dim=1)
753
+
754
+
755
+ class AT_net2_liujin(nn.Module):
756
+ def __init__(self):
757
+ super(AT_net2_liujin, self).__init__()
758
+
759
+ down_blocks = []
760
+ for i in range(8):
761
+ down_blocks.append(DownBlock2d(3 if i == 0 else 2 * (2 ** i),
762
+ 2 * (2 ** (i + 1)),
763
+ kernel_size=3, padding=1))
764
+ self.down_blocks = nn.ModuleList(down_blocks)
765
+
766
+
767
+ # self.lmark_encoder = nn.Sequential(
768
+ # nn.Linear(16,256),
769
+ # nn.ReLU(True),
770
+ # nn.Linear(256,512),
771
+ # nn.ReLU(True),
772
+ # )
773
+ self.pose_encoder = nn.Sequential(
774
+ nn.Linear(6,128),
775
+ nn.ReLU(True),
776
+ nn.Linear(128,256),
777
+ nn.ReLU(True),
778
+ )
779
+
780
+ self.audio_eocder = nn.Sequential(
781
+ conv2d(1,64,3,1,1),
782
+ conv2d(64,128,3,1,1),
783
+ nn.MaxPool2d(3, stride=(1,2)),
784
+ conv2d(128,256,3,1,1),
785
+ conv2d(256,256,3,1,1),
786
+ conv2d(256,512,3,1,1),
787
+ nn.MaxPool2d(3, stride=(2,2))
788
+ )
789
+
790
+ self.audio_eocder_fc = nn.Sequential(
791
+ nn.Linear(1024 *12,2048),
792
+ nn.ReLU(True),
793
+ nn.Linear(2048,256),
794
+ nn.ReLU(True),
795
+ )
796
+
797
+
798
+
799
+
800
+ # self.lstm = nn.LSTM(256*4,256,3,batch_first = True)
801
+ self.lstm_liujin = nn.LSTM(256 * 5, 256, 3, batch_first=True)
802
+ # self.lstm_fc = nn.Sequential(
803
+ # nn.Linear(256,16),
804
+ # )
805
+ self.decon = nn.Sequential(
806
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
807
+ nn.BatchNorm2d(256),
808
+ nn.ReLU(True),
809
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
810
+ nn.BatchNorm2d(128),
811
+ nn.ReLU(True),
812
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True), #16,16
813
+ nn.BatchNorm2d(128),
814
+ nn.ReLU(True),
815
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#32,32
816
+ nn.BatchNorm2d(128),
817
+ nn.ReLU(True),
818
+ nn.ConvTranspose2d(128, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
819
+ # nn.ConvTranspose2d(128, 32*4, kernel_size=2, stride=2, padding=3, bias=True),#64,64
820
+
821
+
822
+ )
823
+ self.generator = Generator(64,256,8)
824
+
825
+
826
+ def forward(self, example_image, audio, pose, jaco_net, weight):
827
+ hidden = ( torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()),
828
+ torch.autograd.Variable(torch.zeros(3, audio.size(0), 256).cuda()))
829
+ outs = example_image
830
+ for down_block in self.down_blocks:
831
+ outs = down_block(outs)
832
+ image_feature = outs
833
+ image_feature = image_feature.view(image_feature.shape[0], -1) #1, 512, 1, 1
834
+ lstm_input = []
835
+ for step_t in range(audio.size(1)):
836
+ current_audio = audio[ : ,step_t , :, :].unsqueeze(1)
837
+ current_feature = self.audio_eocder(current_audio)
838
+ current_feature = current_feature.view(current_feature.size(0), -1)
839
+ current_feature = self.audio_eocder_fc(current_feature)*weight
840
+ pose_f = self.pose_encoder(pose[:,step_t])
841
+ features = torch.cat([image_feature, current_feature, pose_f], 1)
842
+ lstm_input.append(features)
843
+ lstm_input = torch.stack(lstm_input, dim = 1)
844
+ lstm_out, _ = self.lstm(lstm_input, hidden) #1,N,256
845
+
846
+
847
+ fc_out = []
848
+ deco_out = []
849
+ for step_t in range(audio.size(1)):
850
+ fc_in = lstm_out[:,step_t,:]
851
+ # fc_out.append(self.lstm_fc(fc_in))
852
+ if jaco_net == 'cnn':
853
+ fc_feature = torch.unsqueeze(fc_in,2)
854
+ fc_feature = torch.unsqueeze(fc_feature,3)
855
+ deco_out.append(self.decon(fc_feature))
856
+ elif jaco_net == 'gan':
857
+ result,_ = self.generator([fc_in])
858
+ deco_out.append(result)
859
+ else:
860
+ raise Exception("jaco_net type wrong")
861
+
862
+ return torch.stack(deco_out,dim=1)
863
+
864
+
865
+
866
+ class Ct_encoder(nn.Module):
867
+ def __init__(self):
868
+ super(Ct_encoder, self).__init__()
869
+ self.audio_eocder = nn.Sequential(
870
+ conv2d(1,64,3,1,1),
871
+ conv2d(64,128,3,1,1),
872
+ nn.MaxPool2d(3, stride=(1,2)),
873
+ conv2d(128,256,3,1,1),
874
+ conv2d(256,256,3,1,1),
875
+ conv2d(256,512,3,1,1),
876
+ nn.MaxPool2d(3, stride=(2,2))
877
+ )
878
+ self.audio_eocder_fc = nn.Sequential(
879
+ nn.Linear(1024 *12,2048),
880
+ nn.ReLU(True),
881
+ nn.Linear(2048,256),
882
+ nn.ReLU(True),
883
+
884
+ )
885
+
886
+ def forward(self, audio):
887
+
888
+ feature = self.audio_eocder(audio)
889
+ feature = feature.view(feature.size(0),-1)
890
+ x = self.audio_eocder_fc(feature)
891
+
892
+ return x
893
+
894
+
895
+ class EmotionNet(nn.Module):
896
+ def __init__(self):
897
+ super(EmotionNet, self).__init__()
898
+
899
+ self.emotion_eocder = nn.Sequential(
900
+ conv2d(1,64,3,1,1),
901
+
902
+ nn.MaxPool2d((1,3), stride=(1,2)), #[1, 64, 12, 12]
903
+ conv2d(64,128,3,1,1),
904
+
905
+ conv2d(128,256,3,1,1),
906
+
907
+ nn.MaxPool2d((12,1), stride=(12,1)), #[1, 256, 1, 12]
908
+
909
+ conv2d(256,512,3,1,1),
910
+
911
+ nn.MaxPool2d((1,2), stride=(1,2)) #[1, 512, 1, 6]
912
+
913
+ )
914
+ self.emotion_eocder_fc = nn.Sequential(
915
+ nn.Linear(512 *6,2048),
916
+ nn.ReLU(True),
917
+ nn.Linear(2048,128),
918
+ nn.ReLU(True),
919
+
920
+ )
921
+
922
+ self.last_fc = nn.Linear(128,8)
923
+
924
+ self.re_id = nn.Sequential(
925
+ conv2d(512,1024,3,1,1),
926
+
927
+ nn.MaxPool2d((1,2), stride=(1,2)), #[1, 1024, 1, 3]
928
+ conv2d(1024,1024,3,1,1),
929
+
930
+ conv2d(1024,2048,3,1,1),
931
+
932
+ nn.MaxPool2d((1,2), stride=(1,2)) #[1, 2048, 1, 1]
933
+
934
+
935
+ )
936
+ self.re_id_fc = nn.Sequential(
937
+
938
+ nn.Linear(2048,512),
939
+ nn.ReLU(True),
940
+ nn.Linear(512,128),
941
+ nn.ReLU(True),
942
+ )
943
+
944
+
945
+ def forward(self, mfcc):
946
+ # mfcc= torch.unsqueeze(mfcc, 1)
947
+ mfcc=torch.transpose(mfcc,2,3)
948
+ feature = self.emotion_eocder(mfcc)
949
+
950
+ # id_feature = feature.detach()
951
+
952
+ feature = feature.view(feature.size(0),-1)
953
+ x = self.emotion_eocder_fc(feature)
954
+
955
+
956
+ # remove_feature = self.re_id(id_feature)
957
+ # remove_feature = remove_feature.view(remove_feature.size(0),-1)
958
+ # y = self.re_id_fc(remove_feature)
959
+
960
+ return x
961
+
962
+
963
+ class AF2F(nn.Module):
964
+ def __init__(self):
965
+ super(AF2F, self).__init__()
966
+ self.decon = nn.Sequential(
967
+ nn.ConvTranspose2d(384, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
968
+ nn.BatchNorm2d(256),
969
+ nn.ReLU(True),
970
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
971
+ nn.BatchNorm2d(128),
972
+ nn.ReLU(True),
973
+ nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=True), #16,16
974
+ nn.BatchNorm2d(64),
975
+ nn.ReLU(True),
976
+ nn.ConvTranspose2d(64, 64, kernel_size=4, stride=2, padding=1, bias=True),#32,32
977
+ nn.BatchNorm2d(64),
978
+ nn.ReLU(True),
979
+ nn.ConvTranspose2d(64, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
980
+
981
+
982
+ )
983
+
984
+ def forward(self, content,emotion):
985
+ features = torch.cat([content, emotion], 1) #connect tensors inputs and dimension
986
+ features = torch.unsqueeze(features,2)
987
+ features = torch.unsqueeze(features,3)
988
+ x = self.decon(features)
989
+
990
+
991
+ return x
992
+
993
+ class AF2F_s(nn.Module):
994
+ def __init__(self):
995
+ super(AF2F_s, self).__init__()
996
+ self.decon = nn.Sequential(
997
+ nn.ConvTranspose2d(256, 256, kernel_size=6, stride=2, padding=1, bias=True),#4,4
998
+ nn.BatchNorm2d(256),
999
+ nn.ReLU(True),
1000
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
1001
+ nn.BatchNorm2d(128),
1002
+ nn.ReLU(True),
1003
+ nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=True), #16,16
1004
+ nn.BatchNorm2d(64),
1005
+ nn.ReLU(True),
1006
+ nn.ConvTranspose2d(64, 64, kernel_size=4, stride=2, padding=1, bias=True),#32,32
1007
+ nn.BatchNorm2d(64),
1008
+ nn.ReLU(True),
1009
+ nn.ConvTranspose2d(64, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
1010
+
1011
+ nn.ReLU(),
1012
+ )
1013
+
1014
+ def forward(self, content):
1015
+ # features = torch.cat([content, emotion], 1) #connect tensors inputs and dimension
1016
+ features = torch.unsqueeze(content,2)
1017
+ features = torch.unsqueeze(features,3)
1018
+ x = self.decon(features)
1019
+
1020
+
1021
+ return x
1022
+
1023
+
1024
+ class A2I(nn.Module):
1025
+ def __init__(self):
1026
+ super(A2I, self).__init__()
1027
+ self.audio_eocder = nn.Sequential(
1028
+ conv2d(1,64,3,1,1),
1029
+ conv2d(64,128,3,1,1),
1030
+ nn.MaxPool2d((1,5), stride=(1,2)),
1031
+ conv2d(128,256,3,1,1),
1032
+ conv2d(256,256,3,1,1),
1033
+
1034
+ nn.MaxPool2d((5,5), stride=(2,2))
1035
+ )
1036
+ self.decon = nn.Sequential(
1037
+
1038
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
1039
+ nn.BatchNorm2d(128),
1040
+ nn.ReLU(True),
1041
+ nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=True), #16,16
1042
+ nn.BatchNorm2d(64),
1043
+ nn.ReLU(True),
1044
+ nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1, bias=True),#32,32
1045
+ nn.BatchNorm2d(32),
1046
+ nn.ReLU(True),
1047
+ nn.ConvTranspose2d(32, 2, kernel_size=4, stride=2, padding=1, bias=True),#64,64
1048
+
1049
+ nn.ReLU(),
1050
+ )
1051
+
1052
+ def forward(self, mfcc):
1053
+ mfcc= torch.unsqueeze(mfcc, 1)
1054
+ mfcc=torch.transpose(mfcc,2,3)
1055
+ feature = self.audio_eocder(mfcc)
1056
+
1057
+ # id_feature = feature.detach()
1058
+
1059
+ x = self.decon(feature)
1060
+
1061
+ return x
1062
+
1063
+ def kp2gaussian(kp, spatial_size, kp_variance):
1064
+ """
1065
+ Transform a keypoint into gaussian like representation
1066
+ """
1067
+ mean = kp['value'] #[4,10,2]
1068
+
1069
+ coordinate_grid = make_coordinate_grid(spatial_size, mean.type()) #[h,w,2]
1070
+ number_of_leading_dimensions = len(mean.shape) - 1
1071
+ shape = (1,) * number_of_leading_dimensions + coordinate_grid.shape #5
1072
+ coordinate_grid = coordinate_grid.view(*shape) #[1,1,h,w,2]
1073
+ repeats = mean.shape[:number_of_leading_dimensions] + (1, 1, 1)
1074
+ coordinate_grid = coordinate_grid.repeat(*repeats) #[4,10,h,w,2]
1075
+
1076
+ # Preprocess kp shape
1077
+ shape = mean.shape[:number_of_leading_dimensions] + (1, 1, 2)
1078
+ mean = mean.view(*shape) #[4,10,1,1,2]
1079
+
1080
+ mean_sub = (coordinate_grid - mean)
1081
+
1082
+ out = torch.exp(-0.5 * (mean_sub ** 2).sum(-1) / kp_variance)
1083
+
1084
+ return out
1085
+
1086
+
1087
+ def make_coordinate_grid(spatial_size, type):
1088
+ """
1089
+ Create a meshgrid [-1,1] x [-1,1] of given spatial_size.
1090
+ """
1091
+ h, w = spatial_size
1092
+ x = torch.arange(w).type(type)
1093
+ y = torch.arange(h).type(type)
1094
+
1095
+ x = (2 * (x / (w - 1)) - 1)
1096
+ y = (2 * (y / (h - 1)) - 1)
1097
+
1098
+ yy = y.view(-1, 1).repeat(1, w)
1099
+ xx = x.view(1, -1).repeat(h, 1)
1100
+
1101
+ meshed = torch.cat([xx.unsqueeze_(2), yy.unsqueeze_(2)], 2)
1102
+
1103
+ return meshed
1104
+
1105
+
1106
+ class ResBlock2d(nn.Module):
1107
+ """
1108
+ Res block, preserve spatial resolution.
1109
+ """
1110
+
1111
+ def __init__(self, in_features, kernel_size, padding):
1112
+ super(ResBlock2d, self).__init__()
1113
+ self.conv1 = nn.Conv2d(in_channels=in_features, out_channels=in_features, kernel_size=kernel_size,
1114
+ padding=padding)
1115
+ self.conv2 = nn.Conv2d(in_channels=in_features, out_channels=in_features, kernel_size=kernel_size,
1116
+ padding=padding)
1117
+ self.norm1 = BatchNorm2d(in_features, affine=True)
1118
+ self.norm2 = BatchNorm2d(in_features, affine=True)
1119
+
1120
+ def forward(self, x):
1121
+ out = self.norm1(x)
1122
+ out = F.relu(out)
1123
+ out = self.conv1(out)
1124
+ out = self.norm2(out)
1125
+ out = F.relu(out)
1126
+ out = self.conv2(out)
1127
+ out += x
1128
+ return out
1129
+
1130
+
1131
+ class UpBlock2d(nn.Module):
1132
+ """
1133
+ Upsampling block for use in decoder.
1134
+ """
1135
+
1136
+ def __init__(self, in_features, out_features, kernel_size=3, padding=1, groups=1):
1137
+ super(UpBlock2d, self).__init__()
1138
+
1139
+ self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size,
1140
+ padding=padding, groups=groups)
1141
+ self.norm = BatchNorm2d(out_features, affine=True)
1142
+
1143
+ def forward(self, x):
1144
+ out = F.interpolate(x, scale_factor=2)
1145
+ out = self.conv(out)
1146
+ out = self.norm(out)
1147
+ out = F.relu(out)
1148
+ return out
1149
+
1150
+
1151
+ class DownBlock2d(nn.Module):
1152
+ """
1153
+ Downsampling block for use in encoder.
1154
+ """
1155
+
1156
+ def __init__(self, in_features, out_features, kernel_size=3, padding=1, groups=1):
1157
+ super(DownBlock2d, self).__init__()
1158
+ self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features, kernel_size=kernel_size,
1159
+ padding=padding, groups=groups)
1160
+ self.norm = BatchNorm2d(out_features, affine=True)
1161
+ self.pool = nn.AvgPool2d(kernel_size=(2, 2))
1162
+
1163
+ def forward(self, x):
1164
+ out = self.conv(x)
1165
+ out = self.norm(out)
1166
+ out = F.relu(out)
1167
+ out = self.pool(out)
1168
+ return out
1169
+
1170
+
1171
+ class SameBlock2d(nn.Module):
1172
+ """
1173
+ Simple block, preserve spatial resolution.
1174
+ """
1175
+
1176
+ def __init__(self, in_features, out_features, groups=1, kernel_size=3, padding=1):
1177
+ super(SameBlock2d, self).__init__()
1178
+ self.conv = nn.Conv2d(in_channels=in_features, out_channels=out_features,
1179
+ kernel_size=kernel_size, padding=padding, groups=groups)
1180
+ self.norm = BatchNorm2d(out_features, affine=True)
1181
+
1182
+ def forward(self, x):
1183
+ out = self.conv(x)
1184
+ out = self.norm(out)
1185
+ out = F.relu(out)
1186
+ return out
1187
+
1188
+
1189
+ class Encoder(nn.Module):
1190
+ """
1191
+ Hourglass Encoder
1192
+ """
1193
+
1194
+ def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):
1195
+ super(Encoder, self).__init__()
1196
+
1197
+ down_blocks = []
1198
+ for i in range(num_blocks):
1199
+ down_blocks.append(DownBlock2d(in_features if i == 0 else min(max_features, block_expansion * (2 ** i)),
1200
+ min(max_features, block_expansion * (2 ** (i + 1))),
1201
+ kernel_size=3, padding=1))
1202
+ self.down_blocks = nn.ModuleList(down_blocks)
1203
+
1204
+ def forward(self, x):
1205
+ outs = [x]
1206
+ for down_block in self.down_blocks:
1207
+ outs.append(down_block(outs[-1]))
1208
+ return outs
1209
+
1210
+
1211
+ class Decoder(nn.Module):
1212
+ """
1213
+ Hourglass Decoder
1214
+ """
1215
+
1216
+ def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):
1217
+ super(Decoder, self).__init__()
1218
+
1219
+ up_blocks = []
1220
+
1221
+ for i in range(num_blocks)[::-1]:
1222
+ in_filters = (1 if i == num_blocks - 1 else 2) * min(max_features, block_expansion * (2 ** (i + 1)))
1223
+ out_filters = min(max_features, block_expansion * (2 ** i))
1224
+ up_blocks.append(UpBlock2d(in_filters, out_filters, kernel_size=3, padding=1))
1225
+
1226
+ self.up_blocks = nn.ModuleList(up_blocks)
1227
+ self.out_filters = block_expansion + in_features
1228
+
1229
+ def forward(self, x):
1230
+ out = x.pop()
1231
+ for up_block in self.up_blocks:
1232
+ out = up_block(out)
1233
+ skip = x.pop()
1234
+ out = torch.cat([out, skip], dim=1)
1235
+ return out
1236
+
1237
+
1238
+ class Hourglass(nn.Module):
1239
+ """
1240
+ Hourglass architecture.
1241
+ """
1242
+
1243
+ def __init__(self, block_expansion, in_features, num_blocks=3, max_features=256):
1244
+ super(Hourglass, self).__init__()
1245
+ self.encoder = Encoder(block_expansion, in_features, num_blocks, max_features)
1246
+ self.decoder = Decoder(block_expansion, in_features, num_blocks, max_features)
1247
+ self.out_filters = self.decoder.out_filters
1248
+
1249
+ def forward(self, x):
1250
+ return self.decoder(self.encoder(x))
1251
+
1252
+
1253
+ class AntiAliasInterpolation2d(nn.Module):
1254
+ """
1255
+ Band-limited downsampling, for better preservation of the input signal.
1256
+ """
1257
+ def __init__(self, channels, scale):
1258
+ super(AntiAliasInterpolation2d, self).__init__()
1259
+ # sigma = (1 / scale - 1) / 2
1260
+ sigma = 1.5
1261
+ kernel_size = 2 * round(sigma * 4) + 1
1262
+ self.ka = kernel_size // 2
1263
+ self.kb = self.ka - 1 if kernel_size % 2 == 0 else self.ka
1264
+
1265
+ kernel_size = [kernel_size, kernel_size]
1266
+ sigma = [sigma, sigma]
1267
+ # The gaussian kernel is the product of the
1268
+ # gaussian function of each dimension.
1269
+ kernel = 1
1270
+ meshgrids = torch.meshgrid(
1271
+ [
1272
+ torch.arange(size, dtype=torch.float32)
1273
+ for size in kernel_size
1274
+ ]
1275
+ )
1276
+ for size, std, mgrid in zip(kernel_size, sigma, meshgrids):
1277
+ mean = (size - 1) / 2
1278
+ kernel *= torch.exp(-(mgrid - mean) ** 2 / (2 * std ** 2))
1279
+
1280
+ # Make sure sum of values in gaussian kernel equals 1.
1281
+ kernel = kernel / torch.sum(kernel)
1282
+ # Reshape to depthwise convolutional weight
1283
+ kernel = kernel.view(1, 1, *kernel.size())
1284
+ kernel = kernel.repeat(channels, *[1] * (kernel.dim() - 1))
1285
+
1286
+ self.register_buffer('weight', kernel)
1287
+ self.groups = channels
1288
+ self.scale = scale
1289
+ inv_scale = 1 / scale
1290
+ self.int_inv_scale = int(inv_scale)
1291
+
1292
+ def forward(self, input):
1293
+ if self.scale == 1.0:
1294
+ return input
1295
+
1296
+ out = F.pad(input, (self.ka, self.kb, self.ka, self.kb))
1297
+ out = F.conv2d(out, weight=self.weight, groups=self.groups)
1298
+ out = out[:, :, ::self.int_inv_scale, ::self.int_inv_scale]
1299
+
1300
+ return out
1301
+
1302
+ def sigmoid(x):
1303
+ return 1 / (1 + math.exp(-x))
1304
+
1305
+
1306
+ def norm_angle(angle):
1307
+ norm_angle = sigmoid(10 * (abs(angle) / 0.7853975 - 1))
1308
+ return norm_angle
1309
+
1310
+
1311
+ def conv3x3(in_planes, out_planes, stride=1):
1312
+ "3x3 convolution with padding"
1313
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
1314
+ padding=1, bias=False)
1315
+
1316
+
1317
+ class BasicBlock(nn.Module):
1318
+ expansion = 1
1319
+
1320
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
1321
+ super(BasicBlock, self).__init__()
1322
+ self.conv1 = conv3x3(inplanes, planes, stride)
1323
+ self.bn1 = nn.BatchNorm2d(planes)
1324
+ self.relu = nn.ReLU()
1325
+ self.conv2 = conv3x3(planes, planes)
1326
+ self.bn2 = nn.BatchNorm2d(planes)
1327
+ self.downsample = downsample
1328
+ self.stride = stride
1329
+
1330
+ def forward(self, x):
1331
+ residual = x
1332
+
1333
+ out = self.conv1(x)
1334
+ out = self.bn1(out)
1335
+ out = self.relu(out)
1336
+
1337
+ out = self.conv2(out)
1338
+ out = self.bn2(out)
1339
+
1340
+ if self.downsample is not None:
1341
+ residual = self.downsample(x)
1342
+
1343
+ out += residual
1344
+ out = self.relu(out)
1345
+
1346
+ return out
1347
+
1348
+
1349
+ class Bottleneck(nn.Module):
1350
+ expansion = 4
1351
+
1352
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
1353
+ super(Bottleneck, self).__init__()
1354
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
1355
+ self.bn1 = nn.BatchNorm2d(planes)
1356
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
1357
+ padding=1, bias=False)
1358
+ self.bn2 = nn.BatchNorm2d(planes)
1359
+ self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
1360
+ self.bn3 = nn.BatchNorm2d(planes * 4)
1361
+ self.relu = nn.ReLU()
1362
+ self.downsample = downsample
1363
+ self.stride = stride
1364
+
1365
+ def forward(self, x):
1366
+ residual = x
1367
+
1368
+ out = self.conv1(x)
1369
+ out = self.bn1(out)
1370
+ out = self.relu(out)
1371
+
1372
+ out = self.conv2(out)
1373
+ out = self.bn2(out)
1374
+ out = self.relu(out)
1375
+
1376
+ out = self.conv3(out)
1377
+ out = self.bn3(out)
1378
+
1379
+ if self.downsample is not None:
1380
+ residual = self.downsample(x)
1381
+
1382
+ out = out + residual
1383
+ out = self.relu(out)
1384
+
1385
+ return out
1386
+
1387
+ class EmDetector(nn.Module):
1388
+ """
1389
+ Detecting a keypoints. Return keypoint position and jacobian near each keypoint.
1390
+ """
1391
+
1392
+ def __init__(self, block_expansion, num_channels, max_features,
1393
+ num_blocks, scale_factor=1, num_classes=8):
1394
+ super(EmDetector, self).__init__()
1395
+ self.inplanes = 64
1396
+ self.predictor = Hourglass(block_expansion, in_features=num_channels,
1397
+ max_features=max_features, num_blocks=num_blocks)
1398
+
1399
+
1400
+
1401
+
1402
+ self.scale_factor = scale_factor
1403
+ if self.scale_factor != 1:
1404
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
1405
+ self.conv1 = nn.Conv2d(self.predictor.out_filters, 64, kernel_size=3, stride=1, padding=1,
1406
+ bias=False)
1407
+ self.bn1 = nn.BatchNorm2d(64)
1408
+ self.relu = nn.ReLU()
1409
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
1410
+ layers = [2,2,2,2]
1411
+ self.layer1 = self._make_layer(BasicBlock, 64, layers[0])
1412
+ self.layer2 = self._make_layer(BasicBlock, 128, layers[1], stride=2)
1413
+ self.layer3 = self._make_layer(BasicBlock, 256, layers[2], stride=2)
1414
+ self.layer4 = self._make_layer(BasicBlock, 512, layers[3], stride=2)
1415
+ self.avgpool = nn.AdaptiveAvgPool2d(1)
1416
+ self.fc = nn.Linear(512 * BasicBlock.expansion, num_classes)
1417
+ self.classify = Classify()
1418
+ def _make_layer(self, block, planes, blocks, stride=1):
1419
+ downsample = None
1420
+ if stride != 1 or self.inplanes != planes * block.expansion:
1421
+ downsample = nn.Sequential(
1422
+ nn.Conv2d(self.inplanes, planes * block.expansion,
1423
+ kernel_size=1, stride=stride, bias=False),
1424
+ nn.BatchNorm2d(planes * block.expansion),
1425
+ )
1426
+
1427
+ layers = []
1428
+ layers.append(block(self.inplanes, planes, stride, downsample))
1429
+ self.inplanes = planes * block.expansion
1430
+ for i in range(1, blocks):
1431
+ layers.append(block(self.inplanes, planes))
1432
+
1433
+ return nn.Sequential(*layers)
1434
+
1435
+ def adain_feature(self, x): #torch.Size([4, 3, H, W])
1436
+ if self.scale_factor != 1:
1437
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1438
+
1439
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1440
+
1441
+ # out = self.fc(out)
1442
+
1443
+ return feature_map
1444
+
1445
+ def forward(self, x): #torch.Size([4, 3, H, W])
1446
+ if self.scale_factor != 1:
1447
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1448
+
1449
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1450
+ f = self.conv1(feature_map) #[16,64,64,64]
1451
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1452
+ f = self.relu(f)
1453
+ f = self.maxpool(f) #[16, 64, 32, 32]
1454
+
1455
+ f = self.layer1(f) #[16, 64, 32, 32]
1456
+ f = self.layer2(f) #[16, 128, 16, 16])
1457
+ f = self.layer3(f) #[16, 256, 8, 8]
1458
+ f = self.layer4(f) #[16, 512, 4, 4]
1459
+ f = self.avgpool(f) #[16, 512, 1, 1]
1460
+ out = f.squeeze(3).squeeze(2)
1461
+ fake = self.classify(out)
1462
+ # out = self.fc(out)
1463
+
1464
+ return out, fake
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+
1471
+ class Emotion_k(nn.Module):
1472
+ """
1473
+ Detecting a keypoints. Return keypoint position and jacobian near each keypoint.
1474
+ """
1475
+
1476
+ def __init__(self, block_expansion, num_channels, max_features,
1477
+ num_blocks, scale_factor=1, num_classes=8):
1478
+ super(Emotion_k, self).__init__()
1479
+ self.inplanes = 64
1480
+ self.predictor = Hourglass(block_expansion, in_features=num_channels,
1481
+ max_features=max_features, num_blocks=num_blocks)
1482
+
1483
+
1484
+
1485
+
1486
+ self.scale_factor = scale_factor
1487
+ if self.scale_factor != 1:
1488
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
1489
+ self.conv1 = nn.Conv2d(self.predictor.out_filters, 64, kernel_size=3, stride=1, padding=1,
1490
+ bias=False)
1491
+ self.bn1 = nn.BatchNorm2d(64)
1492
+ self.relu = nn.ReLU()
1493
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
1494
+ layers = [2,2,2,2]
1495
+ self.layer1 = self._make_layer(BasicBlock, 64, layers[0])
1496
+ self.layer2 = self._make_layer(BasicBlock, 128, layers[1], stride=2)
1497
+ self.layer3 = self._make_layer(BasicBlock, 256, layers[2], stride=2)
1498
+ self.layer4 = self._make_layer(BasicBlock, 512, layers[3], stride=2)
1499
+ self.avgpool = nn.AdaptiveAvgPool2d(1)
1500
+ self.fc = nn.Linear(512 * BasicBlock.expansion, num_classes)
1501
+
1502
+ self.embed_fn, self.input_ch = get_embedder(10, 0)
1503
+
1504
+ self.fc_p = nn.Sequential(
1505
+ nn.Linear(10 * 126,1024),
1506
+ nn.ReLU(True),
1507
+ nn.Linear(1024,512),
1508
+ nn.ReLU(True),
1509
+
1510
+ )
1511
+ self.fc_n = nn.Sequential(
1512
+ nn.Linear(10 * 6,128),
1513
+ nn.ReLU(True),
1514
+ nn.Linear(128,512),
1515
+ nn.ReLU(True),
1516
+
1517
+ )
1518
+
1519
+ self.fc_all = nn.Sequential(
1520
+ nn.Linear(1024,512),
1521
+ nn.ReLU(True),
1522
+ nn.Linear(512,256),
1523
+ nn.ReLU(True),
1524
+ nn.Linear(256,64),
1525
+ nn.ReLU(True),
1526
+ )
1527
+
1528
+ # self.fc_single = nn.Sequential(
1529
+ # nn.Linear(512,256),
1530
+ # nn.ReLU(True),
1531
+ # nn.Linear(256,64),
1532
+ # nn.ReLU(True),
1533
+ # )
1534
+
1535
+ self.final = nn.Sequential(
1536
+ nn.Conv1d(1,2,4,2,1),
1537
+ nn.MaxPool1d(2,stride=2),
1538
+ nn.ReLU(True),
1539
+ nn.Conv1d(2,4,4,2,1),
1540
+ nn.ReLU(True),
1541
+ nn.Conv1d(4,4,3),
1542
+
1543
+ )
1544
+
1545
+ self.final_4 = nn.Sequential(
1546
+ nn.Conv1d(4,4,3,1,1),
1547
+ nn.MaxPool1d(2,stride=2),
1548
+ nn.ReLU(True),
1549
+ nn.Conv1d(4,4,3,1)
1550
+
1551
+ )
1552
+
1553
+ self.final_10 = nn.Sequential(
1554
+ nn.Conv1d(4,8,3,1,1), #[B,8,16]
1555
+ nn.MaxPool1d(2,stride=2), #[B,8,8]
1556
+ nn.ReLU(True),
1557
+ nn.Conv1d(8,10,3,1), #[B,10,6]
1558
+
1559
+
1560
+ )
1561
+
1562
+ self.classify = Classify()
1563
+
1564
+ def _make_layer(self, block, planes, blocks, stride=1):
1565
+ downsample = None
1566
+ if stride != 1 or self.inplanes != planes * block.expansion:
1567
+ downsample = nn.Sequential(
1568
+ nn.Conv2d(self.inplanes, planes * block.expansion,
1569
+ kernel_size=1, stride=stride, bias=False),
1570
+ nn.BatchNorm2d(planes * block.expansion),
1571
+ )
1572
+
1573
+ layers = []
1574
+ layers.append(block(self.inplanes, planes, stride, downsample))
1575
+ self.inplanes = planes * block.expansion
1576
+ for i in range(1, blocks):
1577
+ layers.append(block(self.inplanes, planes))
1578
+
1579
+ return nn.Sequential(*layers)
1580
+
1581
+ def linear_10(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1582
+ if self.scale_factor != 1:
1583
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1584
+
1585
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1586
+ f = self.conv1(feature_map) #[16,64,64,64]
1587
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1588
+ f = self.relu(f)
1589
+ f = self.maxpool(f) #[16, 64, 32, 32]
1590
+
1591
+ f = self.layer1(f) #[16, 64, 32, 32]
1592
+ f = self.layer2(f) #[16, 128, 16, 16])
1593
+ f = self.layer3(f) #[16, 256, 8, 8]
1594
+ f = self.layer4(f) #[16, 512, 4, 4]
1595
+ f = self.avgpool(f) #[16, 512, 1, 1]
1596
+ out = f.squeeze(3).squeeze(2)
1597
+ fake = self.classify(out)
1598
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1599
+ neu_input = torch.cat((value,jacobian),2)
1600
+ posi_input = self.embed_fn(neu_input)
1601
+ posi_input =posi_input.reshape(posi_input.shape[0],-1)
1602
+ ner_feature = self.fc_p(posi_input)
1603
+ all_fc = self.fc_all(torch.cat((out,ner_feature),1)).reshape(-1,4,16)
1604
+ result = self.final_10(all_fc)
1605
+ e_value = result[:,:,:2]
1606
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],10,2,2)
1607
+ kp = {'value': e_value,'jacobian': e_jacobian}
1608
+
1609
+ return kp, fake
1610
+
1611
+
1612
+ def linear_4(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1613
+ if self.scale_factor != 1:
1614
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1615
+
1616
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1617
+ f = self.conv1(feature_map) #[16,64,64,64]
1618
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1619
+ f = self.relu(f)
1620
+ f = self.maxpool(f) #[16, 64, 32, 32]
1621
+
1622
+ f = self.layer1(f) #[16, 64, 32, 32]
1623
+ f = self.layer2(f) #[16, 128, 16, 16])
1624
+ f = self.layer3(f) #[16, 256, 8, 8]
1625
+ f = self.layer4(f) #[16, 512, 4, 4]
1626
+ f = self.avgpool(f) #[16, 512, 1, 1]
1627
+ out = f.squeeze(3).squeeze(2)
1628
+ fake = self.classify(out)
1629
+ # jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1630
+ # neu_input = torch.cat((value,jacobian),2)
1631
+ # posi_input = self.embed_fn(neu_input)
1632
+ # posi_input =posi_input.reshape(posi_input.shape[0],-1)
1633
+ # ner_feature = self.fc_p(posi_input)
1634
+ # all_fc = self.fc_all(torch.cat((out,ner_feature),1)).reshape(-1,4,16)
1635
+ all_fc = torch.unsqueeze(self.fc_single(out),1)
1636
+ result = self.final(all_fc)
1637
+ e_value = result[:,:,:2]
1638
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],4,2,2)
1639
+ kp = {'value': e_value,'jacobian': e_jacobian}
1640
+ # out = self.fc(out)
1641
+
1642
+ return kp, fake
1643
+
1644
+ def linear_np_10(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1645
+ if self.scale_factor != 1:
1646
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1647
+
1648
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1649
+ f = self.conv1(feature_map) #[16,64,64,64]
1650
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1651
+ f = self.relu(f)
1652
+ f = self.maxpool(f) #[16, 64, 32, 32]
1653
+
1654
+ f = self.layer1(f) #[16, 64, 32, 32]
1655
+ f = self.layer2(f) #[16, 128, 16, 16])
1656
+ f = self.layer3(f) #[16, 256, 8, 8]
1657
+ f = self.layer4(f) #[16, 512, 4, 4]
1658
+ f = self.avgpool(f) #[16, 512, 1, 1]
1659
+ out = f.squeeze(3).squeeze(2)
1660
+ fake = self.classify(out)
1661
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1662
+ neu_input = torch.cat((value,jacobian),2)
1663
+
1664
+ posi_input =neu_input.reshape(neu_input.shape[0],-1)
1665
+ ner_feature = self.fc_n(posi_input)
1666
+ all_fc = self.fc_all(torch.cat((out,ner_feature),1)).reshape(-1,4,16)
1667
+ result = self.final_10(all_fc)
1668
+ e_value = result[:,:,:2]
1669
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],10,2,2)
1670
+ kp = {'value': e_value,'jacobian': e_jacobian}
1671
+ # out = self.fc(out)
1672
+
1673
+ return kp, fake
1674
+
1675
+ def linear_np_4(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1676
+ if self.scale_factor != 1:
1677
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1678
+
1679
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1680
+ f = self.conv1(feature_map) #[16,64,64,64]
1681
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1682
+ f = self.relu(f)
1683
+ f = self.maxpool(f) #[16, 64, 32, 32]
1684
+
1685
+ f = self.layer1(f) #[16, 64, 32, 32]
1686
+ f = self.layer2(f) #[16, 128, 16, 16])
1687
+ f = self.layer3(f) #[16, 256, 8, 8]
1688
+ f = self.layer4(f) #[16, 512, 4, 4]
1689
+ f = self.avgpool(f) #[16, 512, 1, 1]
1690
+ out = f.squeeze(3).squeeze(2)
1691
+ fake = self.classify(out)
1692
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1693
+ neu_input = torch.cat((value,jacobian),2)
1694
+
1695
+ posi_input =neu_input.reshape(neu_input.shape[0],-1)
1696
+ ner_feature = self.fc_n(posi_input)
1697
+ all_fc = torch.unsqueeze(self.fc_all(torch.cat((out,ner_feature),1)),1)
1698
+ result = self.final(all_fc)
1699
+ e_value = result[:,:,:2]
1700
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],4,2,2)
1701
+ kp = {'value': e_value,'jacobian': e_jacobian}
1702
+ # out = self.fc(out)
1703
+
1704
+ return kp, fake
1705
+
1706
+
1707
+ def emotion_feature(self, feature, value, jacobian): #torch.Size([4, 3, H, W])
1708
+
1709
+ out = feature
1710
+ fake = self.classify(out)
1711
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1712
+ neu_input = torch.cat((value,jacobian),2)
1713
+ posi_input = self.embed_fn(neu_input)
1714
+ posi_input =posi_input.reshape(posi_input.shape[0],-1)
1715
+ ner_feature = self.fc_p(posi_input)
1716
+ all_fc = torch.unsqueeze(self.fc_all(torch.cat((out,ner_feature),1)),1)
1717
+ result = self.final(all_fc)
1718
+ e_value = result[:,:,:2]
1719
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],4,2,2)
1720
+ kp = {'value': e_value,'jacobian': e_jacobian}
1721
+ # out = self.fc(out)
1722
+
1723
+ return kp, fake
1724
+
1725
+ def feature(self, x): #torch.Size([4, 3, H, W])
1726
+ if self.scale_factor != 1:
1727
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1728
+
1729
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1730
+ f = self.conv1(feature_map) #[16,64,64,64]
1731
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1732
+ f = self.relu(f)
1733
+ f = self.maxpool(f) #[16, 64, 32, 32]
1734
+
1735
+ f = self.layer1(f) #[16, 64, 32, 32]
1736
+ f = self.layer2(f) #[16, 128, 16, 16])
1737
+ f = self.layer3(f) #[16, 256, 8, 8]
1738
+ f = self.layer4(f) #[16, 512, 4, 4]
1739
+ f = self.avgpool(f) #[16, 512, 1, 1]
1740
+ out = f.squeeze(3).squeeze(2)
1741
+
1742
+ # out = self.fc(out)
1743
+
1744
+ return out
1745
+
1746
+ def forward(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1747
+ if self.scale_factor != 1:
1748
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1749
+
1750
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1751
+ f = self.conv1(feature_map) #[16,64,64,64]
1752
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1753
+ f = self.relu(f)
1754
+ f = self.maxpool(f) #[16, 64, 32, 32]
1755
+
1756
+ f = self.layer1(f) #[16, 64, 32, 32]
1757
+ f = self.layer2(f) #[16, 128, 16, 16])
1758
+ f = self.layer3(f) #[16, 256, 8, 8]
1759
+ f = self.layer4(f) #[16, 512, 4, 4]
1760
+ f = self.avgpool(f) #[16, 512, 1, 1]
1761
+ out = f.squeeze(3).squeeze(2)
1762
+ fake = self.classify(out)
1763
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1764
+ neu_input = torch.cat((value,jacobian),2)
1765
+ posi_input = self.embed_fn(neu_input)
1766
+ posi_input =posi_input.reshape(posi_input.shape[0],-1)
1767
+ ner_feature = self.fc_p(posi_input)
1768
+ all_fc = torch.unsqueeze(self.fc_all(torch.cat((out,ner_feature),1)),1)
1769
+ result = self.final(all_fc)
1770
+ e_value = result[:,:,:2]
1771
+ e_jacobian = result[:,:,2:].reshape(result.shape[0],4,2,2)
1772
+ kp = {'value': e_value,'jacobian': e_jacobian}
1773
+ # out = self.fc(out)
1774
+
1775
+ return kp, fake
1776
+
1777
+ class Emotion_map(nn.Module):
1778
+ """
1779
+ Detecting a keypoints. Return keypoint position and jacobian near each keypoint.
1780
+ """
1781
+
1782
+ def __init__(self, block_expansion, num_channels, max_features,
1783
+ num_blocks, scale_factor=1, num_classes=8):
1784
+ super(Emotion_map, self).__init__()
1785
+ self.inplanes = 64
1786
+ self.predictor = Hourglass(block_expansion, in_features=num_channels,
1787
+ max_features=max_features, num_blocks=num_blocks)
1788
+
1789
+
1790
+
1791
+
1792
+ self.scale_factor = scale_factor
1793
+ if self.scale_factor != 1:
1794
+ self.down = AntiAliasInterpolation2d(num_channels, self.scale_factor)
1795
+ self.conv1 = nn.Conv2d(self.predictor.out_filters, 64, kernel_size=3, stride=1, padding=1,
1796
+ bias=False)
1797
+ self.bn1 = nn.BatchNorm2d(64)
1798
+ self.relu = nn.ReLU()
1799
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
1800
+ layers = [2,2,2,2]
1801
+ self.layer1 = self._make_layer(BasicBlock, 64, layers[0])
1802
+ self.layer2 = self._make_layer(BasicBlock, 128, layers[1], stride=2)
1803
+ self.layer3 = self._make_layer(BasicBlock, 256, layers[2], stride=2)
1804
+ self.layer4 = self._make_layer(BasicBlock, 512, layers[3], stride=2)
1805
+ self.avgpool = nn.AdaptiveAvgPool2d(1)
1806
+ self.fc = nn.Linear(512 * BasicBlock.expansion, num_classes)
1807
+
1808
+ self.embed_fn, self.input_ch = get_embedder(10, 0)
1809
+
1810
+ self.fc_p = nn.Sequential(
1811
+ nn.Linear(10 * 126,1024),
1812
+ nn.ReLU(True),
1813
+ nn.Linear(1024,512),
1814
+ nn.ReLU(True),
1815
+
1816
+ )
1817
+
1818
+ self.fc_all = nn.Sequential(
1819
+ nn.Linear(1024,2048),
1820
+ nn.ReLU(True)
1821
+ )
1822
+
1823
+ self.final = nn.Sequential(
1824
+ nn.ConvTranspose2d(128, 128, kernel_size=4, stride=2, padding=1, bias=True),#8,8
1825
+ nn.BatchNorm2d(128),
1826
+ nn.ReLU(True),
1827
+ nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=True), #16,16
1828
+ nn.BatchNorm2d(64),
1829
+ nn.ReLU(True),
1830
+ nn.ConvTranspose2d(64, 64, kernel_size=4, stride=2, padding=1, bias=True),#32,32
1831
+ nn.BatchNorm2d(64),
1832
+ nn.ReLU(True),
1833
+ nn.ConvTranspose2d(64, 32+3, kernel_size=4, stride=2, padding=1, bias=True),#64,64
1834
+
1835
+ )
1836
+
1837
+
1838
+ self.classify = Classify()
1839
+ self.kp = nn.Conv2d(in_channels=35, out_channels=10, kernel_size=(7, 7),
1840
+ padding=0)
1841
+ self.jacobian = nn.Conv2d(in_channels=35,
1842
+ out_channels=4 * 10, kernel_size=(7, 7), padding=0)
1843
+ self.jacobian.weight.data.zero_()
1844
+ self.jacobian.bias.data.copy_(torch.tensor([1, 0, 0, 1] * 10, dtype=torch.float))
1845
+ self.temperature = 0.1
1846
+
1847
+ self.kp_4 = nn.Conv2d(in_channels=35, out_channels=4, kernel_size=(7, 7),
1848
+ padding=0)
1849
+ self.jacobian_4 = nn.Conv2d(in_channels=35,
1850
+ out_channels=4 * 4, kernel_size=(7, 7), padding=0)
1851
+ self.jacobian_4.weight.data.zero_()
1852
+ self.jacobian_4.bias.data.copy_(torch.tensor([1, 0, 0, 1] * 4, dtype=torch.float))
1853
+
1854
+
1855
+ def _make_layer(self, block, planes, blocks, stride=1):
1856
+ downsample = None
1857
+ if stride != 1 or self.inplanes != planes * block.expansion:
1858
+ downsample = nn.Sequential(
1859
+ nn.Conv2d(self.inplanes, planes * block.expansion,
1860
+ kernel_size=1, stride=stride, bias=False),
1861
+ nn.BatchNorm2d(planes * block.expansion),
1862
+ )
1863
+
1864
+ layers = []
1865
+ layers.append(block(self.inplanes, planes, stride, downsample))
1866
+ self.inplanes = planes * block.expansion
1867
+ for i in range(1, blocks):
1868
+ layers.append(block(self.inplanes, planes))
1869
+
1870
+ return nn.Sequential(*layers)
1871
+
1872
+ def gaussian2kp(self, heatmap):
1873
+ """
1874
+ Extract the mean and from a heatmap
1875
+ """
1876
+ shape = heatmap.shape
1877
+ heatmap = heatmap.unsqueeze(-1) #[4,10,58,58,1]
1878
+ grid = make_coordinate_grid(shape[2:], heatmap.type()).unsqueeze_(0).unsqueeze_(0) #[1,1,58,58,2]
1879
+ value = (heatmap * grid).sum(dim=(2, 3)) #[4,10,2]
1880
+ kp = {'value': value}
1881
+
1882
+ return kp
1883
+
1884
+ def map_4(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1885
+ if self.scale_factor != 1:
1886
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1887
+
1888
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1889
+ f = self.conv1(feature_map) #[16,64,64,64]
1890
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1891
+ f = self.relu(f)
1892
+ f = self.maxpool(f) #[16, 64, 32, 32]
1893
+
1894
+ f = self.layer1(f) #[16, 64, 32, 32]
1895
+ f = self.layer2(f) #[16, 128, 16, 16])
1896
+ f = self.layer3(f) #[16, 256, 8, 8]
1897
+ f = self.layer4(f) #[16, 512, 4, 4]
1898
+ f = self.avgpool(f) #[16, 512, 1, 1]
1899
+ out = f.squeeze(3).squeeze(2)
1900
+ fake = self.classify(out)
1901
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1902
+ neu_input = torch.cat((value,jacobian),2)
1903
+ posi_input = self.embed_fn(neu_input)
1904
+ posi_input =posi_input.reshape(posi_input.shape[0],-1)
1905
+ ner_feature = self.fc_p(posi_input)
1906
+ all_fc = self.fc_all(torch.cat((out,ner_feature),1)).reshape(-1,128,4,4)
1907
+ feature_map = self.final(all_fc)
1908
+ prediction = self.kp_4(feature_map) #[4,10,H/4-6, W/4-6]
1909
+
1910
+ final_shape = prediction.shape
1911
+
1912
+ heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
1913
+ heatmap = F.softmax(heatmap / self.temperature, dim=2)
1914
+ heatmap = heatmap.view(*final_shape) #[4,10,58,58]
1915
+
1916
+ out = self.gaussian2kp(heatmap)
1917
+ out['heatmap'] = heatmap
1918
+
1919
+ if self.jacobian is not None:
1920
+ jacobian_map = self.jacobian_4(feature_map) ##[4,40,H/4-6, W/4-6]
1921
+ jacobian_map = jacobian_map.reshape(final_shape[0], 4, 4, final_shape[2],
1922
+ final_shape[3])
1923
+ heatmap = heatmap.unsqueeze(2)
1924
+
1925
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
1926
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
1927
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
1928
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
1929
+ out['jacobian'] = jacobian
1930
+
1931
+
1932
+
1933
+ return out, fake
1934
+
1935
+ def forward(self, x, value, jacobian): #torch.Size([4, 3, H, W])
1936
+ if self.scale_factor != 1:
1937
+ x = self.down(x) # 0.25 [4, 3, H/4, W/4]
1938
+
1939
+ feature_map = self.predictor(x) #[4,3+32,H/4, W/4]
1940
+ f = self.conv1(feature_map) #[16,64,64,64]
1941
+ f = self.bn1(f) #torch.Size([16, 64, 64, 64])
1942
+ f = self.relu(f)
1943
+ f = self.maxpool(f) #[16, 64, 32, 32]
1944
+
1945
+ f = self.layer1(f) #[16, 64, 32, 32]
1946
+ f = self.layer2(f) #[16, 128, 16, 16])
1947
+ f = self.layer3(f) #[16, 256, 8, 8]
1948
+ f = self.layer4(f) #[16, 512, 4, 4]
1949
+ f = self.avgpool(f) #[16, 512, 1, 1]
1950
+ out = f.squeeze(3).squeeze(2)
1951
+ fake = self.classify(out)
1952
+ jacobian = jacobian.reshape(jacobian.shape[0],jacobian.shape[1],4)
1953
+ neu_input = torch.cat((value,jacobian),2)
1954
+ posi_input = self.embed_fn(neu_input)
1955
+ posi_input =posi_input.reshape(posi_input.shape[0],-1)
1956
+ ner_feature = self.fc_p(posi_input)
1957
+ all_fc = self.fc_all(torch.cat((out,ner_feature),1)).reshape(-1,128,4,4)
1958
+ feature_map = self.final(all_fc)
1959
+
1960
+ prediction = self.kp(feature_map) #[4,10,H/4-6, W/4-6]
1961
+
1962
+ final_shape = prediction.shape
1963
+
1964
+ heatmap = prediction.view(final_shape[0], final_shape[1], -1) #[4, 10, 58*58]
1965
+ heatmap = F.softmax(heatmap / self.temperature, dim=2)
1966
+ heatmap = heatmap.view(*final_shape) #[4,10,58,58]
1967
+
1968
+ out = self.gaussian2kp(heatmap)
1969
+ out['heatmap'] = heatmap
1970
+
1971
+ if self.jacobian is not None:
1972
+ jacobian_map = self.jacobian(feature_map) ##[4,40,H/4-6, W/4-6]
1973
+ jacobian_map = jacobian_map.reshape(final_shape[0], 10, 4, final_shape[2],
1974
+ final_shape[3])
1975
+ heatmap = heatmap.unsqueeze(2)
1976
+
1977
+ jacobian = heatmap * jacobian_map #[4,10,4,H/4-6, W/4-6]
1978
+ jacobian = jacobian.view(final_shape[0], final_shape[1], 4, -1)
1979
+ jacobian = jacobian.sum(dim=-1) #[4,10,4]
1980
+ jacobian = jacobian.view(jacobian.shape[0], jacobian.shape[1], 2, 2) #[4,10,2,2]
1981
+ out['jacobian'] = jacobian
1982
+
1983
+
1984
+
1985
+ return out, fake
1986
+
1987
+
1988
+ def conv2d(channel_in, channel_out,
1989
+ ksize=3, stride=1, padding=1,
1990
+ activation=nn.ReLU,
1991
+ normalizer=nn.BatchNorm2d):
1992
+ layer = list()
1993
+ bias = True if not normalizer else False
1994
+
1995
+ layer.append(nn.Conv2d(channel_in, channel_out,
1996
+ ksize, stride, padding,
1997
+ bias=bias))
1998
+ _apply(layer, activation, normalizer, channel_out)
1999
+ # init.kaiming_normal(layer[0].weight)
2000
+
2001
+ return nn.Sequential(*layer)
2002
+
2003
+ def _apply(layer, activation, normalizer, channel_out=None):
2004
+ if normalizer:
2005
+ layer.append(normalizer(channel_out))
2006
+ if activation:
2007
+ layer.append(activation())
2008
+ return layer
FONT/ops.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+ import torch.nn as nn
4
+ import torch.nn.init as init
5
+ from torch.autograd import Variable
6
+
7
+
8
+ class ResidualBlock(nn.Module):
9
+ def __init__(self, channel_in, channel_out):
10
+ super(ResidualBlock, self).__init__()
11
+
12
+ self.block = nn.Sequential(
13
+ conv3d(channel_in, channel_out, 3, 1, 1),
14
+ conv3d(channel_out, channel_out, 3, 1, 1, activation=None)
15
+ )
16
+
17
+ self.lrelu = nn.ReLU(0.2)
18
+
19
+ def forward(self, x):
20
+ residual = x
21
+ out = self.block(x)
22
+
23
+ out += residual
24
+ out = self.lrelu(out)
25
+ return out
26
+
27
+ def linear(channel_in, channel_out,
28
+ activation=nn.ReLU,
29
+ normalizer=nn.BatchNorm1d):
30
+ layer = list()
31
+ bias = True if not normalizer else False
32
+
33
+ layer.append(nn.Linear(channel_in, channel_out, bias=bias))
34
+ _apply(layer, activation, normalizer, channel_out)
35
+ # init.kaiming_normal(layer[0].weight)
36
+
37
+ return nn.Sequential(*layer)
38
+
39
+
40
+ def conv2d(channel_in, channel_out,
41
+ ksize=3, stride=1, padding=1,
42
+ activation=nn.ReLU,
43
+ normalizer=nn.BatchNorm2d):
44
+ layer = list()
45
+ bias = True if not normalizer else False
46
+
47
+ layer.append(nn.Conv2d(channel_in, channel_out,
48
+ ksize, stride, padding,
49
+ bias=bias))
50
+ _apply(layer, activation, normalizer, channel_out)
51
+ # init.kaiming_normal(layer[0].weight)
52
+
53
+ return nn.Sequential(*layer)
54
+
55
+
56
+ def conv_transpose2d(channel_in, channel_out,
57
+ ksize=4, stride=2, padding=1,
58
+ activation=nn.ReLU,
59
+ normalizer=nn.BatchNorm2d):
60
+ layer = list()
61
+ bias = True if not normalizer else False
62
+
63
+ layer.append(nn.ConvTranspose2d(channel_in, channel_out,
64
+ ksize, stride, padding,
65
+ bias=bias))
66
+ _apply(layer, activation, normalizer, channel_out)
67
+ # init.kaiming_normal(layer[0].weight)
68
+
69
+ return nn.Sequential(*layer)
70
+
71
+
72
+ def nn_conv2d(channel_in, channel_out,
73
+ ksize=3, stride=1, padding=1,
74
+ scale_factor=2,
75
+ activation=nn.ReLU,
76
+ normalizer=nn.BatchNorm2d):
77
+ layer = list()
78
+ bias = True if not normalizer else False
79
+
80
+ layer.append(nn.UpsamplingNearest2d(scale_factor=scale_factor))
81
+ layer.append(nn.Conv2d(channel_in, channel_out,
82
+ ksize, stride, padding,
83
+ bias=bias))
84
+ _apply(layer, activation, normalizer, channel_out)
85
+ # init.kaiming_normal(layer[1].weight)
86
+
87
+ return nn.Sequential(*layer)
88
+
89
+
90
+ def _apply(layer, activation, normalizer, channel_out=None):
91
+ if normalizer:
92
+ layer.append(normalizer(channel_out))
93
+ if activation:
94
+ layer.append(activation())
95
+ return layer
96
+
FONT/process_data.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Thu Jun 24 11:36:01 2021
4
+
5
+ @author: Xinya
6
+ """
7
+
8
+ import os
9
+ import glob
10
+ import time
11
+ import numpy as np
12
+ import csv
13
+ import cv2
14
+ import dlib
15
+
16
+ from skimage import transform as tf
17
+
18
+ detector = dlib.get_frontal_face_detector()
19
+ predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
20
+
21
+
22
+ import imageio
23
+
24
+
25
+
26
+ def save(path, frames, format):
27
+ if format == '.mp4':
28
+ imageio.mimsave(path, frames)
29
+ elif format == '.png':
30
+ if not os.path.exists(path):
31
+
32
+
33
+ os.makedirs(path)
34
+ for j, frame in enumerate(frames):
35
+ cv2.imwrite(path+'/'+str(j)+'.png',frame)
36
+ # imageio.imsave(os.path.join(path, str(j) + '.png'), frames[j])
37
+ else:
38
+ print ("Unknown format %s" % format)
39
+ exit()
40
+
41
+ def crop_image(image_path, out_path):
42
+ template = np.load('./M003_template.npy')
43
+ image = cv2.imread(image_path)
44
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
45
+ rects = detector(gray, 1) #detect human face
46
+ if len(rects) != 1:
47
+ return 0
48
+ for (j, rect) in enumerate(rects):
49
+ shape = predictor(gray, rect) #detect 68 points
50
+ shape = shape_to_np(shape)
51
+
52
+ pts2 = np.float32(template[:47,:])
53
+ # pts2 = np.float32(template[17:35,:])
54
+ # pts1 = np.vstack((landmark[27:36,:], landmark[39,:],landmark[42,:],landmark[45,:]))
55
+ pts1 = np.float32(shape[:47,:]) #eye and nose
56
+ # pts1 = np.float32(landmark[17:35,:])
57
+ tform = tf.SimilarityTransform()
58
+ tform.estimate( pts2, pts1) #Set the transformation matrix with the explicit parameters.
59
+
60
+ dst = tf.warp(image, tform, output_shape=(256, 256))
61
+
62
+ dst = np.array(dst * 255, dtype=np.uint8)
63
+
64
+
65
+ cv2.imwrite(out_path,dst)
66
+
67
+ def shape_to_np(shape, dtype="int"):
68
+ # initialize the list of (x, y)-coordinates
69
+ coords = np.zeros((shape.num_parts, 2), dtype=dtype)
70
+
71
+ # loop over all facial landmarks and convert them
72
+ # to a 2-tuple of (x, y)-coordinates
73
+ for i in range(0, shape.num_parts):
74
+ coords[i] = (shape.part(i).x, shape.part(i).y)
75
+
76
+ # return the list of (x, y)-coordinates
77
+ return coords
78
+
79
+
80
+ def crop_image_tem(video_path, out_path):
81
+ image_all = []
82
+ videoCapture = cv2.VideoCapture(video_path)
83
+ success, frame = videoCapture.read()
84
+ n = 0
85
+ while success :
86
+ image_all.append(frame)
87
+ n = n + 1
88
+ success, frame = videoCapture.read()
89
+
90
+ if len(image_all)!=0 :
91
+ template = np.load('./M003_template.npy')
92
+ image=image_all[0]
93
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
94
+ rects = detector(gray, 1) #detect human face
95
+ if len(rects) != 1:
96
+ return 0
97
+ for (j, rect) in enumerate(rects):
98
+ shape = predictor(gray, rect) #detect 68 points
99
+ shape = shape_to_np(shape)
100
+
101
+ pts2 = np.float32(template[:47,:])
102
+ # pts2 = np.float32(template[17:35,:])
103
+ # pts1 = np.vstack((landmark[27:36,:], landmark[39,:],landmark[42,:],landmark[45,:]))
104
+ pts1 = np.float32(shape[:47,:]) #eye and nose
105
+ # pts1 = np.float32(landmark[17:35,:])
106
+ tform = tf.SimilarityTransform()
107
+ tform.estimate( pts2, pts1) #Set the transformation matrix with the explicit parameters.
108
+ out = []
109
+ for i in range(len(image_all)):
110
+ image = image_all[i]
111
+ dst = tf.warp(image, tform, output_shape=(256, 256))
112
+
113
+ dst = np.array(dst * 255, dtype=np.uint8)
114
+ out.append(dst)
115
+ if not os.path.exists(out_path):
116
+ os.makedirs(out_path)
117
+ save(out_path,out,'.png')
118
+
119
+ def proc_audio(src_mouth_path, dst_audio_path):
120
+ audio_command = 'ffmpeg -i \"{}\" -loglevel error -y -f wav -acodec pcm_s16le ' \
121
+ '-ar 16000 \"{}\"'.format(src_mouth_path, dst_audio_path)
122
+ os.system(audio_command)
123
+
124
+
125
+
126
+ if __name__ == "__main__":
127
+ #video alignment
128
+ video_path = './test/crop/M030_sad_3_001.mp4'
129
+ out_path = './test/crop/M030_sad_3_001'
130
+ crop_image_tem(video_path, out_path)
131
+
132
+ #image alignment
133
+ image_path = './test/raw_image/brade2.jpg'
134
+ out_path = './test/image/brade2.jpg'
135
+ crop_image(image_path, out_path)
136
+
137
+ #change_audio_sample_rate
138
+ src_mouth_path = './test/audio/00015.mp3'
139
+ dst_audio_path = './test/audio/00015.mov'
140
+ proc_audio(src_mouth_path, dst_audio_path)
141
+
142
+
143
+
FONT/requirements.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch==1.10.1
2
+ torchvision==0.11.2
3
+ numpy
4
+ librosa
5
+ opencv-python
6
+ python_speech_features
7
+ pickle
8
+ matplotlib
9
+ scikit-image
10
+ Pillow
11
+ tqdm
12
+ dlib
13
+ scipy
14
+ yaml
15
+ imageio
16
+ csv
FONT/result/all.mov ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dece5be32b925f419a781d3b931ceadfde409a3e89629161afbe61e8bf6cc42d
3
+ size 966293
FONT/result/all_with_pose.mov ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac55c4f07db9444a5291bb619865e04c8361f276fdb4da8f39f95f49b8daed60
3
+ size 1018871
FONT/run.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib
2
+
3
+ matplotlib.use('Agg')
4
+
5
+ import os, sys
6
+ import yaml
7
+ from argparse import ArgumentParser
8
+ from time import gmtime, strftime
9
+ from shutil import copy
10
+
11
+ # from frames_dataset import MeadDataset, AudioDataset, VoxDataset
12
+ from frames_dataset_liujin import MeadDataset, AudioDataset, VoxDataset, HDTFDataset
13
+
14
+ from modules.generator import OcclusionAwareGenerator
15
+ from modules.discriminator import MultiScaleDiscriminator
16
+ from modules.keypoint_detector import KPDetector, Audio_Feature, KPDetector_a
17
+ from modules.util import AT_net,Emotion_k
18
+ # from modules.util import get_logger
19
+ import torch
20
+
21
+ from train import train_part1, train_part1_fine_tune, train_part2
22
+ # from reconstruction import reconstruction
23
+ # from animate import animate
24
+
25
+ import warnings
26
+ warnings.filterwarnings("ignore")
27
+
28
+ if __name__ == "__main__":
29
+
30
+ if sys.version_info[0] < 3:
31
+ raise Exception("You must use Python 3 or higher. Recommended version is Python 3.7")
32
+
33
+ parser = ArgumentParser()
34
+ parser.add_argument("--config", default="config/train_part1.yaml", help="path to config")# required=True
35
+ parser.add_argument("--mode", default="train_part1", choices=["train_part1", "train_part1_fine_tune", "train_part2"])
36
+ parser.add_argument("--log_dir", default='log', help="path to log into")
37
+ parser.add_argument("--checkpoint", default='124_52000.pth.tar', help="path to checkpoint to restore")
38
+ parser.add_argument("--audio_checkpoint", default=None, help="path to audio_checkpoint to restore")
39
+ parser.add_argument("--emo_checkpoint", default=None, help="path to audio_checkpoint to restore")
40
+ parser.add_argument("--device_ids", default="0", type=lambda x: list(map(int, x.split(','))),
41
+ help="Names of the devices comma separated.")
42
+ parser.add_argument("--verbose", dest="verbose", action="store_true", help="Print model architecture")
43
+ parser.set_defaults(verbose=False)
44
+ parser.add_argument("--comment", default='comment', help="comment about experiment")
45
+
46
+ opt = parser.parse_args()
47
+ with open(opt.config) as f:
48
+ config = yaml.load(f)
49
+
50
+ name = os.path.basename(opt.config).split('.')[0]
51
+ if opt.checkpoint is not None:
52
+
53
+ log_dir = os.path.join(opt.log_dir, os.path.basename(opt.config).split('.')[0])
54
+ # log_dir += ' ' + strftime("%d_%m_%y_%H.%M.%S", gmtime())
55
+ log_dir += '_' + opt.comment
56
+ else:
57
+ log_dir = os.path.join(opt.log_dir, os.path.basename(opt.config).split('.')[0])
58
+ # log_dir += ' ' + strftime("%d_%m_%y_%H.%M.%S", gmtime())
59
+ log_dir += '_' + opt.comment
60
+
61
+ if not os.path.exists(log_dir):
62
+ os.makedirs(log_dir)
63
+ if not os.path.exists(os.path.join(log_dir, os.path.basename(opt.config))):
64
+ copy(opt.config, log_dir)
65
+
66
+ # logger = get_logger(os.path.join(log_dir, "log.txt"))
67
+
68
+ generator = OcclusionAwareGenerator(**config['model_params']['generator_params'],
69
+ **config['model_params']['common_params'])
70
+
71
+ if torch.cuda.is_available():
72
+ generator.to(opt.device_ids[0])
73
+
74
+ if opt.verbose:
75
+ print(generator)
76
+
77
+ discriminator = MultiScaleDiscriminator(**config['model_params']['discriminator_params'],
78
+ **config['model_params']['common_params'])
79
+ if torch.cuda.is_available():
80
+ discriminator.to(opt.device_ids[0])
81
+
82
+
83
+
84
+ if opt.verbose:
85
+ print(discriminator)
86
+
87
+ kp_detector = KPDetector(**config['model_params']['kp_detector_params'],
88
+ **config['model_params']['common_params'])
89
+
90
+ kp_detector_a = KPDetector_a(**config['model_params']['kp_detector_params'],
91
+ **config['model_params']['audio_params'])
92
+
93
+ if torch.cuda.is_available():
94
+ kp_detector.to(opt.device_ids[0])
95
+ kp_detector_a.to(opt.device_ids[0])
96
+
97
+ audio_feature = AT_net()
98
+ emo_feature = Emotion_k(block_expansion=32, num_channels=3, max_features=1024,
99
+ num_blocks=5, scale_factor=0.25, num_classes=8)
100
+
101
+ if torch.cuda.is_available():
102
+ audio_feature.to(opt.device_ids[0])
103
+ emo_feature.to(opt.device_ids[0])
104
+
105
+ if opt.verbose:
106
+ print(kp_detector)
107
+ print(kp_detector_a)
108
+ print(audio_feature)
109
+ print(emo_feature)
110
+
111
+ # logger.info("Successfully load models.")
112
+
113
+ if config['dataset_params']['name'] == 'Vox':
114
+ dataset = VoxDataset(is_train=True, **config['dataset_params'])
115
+ test_dataset = VoxDataset(is_train=False, **config['dataset_params'])
116
+ elif config['dataset_params']['name'] == 'Lrw':
117
+ dataset = AudioDataset(is_train=True, **config['dataset_params'])
118
+ test_dataset = AudioDataset(is_train=False, **config['dataset_params'])
119
+ elif config['dataset_params']['name'] == 'MEAD':
120
+ dataset = MeadDataset(is_train=True, **config['dataset_params'])
121
+ test_dataset = MeadDataset(is_train=False, **config['dataset_params'])
122
+ elif config['dataset_params']['name'] == 'hdtf':
123
+ dataset = HDTFDataset(is_train=True, **config['dataset_params'])
124
+ test_dataset = HDTFDataset(is_train=False, **config['dataset_params'])
125
+
126
+
127
+
128
+
129
+ if opt.mode == 'train_part1':
130
+ print("Training part1...")
131
+ train_part1(config, generator, discriminator, kp_detector, kp_detector_a,audio_feature, opt.checkpoint, opt.audio_checkpoint, log_dir, dataset, test_dataset,opt.device_ids, name)
132
+ elif opt.mode == 'train_part1_fine_tune':
133
+ print("Finetune part1...")
134
+ train_part1_fine_tune(config, generator, discriminator, kp_detector, kp_detector_a,audio_feature, opt.checkpoint, opt.audio_checkpoint, log_dir, dataset, test_dataset,opt.device_ids, name)
135
+ elif opt.mode == 'train_part2':
136
+ print("Training part2...")
137
+ train_part2(config, generator, discriminator, kp_detector, emo_feature,kp_detector_a,audio_feature, opt.checkpoint, opt.audio_checkpoint, opt.emo_checkpoint, log_dir, dataset,test_dataset,opt.device_ids, name)
FONT/script_backup.sh ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --pose_given "/data/liujin/dataset/preprocess/LRW/data_file/test_video_pose.npy" \
2
+ --pose_given "/data/liujin/_new_idea_211030_ICME/audio2pose_vae/result/test_pose_long_vae.npy" \
3
+ --audio_checkpoint "./log/train_part1_wav2lip_pretrain_3dmm/294-00010000-checkpoint.pth.tar" \
4
+ --checkpoint "./log/train_part1_fine_tune_wav2lip_pretrain_3dmm/392-00080000-checkpoint.pth.tar" \
5
+ --audio_checkpoint "/data/liujin/EAMM-main/log/train_part1_hdtf_wav2lip_pretrain_3dmm_hdtf/3124-00022500-checkpoint.pth.tar" \
6
+ --checkpoint "/data/liujin/EAMM-main/log/train_part1_fine_tune_hdtf_wav2lip_pretrain_3dmm_hdtf/3341-00005000-checkpoint.pth.tar" \
7
+ --pose_long TRUE \
8
+ --pose_file "/data/liujin/dataset/preprocess/LRW/data_file/test_first_frame_pose.npy" \
9
+ --pose_given "/data/liujin/dataset/preprocess/LRW/data_file/test_video_pose.npy" \
10
+ --source_image ./test/image/RD_Radio10_000.png \
11
+ --source_image "./test/image/ABOUT_00994.jpg" \
12
+ --source_image "/data/liujin/dataset/LRW/lipread_frames/ABOUT/train/ABOUT_00994/000000.jpg" \
13
+ --in_file "/data/liujin/dataset/LRW/lipread_wav/ABOUT/train/ABOUT_00994.wav" \
14
+ --pose_file "/data/liujin/dataset/HDTF/pose_3DDFA_256/RD_Radio20_000/000000.npy" \
15
+ --pose_given "/data/liujin/dataset/preprocess/LRW/data_file/test_pose_long_3ddfa.npy" \
16
+ --source_image "/data/liujin/dataset/HDTF/frames_256/RD_Radio26_000/000000.png" \
17
+ --pose_given "./test/pose_long/50IAfJCypFI_Alex_Kingston_50IAfJCypFI_0001.npy" \
FONT/script_finetune_liujin.sh ADDED
@@ -0,0 +1 @@
 
 
1
+ CUDA_VISIBLE_DEVICES=3 nohup python -u run.py --config config/train_part1_fine_tune.yaml --mode train_part1_fine_tune --checkpoint ckpt/124_52000.pth.tar --audio_checkpoint log/train_part1_wav2lip_pretrain_3dmm/294-00010000-checkpoint.pth.tar --comment wav2lip_pretrain_3dmm > out_liujin_finetune_wav2lip_pretrain_3dmm.log 2>&1 &