tflite квантование как изменить входной dtype

см. возможное решение в конце сообщения


Я пытаюсь полностью квантовать модель keras-vggface из rcmalli для запуска на NPU. Модель - это модель Keras (не tf.keras).

При использовании TF 1.15 для квантования с:

print(tf.version.VERSION)
num_calibration_steps=5

converter = tf.lite.TFLiteConverter.from_keras_model_file('path_to_model.h5')        

#converter.post_training_quantize = True  # This only makes the weight in8 but does not initialize model quantization  
def representative_dataset_gen():
    for _ in range(num_calibration_steps):
        pfad='path_to_image(s)'
        img=cv2.imread(pfad)
        # Get sample input data as a numpy array in a method of your choosing.
        yield [img]
converter.representative_dataset = representative_dataset_gen
tflite_quant_model = converter.convert()
open("quantized_model", "wb").write(tflite_quant_model)

Модель преобразована, но, поскольку мне нужно полное квантование int8, я добавляю:

converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8

Появляется это сообщение об ошибке:

ValueError: невозможно установить тензор: получено значение типа UINT8, но ожидаемый тип FLOAT32 для входа 0, имя: input_1

очевидно, что для ввода модели по-прежнему требуется float32.

Вопросы:

  1. Должен ли я адаптировать метод квантования для изменения входного dtype? или
  2. Do I have to change the input layer of the model to dtype int8 beforehand?
  3. Or is that actually reporting that the model is not actually quantized?

If 1 or 2 is the answer, would you also have a best practice tip for me?


Addition:

Using:

h5_path = 'my_model.h5'
model = keras.models.load_model(h5_path)
model.save(os.getcwd() +'/modelTF2') 

to save the h5 as pb with TF 2.2 and then using converter=tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)

as TF 2.x tflite takes floats, and convert them to uint8s internally. I thought that could be a solution. Unfortunately, this error message appears:

tf.lite.TFLiteConverter.from_keras_model giving 'str' object has no attribute 'call'

Apparently TF2.x cannot handle pure keras models.

using tf.compat.v1.lite.TFLiteConverter.from_keras_model_file() to solve this error just repeats the error from above, as we are back again at "TF 1.15" level.


Addition 2

Другое решение - вручную перенести модель keras в tf.keras. Я займусь этим, если не будет другого решения.


Относительно комментария Мегхна Натрадж

Чтобы воссоздать модель (используя TF 1.13.x), просто:

pip install git+https://github.com/rcmalli/keras-vggface.git

а также

from keras_vggface.vggface import VGGFace   
pretrained_model = VGGFace(model='resnet50', include_top=False, input_shape=(224, 224, 3), pooling='avg')  # pooling: None, avg or max
pretrained_model.summary()
pretrained_model.save("my_model.h5") #using h5 extension

Входной слой подключен. Жаль, это выглядело как хорошее / простое решение.


Возможное решение

Кажется, работает с TF 1.15.3. Я раньше использовал 1.15.0. Я проверю, не сделал ли я случайно что-то другое.

2 ответа

Возможная причина, по которой это не удается, состоит в том, что модель имеет входные тензоры, которые не связаны с выходным тензором, т.е. они, вероятно, не используются.

Вот блокнот colab, где я воспроизвел эту ошибку. Изменитеio_type в начале тетради к tf.uint8 чтобы увидеть ошибку, аналогичную той, которую вы получили.

РЕШЕНИЕ

Вам нужно вручную проверить модель и увидеть, есть ли какие-либо входы, которые болтаются / потеряны / не подключены к выходу, и удалить их.

Разместите ссылку на модель, и я тоже могу попробовать ее отладить.

Этот:

      def representative_data_gen():
  for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
    # Model has only one input so each data point has one element.
    yield [input_value]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen

tflite_model_quant = converter.convert()

генерирует модель Float32 с входными и выходными данными Float32. Этот:

      def representative_data_gen():
  for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
    yield [input_value]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen
# Ensure that if any ops can't be quantized, the converter throws an error
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
# Set the input and output tensors to uint8 (APIs added in r2.3)
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8

tflite_model_quant = converter.convert()

генерирует модель UINT8 с входами и выходами UINT8

Убедиться в этом можно следующим образом:

      interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)
input_type = interpreter.get_input_details()[0]['dtype']
print('input: ', input_type)
output_type = interpreter.get_output_details()[0]['dtype']
print('output: ', output_type)

который возвращает:

      input:  <class 'numpy.uint8'>
output:  <class 'numpy.uint8'>

если вы выбрали полное квантование UINT8. Вы можете дважды проверить это, визуально осмотрев свою модель, используяnetron

Другие вопросы по тегам