How to convert pretrained model to tflite

In the path of arch/pretrained_model, i use under shell to convert model to tflite.
tflite_convert  ^
--output_file  MobileFaceNet_9925_9680.tflite  ^
--graph_def_file  MobileFaceNet_9925_9680.pb    ^
--input_arrays  "input"  ^
--input_shapes  "1,112,112,3"  ^
--output_arrays  embeddings  ^
--output_format  TFLITE

Unfortunate, i get error of this.
λ tflite_convert  ^
More? --output_file  MobileFaceNet_9925_9680.tflite  ^
More? --graph_def_file  MobileFaceNet_9925_9680.pb    ^
More? --input_arrays  "input"  ^
More? --input_shapes  "1,112,112,3"  ^
More? --output_arrays  embeddings  ^
More? --output_format  TFLITE
2019-05-28 15:32:07.380246: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
2019-05-28 15:32:08.157890: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433] Found device 0 with properties:
name: GeForce MX150 major: 6 minor: 1 memoryClockRate(GHz): 1.341
pciBusID: 0000:01:00.0
totalMemory: 2.00GiB freeMemory: 1.62GiB
2019-05-28 15:32:08.185527: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] Adding visible gpu devices: 0
2019-05-28 15:32:08.727623: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-05-28 15:32:08.742876: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990]      0
2019-05-28 15:32:08.753078: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003] 0:   N
2019-05-28 15:32:08.764321: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1365 MB memory) -> physical GPU (device: 0, name: GeForce MX150, pci bus id: 0000:01:00.0, compute capability: 6.1)
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\Scripts\tflite_convert-script.py", line 10, in <module>
    sys.exit(main())
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\tflite_convert.py", line 442, in main
    app.run(main=run_main, argv=sys.argv[:1])
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\python\platform\app.py", line 125, in run
    _sys.exit(main(argv))
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\tflite_convert.py", line 438, in run_main
    _convert_model(tflite_flags)
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\tflite_convert.py", line 191, in _convert_model
    output_data = converter.convert()
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\lite.py", line 455, in convert
    **converter_kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\convert.py", line 442, in toco_convert_impl
    input_data.SerializeToString())
  File "C:\ProgramData\Anaconda3\lib\site-packages\tensorflow\lite\python\convert.py", line 205, in toco_convert_protos
    "TOCO failed. See console for info.\n%s\n%s\n" % (stdout, stderr))
tensorflow.lite.python.convert.ConverterError: TOCO failed. See console for info.
2019-05-28 15:32:13.074828: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
2019-05-28 15:32:13.078767: E tensorflow/core/framework/op_kernel.cc:1325] OpKernel ('op: "WrapDatasetVariant" device_type: "CPU"') for unknown op: WrapDatasetVariant
2019-05-28 15:32:13.079077: E tensorflow/core/framework/op_kernel.cc:1325] OpKernel ('op: "WrapDatasetVariant" device_type: "GPU" host_memory_arg: "input_handle" host_memory_arg: "output_handle"') for unknown op: WrapDatasetVariant
2019-05-28 15:32:13.079438: E tensorflow/core/framework/op_kernel.cc:1325] OpKernel ('op: "UnwrapDatasetVariant" device_type: "CPU"') for unknown op: UnwrapDatasetVariant
2019-05-28 15:32:13.079756: E tensorflow/core/framework/op_kernel.cc:1325] OpKernel ('op: "UnwrapDatasetVariant" device_type: "GPU" host_memory_arg: "input_handle" host_memory_arg: "output_handle"') for unknown op: UnwrapDatasetVariant
2019-05-28 15:32:13.087213: E tensorflow/lite/toco/import_tensorflow.cc:2079] tensorflow::ImportGraphDef failed with status: Not found: Op type not registered 'Placeholder' in binary running on DESKTOP-TG1FKM4. Make sure the Op and Kernel are registered in the binary running in this process. Note that if you are loading a saved graph which used ops from tf.contrib, accessing (e.g.) `tf.contrib.resampler` should be done before importing the graph, as contrib ops are lazily registered when the module is first accessed.
2019-05-28 15:32:13.434412: I tensorflow/lite/toco/graph_transformations/graph_transformations.cc:39] Before Removing unused ops: 2747 operators, 4533 arrays (0 quantized)
2019-05-28 15:32:13.816499: I tensorflow/lite/toco/graph_transformations/graph_transformations.cc:39] After Removing unused ops pass 1: 1810 operators, 3076 arrays (0 quantized)
2019-05-28 15:32:14.122395: I tensorflow/lite/toco/graph_transformations/graph_transformations.cc:39] Before general graph transformations: 1810 operators, 3076 arrays (0 quantized)
2019-05-28 15:32:14.124627: F tensorflow/lite/toco/graph_transformations/resolve_tensorflow_switch.cc:98] Check failed: other_op->type == OperatorType::kMerge Found BatchNormalization as non-selected output from Switch, but only Merge supported.

You need set trainable and is-training param to false, when you generate model.
Steps:

Set trainable, is-training to false.
Create graph.
Import weights from ckpt.
Create frozen model.

I have created frozen model with that changes (with bottleneck size = 192)
FaceMobileNet192_train_false.zip
and TFLite model
FaceMobileNet_Float32.zip

I have used TF 1.14.0

@GulyaevMaxim thanks for sharing this model and @sirius-ai for sharing the code.
Did try to use this model by applying the following operations:

input image in RGB normalized by subtracting 127.5 and then scaling it with 128
L2 normalization, (i.e. divides by the the square root of the sum of squares of all elements of input).
euclidian distance to compare embeddings.

The results do not seem that good, though. Am I using the model - FaceMobileNet192_train_false.zip - correctly?

You need set trainable and is-training param to false, when you generate model.
Steps:

Set trainable, is-training to false.
Create graph.
Import weights from ckpt.
Create frozen model.

I have created frozen model with that changes (with bottleneck size = 192)
FaceMobileNet192_train_false.zip
and TFLite model
FaceMobileNet_Float32.zip

I have used TF 1.14.0

Thank you for your reply, i will try it.

@GulyaevMaxim How to set trainable and is-training param to false ?

@mengfu188 You need set this args when you create mobilenet_v2 object. (See also mobilenet_v2_arg_scope )
I added this params to batch_norm_params
  batch_norm_params = {
      'is_training': False,
      'trainable':False,
      'center': True,
      'scale': True,
      'fused': True,
      'decay': 0.995,
      'epsilon': 2e-5,
      # force in-place updates of mean and variance estimates
      'updates_collections': None,
      # Moving averages ends up in the trainable variables collection
      'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
  }

@manuelcosta74 I created model using checkpoint from this repository.

@manuelcosta74 You can use something like this
inference.zip

@mengfu188 Also you need to check graph (using tensorboard) that you should not have in the graph Switch nodes

@GulyaevMaxim thanks for the demo code.
By looking to the train_nets.py
https://github.com/sirius-ai/MobileFaceNet_TF/blob/f0bae5982be2e030a89b346e6ce5ac8bdcc8f0e0/train_nets.py#L139
i was assuming that model was trained measuring euclidian distances with embeddings with L2 normalization.

@GulyaevMaxim Hello
I use tensorflow 1.14.0
and change batch_norm_params in net/MobileFaceNet.py like you
  batch_norm_params = {
      'is_training': False,
      'trainable': False,
      'center': True,
      'scale': True,
      'fused': True,
      'decay': 0.995,
      'epsilon': 2e-5,
      # force in-place updates of mean and variance estimates
      'updates_collections': None,
      # Moving averages ends up in the trainable variables collection
      'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
  }

I use this script to freeze graph. It change from utils/freeze_graph.py. I add rebuild function. It can freeze graph.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from tensorflow.python.framework import graph_util
from six.moves import xrange
import tensorflow as tf
import argparse
import sys
import os
import re

def get_model_filenames(model_dir):
    files = os.listdir(model_dir)
    meta_files = [s for s in files if s.endswith('.meta')]
    if len(meta_files) == 0:
        raise ValueError('No meta file found in the model directory (%s)' % model_dir)
    elif len(meta_files) > 1:
        raise ValueError('There should not be more than one meta file in the model directory (%s)' % model_dir)
    meta_file = meta_files[0]
    ckpt = tf.train.get_checkpoint_state(model_dir)
    if ckpt and ckpt.model_checkpoint_path:
        ckpt_file = os.path.basename(ckpt.model_checkpoint_path)
        return meta_file, ckpt_file

    meta_files = [s for s in files if '.ckpt' in s]
    max_step = -1
    for f in files:
        step_str = re.match(r'(^model-[\w\- ]+.ckpt-(\d+))', f)
        if step_str is not None and len(step_str.groups()) >= 2:
            step = int(step_str.groups()[1])
            if step > max_step:
                max_step = step
                ckpt_file = step_str.groups()[0]
    return meta_file, ckpt_file

def rebuild_model(args):
    from nets.MobileFaceNet import inference
    inputs = tf.placeholder(name='img_inputs', shape=[None, *args.image_size, 3], dtype=tf.float32)
    labels = tf.placeholder(name='img_labels', shape=[None, ], dtype=tf.int64)
    phase_train_placeholder = tf.placeholder_with_default(tf.constant(False, dtype=tf.bool), shape=None,
                                                          name='phase_train')
    # identity the input, for inference
    inputs = tf.identity(inputs, 'input')

    prelogits, net_points = inference(inputs, bottleneck_layer_size=args.embedding_size,
                                      phase_train=phase_train_placeholder, weight_decay=args.weight_decay)

    embeddings = tf.nn.l2_normalize(prelogits, 1, 1e-10, name='embeddings')

    return inputs, embeddings

def main(args):
    with tf.Graph().as_default():
        with tf.Session() as sess:
            # Load the model metagraph and checkpoint
            print('Model directory: %s' % args.model_dir)
            meta_file, ckpt_file = get_model_filenames(os.path.expanduser(args.model_dir))

            print('Metagraph file: %s' % meta_file)
            print('Checkpoint file: %s' % ckpt_file)

            rebuild_model(args)

            vgg_ref_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='MobileFaceNet')
            init = tf.global_variables_initializer()
            saver_vgg = tf.train.Saver(vgg_ref_vars)  # This is part of the recovery saveer

            saver = tf.train.Saver()  # This is the current new graph saver
            config = tf.ConfigProto()
            config.gpu_options.allow_growth = True
            # with tf.Session(config=config) as sess:
            sess.run(init)
            model_dir_exp = os.path.expanduser(args.model_dir)
            saver_vgg.restore(sess, os.path.join(model_dir_exp, ckpt_file))
            # saver = tf.train.import_meta_graph(os.path.join(model_dir_exp, meta_file), clear_devices=True)
            # tf.get_default_session().run(tf.global_variables_initializer())
            # tf.get_default_session().run(tf.local_variables_initializer())
            # saver.restore(tf.get_default_session(), os.path.join(model_dir_exp, ckpt_file))

            # Retrieve the protobuf graph definition and fix the batch norm nodes
            input_graph_def = sess.graph.as_graph_def()

            # Freeze the graph def
            output_graph_def = freeze_graph_def(sess, input_graph_def, 'embeddings')

        # Serialize and dump the output graph to the filesystem
        with tf.gfile.GFile(args.output_file, 'wb') as f:
            f.write(output_graph_def.SerializeToString())
        print("%d ops in the final graph: %s" % (len(output_graph_def.node), args.output_file))

def freeze_graph_def(sess, input_graph_def, output_node_names):
    for node in input_graph_def.node:
        if node.op == 'RefSwitch':
            node.op = 'Switch'
            for index in xrange(len(node.input)):
                if 'moving_' in node.input[index]:
                    node.input[index] = node.input[index] + '/read'
        elif node.op == 'AssignSub':
            node.op = 'Sub'
            if 'use_locking' in node.attr: del node.attr['use_locking']
        elif node.op == 'AssignAdd':
            node.op = 'Add'
            if 'use_locking' in node.attr: del node.attr['use_locking']

    # Get the list of important nodes
    whitelist_names = []
    for node in input_graph_def.node:
        if (node.name.startswith('MobileFaceNet') or node.name.startswith('embeddings')):
            whitelist_names.append(node.name)

    # Replace all the variables in the graph with constants of the same values
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, input_graph_def, output_node_names.split(","),
        variable_names_whitelist=whitelist_names)
    return output_graph_def

def parse_arguments(argv):
    parser = argparse.ArgumentParser()

    parser.add_argument('--model_dir', type=str, default='arch/pretrained_model',
                        help='Directory containing the metagraph (.meta) file and the checkpoint (ckpt) file containing model parameters')
    parser.add_argument('--output_file', type=str, default='arch/pretrained_model/freeze.pb',
                        help='Filename for the exported graphdef protobuf (.pb)')
    parser.add_argument('--image_size', default=[112, 112], help='the image size')
    parser.add_argument('--embedding_size', type=int,
                        help='Dimensionality of the embedding.', default=192)
    parser.add_argument('--weight_decay', default=5e-5, help='L2 weight regularization.')

    return parser.parse_args(argv)

if __name__ == '__main__':
    main(parse_arguments(sys.argv[1:]))

But when i use this script in windows
tflite_convert  ^
--output_file  freeze.tflite  ^
--graph_def_file  freeze.pb    ^
--input_arrays  "input"  ^
--input_shapes  "1,112,112,3"  ^
--output_arrays  embeddings  ^
--output_format  TFLITE ^
--allow_custom_ops

It show
2019-09-28 16:34:55.530294: F tensorflow/lite/toco/graph_transformations/resolve_tensorflow_switch.cc:98] Check failed: other_op->type == OperatorType::kMerge Found BatchNormalization as non-selected output from Switch, but
only Merge supported.

@GulyaevMaxim Hello
I find train_net.py.
It process image with substracted 127.5 and multiplied 1/128, not like your process.

@mengfu188
I used preprocessing from original FaceNet

2019-09-28 16:34:55.530294: F tensorflow/lite/toco/graph_transformations/resolve_tensorflow_switch.cc:98] Check failed: other_op->type == OperatorType::kMerge Found BatchNormalization as non-selected output from Switch, but
only Merge supported.

This error connects with batch_norm params ('is_training': False, 'trainable': False)

@mengfu188 I will try to use preprocessing from this repository. It can improve total accuracy

I followed @GulyaevMaxim hint, create model from train_net.py with 'is_training': False, 'trainable': False, load checkpoint and get freezed graph which could convert to tflite successfully. Thanks!
freeze_graph.py
from losses.face_losses import insightface_loss, cosineface_loss, combine_loss
from utils.data_process import parse_function, load_data
from nets.MobileFaceNet import inference
# from losses.face_losses import cos_loss
from verification import evaluate
from scipy.optimize import brentq
from utils.common import train
from scipy import interpolate
from datetime import datetime
from sklearn import metrics
import tensorflow as tf
import numpy as np
import argparse
import time
import os
from tensorflow.python.framework import graph_util

slim = tf.contrib.slim

def get_parser():
    parser = argparse.ArgumentParser(description='parameters to train net')
    parser.add_argument('--pretrained_model', type=str, default='', help='Load a pretrained model before training starts.')
    parser.add_argument('--output_file', type=str, help='Filename for the exported graphdef protobuf (.pb)')

    args = parser.parse_args()
    return args

def freeze_graph_def(sess, input_graph_def, output_node_names):
    for node in input_graph_def.node:
        if node.op == 'RefSwitch':
            node.op = 'Switch'
            for index in xrange(len(node.input)):
                if 'moving_' in node.input[index]:
                    node.input[index] = node.input[index] + '/read'
        elif node.op == 'AssignSub':
            node.op = 'Sub'
            if 'use_locking' in node.attr: del node.attr['use_locking']
        elif node.op == 'AssignAdd':
            node.op = 'Add'
            if 'use_locking' in node.attr: del node.attr['use_locking']

    # Get the list of important nodes
    whitelist_names = []
    for node in input_graph_def.node:
        if (node.name.startswith('MobileFaceNet') or node.name.startswith('embeddings')):
            whitelist_names.append(node.name)

    # Replace all the variables in the graph with constants of the same values
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, input_graph_def, output_node_names.split(","),
        variable_names_whitelist=whitelist_names)
    return output_graph_def

if __name__ == '__main__':
    with tf.Graph().as_default():
        args = get_parser()

        # define placeholder
        inputs = tf.placeholder(name='img_inputs', shape=[None, 112, 112, 3], dtype=tf.float32)
        labels = tf.placeholder(name='img_labels', shape=[None, ], dtype=tf.int64)
        phase_train_placeholder = tf.placeholder_with_default(tf.constant(False, dtype=tf.bool), shape=None, name='phase_train')

        # pretrained model path
        pretrained_model = None
        if args.pretrained_model:
            pretrained_model = os.path.expanduser(args.pretrained_model)
            print('Pre-trained model: %s' % pretrained_model)

        # identity the input, for inference
        inputs = tf.identity(inputs, 'input')

        prelogits, net_points = inference(inputs, bottleneck_layer_size=192, phase_train=False, weight_decay=5e-5)

        embeddings = tf.nn.l2_normalize(prelogits, 1, 1e-10, name='embeddings')

        sess = tf.Session()

        # saver to load pretrained model or save model
        # MobileFaceNet_vars = [v for v in tf.trainable_variables() if v.name.startswith('MobileFaceNet')]
        saver = tf.train.Saver(tf.trainable_variables())

        # init all variables
        sess.run(tf.global_variables_initializer())
        sess.run(tf.local_variables_initializer())

        # load pretrained model
        if pretrained_model:
            print('Restoring pretrained model: %s' % pretrained_model)
            ckpt = tf.train.get_checkpoint_state(pretrained_model)
            print(ckpt)
            saver.restore(sess, ckpt.model_checkpoint_path)

        # Retrieve the protobuf graph definition and fix the batch norm nodes
        input_graph_def = sess.graph.as_graph_def()

        # Freeze the graph def
        output_graph_def = freeze_graph_def(sess, input_graph_def, 'embeddings')

        # Serialize and dump the output graph to the filesystem
        with tf.gfile.GFile(args.output_file, 'wb') as f:
            f.write(output_graph_def.SerializeToString())
        print("%d ops in the final graph: %s" % (len(output_graph_def.node), args.output_file))

modified MobileFaceNet.py
# Copyright 2018 The AI boy xsr-ai. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""MobileFaceNets.

MobileFaceNets, which use less than 1 million parameters and are specifically tailored for high-accuracy real-time
face verification on mobile and embedded devices.

here is MobileFaceNets architecture, reference from MobileNet_V2 (https://github.com/xsr-ai/MobileNetv2_TF).

As described in https://arxiv.org/abs/1804.07573.

  MobileFaceNets: Efficient CNNs for Accurate Real-time Face Verification on Mobile Devices

  Sheng Chen, Yang Liu, Xiang Gao, Zhen Han

"""

# Tensorflow mandates these.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from collections import namedtuple
import functools

import tensorflow as tf

slim = tf.contrib.slim

# Conv and InvResBlock namedtuple define layers of the MobileNet architecture
# Conv defines 3x3 convolution layers
# InvResBlock defines 3x3 depthwise convolution followed by 1x1 convolution.
# stride is the stride of the convolution
# depth is the number of channels or filters in a layer
Conv = namedtuple('Conv', ['kernel', 'stride', 'depth', 'ratio'])
DepthwiseConv = namedtuple('DepthwiseConv', ['kernel', 'stride', 'depth', 'ratio'])
InvResBlock = namedtuple('InvResBlock', ['kernel', 'stride', 'depth', 'ratio', 'repeate'])

# _CONV_DEFS specifies the MobileNet body
_CONV_DEFS = [
    Conv(kernel=[3, 3], stride=2, depth=64, ratio=1),
    DepthwiseConv(kernel=[3, 3], stride=1, depth=64, ratio=1),

    InvResBlock(kernel=[3, 3], stride=2, depth=64, ratio=2, repeate=5),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=6),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=2),

    Conv(kernel=[1, 1], stride=1, depth=512, ratio=1),
]

def inverted_block(net, input_filters, output_filters, expand_ratio, stride, scope=None):
    '''fundamental network struture of inverted residual block'''
    with tf.name_scope(scope):
        res_block = slim.conv2d(inputs=net, num_outputs=input_filters * expand_ratio, kernel_size=[1, 1])
        # depthwise conv2d
        res_block = slim.separable_conv2d(inputs=res_block, num_outputs=None, kernel_size=[3, 3], stride=stride, depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
        res_block = slim.conv2d(inputs=res_block, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
        # stride 2 blocks
        if stride == 2:
            return res_block
        # stride 1 block
        else:
            if input_filters != output_filters:
                net = slim.conv2d(inputs=net, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
            return tf.add(res_block, net)

def mobilenet_v2_base(inputs,
                      final_endpoint='Conv2d_7',
                      min_depth=8,
                      conv_defs=None,
                      scope=None):
  """Mobilenet v2.

  Constructs a Mobilenet v2 network from inputs to the given final endpoint.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_0', 'Conv2d_1_InvResBlock', 'Conv2d_2_InvResBlock',
      'Conv2d_3_InvResBlock', 'Conv2d_4_InvResBlock', 'Conv2d_5_InvResBlock,
      'Conv2d_6_InvResBlock', 'Conv2d_7_InvResBlock', 'Conv2d_8'].
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth.
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    scope: Optional variable_scope.

  Returns:
    tensor_out: output tensor corresponding to the final_endpoint.
    end_points: a set of activations for external use, for example summaries or
                losses.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values
                is not allowed.
  """
  depth = lambda d: max(int(d), min_depth)
  end_points = {}

  if conv_defs is None:
    conv_defs = _CONV_DEFS

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs]):
    with slim.arg_scope([slim.conv2d, slim.separable_conv2d], padding='SAME'):

      net = inputs
      for i, conv_def in enumerate(conv_defs):
        end_point_base = 'Conv2d_%d' % i

        if isinstance(conv_def, Conv):
          end_point = end_point_base
          net = slim.conv2d(net, depth(conv_def.depth), conv_def.kernel,
                            stride=conv_def.stride,
                            normalizer_fn=slim.batch_norm,
                            scope=end_point)
          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        elif isinstance(conv_def, DepthwiseConv):
            end_point = 'DepthwiseConv'
            # depthwise conv2d
            net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=conv_def.kernel, stride=conv_def.stride,
                                        depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
            net = slim.conv2d(inputs=net, num_outputs=conv_def.depth, kernel_size=[1, 1], activation_fn=None)
            end_points[end_point] = net
            if end_point == final_endpoint:
                return net, end_points

        elif isinstance(conv_def, InvResBlock):
          end_point = end_point_base + '_InvResBlock'
          # inverted bottleneck blocks
          input_filters = net.shape[3].value
          # first layer needs to consider stride
          net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, conv_def.stride, end_point+'_0')
          for index in range(1, conv_def.repeate):
              suffix = '_' + str(index)
              net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, 1, end_point+suffix)

          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        else:
          raise ValueError('Unknown convolution type %s for layer %d'
                           % (conv_def.ltype, i))
  raise ValueError('Unknown final endpoint %s' % final_endpoint)

def mobilenet_v2(inputs,
                 bottleneck_layer_size=128,
                 is_training=False,
                 min_depth=8,
                 conv_defs=None,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='MobileFaceNet',
                 global_pool=False):
  """Mobilenet v2 model for classification.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
      is omitted and the input features to the logits layer (before dropout)
      are returned instead.
    is_training: whether is training or not.
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth..
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.
    global_pool: Optional boolean flag to control the avgpooling before the
      logits layer. If false or unset, pooling is done with a fixed window
      that reduces default-sized inputs to 1x1, while larger inputs lead to
      larger outputs. If true, any input size is pooled down to 1x1.

  Returns:
    net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
      is a non-zero integer, or the non-dropped-out input to the logits layer
      if bottleneck_layer_size is 0 or None.
    end_points: a dictionary from components of the network to the corresponding
      activation.

  Raises:
    ValueError: Input rank is invalid.
  """
  input_shape = inputs.get_shape().as_list()
  if len(input_shape) != 4:
    raise ValueError('Invalid input tensor rank, expected 4, was: %d' %
                     len(input_shape))

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs], reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout], is_training=is_training):
      net, end_points = mobilenet_v2_base(inputs, scope=scope, min_depth=min_depth, conv_defs=conv_defs)

      with tf.variable_scope('Logits'):
        if global_pool:
          # Global average pooling.
          net = tf.reduce_mean(net, [1, 2], keep_dims=True, name='global_pool')
          end_points['global_pool'] = net
        else:
          # Pooling with a fixed kernel size.
          kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])

          # Global depthwise conv2d
          net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=kernel_size, stride=1,
                                      depth_multiplier=1.0, activation_fn=None, padding='VALID')
          net = slim.conv2d(inputs=net, num_outputs=512, kernel_size=[1, 1], stride=1, activation_fn=None, padding='VALID')
          end_points['GDConv'] = net

        if not bottleneck_layer_size:
          return net, end_points
        # 1 x 1 x 1024
        # net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
        logits = slim.conv2d(net, bottleneck_layer_size, kernel_size=[1, 1], stride=1, activation_fn=None, scope='LinearConv1x1')

        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
      end_points['Logits'] = logits

  return logits, end_points

mobilenet_v2.default_image_size = 112

def wrapped_partial(func, *args, **kwargs):
  partial_func = functools.partial(func, *args, **kwargs)
  functools.update_wrapper(partial_func, func)
  return partial_func

def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  """Define kernel size which is automatically reduced for small input.

  If the shape of the input images is unknown at graph construction time this
  function assumes that the input images are large enough.

  Args:
    input_tensor: input tensor of size [batch_size, height, width, channels].
    kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]

  Returns:
    a tensor with the kernel size.
  """
  shape = input_tensor.get_shape().as_list()
  if shape[1] is None or shape[2] is None:
    kernel_size_out = kernel_size
  else:
    kernel_size_out = [min(shape[1], kernel_size[0]),
                       min(shape[2], kernel_size[1])]
  return kernel_size_out

def prelu(input, name=''):
    alphas = tf.get_variable(name=name + 'prelu_alphas',initializer=tf.constant(0.25,dtype=tf.float32,shape=[input.get_shape()[-1]]))
    pos = tf.nn.relu(input)
    neg = alphas * (input - abs(input)) * 0.5
    return pos + neg

def mobilenet_v2_arg_scope(is_training=True,
                           weight_decay=0.00005,
                           regularize_depthwise=False):
  """Defines the default MobilenetV2 arg scope.

  Args:
    is_training: Whether or not we're training the model.
    weight_decay: The weight decay to use for regularizing the model.
    regularize_depthwise: Whether or not apply regularization on depthwise.

  Returns:
    An `arg_scope` to use for the mobilenet v2 model.
  """
  batch_norm_params = {
      'is_training': is_training,
      'trainable': False,
      'center': True,
      'scale': True,
      'fused': True,
      'decay': 0.995,
      'epsilon': 2e-5,
      # force in-place updates of mean and variance estimates
      'updates_collections': None,
      # Moving averages ends up in the trainable variables collection
      'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
  }

  # Set weight_decay for weights in Conv and InvResBlock layers.
  #weights_init = tf.truncated_normal_initializer(stddev=stddev)
  weights_init = tf.contrib.layers.xavier_initializer(uniform=False)
  regularizer = tf.contrib.layers.l2_regularizer(weight_decay)
  if regularize_depthwise:
    depthwise_regularizer = regularizer
  else:
    depthwise_regularizer = None
  with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
                      weights_initializer=weights_init,
                      activation_fn=prelu, normalizer_fn=slim.batch_norm): #tf.keras.layers.PReLU
    with slim.arg_scope([slim.batch_norm], **batch_norm_params):
      with slim.arg_scope([slim.conv2d], weights_regularizer=regularizer):
        with slim.arg_scope([slim.separable_conv2d],
                            weights_regularizer=depthwise_regularizer) as sc:
          return sc

def inference(images, bottleneck_layer_size=128, phase_train=False,
              weight_decay=0.00005, reuse=False):
    '''build a mobilenet_v2 graph to training or inference.

    Args:
        images: a tensor of shape [batch_size, height, width, channels].
        bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
          is omitted and the input features to the logits layer (before dropout)
          are returned instead.
        phase_train: Whether or not we're training the model.
        weight_decay: The weight decay to use for regularizing the model.
        reuse: whether or not the network and its variables should be reused. To be
          able to reuse 'scope' must be given.

    Returns:
        net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
          is a non-zero integer, or the non-dropped-out input to the logits layer
          if bottleneck_layer_size is 0 or None.
        end_points: a dictionary from components of the network to the corresponding
          activation.

    Raises:
        ValueError: Input rank is invalid.
    '''
    arg_scope = mobilenet_v2_arg_scope(is_training=phase_train, weight_decay=weight_decay)
    with slim.arg_scope(arg_scope):
        return mobilenet_v2(images, bottleneck_layer_size=bottleneck_layer_size, is_training=phase_train, reuse=reuse)

scripts to freeze and convert
python freeze_graph.py --pretrained_model arch/pretrained_model --output_file freeze.pb
tflite_convert --output_file MobileFaceNet.tflite --graph_def_file freeze.pb  --input_arrays "input" --input_shapes "1,112,112,3" --output_arrays embeddings --output_format TFLITE

TensorFlow version 1.14.0

生成模型时，需要将set trainable和is-trainingparam 设置为false。
脚步：

设置trainable，is-training为false。
创建图。
从ckpt导入权重。
创建冻结的模型。

我创建了具有此更改的冻结模型（瓶颈大小= 192）
FaceMobileNet192_train_false.zip
和TFLite模型
FaceMobileNet_Float32.zip

我用过TF 1.14.0

Hello, I converted FaceMobileNet192_train_false.pb to tflite, this model can run normally on the CPU, but it will report an error on the GPU. Using FaceMobileNet_Float32.tflite will not report an error on the GPU. How do you convert pb to tflite.

@mengfu188
I used preprocessing from original FaceNet

There are typically two types of standardizations :

Fixed_standarization :
img = (np.float32(img) - 127.5) / 128.0

per_image_standardization:  prewhiten()

Looking at the training code, i see that the it's done using fixed_standardization whereas prewhiten() function used in the David's facenet repo is per_image_standarization.
I just wonder, are you getting good prediction accuracy for your test data?

Did anyone tried to quantize to uint8?
I can get correct result with f32, but fail with quantization to uint8 with the following command:
flite_convert --output_file tf-lite/MobileFacenet_uint8_128.tflite
--graph_def_file tf-lite/MobileFacenet.pb
--input_arrays "input"
--input_shapes "1,112,112,3"
--output_arrays output
--output_format TFLITE
--mean_values 128
--std_dev_values 127.5
--default_ranges_min 0
--default_ranges_max 255
--inference_type QUANTIZED_UINT8
--inference_input_type QUANTIZED_UINT8
Since mobilefacenet use Fixed_standarization as @milinddeore mentioned for the input.
I just give the rgb image range [0-255] directly as the input to quantized *.tflite model.
Also I tried to modfied --default_ranges_min & max to 0 & 6 as facenet, it doesn't help also.
Could anyone provide some suggestions? Thanks!

thanks

I followed @GulyaevMaxim hint, create model from train_net.py with 'is_training': False, 'trainable': False, load checkpoint and get freezed graph which could convert to tflite successfully. Thanks!
freeze_graph.py
from losses.face_losses import insightface_loss, cosineface_loss, combine_loss
from utils.data_process import parse_function, load_data
from nets.MobileFaceNet import inference
# from losses.face_losses import cos_loss
from verification import evaluate
from scipy.optimize import brentq
from utils.common import train
from scipy import interpolate
from datetime import datetime
from sklearn import metrics
import tensorflow as tf
import numpy as np
import argparse
import time
import os
from tensorflow.python.framework import graph_util

slim = tf.contrib.slim

def get_parser():
    parser = argparse.ArgumentParser(description='parameters to train net')
    parser.add_argument('--pretrained_model', type=str, default='', help='Load a pretrained model before training starts.')
    parser.add_argument('--output_file', type=str, help='Filename for the exported graphdef protobuf (.pb)')

    args = parser.parse_args()
    return args

def freeze_graph_def(sess, input_graph_def, output_node_names):
    for node in input_graph_def.node:
        if node.op == 'RefSwitch':
            node.op = 'Switch'
            for index in xrange(len(node.input)):
                if 'moving_' in node.input[index]:
                    node.input[index] = node.input[index] + '/read'
        elif node.op == 'AssignSub':
            node.op = 'Sub'
            if 'use_locking' in node.attr: del node.attr['use_locking']
        elif node.op == 'AssignAdd':
            node.op = 'Add'
            if 'use_locking' in node.attr: del node.attr['use_locking']

    # Get the list of important nodes
    whitelist_names = []
    for node in input_graph_def.node:
        if (node.name.startswith('MobileFaceNet') or node.name.startswith('embeddings')):
            whitelist_names.append(node.name)

    # Replace all the variables in the graph with constants of the same values
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, input_graph_def, output_node_names.split(","),
        variable_names_whitelist=whitelist_names)
    return output_graph_def

if __name__ == '__main__':
    with tf.Graph().as_default():
        args = get_parser()

        # define placeholder
        inputs = tf.placeholder(name='img_inputs', shape=[None, 112, 112, 3], dtype=tf.float32)
        labels = tf.placeholder(name='img_labels', shape=[None, ], dtype=tf.int64)
        phase_train_placeholder = tf.placeholder_with_default(tf.constant(False, dtype=tf.bool), shape=None, name='phase_train')

        # pretrained model path
        pretrained_model = None
        if args.pretrained_model:
            pretrained_model = os.path.expanduser(args.pretrained_model)
            print('Pre-trained model: %s' % pretrained_model)

        # identity the input, for inference
        inputs = tf.identity(inputs, 'input')

        prelogits, net_points = inference(inputs, bottleneck_layer_size=192, phase_train=False, weight_decay=5e-5)

        embeddings = tf.nn.l2_normalize(prelogits, 1, 1e-10, name='embeddings')

        sess = tf.Session()

        # saver to load pretrained model or save model
        # MobileFaceNet_vars = [v for v in tf.trainable_variables() if v.name.startswith('MobileFaceNet')]
        saver = tf.train.Saver(tf.trainable_variables())

        # init all variables
        sess.run(tf.global_variables_initializer())
        sess.run(tf.local_variables_initializer())

        # load pretrained model
        if pretrained_model:
            print('Restoring pretrained model: %s' % pretrained_model)
            ckpt = tf.train.get_checkpoint_state(pretrained_model)
            print(ckpt)
            saver.restore(sess, ckpt.model_checkpoint_path)

        # Retrieve the protobuf graph definition and fix the batch norm nodes
        input_graph_def = sess.graph.as_graph_def()

        # Freeze the graph def
        output_graph_def = freeze_graph_def(sess, input_graph_def, 'embeddings')

        # Serialize and dump the output graph to the filesystem
        with tf.gfile.GFile(args.output_file, 'wb') as f:
            f.write(output_graph_def.SerializeToString())
        print("%d ops in the final graph: %s" % (len(output_graph_def.node), args.output_file))

modified MobileFaceNet.py
# Copyright 2018 The AI boy xsr-ai. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""MobileFaceNets.

MobileFaceNets, which use less than 1 million parameters and are specifically tailored for high-accuracy real-time
face verification on mobile and embedded devices.

here is MobileFaceNets architecture, reference from MobileNet_V2 (https://github.com/xsr-ai/MobileNetv2_TF).

As described in https://arxiv.org/abs/1804.07573.

  MobileFaceNets: Efficient CNNs for Accurate Real-time Face Verification on Mobile Devices

  Sheng Chen, Yang Liu, Xiang Gao, Zhen Han

"""

# Tensorflow mandates these.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from collections import namedtuple
import functools

import tensorflow as tf

slim = tf.contrib.slim

# Conv and InvResBlock namedtuple define layers of the MobileNet architecture
# Conv defines 3x3 convolution layers
# InvResBlock defines 3x3 depthwise convolution followed by 1x1 convolution.
# stride is the stride of the convolution
# depth is the number of channels or filters in a layer
Conv = namedtuple('Conv', ['kernel', 'stride', 'depth', 'ratio'])
DepthwiseConv = namedtuple('DepthwiseConv', ['kernel', 'stride', 'depth', 'ratio'])
InvResBlock = namedtuple('InvResBlock', ['kernel', 'stride', 'depth', 'ratio', 'repeate'])

# _CONV_DEFS specifies the MobileNet body
_CONV_DEFS = [
    Conv(kernel=[3, 3], stride=2, depth=64, ratio=1),
    DepthwiseConv(kernel=[3, 3], stride=1, depth=64, ratio=1),

    InvResBlock(kernel=[3, 3], stride=2, depth=64, ratio=2, repeate=5),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=6),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=2),

    Conv(kernel=[1, 1], stride=1, depth=512, ratio=1),
]

def inverted_block(net, input_filters, output_filters, expand_ratio, stride, scope=None):
    '''fundamental network struture of inverted residual block'''
    with tf.name_scope(scope):
        res_block = slim.conv2d(inputs=net, num_outputs=input_filters * expand_ratio, kernel_size=[1, 1])
        # depthwise conv2d
        res_block = slim.separable_conv2d(inputs=res_block, num_outputs=None, kernel_size=[3, 3], stride=stride, depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
        res_block = slim.conv2d(inputs=res_block, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
        # stride 2 blocks
        if stride == 2:
            return res_block
        # stride 1 block
        else:
            if input_filters != output_filters:
                net = slim.conv2d(inputs=net, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
            return tf.add(res_block, net)

def mobilenet_v2_base(inputs,
                      final_endpoint='Conv2d_7',
                      min_depth=8,
                      conv_defs=None,
                      scope=None):
  """Mobilenet v2.

  Constructs a Mobilenet v2 network from inputs to the given final endpoint.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_0', 'Conv2d_1_InvResBlock', 'Conv2d_2_InvResBlock',
      'Conv2d_3_InvResBlock', 'Conv2d_4_InvResBlock', 'Conv2d_5_InvResBlock,
      'Conv2d_6_InvResBlock', 'Conv2d_7_InvResBlock', 'Conv2d_8'].
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth.
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    scope: Optional variable_scope.

  Returns:
    tensor_out: output tensor corresponding to the final_endpoint.
    end_points: a set of activations for external use, for example summaries or
                losses.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values
                is not allowed.
  """
  depth = lambda d: max(int(d), min_depth)
  end_points = {}

  if conv_defs is None:
    conv_defs = _CONV_DEFS

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs]):
    with slim.arg_scope([slim.conv2d, slim.separable_conv2d], padding='SAME'):

      net = inputs
      for i, conv_def in enumerate(conv_defs):
        end_point_base = 'Conv2d_%d' % i

        if isinstance(conv_def, Conv):
          end_point = end_point_base
          net = slim.conv2d(net, depth(conv_def.depth), conv_def.kernel,
                            stride=conv_def.stride,
                            normalizer_fn=slim.batch_norm,
                            scope=end_point)
          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        elif isinstance(conv_def, DepthwiseConv):
            end_point = 'DepthwiseConv'
            # depthwise conv2d
            net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=conv_def.kernel, stride=conv_def.stride,
                                        depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
            net = slim.conv2d(inputs=net, num_outputs=conv_def.depth, kernel_size=[1, 1], activation_fn=None)
            end_points[end_point] = net
            if end_point == final_endpoint:
                return net, end_points

        elif isinstance(conv_def, InvResBlock):
          end_point = end_point_base + '_InvResBlock'
          # inverted bottleneck blocks
          input_filters = net.shape[3].value
          # first layer needs to consider stride
          net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, conv_def.stride, end_point+'_0')
          for index in range(1, conv_def.repeate):
              suffix = '_' + str(index)
              net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, 1, end_point+suffix)

          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        else:
          raise ValueError('Unknown convolution type %s for layer %d'
                           % (conv_def.ltype, i))
  raise ValueError('Unknown final endpoint %s' % final_endpoint)

def mobilenet_v2(inputs,
                 bottleneck_layer_size=128,
                 is_training=False,
                 min_depth=8,
                 conv_defs=None,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='MobileFaceNet',
                 global_pool=False):
  """Mobilenet v2 model for classification.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
      is omitted and the input features to the logits layer (before dropout)
      are returned instead.
    is_training: whether is training or not.
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth..
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.
    global_pool: Optional boolean flag to control the avgpooling before the
      logits layer. If false or unset, pooling is done with a fixed window
      that reduces default-sized inputs to 1x1, while larger inputs lead to
      larger outputs. If true, any input size is pooled down to 1x1.

  Returns:
    net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
      is a non-zero integer, or the non-dropped-out input to the logits layer
      if bottleneck_layer_size is 0 or None.
    end_points: a dictionary from components of the network to the corresponding
      activation.

  Raises:
    ValueError: Input rank is invalid.
  """
  input_shape = inputs.get_shape().as_list()
  if len(input_shape) != 4:
    raise ValueError('Invalid input tensor rank, expected 4, was: %d' %
                     len(input_shape))

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs], reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout], is_training=is_training):
      net, end_points = mobilenet_v2_base(inputs, scope=scope, min_depth=min_depth, conv_defs=conv_defs)

      with tf.variable_scope('Logits'):
        if global_pool:
          # Global average pooling.
          net = tf.reduce_mean(net, [1, 2], keep_dims=True, name='global_pool')
          end_points['global_pool'] = net
        else:
          # Pooling with a fixed kernel size.
          kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])

          # Global depthwise conv2d
          net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=kernel_size, stride=1,
                                      depth_multiplier=1.0, activation_fn=None, padding='VALID')
          net = slim.conv2d(inputs=net, num_outputs=512, kernel_size=[1, 1], stride=1, activation_fn=None, padding='VALID')
          end_points['GDConv'] = net

        if not bottleneck_layer_size:
          return net, end_points
        # 1 x 1 x 1024
        # net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
        logits = slim.conv2d(net, bottleneck_layer_size, kernel_size=[1, 1], stride=1, activation_fn=None, scope='LinearConv1x1')

        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
      end_points['Logits'] = logits

  return logits, end_points

mobilenet_v2.default_image_size = 112

def wrapped_partial(func, *args, **kwargs):
  partial_func = functools.partial(func, *args, **kwargs)
  functools.update_wrapper(partial_func, func)
  return partial_func

def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  """Define kernel size which is automatically reduced for small input.

  If the shape of the input images is unknown at graph construction time this
  function assumes that the input images are large enough.

  Args:
    input_tensor: input tensor of size [batch_size, height, width, channels].
    kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]

  Returns:
    a tensor with the kernel size.
  """
  shape = input_tensor.get_shape().as_list()
  if shape[1] is None or shape[2] is None:
    kernel_size_out = kernel_size
  else:
    kernel_size_out = [min(shape[1], kernel_size[0]),
                       min(shape[2], kernel_size[1])]
  return kernel_size_out

def prelu(input, name=''):
    alphas = tf.get_variable(name=name + 'prelu_alphas',initializer=tf.constant(0.25,dtype=tf.float32,shape=[input.get_shape()[-1]]))
    pos = tf.nn.relu(input)
    neg = alphas * (input - abs(input)) * 0.5
    return pos + neg

def mobilenet_v2_arg_scope(is_training=True,
                           weight_decay=0.00005,
                           regularize_depthwise=False):
  """Defines the default MobilenetV2 arg scope.

  Args:
    is_training: Whether or not we're training the model.
    weight_decay: The weight decay to use for regularizing the model.
    regularize_depthwise: Whether or not apply regularization on depthwise.

  Returns:
    An `arg_scope` to use for the mobilenet v2 model.
  """
  batch_norm_params = {
      'is_training': is_training,
      'trainable': False,
      'center': True,
      'scale': True,
      'fused': True,
      'decay': 0.995,
      'epsilon': 2e-5,
      # force in-place updates of mean and variance estimates
      'updates_collections': None,
      # Moving averages ends up in the trainable variables collection
      'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
  }

  # Set weight_decay for weights in Conv and InvResBlock layers.
  #weights_init = tf.truncated_normal_initializer(stddev=stddev)
  weights_init = tf.contrib.layers.xavier_initializer(uniform=False)
  regularizer = tf.contrib.layers.l2_regularizer(weight_decay)
  if regularize_depthwise:
    depthwise_regularizer = regularizer
  else:
    depthwise_regularizer = None
  with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
                      weights_initializer=weights_init,
                      activation_fn=prelu, normalizer_fn=slim.batch_norm): #tf.keras.layers.PReLU
    with slim.arg_scope([slim.batch_norm], **batch_norm_params):
      with slim.arg_scope([slim.conv2d], weights_regularizer=regularizer):
        with slim.arg_scope([slim.separable_conv2d],
                            weights_regularizer=depthwise_regularizer) as sc:
          return sc

def inference(images, bottleneck_layer_size=128, phase_train=False,
              weight_decay=0.00005, reuse=False):
    '''build a mobilenet_v2 graph to training or inference.

    Args:
        images: a tensor of shape [batch_size, height, width, channels].
        bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
          is omitted and the input features to the logits layer (before dropout)
          are returned instead.
        phase_train: Whether or not we're training the model.
        weight_decay: The weight decay to use for regularizing the model.
        reuse: whether or not the network and its variables should be reused. To be
          able to reuse 'scope' must be given.

    Returns:
        net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
          is a non-zero integer, or the non-dropped-out input to the logits layer
          if bottleneck_layer_size is 0 or None.
        end_points: a dictionary from components of the network to the corresponding
          activation.

    Raises:
        ValueError: Input rank is invalid.
    '''
    arg_scope = mobilenet_v2_arg_scope(is_training=phase_train, weight_decay=weight_decay)
    with slim.arg_scope(arg_scope):
        return mobilenet_v2(images, bottleneck_layer_size=bottleneck_layer_size, is_training=phase_train, reuse=reuse)

scripts to freeze and convert
python freeze_graph.py --pretrained_model arch/pretrained_model --output_file freeze.pb
tflite_convert --output_file MobileFaceNet.tflite --graph_def_file freeze.pb  --input_arrays "input" --input_shapes "1,112,112,3" --output_arrays embeddings --output_format TFLITE

TensorFlow version 1.14.0

create model from train_net.py with 'is_training': False, 'trainable': False,

请问create model from train_net.py with 'is_training': False, 'trainable': False这句话的意思是需要运行train_net.py来得到想要的模型吗？

I followed @GulyaevMaxim hint, create model from train_net.py with 'is_training': False, 'trainable': False, load checkpoint and get freezed graph which could convert to tflite successfully. Thanks!
freeze_graph.py
from losses.face_losses import insightface_loss, cosineface_loss, combine_loss
from utils.data_process import parse_function, load_data
from nets.MobileFaceNet import inference
# from losses.face_losses import cos_loss
from verification import evaluate
from scipy.optimize import brentq
from utils.common import train
from scipy import interpolate
from datetime import datetime
from sklearn import metrics
import tensorflow as tf
import numpy as np
import argparse
import time
import os
from tensorflow.python.framework import graph_util

slim = tf.contrib.slim

def get_parser():
    parser = argparse.ArgumentParser(description='parameters to train net')
    parser.add_argument('--pretrained_model', type=str, default='', help='Load a pretrained model before training starts.')
    parser.add_argument('--output_file', type=str, help='Filename for the exported graphdef protobuf (.pb)')

    args = parser.parse_args()
    return args

def freeze_graph_def(sess, input_graph_def, output_node_names):
    for node in input_graph_def.node:
        if node.op == 'RefSwitch':
            node.op = 'Switch'
            for index in xrange(len(node.input)):
                if 'moving_' in node.input[index]:
                    node.input[index] = node.input[index] + '/read'
        elif node.op == 'AssignSub':
            node.op = 'Sub'
            if 'use_locking' in node.attr: del node.attr['use_locking']
        elif node.op == 'AssignAdd':
            node.op = 'Add'
            if 'use_locking' in node.attr: del node.attr['use_locking']

    # Get the list of important nodes
    whitelist_names = []
    for node in input_graph_def.node:
        if (node.name.startswith('MobileFaceNet') or node.name.startswith('embeddings')):
            whitelist_names.append(node.name)

    # Replace all the variables in the graph with constants of the same values
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, input_graph_def, output_node_names.split(","),
        variable_names_whitelist=whitelist_names)
    return output_graph_def

if __name__ == '__main__':
    with tf.Graph().as_default():
        args = get_parser()

        # define placeholder
        inputs = tf.placeholder(name='img_inputs', shape=[None, 112, 112, 3], dtype=tf.float32)
        labels = tf.placeholder(name='img_labels', shape=[None, ], dtype=tf.int64)
        phase_train_placeholder = tf.placeholder_with_default(tf.constant(False, dtype=tf.bool), shape=None, name='phase_train')

        # pretrained model path
        pretrained_model = None
        if args.pretrained_model:
            pretrained_model = os.path.expanduser(args.pretrained_model)
            print('Pre-trained model: %s' % pretrained_model)

        # identity the input, for inference
        inputs = tf.identity(inputs, 'input')

        prelogits, net_points = inference(inputs, bottleneck_layer_size=192, phase_train=False, weight_decay=5e-5)

        embeddings = tf.nn.l2_normalize(prelogits, 1, 1e-10, name='embeddings')

        sess = tf.Session()

        # saver to load pretrained model or save model
        # MobileFaceNet_vars = [v for v in tf.trainable_variables() if v.name.startswith('MobileFaceNet')]
        saver = tf.train.Saver(tf.trainable_variables())

        # init all variables
        sess.run(tf.global_variables_initializer())
        sess.run(tf.local_variables_initializer())

        # load pretrained model
        if pretrained_model:
            print('Restoring pretrained model: %s' % pretrained_model)
            ckpt = tf.train.get_checkpoint_state(pretrained_model)
            print(ckpt)
            saver.restore(sess, ckpt.model_checkpoint_path)

        # Retrieve the protobuf graph definition and fix the batch norm nodes
        input_graph_def = sess.graph.as_graph_def()

        # Freeze the graph def
        output_graph_def = freeze_graph_def(sess, input_graph_def, 'embeddings')

        # Serialize and dump the output graph to the filesystem
        with tf.gfile.GFile(args.output_file, 'wb') as f:
            f.write(output_graph_def.SerializeToString())
        print("%d ops in the final graph: %s" % (len(output_graph_def.node), args.output_file))

modified MobileFaceNet.py
# Copyright 2018 The AI boy xsr-ai. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""MobileFaceNets.

MobileFaceNets, which use less than 1 million parameters and are specifically tailored for high-accuracy real-time
face verification on mobile and embedded devices.

here is MobileFaceNets architecture, reference from MobileNet_V2 (https://github.com/xsr-ai/MobileNetv2_TF).

As described in https://arxiv.org/abs/1804.07573.

  MobileFaceNets: Efficient CNNs for Accurate Real-time Face Verification on Mobile Devices

  Sheng Chen, Yang Liu, Xiang Gao, Zhen Han

"""

# Tensorflow mandates these.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from collections import namedtuple
import functools

import tensorflow as tf

slim = tf.contrib.slim

# Conv and InvResBlock namedtuple define layers of the MobileNet architecture
# Conv defines 3x3 convolution layers
# InvResBlock defines 3x3 depthwise convolution followed by 1x1 convolution.
# stride is the stride of the convolution
# depth is the number of channels or filters in a layer
Conv = namedtuple('Conv', ['kernel', 'stride', 'depth', 'ratio'])
DepthwiseConv = namedtuple('DepthwiseConv', ['kernel', 'stride', 'depth', 'ratio'])
InvResBlock = namedtuple('InvResBlock', ['kernel', 'stride', 'depth', 'ratio', 'repeate'])

# _CONV_DEFS specifies the MobileNet body
_CONV_DEFS = [
    Conv(kernel=[3, 3], stride=2, depth=64, ratio=1),
    DepthwiseConv(kernel=[3, 3], stride=1, depth=64, ratio=1),

    InvResBlock(kernel=[3, 3], stride=2, depth=64, ratio=2, repeate=5),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=6),
    InvResBlock(kernel=[3, 3], stride=2, depth=128, ratio=4, repeate=1),
    InvResBlock(kernel=[3, 3], stride=1, depth=128, ratio=2, repeate=2),

    Conv(kernel=[1, 1], stride=1, depth=512, ratio=1),
]

def inverted_block(net, input_filters, output_filters, expand_ratio, stride, scope=None):
    '''fundamental network struture of inverted residual block'''
    with tf.name_scope(scope):
        res_block = slim.conv2d(inputs=net, num_outputs=input_filters * expand_ratio, kernel_size=[1, 1])
        # depthwise conv2d
        res_block = slim.separable_conv2d(inputs=res_block, num_outputs=None, kernel_size=[3, 3], stride=stride, depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
        res_block = slim.conv2d(inputs=res_block, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
        # stride 2 blocks
        if stride == 2:
            return res_block
        # stride 1 block
        else:
            if input_filters != output_filters:
                net = slim.conv2d(inputs=net, num_outputs=output_filters, kernel_size=[1, 1], activation_fn=None)
            return tf.add(res_block, net)

def mobilenet_v2_base(inputs,
                      final_endpoint='Conv2d_7',
                      min_depth=8,
                      conv_defs=None,
                      scope=None):
  """Mobilenet v2.

  Constructs a Mobilenet v2 network from inputs to the given final endpoint.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_0', 'Conv2d_1_InvResBlock', 'Conv2d_2_InvResBlock',
      'Conv2d_3_InvResBlock', 'Conv2d_4_InvResBlock', 'Conv2d_5_InvResBlock,
      'Conv2d_6_InvResBlock', 'Conv2d_7_InvResBlock', 'Conv2d_8'].
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth.
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    scope: Optional variable_scope.

  Returns:
    tensor_out: output tensor corresponding to the final_endpoint.
    end_points: a set of activations for external use, for example summaries or
                losses.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values
                is not allowed.
  """
  depth = lambda d: max(int(d), min_depth)
  end_points = {}

  if conv_defs is None:
    conv_defs = _CONV_DEFS

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs]):
    with slim.arg_scope([slim.conv2d, slim.separable_conv2d], padding='SAME'):

      net = inputs
      for i, conv_def in enumerate(conv_defs):
        end_point_base = 'Conv2d_%d' % i

        if isinstance(conv_def, Conv):
          end_point = end_point_base
          net = slim.conv2d(net, depth(conv_def.depth), conv_def.kernel,
                            stride=conv_def.stride,
                            normalizer_fn=slim.batch_norm,
                            scope=end_point)
          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        elif isinstance(conv_def, DepthwiseConv):
            end_point = 'DepthwiseConv'
            # depthwise conv2d
            net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=conv_def.kernel, stride=conv_def.stride,
                                        depth_multiplier=1.0, normalizer_fn=slim.batch_norm)
            net = slim.conv2d(inputs=net, num_outputs=conv_def.depth, kernel_size=[1, 1], activation_fn=None)
            end_points[end_point] = net
            if end_point == final_endpoint:
                return net, end_points

        elif isinstance(conv_def, InvResBlock):
          end_point = end_point_base + '_InvResBlock'
          # inverted bottleneck blocks
          input_filters = net.shape[3].value
          # first layer needs to consider stride
          net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, conv_def.stride, end_point+'_0')
          for index in range(1, conv_def.repeate):
              suffix = '_' + str(index)
              net = inverted_block(net, input_filters, depth(conv_def.depth), conv_def.ratio, 1, end_point+suffix)

          end_points[end_point] = net
          if end_point == final_endpoint:
            return net, end_points

        else:
          raise ValueError('Unknown convolution type %s for layer %d'
                           % (conv_def.ltype, i))
  raise ValueError('Unknown final endpoint %s' % final_endpoint)

def mobilenet_v2(inputs,
                 bottleneck_layer_size=128,
                 is_training=False,
                 min_depth=8,
                 conv_defs=None,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='MobileFaceNet',
                 global_pool=False):
  """Mobilenet v2 model for classification.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
      is omitted and the input features to the logits layer (before dropout)
      are returned instead.
    is_training: whether is training or not.
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced output depth to min_depth..
    conv_defs: A list of ConvDef namedtuples specifying the net architecture.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.
    global_pool: Optional boolean flag to control the avgpooling before the
      logits layer. If false or unset, pooling is done with a fixed window
      that reduces default-sized inputs to 1x1, while larger inputs lead to
      larger outputs. If true, any input size is pooled down to 1x1.

  Returns:
    net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
      is a non-zero integer, or the non-dropped-out input to the logits layer
      if bottleneck_layer_size is 0 or None.
    end_points: a dictionary from components of the network to the corresponding
      activation.

  Raises:
    ValueError: Input rank is invalid.
  """
  input_shape = inputs.get_shape().as_list()
  if len(input_shape) != 4:
    raise ValueError('Invalid input tensor rank, expected 4, was: %d' %
                     len(input_shape))

  with tf.variable_scope(scope, 'MobileFaceNet', [inputs], reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout], is_training=is_training):
      net, end_points = mobilenet_v2_base(inputs, scope=scope, min_depth=min_depth, conv_defs=conv_defs)

      with tf.variable_scope('Logits'):
        if global_pool:
          # Global average pooling.
          net = tf.reduce_mean(net, [1, 2], keep_dims=True, name='global_pool')
          end_points['global_pool'] = net
        else:
          # Pooling with a fixed kernel size.
          kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])

          # Global depthwise conv2d
          net = slim.separable_conv2d(inputs=net, num_outputs=None, kernel_size=kernel_size, stride=1,
                                      depth_multiplier=1.0, activation_fn=None, padding='VALID')
          net = slim.conv2d(inputs=net, num_outputs=512, kernel_size=[1, 1], stride=1, activation_fn=None, padding='VALID')
          end_points['GDConv'] = net

        if not bottleneck_layer_size:
          return net, end_points
        # 1 x 1 x 1024
        # net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
        logits = slim.conv2d(net, bottleneck_layer_size, kernel_size=[1, 1], stride=1, activation_fn=None, scope='LinearConv1x1')

        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
      end_points['Logits'] = logits

  return logits, end_points

mobilenet_v2.default_image_size = 112

def wrapped_partial(func, *args, **kwargs):
  partial_func = functools.partial(func, *args, **kwargs)
  functools.update_wrapper(partial_func, func)
  return partial_func

def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  """Define kernel size which is automatically reduced for small input.

  If the shape of the input images is unknown at graph construction time this
  function assumes that the input images are large enough.

  Args:
    input_tensor: input tensor of size [batch_size, height, width, channels].
    kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]

  Returns:
    a tensor with the kernel size.
  """
  shape = input_tensor.get_shape().as_list()
  if shape[1] is None or shape[2] is None:
    kernel_size_out = kernel_size
  else:
    kernel_size_out = [min(shape[1], kernel_size[0]),
                       min(shape[2], kernel_size[1])]
  return kernel_size_out

def prelu(input, name=''):
    alphas = tf.get_variable(name=name + 'prelu_alphas',initializer=tf.constant(0.25,dtype=tf.float32,shape=[input.get_shape()[-1]]))
    pos = tf.nn.relu(input)
    neg = alphas * (input - abs(input)) * 0.5
    return pos + neg

def mobilenet_v2_arg_scope(is_training=True,
                           weight_decay=0.00005,
                           regularize_depthwise=False):
  """Defines the default MobilenetV2 arg scope.

  Args:
    is_training: Whether or not we're training the model.
    weight_decay: The weight decay to use for regularizing the model.
    regularize_depthwise: Whether or not apply regularization on depthwise.

  Returns:
    An `arg_scope` to use for the mobilenet v2 model.
  """
  batch_norm_params = {
      'is_training': is_training,
      'trainable': False,
      'center': True,
      'scale': True,
      'fused': True,
      'decay': 0.995,
      'epsilon': 2e-5,
      # force in-place updates of mean and variance estimates
      'updates_collections': None,
      # Moving averages ends up in the trainable variables collection
      'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
  }

  # Set weight_decay for weights in Conv and InvResBlock layers.
  #weights_init = tf.truncated_normal_initializer(stddev=stddev)
  weights_init = tf.contrib.layers.xavier_initializer(uniform=False)
  regularizer = tf.contrib.layers.l2_regularizer(weight_decay)
  if regularize_depthwise:
    depthwise_regularizer = regularizer
  else:
    depthwise_regularizer = None
  with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
                      weights_initializer=weights_init,
                      activation_fn=prelu, normalizer_fn=slim.batch_norm): #tf.keras.layers.PReLU
    with slim.arg_scope([slim.batch_norm], **batch_norm_params):
      with slim.arg_scope([slim.conv2d], weights_regularizer=regularizer):
        with slim.arg_scope([slim.separable_conv2d],
                            weights_regularizer=depthwise_regularizer) as sc:
          return sc

def inference(images, bottleneck_layer_size=128, phase_train=False,
              weight_decay=0.00005, reuse=False):
    '''build a mobilenet_v2 graph to training or inference.

    Args:
        images: a tensor of shape [batch_size, height, width, channels].
        bottleneck_layer_size: number of predicted classes. If 0 or None, the logits layer
          is omitted and the input features to the logits layer (before dropout)
          are returned instead.
        phase_train: Whether or not we're training the model.
        weight_decay: The weight decay to use for regularizing the model.
        reuse: whether or not the network and its variables should be reused. To be
          able to reuse 'scope' must be given.

    Returns:
        net: a 2D Tensor with the logits (pre-softmax activations) if bottleneck_layer_size
          is a non-zero integer, or the non-dropped-out input to the logits layer
          if bottleneck_layer_size is 0 or None.
        end_points: a dictionary from components of the network to the corresponding
          activation.

    Raises:
        ValueError: Input rank is invalid.
    '''
    arg_scope = mobilenet_v2_arg_scope(is_training=phase_train, weight_decay=weight_decay)
    with slim.arg_scope(arg_scope):
        return mobilenet_v2(images, bottleneck_layer_size=bottleneck_layer_size, is_training=phase_train, reuse=reuse)

scripts to freeze and convert
python freeze_graph.py --pretrained_model arch/pretrained_model --output_file freeze.pb
tflite_convert --output_file MobileFaceNet.tflite --graph_def_file freeze.pb  --input_arrays "input" --input_shapes "1,112,112,3" --output_arrays embeddings --output_format TFLITE

TensorFlow version 1.14.0

hi dear.
so thanks for your solution.
I know this is too late but I get stuck in the problem.
the originial mobilefacenet has a vector with 128 cells as endpoints or model's output but the converted model has 192 cells!?
could you please help me to solve the problem and make the output right exatcly as the original model?


Tabs : tabpanel id is not updated

🐛 Bug Report
When we use the components Tabs, TabList, Tab, TabPanel, the id attribute of the element with role="tabpanel" is not updated when the current tab is changed.
The id keeps its initial value.
For instance with the controlled version provided here - https://react-spectrum.adobe.com/react-aria/Tabs.html#controlled-selection :

triassic is in the id attribute ✅ .
Then when I click on the Jurassic tab :

triassic is still in the id attribute instead of jurassic ❌.

🤔 Expected Behavior

😯 Current Behavior

💁 Possible Solution

🔦 Context

💻 Code Sample
https://codesandbox.io/p/sandbox/react-aria-components-tabs-vqylnh?file=%2Fsrc%2FApp.tsx%3A1%2C1

🌍 Your Environment

Software
Version(s)

react-aria-components
1.0.0-alpha.5

Browser
Google Chrome 114.0.5735.198

Operating System
macOS Ventura 13.4.1 (c)

🧢 Your Company/Team

🕷 Tracking Issue (optional)

Thanks for reporting this, verified locally. I think this line should become something like this:
const id = generateId(state, props.id ?? state?.selectedKey, 'tabpanel');

This wasn't a problem for RSP TabPanels since we updated the key attached to the rendered TabPanel as the selected item was updated, causing a new instance of the id to be generated for the new TabPanel instance as the selected key changed. However, RAC Tabs is different in that a separate TabPanel is made for each tab and as such remains as a single instance linked to a specific tab via its id. So in this case, we actually want the provided id to be part of the TabPanel's generated id rather than the current selectedKey.


User Name is Case Sensitive

Should be case in sensitive. (Android Phone)

Seems like this is an industry standard, so we will do this. I don't believe this would produce any username conflicts right now, while our reach is still limited.
This is a server-side change. As server development is not publicly visible, this issue will be closed once the changes are made.


Indicator dismisses before releasing touch.

Thank you for such nice component!
This issue happens on my device galaxy S2, android 4.0.4. But everything is OK on my another device which runs 4.2.2.
Indicator pops up as soon as I touch it, and then dismisses quickly before I release or begin to drag.
I guess hideFloater was invoked by accident before my releasing. I debugged. It turns out that I'm wrong.
Any idea? Thank you.

Would you try to reproduce the issue using an emulator with 4.0.4 instead of a real device? Please report back, thanks!

I reproduced on an emulator. A bug indeed.

Thanks, I'll take a look into it.


Ability to bootstrap config off a queue

Currently, the spring config clients require a config server URL to bootstrap config from.
The config server can be made HA either by a loadbalancer or a discovery service.
Instead, if we load the config by making an RPC to an AMQP Exchange for configuration, then the config server becomes discoverable and elastic.

Discovery with AMQP is certainly an interesting idea, but I don't think it's specific to config server discovery. Maybe open a new issue in spring-cloud-commons until we can decide where to put it?


exact? can suggest autogenerated proof_1 constants

This is a regression from mathlib's exact? which got removed on the v4.7.0 version bump.
In certain situations, Lean autogenerates constants with names like proof_1 or proof_2. These are not intended to be visible to the end user, but exact? can sometimes suggest them, shadowing more canonical lemmas.
import Mathlib.Data.PNat.Basic

example (f : Nat → Nat) (a : Nat) (hae : f a = 0)
    (h : 0 < Nat.zero) : False := by
  exact?
-- Try this: exact PNat.caseStrongInductionOn.proof_1 h

If I comment out the mathlib import, then exact? gives me something more reasonable:
Try this: exact Nat.not_succ_le_zero 0 h

This is related to an old pull request: #2112. (I'm not sure whether that fix actually works for the current implementation of exact?.)

Here's an example that does not depend on any imports:
example (Person Topic : Type)
    (discusses : Person → Person → Topic)
    (discussion_sym : ∀ (p1 p2 : Person), discusses p1 p2 = discusses p2 p1)
    (p1 : Person) :
    let Person' : Type := { p2 // p2 ≠ p1 }
    ∀ t1 : Topic,
    ∀ α : Person' → Prop,
    let Topic' : Type := { t2 // t2 ≠ t1 }
    ∀ p3 p4 : { x // α x },
    ∀ h10 : discusses ↑↑p3 ↑↑p4 ≠ t1,
    ∀ h11 : discusses ↑↑p4 ↑↑p3 ≠ t1,
    let s1 : Topic' := { val := discusses ↑↑p3 ↑↑p4, property := h10 }
    let s2 : Topic' := { val := discusses ↑↑p4 ↑↑p3, property := h11 }
    s1 = s2 := by
 intro Person' t1 α Topic' p3 p4 h10 h11 s1 s2
 exact?
-- Try this: exact Subtype.instDecidableEqSubtype.proof_1 (discusses p3.val.val p4.val.val) h10
--  (discusses p4.val.val p3.val.val) h11 (discussion_sym p3.val.val p4.val.val)

I don't expect exact? to ever return a proof_1 term like that.
(This example was extracted from this line of code in-the-wild.)

This was closed by #3769.


[ttLib.tables.C_P_A_L] ValueError: invalid literal for int() with base 16: ''

Whenever I try to build my COLR/CPAL/GSUB font, it throws this error and crashes:
Parsing 'CPAL' table...
ERROR: Unhandled exception has occurred
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttx.py", line 389, in main
    process(jobs, options)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttx.py", line 363, in process
    action(input, output, options)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/misc/loggingTools.py", line 372, in wrapper
    return func(*args, **kwds)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttx.py", line 274, in ttCompile
    ttf.importXML(input)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttLib/__init__.py", line 374, in importXML
    reader.read()
  File "/usr/local/lib/python2.7/dist-packages/fontTools/misc/xmlReader.py", line 48, in read
    self._parseFile(self.file)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/misc/xmlReader.py", line 73, in _parseFile
    parser.Parse(chunk, 0)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/misc/xmlReader.py", line 141, in _endElementHandler
    self.currentTable.fromXML(name, attrs, content, self.ttFont)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttLib/tables/C_P_A_L_.py", line 212, in fromXML
    color.fromXML(element[0], element[1], element[2], ttFont)
  File "/usr/local/lib/python2.7/dist-packages/fontTools/ttLib/tables/C_P_A_L_.py", line 258, in fromXML
    self.green = int(value[2:4], 16)
ValueError: invalid literal for int() with base 16: ''

I am using version 3.20.1. I have tried other versions, but they throw the same error. Here's the full log: https://travis-ci.org/TheEssemCraft/twemoji-colr/builds/311894231

it seems like in the ttx file of your CPAL table there is some "color" element which contains an empty "value" attribute. The value of the color "value" attribute must be an hex string (optionally prefixed with #), from 6 to 8 digits: 2 for red, 2 for green, 2 for blue and optionally 2 for alpha.
Ensure none of the color values are empty and retry, thanks

either empty, or incomplete. I see it's crashing on the green, so it may be that it only has the first two digits for red, and lacks the other four for green and blue... just guessing

@anthrotype Would you mind telling me the index for this color element? Thanks.

I have no idea, sorry... you'll have to grep for it in your TTX file

What's a possible regex I could use for this? I'm bad at making them.

try something like
grep -Ern '<color .*value="#?[0-9A-Fa-f]+"' directorty/containing/*.ttx

or if you want to specify a specific number of hex digits, say minium 0, maximum 8, you could do
grep -Ern '<color .*value="#?[0-9A-Fa-f]{0,8}"' directorty/containing/*.ttx

Never mind, I figured it out by just looking through the code. Here's the culprit:
<color index="65" value="ff"/>

As you can see, the value is just ff. I looked through my layerizing javascript, and I think I found something:
function expandColor(c) {
    if (c == undefined) {
        return c;
    }
    c = c.toLowerCase();
    if (c == 'none') {
        return c;
    }
    if (c == 'red') {
        c = '#f00';
    } else if (c == 'green') {
        c = '#0f0';
    } else if (c == 'blue') {
        c = '#00f';
    }
    // c is a hex color that might be shorthand (3 instead of 6 digits)
    if (c.substr(0, 1) == '#' && c.length == 4) {
        c = '#' + c.substr(1, 1) + c.substr(1, 1)
                + c.substr(2, 1) + c.substr(2, 1)
                + c.substr(3, 1) + c.substr(3, 1);
    }
    return c + 'ff';
}

So something is wrong with c. Any ideas? Here's the full script: https://github.com/TheEssemCraft/twemoji-colr/blob/master/layerize.js

I don't have the time to debug your javascript. I can only point you to the code where fontTools parses the CPAL color element from the TTX file:
https://github.com/fonttools/fonttools/blob/f0e0954afc787d53c595a472c2346754c8f6f3d7/Lib/fontTools/ttLib/tables/C_P_A_L_.py#L253-L260
as you can see, it seems that (besides the optional leading # symbol) fonttools is expecting from 6 to 8 digits. The first three sets of digit pairs is for red green and blue. The fourth optional pair of digit is for the alpha and can be omitted.
So you have to make your script output colors in this format if you wish fonttools to be able to parse and compile it.

Ok. Thanks!


fix(utils): rename the arg field in params of utils#fullPayloadToAddr…

…ess to args
BREAKING CHANGE: The arg field in params of utils#fullPayloadToAddress is renamed to args

Codecov Report

Merging #451 into develop will not change coverage.
The diff coverage is 100.00%.

@@           Coverage Diff            @@
##           develop     #451   +/-   ##
========================================
  Coverage    90.69%   90.69%
========================================
  Files           28       28
  Lines         1171     1171
  Branches       273      273
========================================
  Hits          1062     1062
  Misses         108      108
  Partials         1        1

Impacted Files
Coverage Δ

packages/ckb-sdk-utils/src/address/index.ts
100.00% <100.00%> (ø)


Add a capabilities wrapper

This wrapper is given the CAP_NET_BIND_SERVICE capability so that it can
run Envoy with that bit set. This will let Envoy run on a low port as a
non privileged user.
Envoy needs to be able to inherit the capability, but I've verified that
this does not suffer from the same problem of not being able to run when
that capability is explicitly dropped.
In a separate PR I will update the entrypoint so that it calls the
wrapper if the capability is available, and Envoy otherwise

A few notes... I'll do the magic to use the wrapper or not depending on if the capabilities is available in another PR, but locally I yolo'ed the wrapper into the entrypoint and it works great:
bash-5.0$ netstat -anp | grep 80
tcp        0      0 <IP_ADDRESS>:8001          <IP_ADDRESS>:*               LISTEN      -
tcp        0      0 <IP_ADDRESS>:80              <IP_ADDRESS>:*               LISTEN      -

I also checked that if I drop the capability that Envoy still runs.
This might be because of my Go experience, but the x/sys module needed to be installed from git rather than whatever go mod does. The syscalls and structs for the capabilities are about 4 months old and the last release seems to be just over that.

@kflynn this is the one we were talking about on Slack.


Fix typo in CMake custom target / package names

arango instead of arongo
Does this affect any external scripts?

external scripts use make packaging and make packaging clean which only reference the targets in that list. so changing the name shouldn't have any effect, as long as every arongo is gone afterwards.
LGTM.


Telemetry Dashboard: Fix crash and add "cron job"

Review: @dcposch

Merging now, since site is down


[ntpcheck] support serverstats with ntpd 4.2.8+

Summary
Now we support server stats on ntpd just as well.
Test Plan
Ran the code on host with ntpd:
abulimov@u1804:~/go/src/github.com/facebookincubator/ntp/ntpcheck$ ./ntpcheck serverstats
{"ntp.server.packets_received":1966,"ntp.server.packets_dropped":24}

and chrony:
[root@chronyhost ~]# ./ntpchkng serverstats
{"ntp.server.packets_received":2875803805,"ntp.server.packets_dropped":0}


httpjson - support for headers

httpjson supports passing parameters, however it would be nice if it supported configuration of headers and setting them based on config similar to how the parameters are done
Looks like a new config section should be added, struct updated, and headers set at the req level with req.Header.Add(key, value)
Test update needed as well to cover this change

Should we provide headers on per server or per service base?
I guess, you want to use some kind of authorization headers. Thus every server needs its own headers.
This requires some breaking changes to configuration, i.e.:
[[httpjson.services]]
  name = "mycollector"

  [[httpjson.services.servers]]
    url = "http://my.service.com/_stats"
   # as yet another nested list
   [[httpjson.services.servers.headers]]
      "X-API-KEY" = "qwerty"

ping @sparrc

Correct me if I am wrong, but it looks as though it would be best to put it at a service level, not server. I assume you can define one service per JSON API, and differnt servers for similar API's in the cluster, just on differnt machines. If they are similar services, the headers should be treated the same (as the url parameters are). I there is a need to seperate headers per server, it probably should be a differnt service? Not sure.
[httpjson]
  [[httpjson.services]]
    name = "mycollector1"

    servers = [
      "http://my.service1.com/_stats"
    ]

    # HTTP method to use (case-sensitive)
    method = "GET"

   [httpjson.services.parameters]
     event_type = "cpu_spike"
     threshold = "0.75"

   [httpjson.services.headers]
     X-API-KEY = "abc-def-cba-fed"
     Y-Some-Header = "header value"

Closing since we ended up writing a custom plugin anyway. Headers would be nice, but it turned out we needed to do some very specific things with our software that probably do not appyl here.


Language Porting Info

Hey, I'm coming here from this product page http://www.adafruit.com/products/1115
Then to https://learn.adafruit.com/character-lcd-with-raspberry-pi-or-beaglebone-black/usage
And finally I'm here.  So this uses Python.  I'm going to add this to a ruby project, so I feel like I should use the ruby equivalent to this library to minimize the number of languages involved.  It seems as though the ruby equivalent doesn't exist yet though.  Correct me if I'm wrong, but to get the ruby equivelent I'd more or less just need to do a lot of copy and pasting (and do minor syntax editing) from this repo and also this Adafruit_Python_GPIO library https://github.com/adafruit/Adafruit_Python_GPIO and then call it a day, right?  It seems odd that I would be the first to do that, so maybe I'm missing something??  If any repo watchers know of other libraries involved in the i2c chip used in the LCD that I should know about, I'd love to hear about it, and maybe the extra link/info should go into one of the repos so others know.

Oh nice, thanks for checking out the library!  I don't know of a ruby version either, but if you implement one I'd be happy to mention it in the Raspberry Pi character LCD guide so folks might find it.
If it helps too you might not really have to port the whole Python GPIO library over to ruby.  That library is used as a layer to abstract away platform-specific GPIO libraries like RPi.GPIO on the Pi or BBIO on the BeagleBone Black.  If ruby only has a GPIO library for the Pi then you might not worry about porting over the Python GPIO library and instead just make a library with the same interface but that calls the appropriate ruby Pi GPIO library.  I'm not super familiar with what GPIO libraries are around for ruby but I bet you can find some good pointers to them from searching around.
Thanks for checking out the library and let me know if you do make a ruby version that Pi users can use too.


Update chart grafana to 8.5.4

This PR contains the following updates:

Package
Update
Change

grafana (source)
patch
8.5.3 -> 8.5.4

Release Notes

grafana/helm-charts (grafana)
v8.5.4
Compare Source
The leading tool for querying and visualizing time series and metrics.
What's Changed

[grafana] chore: bump k8s-sidecar to 1.28.0 by @mlflr in https://github.com/grafana/helm-charts/pull/3348

New Contributors

@mlflr made their first contribution in https://github.com/grafana/helm-charts/pull/3348

Full Changelog: https://github.com/grafana/helm-charts/compare/mimir-distributed-5.5.0...grafana-8.5.4

Configuration
📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.

[ ] If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

Edited/Blocked Notification
Renovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR.
You can manually request rebase by checking the rebase/retry box above.
⚠ Warning: custom changes will be lost.


extension issue

Does this occur consistently?
Repro steps:

Action: appService.Deploy
Error type: ENOTFOUND
Error Message: getaddrinfo ENOTFOUND redacted:url
Version: 0.24.8
OS: win32
OS Release: 10.0.19045
Product: Visual Studio Code
Product Version: 1.77.3
Language: en

Call Stack
ClientRequest.<anonymous> extension.bundle.js:2:1631436

Please add detailed steps to reproduce the issue.

This issue has been closed automatically because it needs more information and has not had recent activity. See also our issue reporting guidelines.
Happy Coding!


apk update error from latest alpine

Hi, I tried build docker image from alpine:latest (3.6)
My Dockerfile has asked for an update, but it does not work. See the logs below.
When I tried manually in the container using docker run -it, it works.
Step 1/4 : FROM alpine
 ---> 76da55c8019d
Step 2/4 : RUN apk update
 ---> Running in 95477bb69a71
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
ERROR: http://dl-cdn.alpinelinux.org/alpine/v3.6/main: temporary error (try again later)
WARNING: Ignoring APKINDEX.84815163.tar.gz: No such file or directory
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
v3.6.2-190-ga5d68c47df [http://dl-cdn.alpinelinux.org/alpine/v3.6/community]
1 errors; 2895 distinct packages available

So I tried build docker image with alpine:3.3
Finally building works like below logs.
Is it problem from version.
Step 1/4 : FROM alpine:3.3
3.3: Pulling from library/alpine
28db89afc758: Pull complete
Digest: sha256:ae4d16d132e3c93dd09aec45e4c13e9d75ca72e612d221b94fffe2f92de600d7
Status: Downloaded newer image for alpine:3.3
 ---> c1aae6fe9e10
Step 2/4 : RUN apk update
 ---> Running in f475604da9c4
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
v3.3.3-364-g44b88ac [http://dl-cdn.alpinelinux.org/alpine/v3.3/main]
v3.3.3-294-g70e4c85 [http://dl-cdn.alpinelinux.org/alpine/v3.3/community]
OK: 5860 distinct packages available

How many times did you try to build? This is usually a DNS issue somewhere.

This was helpful for me.


Code Quality: Introduced Directory.Build.props

You removed the global.json file?

The outdated one, sorry!


Community Operator Helm Chart should support imagePullSecrets

Describe the Issue
The community-operator helm chart should support imagePullSecrets, which it doesn't as of right now. The option to specify this can be helpful for usecases where a user has to pull an image from a private repo.
Chart Name
community-operator
PR Feature
https://github.com/mongodb/helm-charts/pull/211

Closed by https://github.com/mongodb/helm-charts/pull/211


evaluate endpoints are returning 503s.

e.g. https://www.scala-exercises.org/exercises/sections/cats/foldable/evaluate is unavailable.

I posted in gitter the service was restarted and it looks to be working. I'm currently updating all projects (including evaluator) and fix will be applied in the next days.

It looks good now. Should this be closed?

Thanks @davisharlan :+1:


vulnix: broken build 1.7.1 on macos

Issue description
Master build seems to be broken due to missing python dependency:
uilder for '/nix/store/clyykklxyh65mqvjm107s3s3b8q3h520-python3.6-persistent-4.4.2.drv' failed with exit code 1; last 10 log lines:
      import manuel.capture
  ModuleNotFoundError: No module named 'manuel'
  ----------------------------------------------------------------------
  Ran 517 tests in 1.195s
  FAILED (errors=3)
  Test failed: <unittest.runner.TextTestResult run=517 errors=3 failures=0>
  error: Test failed: <unittest.runner.TextTestResult run=517 errors=3 failures=0>
cannot build derivation '/nix/store/zvpd30bz641804wmgacpi4hbbc8ymn1l-python3.6-ZODB-5.4.0.drv': 1 dependencies couldn't be built
building '/nix/store/1fsgng6q21g8x0w4srp9c7j6anpc0hhw-pythonTools.drv'...
cannot build derivation '/nix/store/f9lg48sr8x8fbhqfihbgpz8vidzam1fb-vulnix-1.7.1.drv': 1 dependencies couldn't be built

cc @ckauhaus
Technical details
nix-info -m
 - system: `"x86_64-darwin"`
 - host os: `Darwin 17.7.0, macOS 10.13.6`
 - multi-user?: `yes`
 - sandbox: `no`
 - version: `nix-env (Nix) 2.0.4`
 - channels(root): `"nixpkgs-18.09pre149107.3878342ef02"`
 - nixpkgs: `/Users/USERNAME/projects/nix-config/nixpkgs

Same issue on all platforms, not just Darwin:
https://hydra.nixos.org/jobset/nixpkgs/trunk/jobs-tab?filter=vulnix

#46364 fixes the broken python dependency python36Packages.persistent, but now another python dependency fails. More work to do...

vulnix is only indirectly broken. python36Packages.BTrees is broken.
See here: https://hydra.nixos.org/build/81027209
Currently BTree does not build with python36 and python27.

@periklis: Looks like BTree has been fixed in the meantime. Please check if the bug is still relevant for you. I cannot reproduce the problem on current master or 18.09.

BTrees was fixed in #46588.

@ckauhaus & @xeji All fine on darwin again. Thanks for this remarkable piece of software. It is really an eye-opener when i can show people - hey look ma, we can have a list of all vulnerable software of a system/image/whatever in a shot.

Great, let's close it then.