My深度学习的总结记录

基于深度学习的人脸替换和人脸重演

基于深度学习的人脸替换(DeepFake)

  1. 人脸数据获取

人脸检测使用的是dlib库[dlib.get_frontal_face_datector()]返回值是rectangle,就是一个矩形。可以获取检测框的左上角和右下角坐标[(x1, y1) (x2, y2)]。
可以通过函数的left,right,top,bottom方法分别获取对应的x1, x2, y1, y2值

  1. 数据增强

分别使用了random_transform,random_warp 两个函数来做数据增强。因为是无监督任务所以其反向转播的误差由图像自己的提供,而要使得数据增强后(代码中warped_image)有对应的样本(代码中的target_image)就要进行图片转换。

warped_image = cv2.remap(image, interp_mapx, interp_mapy, cv2.INTER_LINEAR)#重映射

src_points = numpy.stack([mapx.ravel(), mapy.ravel()], axis=-1)    
dst_points = numpy.mgrid[0:65:16, 0:65:16].T.reshape(-1, 2)    
mat = umeyama(src_points, dst_points, True)[0:2]

target_image = cv2.warpAffine(image, mat, (64, 64))

使用opencv.rmap构造出warped_image
使用umeyama和opencv.warpAffine构造出target_image。
【调用umeyama后获取变换所需的矩阵,最后将原图和所求得矩阵放进warpAffine即可获的增强后对应的target_image。其中warpAffine功能是根据变换矩阵对源矩阵变换。】

  1. 模型搭建

人脸替换网络使用自动编码器,其中包含一个公用的编码器,两个人脸各自的解码器

class Autoencoder(nn.Module):
    def __init__(self):
        super(Autoencoder, self).__init__()

        self.encoder = Encoder()# 一个编码器
        self.decoder_A = Decoder()# 解码器A
        self.decoder_B = Decoder()# 解码器B

    def forward(self, x, select="A"):
        if select == "A":
            x = self.encoder(x)
            out = self.decoder_A(x)
        else:
            x = self.encoder(x)
            out = self.decoder_B(x)
        return out
  1. 模型训练
    图片来自网络,侵删图片来自网络,侵删

模型训练过程中,将A脸输入到编码器中,使用A的解码器还原;将B脸输入到编码器中,使用B的解码器还原,分别计算损失函数和优化。

warped_A = model(warped_A, 'A')
warped_B = model(warped_B, 'B')

loss_A = criterion(warped_A, target_A)
loss_B = criterion(warped_B, target_B)
  1. 模型测试
    在这里插入图片描述图片来自网络,侵删

模型测试过程中,若想将A脸换到B脸上,要将A的人脸使用编码器编码后,使用B的解码器还原。

converted_face = model(batch_warped_img,'B') # 选择解码器B

优化:使用泊松融合
进入神经网络的不是整张图片,而是仅仅只有脸部的小区域。因此测试时,首先截取人脸送进网络,再根据网络的输出覆盖原图部分。
泊松融合的大致思想提供一个一个mask矩阵,背景区域为0,ROI区域(region of insteresing 这里就是指脸部)的区域为255,算法通过该矩阵得知哪一步分是融合的部分,然后通过计算梯度,用梯度场作为指示,修改ROI的像素值,使得边界与原图更为贴切。

 def merge(postion, face, body):
    mask = 255 * np.ones(face.shape, face.dtype)
    center = (postion['left']+(postion['right']-postion['left'])//2, 
			postion['top']+(postion['bot']-postion['top'])//2)
    normal_clone = cv2.seamlessClone(face, body, mask, center, cv2.NORMAL_CLONE)
    return normal_clone

Opencv已经实现了泊松融合的接口,包括三种融合方式,经测试:
NORMAL_CLONE:融合效果比较好
MIXED_CLONE:没有达到换脸的效果
MONOCHROME_TRANSFER:效果较差

基于深度学习的人脸重演(ReenactGAN)

Wayne Wu, Yunxuan Zhang, Cheng Li, Chen Qian, and Chen Change Loy. Reenactgan:Learning to reenact faces via boundary transfer. In Proceedings of the European Conference on Computer Vision (ECCV),2018:603–619.

在这里插入图片描述

主要模型分为三个部分

  1. 编码器

编码器的主体结构为两个级联的沙漏网络Hourglass,其前馈网络为一个7×7的卷积,3个残差模块,两次下采样。

def forward(self, x):
        out = []
        x = self.conv1(x) # 7×7的卷积
        x = self.bn1(x) # 归一化
        x = self.relu(x)  # 激活函数

        x = self.layer1(x)  # 残差网络
        x = self.maxpool(x) # 池化层
        x = self.layer2(x)  # 残差网络
        x = self.layer3(x)  # 残差网络

        for i in range(self.num_stacks):
            y = self.hg[i](x)#1 沙漏模块
            y = self.res[i](y)#2 全卷积网络
            y = self.fc[i](y)#3.1 上分支
            score = self.score[i](y)#3.2 下分支:heatmap
            out.append(score)
            if i < self.num_stacks-1:#后面还有沙漏网络,3上下分支合并
                fc_ = self.fc_[i](y)
                score_ = self.score_[i](score)
                x = x + fc_ + score_

        return out # 返回一系列中间边界热图

编码器效果:
上图为姿势指导脸,下图为中间的边界潜层

  1. 边界空间变形器

    2.1 边界空间变形器的生成器主要包含三部分

第一部分是1组(镜像填充+conv+bn+relu)和两个下采样(conv+bn+relu),第二部分是9个残差块,第三部分是2组(deconv+bn+relu)和一个后馈网络。

https://github.com/jcjohnson/fast-neural-style/

 model = [nn.ReflectionPad2d(3), # 镜像填充,对输入数据扩边
                 nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0,
                           bias=use_bias),
                 norm_layer(ngf),
                 nn.ReLU(True)]

        n_downsampling = 2
        for i in range(n_downsampling): # 2个下采样层
            mult = 2**i
            model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3,
                                stride=2, padding=1, bias=use_bias),
                      norm_layer(ngf * mult * 2),
                      nn.ReLU(True)]

        mult = 2**n_downsampling
        for i in range(n_blocks): # 9个残差模块
            model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)]

        for i in range(n_downsampling):
            mult = 2**(n_downsampling - i)
            model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),
                                         kernel_size=3, stride=2,
                                         padding=1, output_padding=1,
                                         bias=use_bias),
                      norm_layer(int(ngf * mult / 2)),
                      nn.ReLU(True)]
        model += [nn.ReflectionPad2d(3)]
        model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)]
        model += [nn.Sigmoid()]

2.2 判别器部分使用patchGAN,参考pix2pix

 sequence = [
            nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
            nn.LeakyReLU(0.2, True)
        ]

        nf_mult = 1
        nf_mult_prev = 1
        for n in range(1, n_layers):
            nf_mult_prev = nf_mult
            nf_mult = min(2**n, 8)
            sequence += [
                nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
                          kernel_size=kw, stride=2, padding=padw, bias=use_bias),
                norm_layer(ndf * nf_mult),
                nn.LeakyReLU(0.2, True)
            ]

        nf_mult_prev = nf_mult
        nf_mult = min(2**n_layers, 8)
        sequence += [
            nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
                      kernel_size=kw, stride=1, padding=padw, bias=use_bias),
            norm_layer(ndf * nf_mult),
            nn.LeakyReLU(0.2, True)
        ]

        sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)]

变形器在训练过程中,经数据集中的所有人的人脸均输入,规定一个人A为五官提供脸,其他所有人Bi 为姿势指导脸,在所有人之间建立循环一致性损失。

使用GAN,分别训练5个生成模型和5个判别模型,测试时使用G_BA
在这里插入图片描述在这里插入图片描述
变形器效果:
在这里插入图片描述

  1. 解码器

解码器生成器部分使用Unet结构,判别器使用PatchGAN,同样参考pix2pix。

Isola P, Zhu J Y, Zhou T, et al. Image-to-image translation with conditional adversarial networks[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2017: 1125-1134.

生成器有两个,分别是net_B(输入真实图片生成边界图)和net_G(输入边界图生成目标图片)

self.fake_Boundary = self.netBoundaryFeature(self.real_F1)
self.boundary_map = self.fake_Boundary[-1]       
self.fake_F2 = self.netG(self.boundary_map)

作为生成器的Unet可以看做是加了跳跃连接的自编码器,在训练过程中输入图片为五官提供人脸A,使用判别器进行判别从而优化模型。训练过程模型图如下,测试时使用net_G
在这里插入图片描述
解码器效果:
在这里插入图片描述

训练过程踩的坑o(╥﹏╥)o

  1. 人脸识别模型的使用

在人脸替换实验中,导入手机拍摄视频之后换了多个版本的Dlib人脸识别库均不能识别出人脸,最终发现是opencv会自动将手机拍摄图片旋转,所以在图片读入后还需再次旋转,否则会识别不到人脸

 success, frame = cap.read()
 frame = np.rot90(frame,-1)
  1. 使用GPU

在人脸重演训练过程中,需要安装CUDA,但是笔记本不满足设置,本想安装虚拟机,结果发现没有GPU仍然不能安装和训练,经过各种方法的尝试,在此记录强大的google服务器calboratory!!!

calboratory类似于Python编辑的笔记本格式,在首部添加 !便可以使用Linux命令。内置CPU,GPU,TPU和15G的内存,新用户似乎可以免费使用GPU几十个小时,后续9.9美元一个月,比较稳定,但是电脑睡眠屏幕变黑后会停止训练,并且不会自动保存数据(每次分配的服务器都不一样)

calboratory可以与google云端硬盘连接,直接读取硬盘数据和运行代码,训练的模型也可以直接保存到云盘上,使用colaboratory与google drive要先配置:

import os
os.chdir("drive/My Drive/face/ReenactGAN")

将工作地址转移到自己的工作空间中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值