Introduction
GhostFaceNets is a revolutionary facial recognition know-how that makes use of cheap operations with out compromising accuracy. Impressed by attention-based fashions, it revolutionizes facial recognition know-how. This weblog publish explores GhostFaceNets by way of charming visuals and insightful illustrations, aiming to educate, encourage, and spark creativity. The journey shouldn’t be solely a weblog publish, nevertheless a novel exploration of the limitless prospects of GhostFaceNets. Be part of us on this thrilling journey to search out the world of GhostFaceNets.
Finding out Targets
- Comprehend the underlying challenges and motivations driving the occasion of lightweight FR fashions tailored for low computational models (eg: edge).
- Articulate the indepth architectural components of GhostFaceNets, along with the Ghost modules, the DFC consideration division, and the exact variations launched to the backbone GhostNets architectures.
- Give attention to the advantages of GhostFaceNets compared with standard face recognition fashions, by the use of effectivity, accuracy, and computational complexity.
- Acknowledge the important thing contributions made by GhostFaceNets to the sector of face recognition and face verification, and film its potential features all through fully totally different real-time conditions.
This textual content was revealed as a part of the Data Science Blogathon.
Introduction of GhostFaceNets
In as we communicate’s interval of ubiquitous computing and the IOT, FR know-how performs an important operate in quite a few features, along with seamless individual authentication, custom-made experiences, and stronger security measures. Nonetheless, standard facial recognition packages consumes extreme computational belongings, rendering them unsuitable for deployment on low computation models with restricted belongings. That’s the place GhostFaceNets comes into play, that ensures to revolutionize how we technique and implement facial recognition know-how.
Evolution of Lightweight Face Recognition Fashions
As a result of the demand for edge computing and real-time features soared, the need for atmosphere pleasant and lightweight fashions turned paramount. Researchers and engineers alike sought to strike a fragile steadiness between model complexity and effectivity, giving rise to a plethora of lightweight architectures tailored for explicit duties, along with face recognition.
Deep learning algorithms like Convolutional Neural Networks (CNNs) have revolutionized face recognition evaluation, enhancing accuracy compared with standard methods. Nonetheless, these fashions sometimes battle to steadiness effectivity and complexity, significantly for real-world features and resource-constrained models. The Labeled Faces inside the Wild dataset is the gold regular for evaluating new FR fashions, with Delicate CNN architectures lowering parameters and computational complexity. No matter these developments, basically essentially the most right reported effectivity on LFW is 99.33%.
ShiftFaceNet launched a “Shift” operation to chop again the number of parameters in image classification fashions, resulting in a 2-degree accuracy drop. Totally different fashions constructed upon image classification backbones, akin to MobileFaceNets, ShuffleFaceNet, VarGFaceNet, and MixFaceNets, have confirmed improved trade-offs between effectivity and complexity. MobileFaceNets achieved 99.55% LFW accuracy with 1M parameters, whereas ShuffleFaceNet achieved 99.67% LFW accuracy with 2.6M parameters and 557.5 MFLOPs.
VarGFaceNet leveraged VarGNet and achieved 99.85% LFW accuracy with 5M parameters and 1.022 GFLOPs. MixFaceNets achieved 99.68% LFW accuracy with 3.95M parameters and 626.1 MFLOPs. Totally different notable fashions embody AirFace, QuantFace, and PocketNets, which have achieved 99.27% LFW accuracy with 1 GFLOPs, 99.43% LFW accuracy with 1.1M parameters, and 99.58% LFW accuracy with 0.925M parameters and 587.11 MFLOPs.
Understanding GhostFaceNets Construction
Establishing upon the atmosphere pleasant GhostNets architectures (GhostNetV1 and GhostNetV2), the authors recommend GhostFaceNets, a model new set of lightweight architectures tailored for face recognition and face verification. Quite a lot of key modifications had been made:
- The World Widespread Pooling (GAP) layer, pointwise convolution layer (1×1 convolution), and Completely Linked (FC) layer had been modified with a modified World Depthwise Convolution (GDC) recognition head to generate discriminative attribute vectors.
- The ReLU activation carry out utilized in GhostNets was modified with PReLU, which alleviates the vanishing gradient draw back and improves effectivity.
- The normal Completely Linked layers inside the Squeeze-and-Excitation (SE) modules had been modified with convolution layers to reinforce the discriminative power of GhostFaceNets.
- The ArcFace loss carry out was employed for teaching, to implement intra-class compactness, inter-class discrepancy, and improves the discriminative power of realized choices. To bear Arcface loss carry out please examine with my earlier weblog – click here
The authors designed a set of GhostFaceNets fashions by numerous the teaching dataset, the width of the GhostNets architectures, and the stride of the first convolution layer (stem). The following fashions outperform most lightweight SOTA fashions on fully totally different benchmarks, as talked about in subsequent sections.
A. GhostNetV1 and Ghost Modules (Attribute Map Pattern Redundancy)
GhostNetV1, the backbone construction of GhostFaceNets, employs a novel concept known as Ghost modules to generate a positive proportion (denoted as x%) of the attribute maps, whereas the remaining attribute maps are generated using a low-cost linear operation known as as depthwise convolution (DWConv).
In a standard convolutional layer, a 2D filter (kernel) is utilized to a 2D channel of the enter tensor to generate a 2D channel of the output tensor, straight producing a tensor of attribute maps with C’ channels from an enter tensor of C channels. Nonetheless, Ghost modules take a novel technique.
The Ghost module generates the first x% of the output tensor channels using a sequential block of three layers: common convolution, batch normalization, and a nonlinear activation carry out (default: ReLU). The output is then despatched to a second block with depthwise convolution, batch normalization, and ReLU, and the output tensor is achieved by stacking the two blocks.
As confirmed in Decide 1, there are clearly associated and redundant attribute map pairs (ghosts) which may be generated using linear operations, lowering computational complexity with out decreasing effectivity. The authors of GhostNetV1 exploit this commentary by producing these associated and redundant choices using low price operations, pretty than discarding them.
By utilizing Ghost modules, GhostNetV1 can efficiently generate the similar number of attribute maps as an convolutional layer, with essential low cost inside the number of parameters and FLOPs. This allows Ghost modules to be merely built-in into present neural group architectures to chop again computational complexity.
Implementation with Python Code
Underneath code is from ghost_model.py module from backbones folder
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import backend as Okay
from tensorflow.keras.fashions import Model
from tensorflow.keras.layers import (
Activation,
Add,
BatchNormalization,
Concatenate,
Conv2D,
DepthwiseConv2D,
GlobalAveragePooling2D,
Enter,
PReLU,
Reshape,
Multiply,
)
import math
CONV_KERNEL_INITIALIZER = keras.initializers.VarianceScaling(scale=2.0, mode="fan_out", distribution="truncated_normal")
def _make_divisible(v, divisor=4, min_value=None):
"""
This carry out is taken from the distinctive tf repo.
It ensures that every one layers have a channel amount that is divisible by 8
It might be seen proper right here:
https://github.com/tensorflow/fashions/blob/grasp/evaluation/slim/nets/mobilenet/mobilenet.py
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
if new_v < 0.9 * v:
new_v += divisor
return new_v
def activation(inputs):
return Activation("relu")(inputs)
def se_module(inputs, se_ratio=0.25):
#get the channel axis
channel_axis = 1 if Okay.image_data_format() == "channels_first" else -1
#filters = channel axis kind
filters = inputs.kind[channel_axis]
low cost = _make_divisible(filters * se_ratio)
#from None x H x W x C to None x C
se = GlobalAveragePooling2D()(inputs)
#Reshape None x C to None 1 x 1 x C
se = Reshape((1, 1, filters))(se)
#Squeeze by using C*se_ratio. The scale will possible be 1 x 1 x C*se_ratio
se = Conv2D(low cost, kernel_size=1, use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER)(se)
# se = PReLU(shared_axes=[1, 2])(se)
se = Activation("relu")(se)
#Excitation using C filters. The scale will possible be 1 x 1 x C
se = Conv2D(filters, kernel_size=1, use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER)(se)
se = Activation("hard_sigmoid")(se)
return Multiply()([inputs, se])
def ghost_module(inputs, out, convkernel=1, dwkernel=3, add_activation=True):
# conv_out_channel = math.ceil(out * 1.0 / 2)
conv_out_channel = out // 2
# tf.print("[ghost_module] out:", out, "conv_out_channel:", conv_out_channel)
cc = Conv2D(conv_out_channel, convkernel, use_bias=False, strides=(1, 1), padding="similar", kernel_initializer=CONV_KERNEL_INITIALIZER)(
inputs
) # padding=kernel_size//2
cc = BatchNormalization(axis=-1)(cc)
if add_activation:
cc = activation(cc)
channel = int(out - conv_out_channel)
nn = DepthwiseConv2D(dwkernel, 1, padding="similar", use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER)(cc) # padding=dw_size//2
nn = BatchNormalization(axis=-1)(nn)
if add_activation:
nn = activation(nn)
return Concatenate()([cc, nn])
def ghost_bottleneck(inputs, dwkernel, strides, exp, out, se_ratio=0, shortcut=True):
nn = ghost_module(inputs, exp, add_activation=True) # ghost1 = GhostModule(in_chs, exp, relu=True)
if strides > 1:
# Additional depth conv if strides elevated than 1
nn = DepthwiseConv2D(dwkernel, strides, padding="similar", use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER)(nn)
nn = BatchNormalization(axis=-1)(nn)
# nn = Activation('relu')(nn)
if se_ratio > 0:
# Squeeze and excite
nn = se_module(nn, se_ratio) # se = SqueezeExcite(exp, se_ratio=se_ratio)
# Stage-wise linear projection
nn = ghost_module(nn, out, add_activation=False) # ghost2 = GhostModule(exp, out, relu=False)
# nn = BatchNormalization(axis=-1)(nn)
if shortcut:
xx = DepthwiseConv2D(dwkernel, strides, padding="similar", use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER)(
inputs
) # padding=(dw_kernel_size-1)//2
xx = BatchNormalization(axis=-1)(xx)
xx = Conv2D(out, (1, 1), strides=(1, 1), padding="professional", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(xx) # padding=0
xx = BatchNormalization(axis=-1)(xx)
else:
xx = inputs
return Add()([xx, nn])
#1.3 is the width of the GhostNet as inside the paper (Desk 7)
def GhostNet(input_shape=(224, 224, 3), include_top=True, programs=0, width=1.3, strides=2, title="GhostNet"):
inputs = Enter(kind=input_shape)
out_channel = _make_divisible(16 * width, 4)
nn = Conv2D(out_channel, (3, 3), strides=strides, padding="similar", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(inputs) # padding=1
nn = BatchNormalization(axis=-1)(nn)
nn = activation(nn)
dwkernels = [3, 3, 3, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5]
exps = [16, 48, 72, 72, 120, 240, 200, 184, 184, 480, 672, 672, 960, 960, 960, 512]
outs = [16, 24, 24, 40, 40, 80, 80, 80, 80, 112, 112, 160, 160, 160, 160, 160]
use_ses = [0, 0, 0, 0.25, 0.25, 0, 0, 0, 0, 0.25, 0.25, 0.25, 0, 0.25, 0, 0.25]
strides = [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1]
pre_out = out_channel
for dwk, stride, exp, out, se in zip(dwkernels, strides, exps, outs, use_ses):
out = _make_divisible(out * width, 4) # [ 20 32 32 52 52 104 104 104 104 144 144 208 208 208 208 208 ]
exp = _make_divisible(exp * width, 4) # [ 20 64 92 92 156 312 260 240 240 624 872 872 1248 1248 1248 664 ]
shortcut = False if out == pre_out and stride == 1 else True
nn = ghost_bottleneck(nn, dwk, stride, exp, out, se, shortcut)
pre_out = out # [ 20 32 32 52 52 104 104 104 104 144 144 208 208 208 208 208 ]
out = _make_divisible(exps[-1] * width, 4) #664
nn = Conv2D(out, (1, 1), strides=(1, 1), padding="professional", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(nn) # padding=0
nn = BatchNormalization(axis=-1)(nn)
nn = activation(nn)
if include_top:
nn = GlobalAveragePooling2D()(nn)
nn = Reshape((1, 1, int(nn.kind[1])))(nn)
nn = Conv2D(1280, (1, 1), strides=(1, 1), padding="similar", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(nn)
nn = BatchNormalization(axis=-1)(nn)
nn = activation(nn)
nn = Conv2D(programs, (1, 1), strides=(1, 1), padding="similar", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(nn)
nn = Okay.squeeze(nn, 1)
nn = Activation("softmax")(nn)
return Model(inputs=inputs, outputs=nn, title=title)
B. GhostNetV2
GhostNetV2 introduces essential enhancements to the Ghost module of GhostNetV1, aiming to grab long-range dependencies further efficiently. The essential factor innovation is the incorporation of a novel attention-based layer known as the DFC consideration division, designed to generate consideration maps with worldwide receptive fields using convolutions. In distinction to standard self-attention layers, the DFC consideration division achieves extreme effectivity whereas capturing dependencies between pixels all through fully totally different spatial areas. This effectivity is important for {{hardware}} compatibility and inference tempo, as many prior consideration modules relied on computationally intensive tensor operations.
GhostNetV2’s construction encompasses a brand new bottleneck development, allowing the Ghost module and DFC consideration division to operate in parallel. It gathers information from diverse viewpoints and aggregating it into the last word output. This feature-wise product ensures full safety of enter data all through diverse patches.
The DFC consideration division consists of 5 operations: downsampling, convolution, horizontal and vertical completely associated (FC) layers, and sigmoid activation(Refer the above image). To mitigate computational overhead, we take advantage of native frequent pooling for downsampling and bilinear interpolation for upsampling. Decomposing the FC layer into horizontal and vertical parts reduces complexity whereas capturing long-range dependencies alongside every dimensions.
Whole, GhostNetV2 represents a serious improvement in attention-based fashions, offering improved effectivity and effectiveness in capturing long-range dependencies. Seen aids akin to diagrams illustrating the construction and operations of the DFC consideration division can improve understanding and engagement for readers. Place these diagrams strategically contained in the textual content material to reinforce the explanations and facilitate comprehension.
Implementation with Python Code
Underneath code is from ghostv2.py module from backbones folder
!pip arrange keras_cv_attention_models
import tensorflow as tf
from tensorflow import keras
from keras_cv_attention_models.attention_layers import (
activation_by_name,
batchnorm_with_activation,
conv2d_no_bias,
depthwise_conv2d_no_bias,
make_divisible,
se_module,
add_pre_post_process,
)
from keras_cv_attention_models.download_and_load import reload_model_weights
PRETRAINED_DICT = {
"ghostnetv2_1x": {"imagenet": "4f28597d5f72731ed4ef4f69ec9c1799"},
"ghostnet_1x": {"imagenet": "df1de036084541c5b8bd36b179c74577"},
}
def ghost_module(inputs, out_channel, activation="relu", title=""):
ratio = 2
hidden_channel = int(tf.math.ceil(float(out_channel) / ratio))
primary_conv = conv2d_no_bias(inputs, hidden_channel, title=title + "prim_")
primary_conv = batchnorm_with_activation(primary_conv, activation=activation, title=title + "prim_")
cheap_conv = depthwise_conv2d_no_bias(primary_conv, kernel_size=3, padding="SAME", title=title + "cheap_")
cheap_conv = batchnorm_with_activation(cheap_conv, activation=activation, title=title + "cheap_")
return keras.layers.Concatenate()([primary_conv, cheap_conv])
def ghost_module_multiply(inputs, out_channel, activation="relu", title=""):
nn = ghost_module(inputs, out_channel, activation=activation, title=title)
# shortcut = keras.layers.AvgPool2D(pool_size=2, strides=2, padding="SAME")(inputs)
shortcut = keras.layers.AvgPool2D(pool_size=2, strides=2)(inputs)
shortcut = conv2d_no_bias(shortcut, out_channel, title=title + "short_1_")
shortcut = batchnorm_with_activation(shortcut, activation=None, title=title + "short_1_")
shortcut = depthwise_conv2d_no_bias(shortcut, (1, 5), padding="SAME", title=title + "short_2_")
shortcut = batchnorm_with_activation(shortcut, activation=None, title=title + "short_2_")
shortcut = depthwise_conv2d_no_bias(shortcut, (5, 1), padding="SAME", title=title + "short_3_")
shortcut = batchnorm_with_activation(shortcut, activation=None, title=title + "short_3_")
shortcut = activation_by_name(shortcut, "sigmoid", title=title + "short_")
shortcut = tf.image.resize(shortcut, tf.kind(inputs)[1:-1], antialias=False, methodology="bilinear")
return keras.layers.Multiply()([shortcut, nn])
def ghost_bottleneck(
inputs, out_channel, first_ghost_channel, kernel_size=3, strides=1, se_ratio=0, shortcut=True, use_ghost_module_multiply=False, activation="relu", title=""
):
if shortcut:
shortcut = depthwise_conv2d_no_bias(inputs, kernel_size, strides, padding="similar", title=title + "short_1_")
shortcut = batchnorm_with_activation(shortcut, activation=None, title=title + "short_1_")
shortcut = conv2d_no_bias(shortcut, out_channel, title=title + "short_2_")
shortcut = batchnorm_with_activation(shortcut, activation=None, title=title + "short_2_")
else:
shortcut = inputs
if use_ghost_module_multiply:
nn = ghost_module_multiply(inputs, first_ghost_channel, activation=activation, title=title + "ghost_1_")
else:
nn = ghost_module(inputs, first_ghost_channel, activation=activation, title=title + "ghost_1_")
if strides > 1:
nn = depthwise_conv2d_no_bias(nn, kernel_size, strides, padding="similar", title=title + "down_")
nn = batchnorm_with_activation(nn, activation=None, title=title + "down_")
if se_ratio > 0:
nn = se_module(nn, se_ratio=se_ratio, divisor=4, activation=("relu", "hard_sigmoid_torch"), title=title + "se_")
nn = ghost_module(nn, out_channel, activation=None, title=title + "ghost_2_")
return keras.layers.Add(title=title + "output")([shortcut, nn])
def GhostNetV2(
stem_width=16,
stem_strides=2,
width_mul=1.0,
num_ghost_module_v1_stacks=2, # num of `ghost_module` stcks on the top, others are `ghost_module_multiply`, set `-1` for all using `ghost_module`
input_shape=(224, 224, 3),
num_classes=1000,
activation="relu",
classifier_activation="softmax",
dropout=0,
pretrained=None,
model_name="ghostnetv2",
kwargs=None,
):
inputs = keras.layers.Enter(input_shape)
stem_width = make_divisible(stem_width * width_mul, divisor=4)
nn = conv2d_no_bias(inputs, stem_width, 3, strides=stem_strides, padding="similar", title="stem_")
nn = batchnorm_with_activation(nn, activation=activation, title="stem_")
""" ranges """
kernel_sizes = [3, 3, 3, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5]
first_ghost_channels = [16, 48, 72, 72, 120, 240, 200, 184, 184, 480, 672, 672, 960, 960, 960, 960]
out_channels = [16, 24, 24, 40, 40, 80, 80, 80, 80, 112, 112, 160, 160, 160, 160, 160]
se_ratios = [0, 0, 0, 0.25, 0.25, 0, 0, 0, 0, 0.25, 0.25, 0.25, 0, 0.25, 0, 0.25]
strides = [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1]
for stack_id, (kernel, stride, first_ghost, out_channel, se_ratio) in enumerate(zip(kernel_sizes, strides, first_ghost_channels, out_channels, se_ratios)):
stack_name = "stack{}_".format(stack_id + 1)
out_channel = make_divisible(out_channel * width_mul, 4)
first_ghost_channel = make_divisible(first_ghost * width_mul, 4)
shortcut = False if out_channel == nn.kind[-1] and stride == 1 else True
use_ghost_module_multiply = True if num_ghost_module_v1_stacks >= 0 and stack_id >= num_ghost_module_v1_stacks else False
nn = ghost_bottleneck(
nn, out_channel, first_ghost_channel, kernel, stride, se_ratio, shortcut, use_ghost_module_multiply, activation=activation, title=stack_name
)
nn = conv2d_no_bias(nn, make_divisible(first_ghost_channels[-1] * width_mul, 4), 1, strides=1, title="pre_")
nn = batchnorm_with_activation(nn, activation=activation, title="pre_")
if num_classes > 0:
nn = keras.layers.GlobalAveragePooling2D(keepdims=True)(nn)
nn = conv2d_no_bias(nn, 1280, 1, strides=1, use_bias=True, title="features_")
nn = activation_by_name(nn, activation, title="features_")
nn = keras.layers.Flatten()(nn)
if dropout > 0 and dropout < 1:
nn = keras.layers.Dropout(dropout)(nn)
nn = keras.layers.Dense(num_classes, dtype="float32", activation=classifier_activation, title="head")(nn)
model = keras.fashions.Model(inputs, nn, title=model_name)
add_pre_post_process(model, rescale_mode="torch")
reload_model_weights(model, PRETRAINED_DICT, "ghostnetv2", pretrained)
return model
def GhostNetV2_1X(input_shape=(224, 224, 3), num_classes=1000, activation="relu", classifier_activation="softmax", pretrained="imagenet", **kwargs):
return GhostNetV2(**locals(), model_name="ghostnetv2_1x", **kwargs)
""" GhostNet V1 """
def GhostNet(
stem_width=16,
stem_strides=2,
width_mul=1.0,
num_ghost_module_v1_stacks=-1, # num of `ghost_module` stcks on the top, others are `ghost_module_multiply`, set `-1` for all using `ghost_module`
input_shape=(224, 224, 3),
num_classes=1000,
activation="relu",
classifier_activation="softmax",
dropout=0,
pretrained=None,
model_name="ghostnet",
kwargs=None,
):
return GhostNetV2(**locals())
def GhostNet_1X(input_shape=(224, 224, 3), num_classes=1000, activation="relu", classifier_activation="softmax", pretrained="imagenet", **kwargs):
return GhostNet(**locals(), model_name="ghostnet_1x", **kwargs)
The Ghost module in GhostNetV1 incorporates the DFC consideration division, whereas GhostNetV2 employs it.
C. GhostFaceNets Construction
Establishing upon the GhostNetV1 construction, the authors of GhostFaceNets made plenty of key modifications to tailor the model for face recognition and face verification duties.
GhostFaceNets are a serious improvement in lightweight face recognition and face verification fashions, incorporating key modifications to reinforce effectivity and effectivity. One notable enchancment is utilizing a modified Ghost Depthwise Convolution layer, altering the World Widespread Pooling layer in image classification fashions. This allows the group to review numerous weights for numerous attribute map fashions, enhancing discriminative power and effectivity.
GhostFaceNets use the Parametric Rectified Linear Unit (PReLU) activation carry out instead of ReLU, enabling detrimental activations for classy nonlinear options finding out, enhancing group effectivity in face recognition duties. Convolutions substitute customary FC layers in Squeeze-and-Excitation modules.
GhostFaceNets introduce a novel consideration mechanism inside SE modules, enhancing channel interdependencies at minimal computational worth. This mechanism adjusts channel weight to prioritize important choices and reduces sensitivity to a lot much less associated ones, offering flexibility in downsampling strategies.
GhostFaceNets variants design with configurable backbones, width multipliers, and stride parameters for generalization and adaptability. Experiments with hyperparameters and training datasets, along with MS1MV2 and MS1MV3, optimize effectivity using ArcFace teaching loss carry out, minimizing intra-class gap and enhancing inter-class differentiation.
Requirements to Run Python Code
Please use the beneath requirements to run the code, python mannequin is 3.9.12:
- TensorFlow==2.8.0
- Keras==2.8.0
- keras_cv_attention_models
- glob2
- pandas
- tqdm
- scikit-image
Implementation with Python Code
Underneath code is from module from main folder.
import tensorflow as tf
from tensorflow import keras
import tensorflow.keras.backend as Okay
def __init_model_from_name__(title, input_shape=(112, 112, 3), weights="imagenet", **kwargs):
name_lower = title.lower()
""" Main model """
if name_lower == "ghostnetv1":
from backbones import ghost_model
xx = ghost_model.GhostNet(input_shape=input_shape, include_top=False, width=1, **kwargs)
elif name_lower == "ghostnetv2":
from backbones import ghostv2
xx = ghostv2.GhostNetV2(stem_width=16,
stem_strides=1,
width_mul=1.3,
num_ghost_module_v1_stacks=2, # num of `ghost_module` stcks on the top, others are `ghost_module_multiply`, set `-1` for all using `ghost_module`
input_shape=(112, 112, 3),
num_classes=0,
activation="prelu",
classifier_activation=None,
dropout=0,
pretrained=None,
model_name="ghostnetv2",
**kwargs)
else:
return None
xx.trainable = True
return xx
def buildin_models(
stem_model,
dropout=1,
emb_shape=512,
input_shape=(112, 112, 3),
output_layer="GDC",
bn_momentum=0.99,
bn_epsilon=0.001,
add_pointwise_conv=False,
pointwise_conv_act="relu",
use_bias=False,
scale=True,
weights="imagenet",
**kwargs
):
if isinstance(stem_model, str):
xx = __init_model_from_name__(stem_model, input_shape, weights, **kwargs)
title = stem_model
else:
title = stem_model.title
xx = stem_model
if bn_momentum != 0.99 or bn_epsilon != 0.001:
print(">>>> Change BatchNormalization momentum and epsilon default value.")
for ii in xx.layers:
if isinstance(ii, keras.layers.BatchNormalization):
ii.momentum, ii.epsilon = bn_momentum, bn_epsilon
xx = keras.fashions.clone_model(xx)
inputs = xx.inputs[0]
nn = xx.outputs[0]
if add_pointwise_conv: # Model using `pointwise_conv + GDC` / `pointwise_conv + E` is smaller than `E`
filters = nn.kind[-1] // 2 if add_pointwise_conv == -1 else 512 # Compitable with earlier fashions...
nn = keras.layers.Conv2D(filters, 1, use_bias=False, padding="professional", title="pw_conv")(nn)
nn = keras.layers.BatchNormalization(momentum=bn_momentum, epsilon=bn_epsilon, title="pw_bn")(nn)
if pointwise_conv_act.lower() == "prelu":
nn = keras.layers.PReLU(shared_axes=[1, 2], title="pw_" + pointwise_conv_act)(nn)
else:
nn = keras.layers.Activation(pointwise_conv_act, title="pw_" + pointwise_conv_act)(nn)
""" GDC """
nn = keras.layers.DepthwiseConv2D(nn.kind[1], use_bias=False, title="GDC_dw")(nn)
nn = keras.layers.BatchNormalization(momentum=bn_momentum, epsilon=bn_epsilon, title="GDC_batchnorm")(nn)
if dropout > 0 and dropout < 1:
nn = keras.layers.Dropout(dropout)(nn)
nn = keras.layers.Conv2D(emb_shape, 1, use_bias=use_bias, kernel_initializer="glorot_normal", title="GDC_conv")(nn)
nn = keras.layers.Flatten(title="GDC_flatten")(nn)
embedding = keras.layers.BatchNormalization(momentum=bn_momentum, epsilon=bn_epsilon, scale=scale, title="pre_embedding")(nn)
embedding_fp32 = keras.layers.Activation("linear", dtype="float32", title="embedding")(embedding)
basic_model = keras.fashions.Model(inputs, embedding_fp32, title=xx.title)
return basic_model
def add_l2_regularizer_2_model(model, weight_decay, custom_objects={}, apply_to_batch_normal=False, apply_to_bias=False):
# https://github.com/keras-team/keras/factors/2717#issuecomment-456254176
if 0:
regularizers_type = {}
for layer in model.layers:
rrs = [kk for kk in layer.__dict__.keys() if "regularizer" in kk and not kk.startswith("_")]
if len(rrs) != 0:
# print(layer.title, layer.__class__.__name__, rrs)
if layer.__class__.__name__ not in regularizers_type:
regularizers_type[layer.__class__.__name__] = rrs
print(regularizers_type)
for layer in model.layers:
attrs = []
if isinstance(layer, keras.layers.Dense) or isinstance(layer, keras.layers.Conv2D):
# print(">>>> Dense or Conv2D", layer.title, "use_bias:", layer.use_bias)
attrs = ["kernel_regularizer"]
if apply_to_bias and layer.use_bias:
attrs.append("bias_regularizer")
elif isinstance(layer, keras.layers.DepthwiseConv2D):
# print(">>>> DepthwiseConv2D", layer.title, "use_bias:", layer.use_bias)
attrs = ["depthwise_regularizer"]
if apply_to_bias and layer.use_bias:
attrs.append("bias_regularizer")
elif isinstance(layer, keras.layers.SeparableConv2D):
attrs = ["pointwise_regularizer", "depthwise_regularizer"]
if apply_to_bias and layer.use_bias:
attrs.append("bias_regularizer")
elif apply_to_batch_normal and isinstance(layer, keras.layers.BatchNormalization):
if layer.coronary heart:
attrs.append("beta_regularizer")
if layer.scale:
attrs.append("gamma_regularizer")
elif apply_to_batch_normal and isinstance(layer, keras.layers.PReLU):
attrs = ["alpha_regularizer"]
for attr in attrs:
if hasattr(layer, attr) and layer.trainable:
setattr(layer, attr, keras.regularizers.L2(weight_decay / 2))
return keras.fashions.clone_model(model)
def replace_ReLU_with_PReLU(model, target_activation="PReLU", **kwargs):
from tensorflow.keras.layers import ReLU, PReLU, Activation
def convert_ReLU(layer):
# print(layer.title)
if isinstance(layer, ReLU) or (isinstance(layer, Activation) and layer.activation == keras.activations.relu):
if target_activation == "PReLU":
layer_name = layer.title.substitute("_relu", "_prelu")
print(">>>> Convert ReLU:", layer.title, "-->", layer_name)
# Default preliminary value in mxnet and pytorch is 0.25
return PReLU(shared_axes=[1, 2], alpha_initializer=tf.initializers.Mounted(0.25), title=layer_name, **kwargs)
elif isinstance(target_activation, str):
layer_name = layer.title.substitute("_relu", "_" + target_activation)
print(">>>> Convert ReLU:", layer.title, "-->", layer_name)
return Activation(activation=target_activation, title=layer_name, **kwargs)
else:
act_class_name = target_activation.__name__
layer_name = layer.title.substitute("_relu", "_" + act_class_name)
print(">>>> Convert ReLU:", layer.title, "-->", layer_name)
return target_activation(**kwargs)
return layer
input_tensors = keras.layers.Enter(model.input_shape[1:])
return keras.fashions.clone_model(model, input_tensors=input_tensors, clone_function=convert_ReLU)
def convert_to_mixed_float16(model, convert_batch_norm=False):
protection = keras.mixed_precision.Protection("mixed_float16")
policy_config = keras.utils.serialize_keras_object(protection)
from tensorflow.keras.layers import InputLayer, Activation
from tensorflow.keras.activations import linear, softmax
def do_convert_to_mixed_float16(layer):
if not convert_batch_norm and isinstance(layer, keras.layers.BatchNormalization):
return layer
if isinstance(layer, InputLayer):
return layer
if isinstance(layer, Activation) and layer.activation == softmax:
return layer
if isinstance(layer, Activation) and layer.activation == linear:
return layer
aa = layer.get_config()
aa.exchange({"dtype": policy_config})
bb = layer.__class__.from_config(aa)
bb.assemble(layer.input_shape)
bb.set_weights(layer.get_weights())
return bb
input_tensors = keras.layers.Enter(model.input_shape[1:])
mm = keras.fashions.clone_model(model, input_tensors=input_tensors, clone_function=do_convert_to_mixed_float16)
if model.constructed:
mm.compile(optimizer=model.optimizer, loss=model.compiled_loss, metrics=model.compiled_metrics)
# mm.optimizer, mm.compiled_loss, mm.compiled_metrics = model.optimizer, model.compiled_loss, model.compiled_metrics
# mm.constructed = True
return mm
def convert_mixed_float16_to_float32(model):
from tensorflow.keras.layers import InputLayer, Activation
from tensorflow.keras.activations import linear
def do_convert_to_mixed_float16(layer):
if not isinstance(layer, InputLayer) and by no means (isinstance(layer, Activation) and layer.activation == linear):
aa = layer.get_config()
aa.exchange({"dtype": "float32"})
bb = layer.__class__.from_config(aa)
bb.assemble(layer.input_shape)
bb.set_weights(layer.get_weights())
return bb
return layer
input_tensors = keras.layers.Enter(model.input_shape[1:])
return keras.fashions.clone_model(model, input_tensors=input_tensors, clone_function=do_convert_to_mixed_float16)
def convert_to_batch_renorm(model):
def do_convert_to_batch_renorm(layer):
if isinstance(layer, keras.layers.BatchNormalization):
aa = layer.get_config()
aa.exchange({"renorm": True, "renorm_clipping": {}, "renorm_momentum": aa["momentum"]})
bb = layer.__class__.from_config(aa)
bb.assemble(layer.input_shape)
bb.set_weights(layer.get_weights() + bb.get_weights()[-3:])
return bb
return layer
input_tensors = keras.layers.Enter(model.input_shape[1:])
return keras.fashions.clone_model(model, input_tensors=input_tensors, clone_function=do_convert_to_batch_renorm)
Key Choices and Benefits of GhostFaceNets
- Lightweight and Surroundings pleasant: GhostFaceNets leverage atmosphere pleasant GhostNet architectures and modules, very good for real-time, cell, and embedded deployment.
- Appropriate and Sturdy: They ship right and durable face recognition and verification effectivity, outperforming many state-of-the-art fashions on fully totally different benchmarks.
- Modified GDC Recognition Head: The modified GDC recognition head generates discriminative attribute vectors, enhancing the model’s effectivity.
- PReLU Activation: Utilizing PReLU as a result of the nonlinear activation carry out alleviates the vanishing gradient draw back. It moreover improves effectivity compared with ReLU.
- Consideration-based Enhancements: Incorporating the DFC consideration division in GhostNetV2 enhances effectivity by capturing long-range dependencies and contextual information.
Experimental Validation and Effectivity Metrics
The authors of GhostFaceNets rigorously examined the model’s effectivity on fully totally different benchmark datasets, along with the widely-acclaimed Labeled Faces inside the Wild (LFW) and YouTube Faces (YTF) datasets. The outcomes had been good, with GhostFaceNets attaining state-of-the-art effectivity whereas sustaining a majorly smaller model dimension and reduce computational complexity compared with present face recognition fashions.
Functions and Future Prospects
GhostFaceNets opens up a world of prospects like:
- Face recognition features on edge models.
- From protected individual authentication on cell models to intelligent surveillance packages.
- The potential features are big and numerous.
As a result of the demand for edge computing and real-time face recognition continues to develop, GhostFaceNets represents a major step forward inside the space, paving the easiest way for future developments and enhancements. Researchers and engineers can assemble upon this groundbreaking work, exploring new architectures, optimization strategies, and features to extra push the boundaries of atmosphere pleasant and proper face recognition.
Conclusion
GhostFaceNets is a groundbreaking engineering innovation that makes use of deep finding out strategies and edge computing to create lightweight face recognition fashions. It makes use of ghost modules to ship right and durable recognition capabilities whereas sustaining a computationally atmosphere pleasant footprint. As a result of the world embraces ubiquitous computing and the Internet of Points, GhostFaceNets is a beacon of innovation. Integrating face recognition know-how into every day life to reinforce experiences and security with out sacrificing effectivity or effectivity.
Key Takeaways
- GhostFaceNets is a groundbreaking improvement in lightweight face recognition. It balances effectivity and accuracy, making it very good for deploying facial recognition know-how on models with restricted computational belongings.
- The construction enhances face recognition effectivity and effectiveness by incorporating Ghost modules, DFC consideration division, and PReLU activation. It moreover guaranteeing accuracy with out compromising effectiveness.
- DFC consideration division in GhostNetV2 successfully captures long-range dependencies, enhancing contextual understanding with minimal computational burden.
- GhostFaceNets excel on benchmarks, with compact sizes and atmosphere pleasant computation, very good for real-world features.
Steadily Requested Questions
A. GhostFaceNets achieves effectivity by way of revolutionary architectural enhancements, leveraging Ghost modules, modified GDC recognition heads, and attention-based mechanisms identical to the DFC consideration division. These optimizations cut back computational complexity whereas sustaining accuracy.
A. GhostFaceNets distinguishes itself by balancing effectivity and accuracy. In distinction to standard fashions requiring substantial computational belongings, GhostFaceNets makes use of lightweight architectures and a spotlight mechanisms to realize extreme effectivity on edge models.
A. GhostFaceNets construction accommodates Ghost modules for atmosphere pleasant attribute map period and modified GDC recognition heads for discriminative attribute vectors. It moreover employs PReLU activation and attention-based mechanisms identical to the DFC consideration division for capturing dependencies.
A. GhostFaceNets excelled on LFW and YTF, exhibiting greater effectivity with smaller sizes and fewer complexity.
References
The media confirmed on this text should not be owned by Analytics Vidhya and is used on the Author’s discretion.