softmax_settings.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # SPDX-FileCopyrightText: Copyright 2010-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
  2. #
  3. # SPDX-License-Identifier: Apache-2.0
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the License); you may
  6. # not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an AS IS BASIS, WITHOUT
  13. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. import math
  18. from test_settings import TestSettings
  19. import tensorflow as tf
  20. import tf_keras as keras
  21. class SoftmaxSettings(TestSettings):
  22. softmax_input_integer_bits = 5
  23. def __init__(self,
  24. dataset,
  25. testtype,
  26. regenerate_weights,
  27. regenerate_input,
  28. regenerate_biases,
  29. schema_file,
  30. x_in=5,
  31. y_in=1,
  32. randmin=TestSettings.INT8_MIN,
  33. randmax=TestSettings.INT8_MAX,
  34. int16xint8=False,
  35. inInt8outInt16=False,
  36. input_scale=0.003922,
  37. input_zp=-128,
  38. interpreter="tensorflow"):
  39. super().__init__(dataset,
  40. testtype,
  41. regenerate_weights,
  42. regenerate_input,
  43. regenerate_biases,
  44. schema_file,
  45. 1,
  46. 1,
  47. x_in,
  48. y_in,
  49. 1,
  50. 1,
  51. 1,
  52. 1,
  53. False,
  54. randmin,
  55. randmax,
  56. int16xint8=int16xint8,
  57. interpreter=interpreter)
  58. self.x_input = self.x_output = x_in
  59. self.y_input = self.y_output = y_in
  60. self.inInt8outInt16 = inInt8outInt16
  61. if self.inInt8outInt16 and self.is_int16xint8:
  62. raise RuntimeError("Specify input as either s8 or s16")
  63. if self.inInt8outInt16:
  64. self.input_scale = input_scale
  65. self.json_template = "TestCases/Common/Softmax/softmax_int8_to_int16_template.json"
  66. self.json_replacements = {
  67. "num_rows": self.y_input,
  68. "row_size": self.x_input,
  69. "input_scale": input_scale,
  70. "input_zp": input_zp
  71. }
  72. def calc_softmax_params(self):
  73. if self.is_int16xint8:
  74. input_scale_beta_rescale = self.input_scale / (10.0 / 65535.0)
  75. (self.input_multiplier, self.input_left_shift) = self.quantize_scale(input_scale_beta_rescale)
  76. else:
  77. input_real_multiplier = min(self.input_scale * (1 << (31 - self.softmax_input_integer_bits)), (1 << 31) - 1)
  78. (self.input_multiplier, self.input_left_shift) = self.quantize_scale(input_real_multiplier)
  79. self.diff_min = ((1 << self.softmax_input_integer_bits) - 1) * \
  80. (1 << (31 - self.softmax_input_integer_bits)) / \
  81. (1 << self.input_left_shift)
  82. self.diff_min = math.floor(self.diff_min)
  83. def write_c_config_header(self) -> None:
  84. super().write_c_config_header(write_common_parameters=False)
  85. filename = self.config_data
  86. filepath = self.headers_dir + filename
  87. prefix = self.testdataset.upper()
  88. with open(filepath, "a") as f:
  89. f.write("#define {}_NUM_ROWS {}\n".format(prefix, self.y_input))
  90. f.write("#define {}_ROW_SIZE {}\n".format(prefix, self.x_input))
  91. f.write("#define {}_INPUT_MULT {}\n".format(prefix, self.input_multiplier))
  92. f.write("#define {}_INPUT_LEFT_SHIFT {}\n".format(prefix, self.input_left_shift))
  93. if not self.is_int16xint8:
  94. f.write("#define {}_DIFF_MIN {}\n".format(prefix, -self.diff_min))
  95. f.write("#define {}_DST_SIZE {}\n".format(prefix, self.x_output * self.y_output))
  96. def get_softmax_randomized_input_data(self, input_data, input_shape):
  97. # Generate or load saved input data unless hardcoded data provided.
  98. if input_data is not None:
  99. input_data = tf.reshape(input_data, input_shape)
  100. else:
  101. input_data = self.get_randomized_data(input_shape,
  102. self.inputs_table_file,
  103. regenerate=self.regenerate_new_input)
  104. return input_data
  105. def generate_data(self, input_data=None, weights=None, biases=None) -> None:
  106. input_data = self.get_softmax_randomized_input_data(input_data, [self.y_input, self.x_input])
  107. if self.is_int16xint8:
  108. inttype = tf.int16
  109. datatype = "int16_t"
  110. else:
  111. inttype = tf.int8
  112. datatype = "int8_t"
  113. self.generate_c_array(self.input_data_file_prefix, input_data, datatype=datatype)
  114. # Generate reference.
  115. if self.inInt8outInt16:
  116. # Output is int16.
  117. datatype = "int16_t"
  118. # Keras does not support int8 input and int16 output for Softmax.
  119. # Using a template json instead.
  120. generated_json = self.generate_json_from_template()
  121. self.flatc_generate_tflite(generated_json, self.schema_file)
  122. interpreter = self.Interpreter(model_path=str(self.model_path_tflite),
  123. experimental_op_resolver_type=self.OpResolverType.BUILTIN_REF)
  124. interpreter.allocate_tensors()
  125. all_layers_details = interpreter.get_tensor_details()
  126. input_layer = all_layers_details[0]
  127. output_layer = all_layers_details[1]
  128. interpreter.set_tensor(input_layer["index"], tf.cast(input_data, tf.int8))
  129. interpreter.invoke()
  130. output_data = interpreter.get_tensor(output_layer["index"])
  131. else:
  132. # Create a one-layer Keras model.
  133. model = keras.models.Sequential()
  134. input_shape = (self.y_input, self.x_input)
  135. model.add(keras.layers.Softmax(input_shape=input_shape))
  136. interpreter = self.convert_and_interpret(model, inttype, tf.expand_dims(input_data, axis=0))
  137. output_details = interpreter.get_output_details()
  138. interpreter.invoke()
  139. output_data = interpreter.get_tensor(output_details[0]["index"])
  140. self.calc_softmax_params()
  141. self.generate_c_array(self.output_data_file_prefix, output_data, datatype=datatype)
  142. self.write_c_config_header()
  143. self.write_c_header_wrapper()