🤪

TensorFlow Lite への acos (アークコサイン) の近似計算実装

2021/09/21に公開

acos が TensorFlow Lite に実装されていなかったので、 C の実装を Python + TensorFlow へ置き換えて擬似的に再現する。

float acos(float x) {
  float negate = float(x < 0);
  x = abs(x);
  float ret = -0.0187293;
  ret = ret * x;
  ret = ret + 0.0742610;
  ret = ret * x;
  ret = ret - 0.2121144;
  ret = ret * x;
  ret = ret + 1.5707288;
  ret = ret * sqrt(1.0-x);
  ret = ret - 2 * negate * ret;
  return negate * 3.14159265358979 + ret;
}
import tensorflow as tf
import numpy as np

# TensorFlow #########################################################
# x = tf.constant(0.70710678118655) # cos45 = 0.70710678118655 = x
x = tf.constant(-0.5) # cos120 = -0.5 = x

# neg = tf.math.divide(tf.math.multiply(tf.minimum(x, 0), -1), tf.abs(x))
# OAK-D (MyriadX) へ対応させるためあえてtf.abs()非使用
x_abs = tf.math.sqrt(tf.math.square(x))
neg = tf.math.divide(tf.math.multiply(tf.minimum(x, 0), -1), x_abs)
x = x_abs
y = tf.constant(-0.0187293)
y = tf.math.multiply(y, x)
y = tf.math.add(y, 0.0742610)
y = tf.math.multiply(y, x)
y = tf.math.subtract(y, 0.2121144)
y = tf.math.multiply(y, x)
y = tf.math.add(y, 1.5707288)
y = tf.math.multiply(y, tf.sqrt(tf.math.subtract(1.0, x)))
y = tf.math.multiply(y, tf.math.subtract(1.0, tf.math.multiply(2.0, neg)))
acos = tf.math.add(tf.math.multiply(neg, 3.14159265358979), y)
print(f'x: {x}')
print(f'neg: {neg}')
print(f'y: {y}')
print(f'acos: {acos}')
print(f'θ: {180 * acos / 3.14159265358979}')


# TensorFlow Lite ####################################################
i = tf.keras.layers.Input(shape=[1], dtype=tf.float32)
# neg = tf.math.divide(tf.math.multiply(tf.minimum(i, 0), -1), tf.abs(i))
# OAK-D (MyriadX) へ対応させるためあえてtf.abs()非使用
x_abs = tf.math.sqrt(tf.math.square(i))
neg = tf.math.divide(tf.math.multiply(tf.minimum(i, 0), -1), x_abs)
x = x_abs
y = tf.constant(-0.0187293)
y = tf.math.multiply(y, x)
y = tf.math.add(y, 0.0742610)
y = tf.math.multiply(y, x)
y = tf.math.subtract(y, 0.2121144)
y = tf.math.multiply(y, x)
y = tf.math.add(y, 1.5707288)
y = tf.math.multiply(y, tf.sqrt(tf.math.subtract(1.0, x)))
y = tf.math.multiply(y, tf.math.subtract(1.0, tf.math.multiply(2.0, neg)))
acos = tf.math.add(tf.math.multiply(neg, 3.14159265358979), y)

model = tf.keras.models.Model(inputs=i, outputs=acos)
model.summary()
output_path = 'saved_model'
tf.saved_model.save(model, output_path)
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS,
    tf.lite.OpsSet.SELECT_TF_OPS
]
tflite_model = converter.convert()
open(f"{output_path}/test.tflite", "wb").write(tflite_model)

interpreter = tf.lite.Interpreter(
    model_path='saved_model/test.tflite',
    num_threads=4
)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
interpreter.set_tensor(
    input_details[0]['index'],
    np.asarray([[-0.5]]).astype(np.float32)
)
interpreter.invoke()
output_details = interpreter.get_output_details()
res = interpreter.get_tensor(output_details[0]['index'])[0][0]
print(f'TFLite acos: {res}')
print(f'TFLite θ: {180 * res / 3.14159265358979}')
x   : 0.5
neg : 1.0
y   : -1.0471513271331787
acos: 2.0944414138793945
θ   : 120.00264739990234

TFLite acos: 2.0944414138793945
TFLite θ: 120.00265345270219

acos

https://keisan.casio.jp/exec/system/1260261251

https://keisan.casio.jp/exec/system/1260315699

https://developer.download.nvidia.com/cg/acos.html

https://developer.download.nvidia.com/cg/atan.html

https://developer.download.nvidia.com/cg/atan2.html

https://developer.download.nvidia.com/cg/asin.html

  • Atan / Atan2 の置き換え検討
eps = 1e-6

t3 = 5.0
y = -1.0
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
-5.0

t3 = 5.0
y = 1.0
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
5.0

t3 = 5.0
y = 0.0
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
5.0

t3 = 5.0
y = -1e-16
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
-0.0

t3 = 5.0
y = -1e-8
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
-5.0

t3 = 5.0
y = -1e-9
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
-0.0

t3 = 5.0
y = 1e-9
t3 = t3 * tf.math.ceil(y / (tf.math.sqrt(y*y)+eps) + eps)
-0.0


t3 = 5.0
y = -1e-9
tf.where(tf.math.less(y, 0), t3 * -1, t3)

Discussion