DINet训练/推理过程中需要用到OPenFace的人脸数据,所以使用DINet训练定制数字人,需要配置OPenFace和DINet两个项目的环境。我是使用conda创建了一个dinet的虚拟环境,DINet项目中需要的TensorFlow和pytorch版本比较低,python版本选择3.7。
DINet项目的环境配置比较简单,pip install -r requirements.txt
即可,由于cuda的版本为10.1,A800不支持10.1,遂将pytorch卸载,重新下载安装1.13的pytorch和11.6的cuda。
OpenFace
OPenFace的环境配置比较麻烦,一开始我使用docker安装,但是docker里面的基础配置太低,很多包和库没办法兼容,升级也比较麻烦,不建议用docker。在我创建的dinet虚拟环境中,参考install.sh中的步骤,安装成功。
环境配置
- 首先需要下载模型,运行download_models.sh,服务器下载链接超时,不能够下载。我自己先按照download_models.sh中的网址,单独下载,然后上传服务器,将下载的模型放在
lib/local/LandmarkDetector/model/patch_experts
目录下。 - conda创建虚拟环境时,已经安装了gcc和g++,g++ -c和gcc -v 查看版本,不需要进行cmake的编译安装。为了后续的依赖能成功编译,先安装OpenBLAS和Boost。
sudo apt-get install libopenblas-dev # openblas
sudo apt-get install libboost-all-dev # boost
- 安装opencv
sudo apt-get -y install libopenblas-dev liblapack-dev
sudo apt-get -y install libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev
sudo apt-get -y install libtbb2 libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev
wget https://github.com/opencv/opencv/archive/4.1.0.zip
unzip 4.1.0.zip
cd opencv-4.1.0
mkdir -p build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_CUDA=OFF -D BUILD_SHARED_LIBS=OFF ..
make -j4
sudo make install
- 安装dlib
wget http://dlib.net/files/dlib-19.13.tar.bz2;
tar xf dlib-19.13.tar.bz2;
cd dlib-19.13;
mkdir -p build;
cd build;
cmake ..
cmake --build . --config Release;
sudo make install
sudo ldconfig
- 依赖已经安装完成,此步骤进行OpenFace的编译。
mkdir -p build
cd build
cmake -D CMAKE_CXX_COMPILER=g++ -D CMAKE_C_COMPILER=gcc -D CMAKE_BUILD_TYPE=RELEASE ..
make
至此,OPenFace编译完成,在build/bin目录下,会有四个可执行文件。
提取特征
FaceLandmarkImg、FaceLandmarkVid、FaceLandmarkVidMulti和FeatureExtraction四个可执行文件的命令行参数,见链接。
使用FeatureExtraction提取后续用于DINet的csv文件,命令如下所示。
./build/bin/FeatureExtraction -f your_videos.mp4 -out_dir processed_results_path
特征处理
FeatureExtraction生成的csv文件有很多列数据,在DINet中并不需要。使用pandas库提取csv中的某些行并生成新的csv文件,示例代码如下所示。
- base_csv_file为DINet中提供的训练/测试样例的csv文件,get_columns函数提取base_csv_file文件中所有的列属性列表columns。
- get_new_csv函数从input_csv_file中提取columns相关列数据,并保存在out_csv_file中。out_csv_file可用于DINet训练/测试。
import pandas as pd
import argparse
def get_columns(base_csv_file):
base_data = pd.read_csv(base_csv_file)
columns = [column.strip() for column in base_data]
return columns
def get_new_csv(input_csv_file, out_csv_file, columns):
df = pd.DataFrame(pd.read_csv(input_csv_file))
df_col = df[columns]
df_col.to_csv(out_csv_file, index=None, encoding='utf-8')
# base_csv_file 为DINet中自带的训练/测试样例的csv文件。
columns = get_columns(base_csv_file)
get_new_csv(input_csv_file, output_csv_file, columns)
DINet
推理
首先,先下载预训练模型asserts.zip,近1G,然后解压。在asserts/examples中提供了测试的源mp4视频,和其相对应的csv人脸数据,和若干wav语音文件,一句下述命令行进行测试推理。
python inference.py --mouth_region_size=256 --source_video_path=./asserts/examples/testx.mp4 --source_openface_landmark_path=./asserts/examples/testx.csv --driving_audio_path=./asserts/examples/driving_audio_x.wav --pretrained_clip_DINet_path=./asserts/clip_training_DINet_256mouth.pth
driving_audio_path的输入是wav格式的语音,如果语音是mp3格式,可以使用mmpeg将mp3格式转换成wav格式。
ffmpeg -i audio.mp3 -f wav audio.wav
如果想推理自己的视频文件,按上述OpenFace的提取特征和特征处理步骤得到自己视频的csv文件,使用上述命令行即可。但是,因为自己的视频,没有包含在训练集中,所以推理得到的视频中人脸会有所改变。我从央视下载新闻联播视频,测试了康辉的视频,推理得到的视频中的人与康辉相像,但是不是康辉。说明DINet给出来的预训练模型的泛化性还不是很好。
因此,为了能够更好的效果,需要对康辉的视频进行训练。
数据前处理
- 将要训练的视频放在"./asserts/split_video_25fps",使用OpenFace处理得到的相关csv文件放在"./asserts/split_video_25fps_landmark_openface"文件夹下。如果源视频不是25帧率的视频,可用ffmpeg进行处理。
ffmpeg -i video.mp4 -r 25 video_25.mp4
- 前期,可以按照下述命令一次一个命令对数据进行预处理。
# 从所有视频中提取每一帧并保存在"./asserts/split_video_25fps_frame"
python data_processing.py --extract_video_frame
# 从所有视频中提取音频,并保存在"./asserts/split_video_25fps_audio"
python data_processing.py --extract_audio
# 从所有音频中提取deepspeech特征并把deepspeech特征保存在"./asserts/split_video_25fps_deepspeech"
python data_processing.py --extract_deep_speech
# 从所有视频中切除人脸,并把所有图像保存在"./asserts/split_video_25fps_crop_face"
python data_processing.py --crop_face
# 生成训练的json文件,保存为"./asserts/training_json.json"
python data_processing.py --generate_training_json
等熟练之后,这些预处理可一起运行。
nohup python data_processing.py --extract_video_frame --extract_audio --extract_deep_speech --crop_face --generate_training_json &
训练
训练分为两大步,四小步。两大步分别是frame training stage 和 clip training stage。DINet项目中允许以任意分辨率的视频进行训练,480p的视频训练后推理得到的视频,嘴部会明显模糊。1080p的视频则无此问题。
frame training stage
# 第一步,以104x80的分辨率训练DINet。此步骤嘴部区域分辨率是64x64
python train_DINet_frame.py --augment_num=32 --mouth_region_size=64 --batch_size=24 --result_path=./asserts/training_model_weight/frame_training_64
# 第二步,以第一步训练得到的模型作为预训练模型,以更高的分辨率208x160训练DINet。此步骤嘴部区域分辨率是128x128
python train_DINet_frame.py --augment_num=100 --mouth_region_size=128 --batch_size=80 --coarse2fine --coarse_model_path=./asserts/training_model_weight/frame_training_64/xxxxxx.pth --result_path=./asserts/training_model_weight/frame_training_128
#第三步,以第二步训练得到的模型作为预训练模型,以更高的分辨率416x320训练DINet。此步骤嘴部区域分辨率是256x256
python train_DINet_frame.py --augment_num=20 --mouth_region_size=256 --batch_size=12 --coarse2fine --coarse_model_path=./asserts/training_model_weight/frame_training_128/xxxxxx.pth --result_path=./asserts/training_model_weight/frame_training_256
clip training stage
clip training阶段,以frame training阶段256x256的模型和syncnet的模型作为预训练模型,训练DINet。
python train_DINet_clip.py --augment_num=3 --mouth_region_size=256 --batch_size=3 --pretrained_syncnet_path=./asserts/syncnet_256mouth.pth --pretrained_frame_DINet_path=./asserts/training_model_weight/frame_training_256/xxxxx.pth --result_path=./asserts/training_model_weight/clip_training_256
至此,训练完成,用于推理的模型保存在“./asserts/training_model_weight/clip_training_256”文件夹下。