1

I trained my yolov4 model on custom dataset, and it is giving me around 90-100% accuracy, great! But I want to convert the weights to TFlite because I need to do some detection task on edge device. But after I converted it to first TF weights and then TFLite weight, It outputs really random predictions as shown in the image below. The first image is from Darknet detection and second is from TFLite detection.

Darknet detection using the command:

!./darknet detector test data/obj.data cfg/yolov4-obj.cfg /content/drive/MyDrive/yolov4/backup/yolov4-obj_last.weights /content/drive/MyDrive/yolov4/test/t2.webp -thresh 0.3

enter image description here

Using TFLite weights: python detect.py

enter image description here

I don't know what is causing this. Also, I didn't ran into any errors while converting the darknet weights to tflite weights. Below are the scripts:

  1. save_model.py - Save custom yolov4 tf model for tflite converting

python save_model.py --weights ./data/custom.weights --output ./checkpoints/custom-416 --input_size 416 --model yolov4 --framework tflite

import tensorflow as tf
from absl import app, flags, logging
from absl.flags import FLAGS
from core.yolov4 import YOLO, decode, filter_boxes
import core.utils as utils
from core.config import cfg

flags.DEFINE_string('weights', './data/yolov4.weights', 'path to weights file')
flags.DEFINE_string('output', './checkpoints/yolov4-416', 'path to output')
flags.DEFINE_boolean('tiny', False, 'is yolo-tiny or not')
flags.DEFINE_integer('input_size', 416, 'define input size of export model')
flags.DEFINE_float('score_thres', 0.2, 'define score threshold')
flags.DEFINE_string('framework', 'tf', 'define what framework do you want to convert (tf, trt, tflite)')
flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4')

def save_tf():
  STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config()

  input_layer = tf.keras.layers.Input([FLAGS.input_size, FLAGS.input_size, 3])
  feature_maps = YOLO(input_layer, NUM_CLASS, FLAGS.model, FLAGS.tiny)
  bbox_tensors = []
  prob_tensors = []
  if FLAGS.tiny:
    for i, fm in enumerate(feature_maps):
      if i == 0:
        output_tensors = decode(fm, FLAGS.input_size // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework)
      else:
        output_tensors = decode(fm, FLAGS.input_size // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework)
      bbox_tensors.append(output_tensors[0])
      prob_tensors.append(output_tensors[1])
  else:
    for i, fm in enumerate(feature_maps):
      if i == 0:
        output_tensors = decode(fm, FLAGS.input_size // 8, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework)
      elif i == 1:
        output_tensors = decode(fm, FLAGS.input_size // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework)
      else:
        output_tensors = decode(fm, FLAGS.input_size // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework)
      bbox_tensors.append(output_tensors[0])
      prob_tensors.append(output_tensors[1])
  pred_bbox = tf.concat(bbox_tensors, axis=1)
  pred_prob = tf.concat(prob_tensors, axis=1)
  if FLAGS.framework == 'tflite':
    pred = (pred_bbox, pred_prob)
  else:
    boxes, pred_conf = filter_boxes(pred_bbox, pred_prob, score_threshold=FLAGS.score_thres, input_shape=tf.constant([FLAGS.input_size, FLAGS.input_size]))
    pred = tf.concat([boxes, pred_conf], axis=-1)
  model = tf.keras.Model(input_layer, pred)
  utils.load_weights(model, FLAGS.weights, FLAGS.model, FLAGS.tiny)
  model.summary()
  model.save(FLAGS.output)

def main(_argv):
  save_tf()

if __name__ == '__main__':
    try:
        app.run(main)
    except SystemExit:
        pass
  1. python convert2tflite.py - Now, convert the above yolov4 tf model to tflite weights.
import tensorflow as tf
from absl import logging
import numpy as np

def save_tflite(model_path, tf_weights_path, quantize_mode='float16'):
  converter = tf.lite.TFLiteConverter.from_saved_model(tf_weights_path)
  tflite_model = converter.convert()
  open(model_path, 'wb').write(tflite_model)

  logging.info("model saved to: {}".format(model_path))

def demo(model_path):
  interpreter = tf.lite.Interpreter(model_path=model_path)
  interpreter.allocate_tensors()
  logging.info('tflite model loaded')

  input_details = interpreter.get_input_details()
  print(input_details)
  output_details = interpreter.get_output_details()
  print(output_details)

  input_shape = input_details[0]['shape']

  input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32)

  interpreter.set_tensor(input_details[0]['index'], input_data)
  interpreter.invoke()
  output_data = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))]

  print(output_data)

def main():
  save_tflite(
    tf_weights_path='./checkpoints/anpr-416',
    model_path='./checkpoints/anpr-416.tflite'
  )
  demo(model_path='./checkpoints/anpr-416.tflite')

if __name__ == '__main__':
    try:
        main()
    except SystemExit:
        pass

If anyone could give any insights, I would really appreciate it! Thank you!

dev1ce
  • 1,419
  • 1
  • 19
  • 39
  • It seems OK (except for the paths "anpr-416" of the model but I presume they are OK also). You have to show the inference for the model and the tflite model to see what is going wrong. Because at the conversion to .tflite you are doing: `input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32)` meaning you are passing random values. – Farmaker Aug 10 '21 at 08:06
  • @Farmaker Hey, thanks for answering, I solved the problem! I've posted an answer! And also, the line `np.array(np.random.random_sample(input_shape), dtype=np.float32)` was just for a demo purpose as can you see the name of the function `demo()`. – dev1ce Aug 10 '21 at 08:14

1 Answers1

2

Okay so, What I did wrong was, I didn't change the classes names in obj.names file while converting to TF model, which is located inside core/config.py, So after making the required changes in obj.names file inside core/config.py, I was able to make the correct detections now!

enter image description here

dev1ce
  • 1,419
  • 1
  • 19
  • 39