吴恩达深度学习_4_Week4特殊应用:人脸识别

为开心之家进行人脸识别


1、问题描述
2、YOLO
3、在图像上测试训练YOLO


第四门课:卷积神经网络
第四周:特殊应用:人脸识别和神经风格转换

将构建一个人脸识别系统。这里介绍的很多想法都来自于FaceNet
人脸识别问题通常分为两类:
1、人脸验证 - “这个人是声称的人吗?”。例如,在一些机场,你可以通过让系统扫描你的护照并验证你(护照持有人)是否是正确的人来通过海关。使用面部验证解锁的手机也是使用人脸验证。这是一个1对1的匹配问题。
2、人脸识别 - “这个人是谁?”。例如,视频讲座展示了一个人脸识别视频(https://www.youtube.com/watch?v=wr4rx0Spihs),百度员工进入办公室时无需其他身份识别。这是一个1对K的匹配问题。
FaceNet学习了一个神经网络,将人脸图像编码成一个由128个数字组成的向量。通过比较这两个向量,你可以确定两张图片是否是同一个人。
在这个作业中,你将:
1、实现三元组损失函数
2、使用预训练模型将人脸图像映射到128维编码
3、使用这些编码进行人脸验证和人脸识别
在这个练习中,我们将使用一个预训练模型,该模型使用“通道优先”的约定表示ConvNet的激活,而不是课堂和之前的编程作业中使用的“通道后”的约定。换句话说,一个图像批次的形状将是 (𝑚,𝑛𝐶,𝑛𝐻,𝑛𝑊) 而不是 (𝑚,𝑛𝐻,𝑛𝑊,𝑛𝐶)。这两种约定在开源实现中都有一定的影响力;在深度学习社区中尚没有统一的标准。

from keras.models import Sequential
from keras.layers import Conv2D, ZeroPadding2D, Activation, Input, concatenate
from keras.models import Model
from keras.layers.normalization import BatchNormalization
from keras.layers.pooling import MaxPooling2D, AveragePooling2D
from keras.layers.merge import Concatenate
from keras.layers.core import Lambda, Flatten, Dense
from keras.initializers import glorot_uniform
from keras.engine.topology import Layer
from keras import backend as K
K.set_image_data_format('channels_first')
import cv2
import os
import numpy as np
from numpy import genfromtxt
import pandas as pd
import tensorflow as tf
from fr_utils import *
from inception_blocks_v2 import *

np.set_printoptions(threshold=np.nan)

一、初级人脸识别

在人脸验证中,你会得到两张图片,你需要判断它们是否是同一个人。最简单的方法是逐像素比较这两张图片。如果原始图片之间的距离小于选定的阈值,那么它们可能是同一个人!
在这里插入图片描述
当然,这个算法表现非常差,因为像素值会因照明变化、人脸朝向、头部位置微小变化等而发生剧烈变化。
你会发现,与其使用原始图像,不如学习一个编码 𝑓(𝑖𝑚𝑔),以便对该编码的逐元素比较能够更准确地判断两张图片是否是同一个人。

二、将人脸图像编码为128维向量

1、使用ConvNet计算编码

FaceNet模型需要大量的数据和长时间的训练。因此,按照应用深度学习的常见做法,我们只需加载已经由他人训练好的权重。该网络架构遵循Szegedy等人提出的Inception模型。我们提供了Inception网络的实现。你可以在inception_blocks.py文件中查看其实现方式(通过在Jupyter笔记本的顶部选择"File->Open…"来查看。
你需要知道的关键信息是:
1、该网络以96x96维度的RGB图像作为输入。具体而言,将一张人脸图像(或批量的 𝑚
张人脸图像)作为形状为 (𝑚,𝑛𝐶,𝑛𝐻,𝑛𝑊)=(𝑚,3,96,96)的张量输入。
2、它输出一个形状为 (𝑚,128)的矩阵,将每张输入的人脸图像编码为一个128维向量。
运行下面的单元格来创建人脸图像的模型。

FRmodel = faceRecoModel(input_shape=(3, 96, 96))
print("Total Params:", FRmodel.count_params())

Total Params: 3743280
通过在最后一层使用一个具有128个神经元的全连接层,该模型确保输出是一个大小为128的编码向量。然后,你可以使用这些编码来比较两张人脸图像,如下所示:
在这里插入图片描述
图2:通过计算两个编码之间的距离并进行阈值化,可以确定这两张图片是否代表同一个人。
因此,如果一个编码是好的,那么:
1、同一个人的两张图片的编码之间非常相似。
2、不同人的两张图片的编码之间非常不同。
三元组损失函数对此进行了形式化,并试图将同一个人的编码(锚点和正例)拉近,同时将不同人的编码(锚点和负例)拉远。
在这里插入图片描述
图3:在接下来的部分中,我们将从左到右依次称这些图片为:锚点(A),正例(P),负例(N)

2、三元组损失

对于一张图片𝑥,我们用它的编码𝑓(𝑥)来表示,其中𝑓是由神经网络计算得到的函数。
在这里插入图片描述
训练将使用图片的三元组(𝐴,𝑃,𝑁):
1、A是"锚点"图片——一个人的照片。
2、P是"正例"图片——与锚点图片表示同一个人的照片。
3、N是"负例"图片——与锚点图片表示不同的人的照片。
这些三元组被选择为训练样本,以便最大程度地增加锚点与正例之间的相似性,并最大程度地减小锚点与负例之间的相似性。
在这里插入图片描述
1、术语 (1) 是给定三元组中锚点 “A” 和正例 “P” 之间的平方距离;你希望这个值较小。
2、术语 (2) 是给定三元组中锚点 “A” 和负例 “N” 之间的平方距离;你希望这个值相对较大,因此在它前面有一个负号是有意义的。
3、𝛼 是被称为边界的超参数。它是一个需要手动选择的值。我们将使用 𝛼=0.2 。
大多数实现还会对编码向量进行归一化,使其范数为1(即 ∣∣𝑓(𝑖𝑚𝑔)∣∣2 =1)

练习:按照公式 (3) 的定义实现三元组损失。以下是四个步骤:
在这里插入图片描述

据公式(3)定义的三元组损失的实现
参数:
y_true - 真实标签,在Keras中定义损失函数时需要,但在这个函数中不需要。
y_pred - 包含三个对象的Python列表:
anchor - 锚点图像的编码,形状为(None,128)
positive - 正例图像的编码,形状为(None,128)
negative - 负例图像的编码,形状为(None,128)
返回值:loss - 实数,损失的值
# GRADED FUNCTION: triplet_loss
def triplet_loss(y_true, y_pred, alpha = 0.2):
    anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
    
    # Step 1: Compute the (encoding) distance between the anchor and the positive, you will need to sum over axis=-1
    pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)))

    # Step 2: Compute the (encoding) distance between the anchor and the negative, you will need to sum over axis=-1
    neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)))

    # Step 3: subtract the two previous distances and add alpha.
    basic_loss = tf.add(tf.subtract(pos_dist,neg_dist), alpha)

    # Step 4: Take the maximum of basic_loss and 0.0. Sum over the training examples.
    loss = tf.reduce_sum(tf.maximum(basic_loss, 0.))

    return loss
    
with tf.Session() as test:
    tf.set_random_seed(1)
    y_true = (None, None, None)
    y_pred = (tf.random_normal([3, 128], mean=6, stddev=0.1, seed = 1),
              tf.random_normal([3, 128], mean=1, stddev=1, seed = 1),
              tf.random_normal([3, 128], mean=3, stddev=4, seed = 1))
    loss = triplet_loss(y_true, y_pred)
    
    print("loss = " + str(loss.eval()))

loss 528.143

三、加载预训练模型

人脸识别模型已经在一个大型的人脸识别数据集上进行了训练。运行下面的代码来加载训练好的模型的权重。这可能需要几分钟的时间,因为模型的文件相对较大。

FRmodel.compile(optimizer = 'adam', loss = triplet_loss, metrics = ['accuracy'])
load_weights_from_FaceNet(FRmodel)

在这里插入图片描述

四、应用模型

回到快乐屋!自从你在之前的任务中为房屋实现了快乐识别后,居民们过上了幸福的生活。
然而,出现了一些问题:快乐屋变得如此快乐,以至于附近的每个快乐的人都来到你的客厅玩耍。房屋变得非常拥挤,对居民们产生了负面影响。所有这些随机的快乐的人还吃光了你的食物。
因此,你决定改变进门政策,不再让随机的快乐的人进入,即使他们很快乐!相反,你想建立一个人脸验证系统,只允许指定名单上的人进入。为了被允许进入,每个人都必须刷一张身份证(ID卡)在门口进行身份验证。然后人脸识别系统会检查他们是否是他们声称的人。

1、人脸验证

让我们建立一个数据库,其中包含每个被允许进入快乐屋的人的一个编码向量。为了生成编码,我们使用img_to_encoding(image_path, model),它基本上在指定的图像上运行模型的前向传播。
运行以下代码来建立数据库(表示为Python字典)。该数据库将每个人的姓名映射到他们面部的128维编码。

database = {}
database["danielle"] = img_to_encoding("images/danielle.png", FRmodel)
database["younes"] = img_to_encoding("images/younes.jpg", FRmodel)
database["tian"] = img_to_encoding("images/tian.jpg", FRmodel)
database["andrew"] = img_to_encoding("images/andrew.jpg", FRmodel)
database["kian"] = img_to_encoding("images/kian.jpg", FRmodel)
database["dan"] = img_to_encoding("images/dan.jpg", FRmodel)
database["sebastiano"] = img_to_encoding("images/sebastiano.jpg", FRmodel)
database["bertrand"] = img_to_encoding("images/bertrand.jpg", FRmodel)
database["kevin"] = img_to_encoding("images/kevin.jpg", FRmodel)
database["felix"] = img_to_encoding("images/felix.jpg", FRmodel)
database["benoit"] = img_to_encoding("images/benoit.jpg", FRmodel)
database["arnaud"] = img_to_encoding("images/arnaud.jpg", FRmodel)

现在,当有人出现在你的前门并刷身份证(从而告诉你他们的姓名)时,你可以在数据库中查找他们的编码,并用它来检查站在前门的人是否与身份证上的姓名匹配。
练习:实现verify()函数,检查前门摄像头拍摄的照片(image_path)是否确实是名为"identity"的人。你需要执行以下步骤:
1、计算image_path图像的编码
2、计算该编码与存储在数据库中的identity图像的编码之间的距离
3、如果距离小于0.7,则打开门;否则不打开。
如上所述,你应该使用L2距离(np.linalg.norm)。 (注意:在此实现中,与阈值0.7相比较的是L2距离,而不是L2距离的平方。)

函数验证位于 "image_path" 图像上的人是否是 "identity"。
参数:
image_path - 图像的路径
identity - 字符串,你想要验证身份的人的姓名。必须是快乐屋的居民。
database - Python字典,将被允许进入的人的姓名(字符串)映射到他们的编码(向量)。
model - Keras中的Inception模型实例
返回值:
dist - "image_path" 图像与数据库中 "identity" 图像之间的距离。
door_open - 如果应该打开门,则为True。否则为False。
# GRADED FUNCTION: verify
def verify(image_path, identity, database, model):
    # Step 1: Compute the encoding for the image. Use img_to_encoding() see example above. (≈ 1 line)
    encoding = img_to_encoding(image_path, model)
  
    # Step 2: Compute distance with identity's image (≈ 1 line)
    dist = np.linalg.norm(encoding - database[identity])
  
    # Step 3: Open the door if dist < 0.7, else don't open (≈ 3 lines)
    if dist < 0.7:
        print("It's " + str(identity) + ", welcome home!")
        door_open = True
    else:
        print("It's not " + str(identity) + ", please go away")
        door_open = False
        
    return dist, door_open
    
verify("images/camera_0.jpg", "younes", database, FRmodel)

输出:
It’s younes, welcome home! (0.65939283, True)

Benoit在上周末打破了水族馆,已被禁止进入房屋并从数据库中移除。他偷了Kian的身份证,并回到房屋试图冒充Kian。前门摄像头拍摄了Benoit的照片(“images/camera_2.jpg”)。让我们运行验证算法来检查Benoit是否可以进入。

verify("images/camera_2.jpg", "kian", database, FRmodel)

It’s not kian, please go away (0.86224014, False)

2、人脸识别

你的人脸验证系统基本上运行良好。但由于Kian的身份证被盗,他当晚回到房屋时无法进入!
为了减少这种麻烦事,你想将人脸验证系统改为人脸识别系统。这样,没有人再需要携带身份证了。授权人只需走到房屋前,前门就会为他们解锁!
你将实现一个人脸识别系统,它以图像作为输入,并确定它是否是授权人之一(如果是,还可以确定是谁)。与之前的人脸验证系统不同,我们不再将人的姓名作为另一个输入。

练习:实现who_is_it()函数。你需要执行以下步骤:
1、计算image_path图像的目标编码
2、找到与目标编码具有最小距离的数据库编码。
将min_dist变量初始化为足够大的数值(100)。它将帮助你跟踪哪个编码与输入编码最接近。
遍历数据库字典的名称和编码。使用for (name, db_enc) in database.items()进行循环。
计算目标“编码”与数据库中当前“编码”的L2距离。
如果这个距离小于min_dist,则将min_dist设置为dist,并将identity设置为name。

通过找到位于 "image_path" 图像上的人来实现快乐屋的人脸识别。
参数:
image_path - 图像的路径
database - 包含图像编码及其对应姓名的数据库
model - Keras中的Inception模型实例
返回值:
min_dist - "image_path" 编码与数据库中编码之间的最小距离
identity - 字符串,对于 "image_path" 图像上的人的姓名预测
# GRADED FUNCTION: who_is_it
def who_is_it(image_path, database, model):
 
    ## Step 1: Compute the target "encoding" for the image. Use img_to_encoding() see example above. 
    encoding = img_to_encoding(image_path, model)

    ## Step 2: Find the closest encoding ##
    # Initialize "min_dist" to a large value, say 100 (≈1 line)
    min_dist = 100
    # Loop over the database dictionary's names and encodings.
    for (name, db_enc) in database.items():
        # Compute L2 distance between the target "encoding" and the current "emb" from the database. 
        dist = np.linalg.norm(encoding - db_enc)
        # If this distance is less than the min_dist, then set min_dist to dist, and identity to name. 
        if dist < min_dist:
            min_dist = dist
            identity = name
            
    if min_dist > 0.7:
        print("Not in the database.")
    else:
        print ("it's " + str(identity) + ", the distance is " + str(min_dist))
        
    return min_dist, identity

who_is_it("images/camera_0.jpg", database, FRmodel)

输出:
it’s younes, the distance is 0.659393 (0.65939283, ‘younes’)
你可以将 “camera_0.jpg”(younes的照片)更改为 “camera_1.jpg”(bertrand的照片),并查看结果。

你的Happy House运行良好。它只让授权人员进入,人们不再需要随身携带身份证了!
你已经看到了最先进的人脸识别系统是如何工作的。
尽管我们不会在这里实现它,但以下是进一步改进算法的一些方法:
1、将每个人的更多图像(在不同光照条件下,不同日期拍摄的图像等)放入数据库中。然后,对于给定的新图像,将新的人脸与该人的多张照片进行比较。这将提高准确性。
2、将图像裁剪为仅包含面部,减少面部周围的“边界”区域。这种预处理去除了面部周围的一些无关像素,也使算法更加鲁棒。

记住:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值