gmalivenko / pytorch2keras

PyTorch to Keras model convertor
https://pytorch2keras.readthedocs.io/en/latest/
MIT License
857 stars 143 forks source link

converts torch model with dtype double (float64) to keras with float32 #140

Open HarHarLinks opened 2 years ago

HarHarLinks commented 2 years ago

I don't know whether this issue is actually with this project (the "pytorch2onnx" part) or rather onnx2keras. Please move it if applicable.


Describe the bug I'm trying to convert a model that uses double (float64) datatype throughout, it looks like this, created with torch.jit.script.

graph(%input_0 : Double(1, 2, strides=[2, 1], requires_grad=0, device=cpu),
      %layers.0.weight : Double(100, 2, strides=[2, 1], requires_grad=0, device=cpu),
      %layers.0.bias : Double(100, strides=[1], requires_grad=0, device=cpu),
      %layers.2.weight : Double(100, 100, strides=[100, 1], requires_grad=0, device=cpu),
      %layers.2.bias : Double(100, strides=[1], requires_grad=0, device=cpu),
      %layers.4.weight : Double(2, 100, strides=[100, 1], requires_grad=0, device=cpu),
      %layers.4.bias : Double(2, strides=[1], requires_grad=0, device=cpu)):
  %7 : Double(1, 100, strides=[100, 1], device=cpu) = onnx::Gemm[alpha=1., beta=1., transB=1](%input_0, %layers.0.weight, %layers.0.bias) # python3.7/site-packages/torch/nn/functional.py:1848:11
  %8 : Double(1, 100, strides=[100, 1], device=cpu) = onnx::Relu(%7) # python3.7/site-packages/torch/nn/functional.py:1299:17
  %9 : Double(1, 100, strides=[100, 1], device=cpu) = onnx::Gemm[alpha=1., beta=1., transB=1](%8, %layers.2.weight, %layers.2.bias) # python3.7/site-packages/torch/nn/functional.py:1848:11
  %10 : Double(1, 100, strides=[100, 1], device=cpu) = onnx::Relu(%9) # python3.7/site-packages/torch/nn/functional.py:1299:17
  %output_0 : Double(1, 2, strides=[2, 1], requires_grad=0, device=cpu) = onnx::Gemm[alpha=1., beta=1., transB=1](%10, %layers.4.weight, %layers.4.bias) # python3.7/site-packages/torch/nn/functional.py:1848:11
  return (%output_0)
DEBUG:onnx2keras:Output TF Layer -> KerasTensor(type_spec=TensorSpec(shape=(None, 100), dtype=tf.float32, name=None), name='7/BiasAdd:0', description="created by layer '7'")
DEBUG:onnx2keras:Output TF Layer -> KerasTensor(type_spec=TensorSpec(shape=(None, 100), dtype=tf.float32, name=None), name='8/Relu:0', description="created by layer '8'")
DEBUG:onnx2keras:Output TF Layer -> KerasTensor(type_spec=TensorSpec(shape=(None, 100), dtype=tf.float32, name=None), name='9/BiasAdd:0', description="created by layer '9'")
DEBUG:onnx2keras:Output TF Layer -> KerasTensor(type_spec=TensorSpec(shape=(None, 100), dtype=tf.float32, name=None), name='10/Relu:0', description="created by layer '10'")
DEBUG:onnx2keras:Output TF Layer -> KerasTensor(type_spec=TensorSpec(shape=(None, 2), dtype=tf.float32, name=None), name='output_0/BiasAdd:0', description="created by layer 'output_0'")

Expected behavior double -> double

Script

    # 1) load PyTorch model
    model = torch.jit.load(args.torch)

    # 2) create dummy variable with correct shape
    shape = (2)
    input_np = np.random.uniform(low=0, high=1, size=(1,2))
    input_var = Variable(torch.DoubleTensor(input_np))

    # 3) trace the model using dummy variable
    k_model = pytorch_to_keras(model, input_var, [shape], verbose=True)

    # 4) save keras (Tensorflow format) model
    # https://www.tensorflow.org/guide/keras/save_and_serialize#how_to_save_and_load_a_model
    k_model.save(args.keras)
HarHarLinks commented 2 years ago

I was able to overcome this by this method: https://stackoverflow.com/questions/47895494/how-to-convert-all-layers-of-a-pretrained-keras-model-to-a-different-dtype-from

i.e. since my model uses only float64, I changed converter.py of onnx2keras thusly:

@@ -3,6 +3,7 @@
 """

 from tensorflow import keras
+from tensorflow.keras import backend as K
 import logging
 import inspect
 import collections
@@ -48,6 +49,8 @@
     :param change_ordering: change ordering to HWC (experimental)
     :return: Keras model
     """
+    K.set_floatx('float64')
+
     # Use channels first format by default.
     keras_fmt = keras.backend.image_data_format()
     keras.backend.set_image_data_format('channels_first')

However I'm posting this here merely as a hardcoded workaround, so this still should be addressed properly by someone who actually understands how the converter works.