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.
Вопросы:
- Должен ли я адаптировать метод квантования для изменения входного dtype? или
- Do I have to change the input layer of the model to dtype int8 beforehand?
- 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