При попытке реализовать модель tenorflow lite в Android studio, я получаю ошибку несовместимых типов данных - PullRequest
1 голос
/ 30 апреля 2020

Я построил простую многоклассовую классификационную модель тензорного потока в python, используя последовательные керасы. И сейчас я пытаюсь запустить эту модель в Android studio, но я получаю следующую ошибку в Android studio.

java.lang.IllegalArgumentException: Cannot convert between a TensorFlowLite tensor with type INT64 and a Java object of type [[F (which is compatible with the TensorFlowLite type FLOAT32).

Сначала я вставлю код google colab notebook, который использовал для создания модель. По существу, есть две входные переменные (2 целых числа), и модель затем классифицирует вероятность получения 171 различных классов на основе этих 2 входных переменных. Затем я включу код java, используемый в студии android для запуска модели tflite.

Это код python, используемый для построения модели классификации

import io
df = pd.read_csv(io.BytesIO(data_to_load['species_by_location_v4.csv']))

# CREATE X ARRAY
# This is the array containing the explanatory variables (in this case pentad and month)

loc_array = df.iloc[:, 1:3]
print(loc_array)

# create y array (classes to be predicted)

label_array = df.iloc[:, 4]

# get number of distinct classes and convert y array to consecutive integers from 0 to 170 (y_true)

raw_y_true = label_array
mapping_to_numbers = {}
y_true = np.zeros((len(raw_y_true)))
for i, raw_label in enumerate(raw_y_true):
    if raw_label not in mapping_to_numbers:
        mapping_to_numbers[raw_label] = len(mapping_to_numbers)
    y_true[i] = mapping_to_numbers[raw_label]
print(y_true)
# [0. 1. 2. 3. 1. 2.]
print(mapping_to_numbers)

# get number of distinct classes

num_classes = len(mapping_to_numbers)
print(num_classes)


# create simple model

model = tf.keras.Sequential([
  tf.keras.layers.Dense(num_classes, activation='softmax')
])

# compile model

model.compile(
    optimizer = 'adam',
    loss='sparse_categorical_crossentropy', 
    metrics=['accuracy']
)

# train model

history = model.fit(loc_array, y_true, epochs=500, verbose=False)
print('finished')

# create labels file

labels = '\n'.join(mapping_to_numbers.keys())

with open('labels_locmth.txt', 'w') as f:
  f.write(labels)

!cat labels.txt

# convert to tflite

saved_model_dir = 'save/fine_tuning'
tf.saved_model.save(model, saved_model_dir)

converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
tflite_model = converter.convert()

with open('model_locmth.tflite', 'wb') as f:
  f.write(tflite_model)


В python я могу использовать следующий код для запуска прогноза с использованием модели. Он просто требует 2 целочисленных значения в качестве входных переменных, в данном случае 63669 и 2.

temp = {'pentad_unique_key': [63669], 'mth': [2] }
test_x = pd.DataFrame(temp, columns = ['pentad_unique_key', 'mth'])
result = model.predict(test_x, batch_size=None, verbose=0, steps=None)

Теперь в Android studio я использую следующий код, чтобы попытаться запустить модель. Я пытаюсь передать ему те же два целых числа, что и в коде python выше. В заключительной строке я получаю сообщение об ошибке выше.

float[][] inputVal = new float[1][2];
inputVal[0][0] = 63669;
inputVal[0][1] = 2;

float[][] outputs = new float[1][171];

tflite.run(inputVal, outputs);

Вот как я создаю объект tflite

try{
   tflite = new Interpreter(loadModelFile());
   labelList = loadLabelList();
} catch (Exception ex) {
   ex.printStackTrace();
}

Вот метод loadModelFile

private MappedByteBuffer loadModelFile() throws IOException {

    // Open the model using an input stream and memory map it to load
    AssetFileDescriptor fileDescriptor = this.getAssets().openFd("model_locmth.tflite");
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
    FileChannel fileChannel = inputStream.getChannel();
    long startOffset = fileDescriptor.getStartOffset();
    long declaredLength = fileDescriptor.getDeclaredLength();
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);

}

У меня такое ощущение, что проблема в том, что связано с массивом inputVal?

1 Ответ

1 голос
/ 04 мая 2020

Как упоминалось ранее, я думаю, что проблема связана с вводом dtype y_true. когда вы создаете y_true как

y_true = np.zeros((len(raw_y_true)))

, он будет показывать dtype как np.int64, как это было по умолчанию для dtype.
Модели tflite могут работать с float32 (не int64 или float64), как упоминалось в ошибка, поэтому вам нужно определить y_true как

y_true = np.zeros((len(raw_y_true)),dtype=np.float32)

Итак, я изменил только приведенную выше строку в следующем разделе кода

label_array = df.iloc[:, 4]

raw_y_true = label_array
mapping_to_numbers = {}
y_true = np.zeros((len(raw_y_true)),dtype=np.float32)
for i, raw_label in enumerate(raw_y_true):
    if raw_label not in mapping_to_numbers:
        mapping_to_numbers[raw_label] = len(mapping_to_numbers)
    y_true[i] = mapping_to_numbers[raw_label]
print(y_true)
# [0. 1. 2. 3. 1. 2.]
print(mapping_to_numbers)

print(np.argmax(result)) # 122

Одно из предложений заключается в использовании операций тензорного потока в код, где когда-либо это возможно. Например, вместо np.zeros, используйте tf.zeros et c.

Ранее у меня была похожая ошибка для простой модели, где я использовал float64. Полный код этой модели и ошибки вы можете увидеть здесь . Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...