https://www.dong-blog.fun/post/360#Docker
之前没打镜像,后悔!搞了半天,记录下来。
这里有Dockerfile:
bash展开代码FROM registry.us-west-1.aliyuncs.com/modelscope-repo/modelscope:ubuntu20.04-cuda11.7.1-py38-torch2.0.1-tf1.15.5-1.8.1
RUN apt-get update && apt-get install -y libjemalloc-dev && rm -rf /var/lib/apt/lists/*
RUN useradd -m -u 1000 user
USER user
ENV HOME=/home/user \
PATH=/home/user/.local/bin:$PATH
WORKDIR $HOME
RUN chmod 777 $HOME
RUN mkdir $HOME/modelscope_cache
ENV MODELSCOPE_CACHE=$HOME/modelscope_cache
ENV GRADIO_SERVER_NAME=0.0.0.0
EXPOSE 7860
RUN echo 'cloning facechain:hf_space_fact'
RUN git clone -b feat/hf_space_fact https://github.com/modelscope/facechain.git
WORKDIR $HOME/facechain
RUN pip install -r requirements.txt
ENV LD_PRELOAD=/lib/x86_64-linux-gnu/libjemalloc.so
ENV PYTHONPATH=.
CMD ["python", "app.py"]
不以root运行。进去后还需要适配一些代码。
启动
bash展开代码docker run -it --net host --gpus all kevinchina/deeplearning:fact_face_swapev1 /bin/bash
cd facechain
$ GRADIO_SERVER_PORT=9872 python3 app.py
这是 FaceChain 生成写真的核心,它不仅仅是简单的“换脸”,而是基于用户的人脸特征“生成”一张新的人像。
特征提取 (Feature Extraction):
face_adapter/face_adapter_v1.py 中的 Face_Extracter_v1 类。face_detection (RetinaFace) 检测人脸,并进行对齐 (align) 和分割 (segmentation_pipeline),只保留人脸区域。Face_Transformer) 模型来提取人脸的特征嵌入 (Embeddings)。Face_Prj_Resampler) 进行处理。这个模块的作用是将人脸特征转换成 Stable Diffusion (SD) 模型可以理解的格式和维度 (768维)。特征注入与生成 (Injection & Generation):
face_adapter/face_adapter_v1.py 中的 FaceAdapter_v1 类。FaceAttnProcessor)。这是一个显式的“换脸”步骤,在 UI 中对应“是否使用人脸相似度增强”选项。
facechain/inference_fact.py 中的 face_swap_fn 函数。damo/cv_unet_face_fusion_torch 模型。这是一个专门的基于 UNet 的人脸融合模型。查看 Face_Prj_Resampler 的实现,以及它如何将人脸特征转换为 SD 1.5 可用的格式:
是的,Face_Prj_Resampler 是一个神经网络模型(继承自 nn.Module)。
180:224:face_adapter/face_adapter_v1.py展开代码class Face_Prj_Resampler(nn.Module): def __init__( self, dim=1024, depth=4, dim_head=64, heads=12, num_queries=16, embedding_dim=512, output_dim=768, ff_mult=4, ): super().__init__() self.latents = nn.Parameter(torch.randn(1, num_queries, dim) / dim**0.5) self.proj_in = nn.Linear(embedding_dim, dim) self.proj_out = nn.Linear(dim, output_dim) self.norm_out = nn.LayerNorm(output_dim) self.layers = nn.ModuleList([]) for _ in range(depth): self.layers.append( nn.ModuleList( [ PerceiverAttention(dim=dim, dim_head=dim_head, heads=heads), FeedForward(dim=dim, mult=ff_mult), ] ) ) def forward(self, x): latents = self.latents.repeat(x.size(0), 1, 1) x = self.proj_in(x) for attn, ff in self.layers: latents = attn(x, latents) + latents latents = ff(latents) + latents # print(latents.shape) # 16,1024 latents = self.proj_out(latents) return self.norm_out(latents)
它使用 Perceiver Attention 机制,将人脸特征压缩并转换为固定数量的 token。
是的。流程如下:
Face_Transformer 提取人脸特征(512 维)Face_Prj_Resampler 将其转换为 16 个 token,每个 token 768 维(与 SD 1.5 的 embedding 维度一致)241:251:face_adapter/face_adapter_v1.py展开代码def forward(self, face_img): avr_face_rep, _ = self.face_transformer(face_img) face_g_embed = self.face_prj_wofc(avr_face_rep) neg_face_g_embed = self.face_prj_wofc(torch.zeros_like(avr_face_rep)) num_ims, seq_len, _ = face_g_embed.shape face_g_embed = face_g_embed.view(1, num_ims * seq_len, -1) neg_face_g_embed = neg_face_g_embed.view(1, num_ims * seq_len, -1) return face_g_embed, neg_face_g_embed
人脸 token 会被拼接到文本 prompt 的 embeddings 后面:
417:425:face_adapter/face_adapter_v1.py展开代码with torch.inference_mode(): prompt_embeds = self.pipe._encode_prompt( prompt, device=self.device, num_images_per_prompt=num_samples, do_classifier_free_guidance=True, negative_prompt=negative_prompt) negative_prompt_embeds_, prompt_embeds_ = prompt_embeds.chunk(2) prompt_embeds = torch.cat([prompt_embeds_, image_prompt_embeds], dim=1) if self.cfg_face: negative_prompt_embeds = torch.cat([negative_prompt_embeds_, neg_image_prompt_embeds], dim=1) else: negative_prompt_embeds = torch.cat([negative_prompt_embeds_, image_prompt_embeds], dim=1)
在 FaceAttnProcessor 中,这些 token 会被分离出来,并通过 self-attention 和 cross-attention 影响生成过程:
324:333:face_adapter/face_attention_processor_v1.py展开代码else: # get encoder_hidden_states, ip_hidden_states end_pos = encoder_hidden_states.shape[1] - 16 * self.num_ims encoder_hidden_states, face_hidden_states = encoder_hidden_states[:, :end_pos, :], encoder_hidden_states[:, end_pos:, :] if attn.norm_cross: encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) N_visual = hidden_states.shape[1] face_hidden_states = self.linear(face_hidden_states) hidden_states = hidden_states + self.scale*torch.tanh(self.alpha_attn) * self.attn( self.norm1(torch.cat([hidden_states, face_hidden_states],dim=1)), attn)[:,0:N_visual,:]
查找代码中所有模型下载位置,整理下载的模型列表:
运行 FaceChain 后,会下载约 40+ GB 的模型,主要包括:


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!