Introduction
GhostFaceNets is a revolutionary facial recognition know-how that makes use of inexpensive operations with out compromising accuracy. Impressed by attention-based fashions, it revolutionizes facial recognition know-how. This weblog publish explores GhostFaceNets via charming visuals and insightful illustrations, aiming to coach, encourage, and spark creativity. The journey is not only a weblog publish, however a novel exploration of the limitless prospects of GhostFaceNets. Be a part of us on this thrilling journey to find the world of GhostFaceNets.
Studying Targets
- Comprehend the underlying challenges and motivations driving the event of light-weight FR fashions tailor-made for low computational units (eg: edge).
- Articulate the indepth architectural parts of GhostFaceNets, together with the Ghost modules, the DFC consideration department, and the precise variations launched to the spine GhostNets architectures.
- Focus on the benefits of GhostFaceNets in comparison with conventional face recognition fashions, by way of effectivity, accuracy, and computational complexity.
- Acknowledge the key contributions made by GhostFaceNets to the sector of face recognition and face verification, and picture its potential functions throughout completely different real-time situations.
This text was revealed as part of the Data Science Blogathon.
Introduction of GhostFaceNets
In as we speak’s period of ubiquitous computing and the IOT, FR know-how performs an vital function in numerous functions, together with seamless person authentication, customized experiences, and stronger safety measures. Nevertheless, conventional facial recognition programs consumes excessive computational assets, rendering them unsuitable for deployment on low computation units with restricted assets. That is the place GhostFaceNets comes into play, that guarantees to revolutionize how we method and implement facial recognition know-how.
Evolution of Light-weight Face Recognition Fashions
Because the demand for edge computing and real-time functions soared, the necessity for environment friendly and light-weight fashions turned paramount. Researchers and engineers alike sought to strike a fragile steadiness between mannequin complexity and efficiency, giving rise to a plethora of light-weight architectures tailor-made for particular duties, together with face recognition.
Deep learning algorithms like Convolutional Neural Networks (CNNs) have revolutionized face recognition analysis, enhancing accuracy in comparison with conventional strategies. Nevertheless, these fashions typically battle to steadiness efficiency and complexity, particularly for real-world functions and resource-constrained units. The Labeled Faces within the Wild dataset is the gold normal for evaluating new FR fashions, with Mild CNN architectures decreasing parameters and computational complexity. Regardless of these developments, essentially the most correct reported efficiency on LFW is 99.33%.
ShiftFaceNet launched a “Shift” operation to cut back the variety of parameters in picture classification fashions, leading to a 2-degree accuracy drop. Different fashions constructed upon picture classification backbones, akin to MobileFaceNets, ShuffleFaceNet, VarGFaceNet, and MixFaceNets, have proven improved trade-offs between efficiency 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. 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 Structure
Constructing upon the environment friendly GhostNets architectures (GhostNetV1 and GhostNetV2), the authors suggest GhostFaceNets, a brand new set of light-weight architectures tailor-made for face recognition and face verification. A number of key modifications had been made:
- The World Common Pooling (GAP) layer, pointwise convolution layer (1×1 convolution), and Totally Linked (FC) layer had been changed with a modified World Depthwise Convolution (GDC) recognition head to generate discriminative characteristic vectors.
- The ReLU activation perform utilized in GhostNets was changed with PReLU, which alleviates the vanishing gradient downside and improves efficiency.
- The traditional Totally Linked layers within the Squeeze-and-Excitation (SE) modules had been changed with convolution layers to enhance the discriminative energy of GhostFaceNets.
- The ArcFace loss perform was employed for coaching, to implement intra-class compactness, inter-class discrepancy, and improves the discriminative energy of realized options. To undergo Arcface loss perform please check with my earlier weblog – click here
The authors designed a set of GhostFaceNets fashions by various the coaching dataset, the width of the GhostNets architectures, and the stride of the primary convolution layer (stem). The ensuing fashions outperform most light-weight SOTA fashions on completely different benchmarks, as mentioned in subsequent sections.
A. GhostNetV1 and Ghost Modules (Characteristic Map Sample Redundancy)
GhostNetV1, the spine structure of GhostFaceNets, employs a novel idea referred to as Ghost modules to generate a sure proportion (denoted as x%) of the characteristic maps, whereas the remaining characteristic maps are generated utilizing a low-cost linear operation referred to as as depthwise convolution (DWConv).
In a conventional 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 characteristic maps with C’ channels from an enter tensor of C channels. Nevertheless, Ghost modules take a unique method.
The Ghost module generates the primary x% of the output tensor channels utilizing a sequential block of three layers: regular convolution, batch normalization, and a nonlinear activation perform (default: ReLU). The output is then despatched to a second block with depthwise convolution, batch normalization, and ReLU, and the output tensor is accomplished by stacking the 2 blocks.
As proven in Determine 1, there are clearly related and redundant characteristic map pairs (ghosts) that may be generated utilizing linear operations, decreasing computational complexity with out lowering efficiency. The authors of GhostNetV1 exploit this commentary by producing these related and redundant options utilizing low cost operations, fairly than discarding them.
By using Ghost modules, GhostNetV1 can successfully generate the identical variety of characteristic maps as an convolutional layer, with important discount within the variety of parameters and FLOPs. This enables Ghost modules to be simply built-in into current neural community architectures to cut back computational complexity.
Implementation with Python Code
Under code is from ghost_model.py module from backbones folder
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import backend as Ok
from tensorflow.keras.fashions import Mannequin
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 perform is taken from the unique tf repo.
It ensures that each one layers have a channel quantity that's divisible by 8
It may be seen right here:
https://github.com/tensorflow/fashions/blob/grasp/analysis/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 Ok.image_data_format() == "channels_first" else -1
#filters = channel axis form
filters = inputs.form[channel_axis]
discount = _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 utilizing C*se_ratio. The dimensions will likely be 1 x 1 x C*se_ratio
se = Conv2D(discount, kernel_size=1, use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER)(se)
# se = PReLU(shared_axes=[1, 2])(se)
se = Activation("relu")(se)
#Excitation utilizing C filters. The dimensions will likely 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="identical", 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="identical", 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:
# Further depth conv if strides increased than 1
nn = DepthwiseConv2D(dwkernel, strides, padding="identical", 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)
# Level-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="identical", 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="legitimate", 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 within the paper (Desk 7)
def GhostNet(input_shape=(224, 224, 3), include_top=True, courses=0, width=1.3, strides=2, title="GhostNet"):
inputs = Enter(form=input_shape)
out_channel = _make_divisible(16 * width, 4)
nn = Conv2D(out_channel, (3, 3), strides=strides, padding="identical", 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="legitimate", 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.form[1])))(nn)
nn = Conv2D(1280, (1, 1), strides=(1, 1), padding="identical", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(nn)
nn = BatchNormalization(axis=-1)(nn)
nn = activation(nn)
nn = Conv2D(courses, (1, 1), strides=(1, 1), padding="identical", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(nn)
nn = Ok.squeeze(nn, 1)
nn = Activation("softmax")(nn)
return Mannequin(inputs=inputs, outputs=nn, title=title)
B. GhostNetV2
GhostNetV2 introduces important enhancements to the Ghost module of GhostNetV1, aiming to seize long-range dependencies extra successfully. The important thing innovation is the incorporation of a novel attention-based layer referred to as the DFC consideration department, designed to generate consideration maps with international receptive fields utilizing convolutions. In contrast to conventional self-attention layers, the DFC consideration department achieves excessive effectivity whereas capturing dependencies between pixels throughout completely different spatial areas. This effectivity is essential for {hardware} compatibility and inference pace, as many prior consideration modules relied on computationally intensive tensor operations.
GhostNetV2’s structure encompasses a new bottleneck construction, permitting the Ghost module and DFC consideration department to function in parallel. It gathers info from varied viewpoints and aggregating it into the ultimate output. This feature-wise product ensures complete protection of enter information throughout varied patches.
The DFC consideration department consists of 5 operations: downsampling, convolution, horizontal and vertical absolutely related (FC) layers, and sigmoid activation(Refer the above picture). To mitigate computational overhead, we make the most of native common pooling for downsampling and bilinear interpolation for upsampling. Decomposing the FC layer into horizontal and vertical elements reduces complexity whereas capturing long-range dependencies alongside each dimensions.
Total, GhostNetV2 represents a major development in attention-based fashions, providing improved effectivity and effectiveness in capturing long-range dependencies. Visible aids akin to diagrams illustrating the structure and operations of the DFC consideration department can enhance understanding and engagement for readers. Place these diagrams strategically inside the textual content to enhance the reasons and facilitate comprehension.
Implementation with Python Code
Under code is from ghostv2.py module from backbones folder
!pip set up 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.picture.resize(shortcut, tf.form(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="identical", 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="identical", 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 pinnacle, others are `ghost_module_multiply`, set `-1` for all utilizing `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="identical", title="stem_")
nn = batchnorm_with_activation(nn, activation=activation, title="stem_")
""" levels """
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.form[-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)
mannequin = keras.fashions.Mannequin(inputs, nn, title=model_name)
add_pre_post_process(mannequin, rescale_mode="torch")
reload_model_weights(mannequin, PRETRAINED_DICT, "ghostnetv2", pretrained)
return mannequin
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 pinnacle, others are `ghost_module_multiply`, set `-1` for all utilizing `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 department, whereas GhostNetV2 employs it.
C. GhostFaceNets Structure
Constructing upon the GhostNetV1 structure, the authors of GhostFaceNets made a number of key modifications to tailor the mannequin for face recognition and face verification duties.
GhostFaceNets are a major development in light-weight face recognition and face verification fashions, incorporating key modifications to enhance efficiency and effectivity. One notable enchancment is using a modified Ghost Depthwise Convolution layer, changing the World Common Pooling layer in picture classification fashions. This enables the community to study various weights for various characteristic map models, enhancing discriminative energy and efficiency.
GhostFaceNets use the Parametric Rectified Linear Unit (PReLU) activation perform as an alternative of ReLU, enabling detrimental activations for complicated nonlinear features studying, enhancing community efficiency in face recognition duties. Convolutions substitute standard FC layers in Squeeze-and-Excitation modules.
GhostFaceNets introduce a novel consideration mechanism inside SE modules, enhancing channel interdependencies at minimal computational value. This mechanism adjusts channel weight to prioritize vital options and reduces sensitivity to much less related ones, providing flexibility in downsampling methods.
GhostFaceNets variants design with configurable backbones, width multipliers, and stride parameters for generalization and flexibility. Experiments with hyperparameters and coaching datasets, together with MS1MV2 and MS1MV3, optimize efficiency utilizing ArcFace coaching loss perform, minimizing intra-class hole and enhancing inter-class differentiation.
Necessities to Run Python Code
Please use the beneath necessities to run the code, python model 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
Under code is from module from major folder.
import tensorflow as tf
from tensorflow import keras
import tensorflow.keras.backend as Ok
def __init_model_from_name__(title, input_shape=(112, 112, 3), weights="imagenet", **kwargs):
name_lower = title.decrease()
""" Primary mannequin """
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 pinnacle, others are `ghost_module_multiply`, set `-1` for all utilizing `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 worth.")
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: # Mannequin utilizing `pointwise_conv + GDC` / `pointwise_conv + E` is smaller than `E`
filters = nn.form[-1] // 2 if add_pointwise_conv == -1 else 512 # Compitable with earlier fashions...
nn = keras.layers.Conv2D(filters, 1, use_bias=False, padding="legitimate", title="pw_conv")(nn)
nn = keras.layers.BatchNormalization(momentum=bn_momentum, epsilon=bn_epsilon, title="pw_bn")(nn)
if pointwise_conv_act.decrease() == "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.form[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.Mannequin(inputs, embedding_fp32, title=xx.title)
return basic_model
def add_l2_regularizer_2_model(mannequin, weight_decay, custom_objects={}, apply_to_batch_normal=False, apply_to_bias=False):
# https://github.com/keras-team/keras/points/2717#issuecomment-456254176
if 0:
regularizers_type = {}
for layer in mannequin.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 mannequin.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.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(mannequin)
def replace_ReLU_with_PReLU(mannequin, 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 worth in mxnet and pytorch is 0.25
return PReLU(shared_axes=[1, 2], alpha_initializer=tf.initializers.Fixed(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(mannequin.input_shape[1:])
return keras.fashions.clone_model(mannequin, input_tensors=input_tensors, clone_function=convert_ReLU)
def convert_to_mixed_float16(mannequin, convert_batch_norm=False):
coverage = keras.mixed_precision.Coverage("mixed_float16")
policy_config = keras.utils.serialize_keras_object(coverage)
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.replace({"dtype": policy_config})
bb = layer.__class__.from_config(aa)
bb.construct(layer.input_shape)
bb.set_weights(layer.get_weights())
return bb
input_tensors = keras.layers.Enter(mannequin.input_shape[1:])
mm = keras.fashions.clone_model(mannequin, input_tensors=input_tensors, clone_function=do_convert_to_mixed_float16)
if mannequin.constructed:
mm.compile(optimizer=mannequin.optimizer, loss=mannequin.compiled_loss, metrics=mannequin.compiled_metrics)
# mm.optimizer, mm.compiled_loss, mm.compiled_metrics = mannequin.optimizer, mannequin.compiled_loss, mannequin.compiled_metrics
# mm.constructed = True
return mm
def convert_mixed_float16_to_float32(mannequin):
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 never (isinstance(layer, Activation) and layer.activation == linear):
aa = layer.get_config()
aa.replace({"dtype": "float32"})
bb = layer.__class__.from_config(aa)
bb.construct(layer.input_shape)
bb.set_weights(layer.get_weights())
return bb
return layer
input_tensors = keras.layers.Enter(mannequin.input_shape[1:])
return keras.fashions.clone_model(mannequin, input_tensors=input_tensors, clone_function=do_convert_to_mixed_float16)
def convert_to_batch_renorm(mannequin):
def do_convert_to_batch_renorm(layer):
if isinstance(layer, keras.layers.BatchNormalization):
aa = layer.get_config()
aa.replace({"renorm": True, "renorm_clipping": {}, "renorm_momentum": aa["momentum"]})
bb = layer.__class__.from_config(aa)
bb.construct(layer.input_shape)
bb.set_weights(layer.get_weights() + bb.get_weights()[-3:])
return bb
return layer
input_tensors = keras.layers.Enter(mannequin.input_shape[1:])
return keras.fashions.clone_model(mannequin, input_tensors=input_tensors, clone_function=do_convert_to_batch_renorm)
Key Options and Advantages of GhostFaceNets
- Light-weight and Environment friendly: GhostFaceNets leverage environment friendly GhostNet architectures and modules, superb for real-time, cell, and embedded deployment.
- Correct and Strong: They ship correct and sturdy face recognition and verification efficiency, outperforming many state-of-the-art fashions on completely different benchmarks.
- Modified GDC Recognition Head: The modified GDC recognition head generates discriminative characteristic vectors, enhancing the mannequin’s efficiency.
- PReLU Activation: Using PReLU because the nonlinear activation perform alleviates the vanishing gradient downside. It additionally improves efficiency in comparison with ReLU.
- Consideration-based Enhancements: Incorporating the DFC consideration department in GhostNetV2 enhances efficiency by capturing long-range dependencies and contextual info.
Experimental Validation and Efficiency Metrics
The authors of GhostFaceNets rigorously examined the mannequin’s efficiency on completely different benchmark datasets, together with the widely-acclaimed Labeled Faces within the Wild (LFW) and YouTube Faces (YTF) datasets. The outcomes had been nice, with GhostFaceNets attaining state-of-the-art efficiency whereas sustaining a majorly smaller mannequin dimension and decrease computational complexity in comparison with current face recognition fashions.
Purposes and Future Prospects
GhostFaceNets opens up a world of prospects like:
- Face recognition functions on edge units.
- From safe person authentication on cell units to clever surveillance programs.
- The potential functions are huge and various.
Because the demand for edge computing and real-time face recognition continues to develop, GhostFaceNets represents a significant step ahead within the area, paving the best way for future developments and improvements. Researchers and engineers can construct upon this groundbreaking work, exploring new architectures, optimization methods, and functions to additional push the boundaries of environment friendly and correct face recognition.
Conclusion
GhostFaceNets is a groundbreaking engineering innovation that makes use of deep studying methods and edge computing to create light-weight face recognition fashions. It makes use of ghost modules to ship correct and sturdy recognition capabilities whereas sustaining a computationally environment friendly footprint. Because the world embraces ubiquitous computing and the Web of Issues, GhostFaceNets is a beacon of innovation. Integrating face recognition know-how into each day life to enhance experiences and safety with out sacrificing efficiency or effectivity.
Key Takeaways
- GhostFaceNets is a groundbreaking development in light-weight face recognition. It balances effectivity and accuracy, making it superb for deploying facial recognition know-how on units with restricted computational assets.
- The structure enhances face recognition effectivity and effectiveness by incorporating Ghost modules, DFC consideration department, and PReLU activation. It additionally guaranteeing accuracy with out compromising effectiveness.
- DFC consideration department in GhostNetV2 effectively captures long-range dependencies, enhancing contextual understanding with minimal computational burden.
- GhostFaceNets excel on benchmarks, with compact sizes and environment friendly computation, superb for real-world functions.
Steadily Requested Questions
A. GhostFaceNets achieves effectivity via revolutionary architectural enhancements, leveraging Ghost modules, modified GDC recognition heads, and attention-based mechanisms just like the DFC consideration department. These optimizations scale back computational complexity whereas sustaining accuracy.
A. GhostFaceNets distinguishes itself by balancing effectivity and accuracy. In contrast to conventional fashions requiring substantial computational assets, GhostFaceNets makes use of light-weight architectures and a focus mechanisms to attain excessive efficiency on edge units.
A. GhostFaceNets structure contains Ghost modules for environment friendly characteristic map era and modified GDC recognition heads for discriminative characteristic vectors. It additionally employs PReLU activation and attention-based mechanisms just like the DFC consideration department for capturing dependencies.
A. GhostFaceNets excelled on LFW and YTF, exhibiting higher efficiency with smaller sizes and fewer complexity.
References
The media proven on this article shouldn’t be owned by Analytics Vidhya and is used on the Writer’s discretion.