0 - Package version
Package Version
----------------------------- --------------
imageio 2.33.1
keras 2.6.0
Keras-Preprocessing 1.1.2
matplotlib 3.7.2
numpy 1.21.6
tensorflow 2.6.0
1 - Import packages
import tensorflow as tf
from fr_utils import *
from inception_blocks_v3 import *
2 - Using an ConvNet to compute encodings
FRmodel = faceRecoModel(input_shape=(3, 96, 96))
print("Total Params:", FRmodel.count_params())
'''
Output 输出
Total Params: 3743280
'''
3 - The Triplet Loss
# GRADED FUNCTION: triplet_loss
def triplet_loss(y_true, y_pred, alpha=0.2):
"""
Implementation of the triplet loss as defined by formula (3)
Arguments:
y_true -- true labels, required when you define a loss in Keras, you don't need it in this function.
y_pred -- python list containing three objects:
anchor -- the encodings for the anchor images, of shape (None, 128)
positive -- the encodings for the positive images, of shape (None, 128)
negative -- the encodings for the negative images, of shape (None, 128)
Returns:
loss -- real number, value of the loss
"""
anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
"""
bug
pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), axis=1)
neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), axis=1)
"""
### START CODE HERE ### (≈ 4 lines)
# 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)))
print(pos_dist)
# 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)))
print(neg_dist)
# Step 3: subtract the two previous distances and add alpha.
basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
print(basic_loss)
# 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.0))
print()
### END CODE HERE ###
return loss
tf.random.set_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),
)
# print(y_pred)
loss = triplet_loss(y_true, y_pred)
print("loss = " + str(loss))
4 - Loading the trained model
FRmodel.compile(optimizer="adam", loss=triplet_loss, metrics=["accuracy"])
load_weights_from_FaceNet(FRmodel)
5 - Applying the model
5.1 - Face Verification
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)
# GRADED FUNCTION: verify
def verify(image_path, identity, database, model):
"""
Function that verifies if the person on the "image_path" image is "identity".
Arguments:
image_path -- path to an image
identity -- string, name of the person you'd like to verify the identity. Has to be a resident of the Happy house.
database -- python dictionary mapping names of allowed people's names (strings) to their encodings (vectors).
model -- your Inception model instance in Keras
Returns:
dist -- distance between the image_path and the image of "identity" in the database.
door_open -- True, if the door should open. False otherwise.
"""
### START CODE HERE ###
# 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
### END CODE HERE ###
return dist, door_open
verify("images/camera_0.jpg", "younes", database, FRmodel)
verify("images/camera_2.jpg", "kian", database, FRmodel)
5.2 - Face Recognition
# GRADED FUNCTION: who_is_it
def who_is_it(image_path, database, model):
"""
Implements face recognition for the happy house by finding who is the person on the image_path image.
Arguments:
image_path -- path to an image
database -- database containing image encodings along with the name of the person on the image
model -- your Inception model instance in Keras
Returns:
min_dist -- the minimum distance between image_path encoding and the encodings from the database
identity -- string, the name prediction for the person on image_path
"""
### START CODE HERE ###
## Step 1: Compute the target "encoding" for the image. Use img_to_encoding() see example above. ## (≈ 1 line)
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. (≈ 1 line)
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. (≈ 3 lines)
if dist < min_dist:
min_dist = dist
identity = name
### END CODE HERE ###
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)
6 - 在引用的文件中有几个地方要改:
6.1 - fr_utils.py
# 导入BatchNormalization的所属的package不同于TF1
# from keras.layers.normalization import BatchNormalization
from tensorflow.keras.layers import BatchNormalization
6.2 - inception_blocks_v2.py
# faceRecoMedel中convolution,Pooling & ZeroPadding函数没有加入参数data_format='channels_first',会导致输出的张量维度不正确
def faceRecoModel(input_shape):
"""
Implementation of the Inception model used for FaceNet
Arguments:
input_shape -- shape of the images of the dataset
Returns:
model -- a Model() instance in Keras
"""
# Define the input as a tensor with shape input_shape
X_input = Input(input_shape)
# Zero-Padding
X = ZeroPadding2D((3, 3) ,data_format='channels_first')(X_input)
# First Block
X = Conv2D(64, (7, 7), strides = (2, 2), name = 'conv1' ,data_format='channels_first')(X)
X = BatchNormalization(axis = 1, name = 'bn1')(X)
X = Activation('relu')(X)
# Zero-Padding + MAXPOOL
X = ZeroPadding2D((1, 1) ,data_format='channels_first')(X)
X = MaxPooling2D((3, 3), strides = 2 ,data_format='channels_first')(X)
# Second Block
X = Conv2D(64, (1, 1), strides = (1, 1), name = 'conv2' ,data_format='channels_first')(X)
X = BatchNormalization(axis = 1, epsilon=0.00001, name = 'bn2')(X)
X = Activation('relu')(X)
# Zero-Padding + MAXPOOL
X = ZeroPadding2D((1, 1) ,data_format='channels_first')(X)
# Second Block
X = Conv2D(192, (3, 3), strides = (1, 1), name = 'conv3' ,data_format='channels_first')(X)
X = BatchNormalization(axis = 1, epsilon=0.00001, name = 'bn3')(X)
X = Activation('relu')(X)
# Zero-Padding + MAXPOOL
X = ZeroPadding2D((1, 1) ,data_format='channels_first')(X)
X = MaxPooling2D(pool_size = 3, strides = 2 ,data_format='channels_first')(X)
# Inception 1: a/b/c
X = inception_block_1a(X)
X = inception_block_1b(X)
X = inception_block_1c(X)
# Inception 2: a/b
X = inception_block_2a(X)
X = inception_block_2b(X)
# Inception 3: a/b
X = inception_block_3a(X)
X = inception_block_3b(X)
# Top layer
X = AveragePooling2D(pool_size=(3, 3), strides=(1, 1), data_format='channels_first')(X)
X = Flatten()(X)
X = Dense(128, name='dense_layer')(X)
# L2 normalization
X = Lambda(lambda x: K.l2_normalize(x,axis=1))(X)
# Create model instance
model = Model(inputs = X_input, outputs = X, name='FaceRecoModel')
return model