FaceChain

编程入门 行业动态 更新时间:2024-10-09 17:27:21

<a href=https://www.elefans.com/category/jswz/34/1669230.html style=FaceChain"/>

FaceChain

功能上近似“秒鸭相机”?

  • 官方代码:

  • 论文:《FaceChain: A Playground for Identity-Preserving Portrait Generation》

  • 我的注释代码:

  • 魔搭体验:

  • huggingface体验:

  • 视频介绍:

日期:2023/9/6 目前facechain还处于快速迭代中,当你看到这篇文章时,可能代码仓库有了新变化。

FaceChain 是阿里达摩院开源的一个功能上近似“秒鸭相机”的项目。作为程序员和AIGC爱好者,我决定从代码层面看看它的实现流程是什么样的。facechain,顾名思义,就是对人脸(face)做一连串(chain)的处理。那这些处理包括哪些呢,又是怎么串联起来的呢?它的基本原理在官方文档README_ZH.md里有介绍,这里再粘贴一下。整体工作流程图是这样的:​​​​​​​训练阶段

输入:用户上传的包含清晰人脸区域的图像 

输出:人脸LoRA模型 

描述:首先,我们分别使用基于朝向判断的图像旋转模型,以及基于人脸检测和关键点模型的人脸精细化旋转方法处理用户上传图像,得到包含正向人脸的图像;接下来,我们使用人体解析模型和人像美肤模型,以获得高质量的人脸训练图像;随后,我们使用人脸属性模型和文本标注模型,结合标签后处理方法,产生训练图像的精细化标签;最后,我们使用上述图像和标签数据微调Stable Diffusion模型得到人脸LoRA模型。

推断阶段

输入:训练阶段用户上传图像,预设的用于生成个人写真的输入提示词 

输出:个人写真图像 

描述:首先,我们将人脸LoRA模型和风格LoRA模型的权重融合到Stable Diffusion模型中;接下来,我们使用Stable Diffusion模型的文生图功能,基于预设的输入提示词初步生成个人写真图像;随后,我们使用人脸融合模型进一步改善上述写真图像的人脸细节,其中用于融合的模板人脸通过人脸质量评估模型在训练图像中挑选;最后,我们使用人脸识别模型计算生成的写真图像与模板人脸的相似度,以此对写真图像进行排序,并输出排名靠前的个人写真图像作为最终输出结果。

安装

为了了解背后的工作流程,我得先跑通代码。安装上与官方教程有所不同,因人而异。

  1. 克隆到本地:

GIT_LFS_SKIP_SMUDGE=1 git clone .git --depth 1
cd facechain
  1. 安装依赖包。为了加快安装速度,可以配置一下pip源或临时使用国内源。

pip3 install -r requirements.txt -i /
  1. 因为我的Ubuntu上是无GUI界面的,所以我得安装headless版,而且最新版本会报错:“partially initialized module 'cv2' has no attribute 'gapi_wip_gst_GStreamerPipeline' (most likely due to a circular import)”,解决办法是先写卸载干净opencv:

pip3 uninstall opencv-python
pip3 uninstall opencv-contrib-python
pip3 uninstall opencv-python-headless
pip3 uninstall opencv-contrib-python-headless

然后安装headless的指定版本:

pip3 install opencv-python-headless==4.4.0.46 -i /
pip3 install opencv-contrib-python-headless==4.4.0.46 -i  
  1. 安装mmcv,但mim install mmcv-full==1.7.0失败,我改成用pip3 install mmcv-full==1.7.0.

  2. 我的服务器原本安装的diffusers版本是0.14,结果报错:“No module named 'diffusers.models.attention_processor'”,后面通过pip3 install diffusers -U -i /升级成0.20后就好了。onnxruntime也要升级到最新版,不然有报错的风险。

  3. 后面如果你运行python app.py来启动web ui界面的话,可能会遇到报错:“ImportError: cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_' (/opt/conda/lib/python3.8/site-packages/urllib3/util/ssl_.py)”,这个原因是因为urllib3版本太高,太低的话又会另外一个报错:“ init() got an unexpected keyword argument 'allowed_methods'”,安装特定版本就可以了:pip install urllib3==1.26.16

训练

虽然我的服务器是无GUI的ubuntu系统,但实测仍然可以打开gradio webui进行训练和推理,不过下面的笔记仍然是用命令行的方式操作。

  1. 首先在根目录下创建了文件夹 imgs,放入你要合成的人脸的照片,我这里的例子是从百度图片下载下来的五月天阿信的照片,要求每张照片中只有一个主角人脸。代码内会自己选择最相似、最可能是同一个人的最多15张图片作为训练集,也就是说你准备的图片太多也没有太大用处,数量多不如质量高。

        2. 运行以下命令行启动训练:

PYTHONPATH=. sh train_lora.sh "ly261666/cv_portrait_model" "v2.0" "film/film" "./imgs" "./processed" "./output"

命令行中的ly261666/cv_portrait_model是一个预训练模型,也就是基模型leosamsMoonfilm_filmGrain20,不用修改,它来自。训练十几分钟就训练好了。但是,在训练前会下载很多依赖模型,这个时间可能就要半个小时以上。训练出来的LoRA模型位于facechain/output/pytorch_lora_weights.bin。

代码解析

PYTHONPATH=. sh train_lora.sh "ly261666/cv_portrait_model" "v2.0" "film/film" "./imgs" "./processed" "./output"可知,我们执行的是train_lora.sh,它里面又调用了facechain/train_text_to_image_lora.py,所以我们重点看一下这个train_text_to_image_lora.py这个文件。

train_text_to_image_lora.py 应该是改编自:.py ,以后自己训练其他LoRA模型的话,也可以基于这个脚本进行改编。

我们直达它的def main()函数,主要的两个训练前处理函数的注释如下:

# note: 检查图片中的人脸是否需要旋转角度,矫正过的图片保存在processed文件夹内
prepare_dataset(args.dataset_name, args.output_dataset_name)
# note: 背后调用的是class Blipv2()的def __call__()
# 依次对图片进行:缩放、检测出人脸,将人脸矫正、缩放、裁剪出人脸区域、美肤、分割出人头区域、
# 人脸关键点检测(如果检测不出或置信度低于阈值,则跳过)、使用DeepDanbooru对分割出的人头区域打标签、
# 估计人脸属性(包括性别年龄,后处理会合并进标签里)、生成的结果位于processed_labeled文件夹
data_process_fn(input_img_dir=args.output_dataset_name, use_data_process=True)

函数data_process_fn里那么多处理步骤要用到模型列表(.md#%E6%A8%A1%E5%9E%8B%E5%88%97%E8%A1%A8)里的很多模型。比如cv_ddsar_face-detection_iclr23-damofd负责检测出图片中的人脸,cv_resnet101_image-multiple-human-parsing负责分割出人头区域、cv_unet_skin_retouching_torch负责对人脸美肤。因为要下载这些模型,所以这一步会比较耗时。

训练流程跟常规的stable diffusion训练一样,没啥特别之处,这里不再复述:

# note: 开始训练人脸LoRA模型
for epoch in range(first_epoch, args.num_train_epochs):

训练结束保存LoRA模型权重:

# note: 使用diffusers的save_attn_procs保存LoRA模型权重,导出facechain/output/pytorch_lora_weights.bin
unet.save_attn_procs(args.output_dir,safe_serialization=False)

我们再来看看训练阶段的中间产物。这是processed_labeled文件夹内的内容,也就是训练stable diffusion用的数据集:可以看到人头区域被分割了出来,当然它做过了矫正和美肤。metadata.jsonl里是每张图片的标签,它里面的内容就是: 

推理

执行推理的命令行是python run_inference.py。顺利的话,一会儿之后就能在generated文件夹内看到5张合成的证件照了,效果如下(如果侵犯了肖像权,请联系我删除掉):我又跑了一次,生成的效果如下:​​​​​​​看完这些结果,我发现一个人的外貌特征除了五官外,还有发型、头型、头身比例,这些也很有区分度。

代码解析

run_inference.py背后调用的主要是facechain\inference.py这个文件,让我们来看一下这个文件。首先看def main_diffusion_inference的注释:

 pipe = StableDiffusionPipeline.from_pretrained(base_model_path, torch_dtype=torch.float32)lora_style_path = style_model_pathlora_human_path = lora_model_path# note: 将ly261666/cv_portrait_model这个基础模型,连同我们训练的人物LoRA模型和默认风格LoRA模型,三者的权重合并成一个新模型。pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True)pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=lora_human_path.endswith('safetensors'))

使用融合三者权重后的扩散模型进行生图,在txt2img函数内,你可以对其进行进一步的定制化(比如调节图片宽高、去噪步数等):  whaosoft aiot   

 # note: 万事具备,开始运行扩散模型生成10张候选图片images_style = txt2img(pipe, trigger_style + add_prompt_style + pos_prompt, neg_prompt, num_images=10)

然后看class GenPortraitdef __call__的注释:

# note: 内部会调用扩散模型生成10张候选图片,也就是调用了上面的def main_diffusion_inference
gen_results=main_model_inference(self.pose_model_path,self.pose_image,self.use_depth_control,
self.pos_prompt,self.neg_prompt,
self.style_model_path,self.multiplier_style,self.multiplier_human,
self.use_main_model,input_img_dir=input_img_dir,
lora_model_path=lora_model_path,base_model_path=base_model_path)
# note: 从processed_labeled文件夹内选择一张质量最好的抠出来的人头图片
selected_face=select_high_quality_face(input_img_dir)
# note: 保存中间结果以便可视化(我自己加的)
intermediate_folder="./intermediate"
os.makedirs(intermediate_folder,exist_ok=True)
selected_face.save(os.path.join(intermediate_folder,"selected_face.jpg"))
fori,imginenumerate(gen_results):
img.save(os.path.join(intermediate_folder,f"{i}.jpg"))
# note: 将gen_results列表里的10张图片中的人脸都换成selected_face
swap_results=face_swap_fn(self.use_face_swap,gen_results,selected_face)
# 将10张换脸后的图片的embedding和selected_face的embedding作比较,选出跟selected_face最相似的num_gen_images张图片
rank_results=post_process_fn(self.use_post_process,swap_results,selected_face,
num_gen_images=num_gen_images)
# stylization
final_gen_results=stylization_fn(self.use_stylization,rank_results)
returnfinal_gen_results

run_inference.py使用的是默认风格,默认风格其实也是一种风格,这种风格是zjz_mj_jiyi_small_addtxt_fromleo()。默认风格模型的话支持这些服装风格:工作服、盔甲风、T恤衫、汉服风、女士晚礼服、赛博朋克。如果是其他风格模型,有凤冠霞帔、冬季汉服、校服风、婚纱风、拍立得风、仙女风,这些风格模型自带服装风格,不再支持自定义服装风格。

换脸用到的模型是: ,这让我想到了deepfacelab也是用到了这个技术。

我在想,如果不换脸的话,SD的原始输出是什么样的,于是我在代码里加入了保存SD生图后、换脸前的中间结果(即gen_resultsselected_face)的代码,可视化如下:​​​​​​​可以看到,SD输出的原始输出图片中的人脸跟实际真人差距还是比较大,说明光靠几张图片和LoRA很难学习到一个相似的人脸,还得靠cv_unet_face_fusion_torch来换脸。

另外,我发现constants.py里的pos_prompt_with_clothpos_prompt_with_style自带了slim body,我觉得这会降低相似度,毕竟每个人的体型是不一样的,我删除掉后重新生成了一下,整体效果好像好了一点点:​​​​​​​

更多推荐

FaceChain

本文发布于:2024-02-07 10:16:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1756242.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:FaceChain

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!