diff --git a/examples/vision/captcha_ocr.py b/examples/vision/captcha_ocr.py index 3a2b8e9627..a6bac599ff 100644 --- a/examples/vision/captcha_ocr.py +++ b/examples/vision/captcha_ocr.py @@ -2,9 +2,10 @@ Title: OCR model for reading Captchas Author: [A_K_Nain](https://twitter.com/A_K_Nain) Date created: 2020/06/14 -Last modified: 2020/06/26 +Last modified: 2024/03/13 Description: How to implement an OCR model using CNNs, RNNs and CTC loss. Accelerator: GPU +Converted to Keras 3 by: [Sitam Meur](https://github.com/sitamgithub-MSIT) """ """ @@ -26,7 +27,6 @@ os.environ["KERAS_BACKEND"] = "tensorflow" -import os import numpy as np import matplotlib.pyplot as plt @@ -35,6 +35,7 @@ import tensorflow as tf import keras +from keras import ops from keras import layers """ @@ -109,9 +110,9 @@ def split_data(images, labels, train_size=0.9, shuffle=True): # 1. Get the total size of the dataset size = len(images) # 2. Make an indices array and shuffle it, if required - indices = np.arange(size) + indices = ops.arange(size) if shuffle: - np.random.shuffle(indices) + keras.random.shuffle(indices) # 3. Get the size of training samples train_samples = int(size * train_size) # 4. Split data into training and validation sets @@ -132,10 +133,10 @@ def encode_single_sample(img_path, label): # 3. Convert to float32 in [0, 1] range img = tf.image.convert_image_dtype(img, tf.float32) # 4. Resize to the desired size - img = tf.image.resize(img, [img_height, img_width]) + img = ops.image.resize(img, [img_height, img_width]) # 5. Transpose the image because we want the time # dimension to correspond to the width of the image. - img = tf.transpose(img, perm=[1, 0, 2]) + img = ops.transpose(img, axes=[1, 0, 2]) # 6. Map the characters in label to numbers label = char_to_num(tf.strings.unicode_split(label, input_encoding="UTF-8")) # 7. Return a dict as our model is expecting two inputs @@ -184,13 +185,15 @@ def encode_single_sample(img_path, label): def ctc_batch_cost(y_true, y_pred, input_length, label_length): - label_length = tf.cast(tf.squeeze(label_length, axis=-1), tf.int32) - input_length = tf.cast(tf.squeeze(input_length, axis=-1), tf.int32) - sparse_labels = tf.cast(ctc_label_dense_to_sparse(y_true, label_length), tf.int32) + label_length = ops.cast(ops.squeeze(label_length, axis=-1), dtype="int32") + input_length = ops.cast(ops.squeeze(input_length, axis=-1), dtype="int32") + sparse_labels = ops.cast( + ctc_label_dense_to_sparse(y_true, label_length), dtype="int32" + ) - y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon()) + y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon()) - return tf.expand_dims( + return ops.expand_dims( tf.compat.v1.nn.ctc_loss( inputs=y_pred, labels=sparse_labels, sequence_length=input_length ), @@ -199,41 +202,43 @@ def ctc_batch_cost(y_true, y_pred, input_length, label_length): def ctc_label_dense_to_sparse(labels, label_lengths): - label_shape = tf.shape(labels) - num_batches_tns = tf.stack([label_shape[0]]) - max_num_labels_tns = tf.stack([label_shape[1]]) + label_shape = ops.shape(labels) + num_batches_tns = ops.stack([label_shape[0]]) + max_num_labels_tns = ops.stack([label_shape[1]]) def range_less_than(old_input, current_input): - return tf.expand_dims(tf.range(tf.shape(old_input)[1]), 0) < tf.fill( + return ops.expand_dims(ops.arange(ops.shape(old_input)[1]), 0) < tf.fill( max_num_labels_tns, current_input ) - init = tf.cast(tf.fill([1, label_shape[1]], 0), tf.bool) + init = ops.cast(tf.fill([1, label_shape[1]], 0), dtype="bool") dense_mask = tf.compat.v1.scan( range_less_than, label_lengths, initializer=init, parallel_iterations=1 ) dense_mask = dense_mask[:, 0, :] - label_array = tf.reshape( - tf.tile(tf.range(0, label_shape[1]), num_batches_tns), label_shape + label_array = ops.reshape( + ops.tile(ops.arange(0, label_shape[1]), num_batches_tns), label_shape ) label_ind = tf.compat.v1.boolean_mask(label_array, dense_mask) - batch_array = tf.transpose( - tf.reshape( - tf.tile(tf.range(0, label_shape[0]), max_num_labels_tns), + batch_array = ops.transpose( + ops.reshape( + ops.tile(ops.arange(0, label_shape[0]), max_num_labels_tns), tf.reverse(label_shape, [0]), ) ) batch_ind = tf.compat.v1.boolean_mask(batch_array, dense_mask) - indices = tf.transpose( - tf.reshape(tf.concat([batch_ind, label_ind], axis=0), [2, -1]) + indices = ops.transpose( + ops.reshape(ops.concatenate([batch_ind, label_ind], axis=0), [2, -1]) ) vals_sparse = tf.compat.v1.gather_nd(labels, indices) return tf.SparseTensor( - tf.cast(indices, tf.int64), vals_sparse, tf.cast(label_shape, tf.int64) + ops.cast(indices, dtype="int64"), + vals_sparse, + ops.cast(label_shape, dtype="int64"), ) @@ -245,12 +250,12 @@ def __init__(self, name=None): def call(self, y_true, y_pred): # Compute the training-time loss value and add it # to the layer using `self.add_loss()`. - batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64") - input_length = tf.cast(tf.shape(y_pred)[1], dtype="int64") - label_length = tf.cast(tf.shape(y_true)[1], dtype="int64") + batch_len = ops.cast(ops.shape(y_true)[0], dtype="int64") + input_length = ops.cast(ops.shape(y_pred)[1], dtype="int64") + label_length = ops.cast(ops.shape(y_true)[1], dtype="int64") - input_length = input_length * tf.ones(shape=(batch_len, 1), dtype="int64") - label_length = label_length * tf.ones(shape=(batch_len, 1), dtype="int64") + input_length = input_length * ops.ones(shape=(batch_len, 1), dtype="int64") + label_length = label_length * ops.ones(shape=(batch_len, 1), dtype="int64") loss = self.loss_fn(y_true, y_pred, input_length, label_length) self.add_loss(loss) @@ -355,10 +360,10 @@ def build_model(): def ctc_decode(y_pred, input_length, greedy=True, beam_width=100, top_paths=1): - input_shape = tf.shape(y_pred) + input_shape = ops.shape(y_pred) num_samples, num_steps = input_shape[0], input_shape[1] - y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon()) - input_length = tf.cast(input_length, tf.int32) + y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon()) + input_length = ops.cast(input_length, dtype="int32") if greedy: (decoded, log_prob) = tf.nn.ctc_greedy_decoder( diff --git a/examples/vision/ipynb/captcha_ocr.ipynb b/examples/vision/ipynb/captcha_ocr.ipynb index 7fd7b5b99e..037c1176ee 100644 --- a/examples/vision/ipynb/captcha_ocr.ipynb +++ b/examples/vision/ipynb/captcha_ocr.ipynb @@ -10,7 +10,7 @@ "\n", "**Author:** [A_K_Nain](https://twitter.com/A_K_Nain)
\n", "**Date created:** 2020/06/14
\n", - "**Last modified:** 2020/06/26
\n", + "**Last modified:** 2024/03/13
\n", "**Description:** How to implement an OCR model using CNNs, RNNs and CTC loss." ] }, @@ -41,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -51,7 +51,6 @@ "\n", "os.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n", "\n", - "import os\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", @@ -60,6 +59,7 @@ "\n", "import tensorflow as tf\n", "import keras\n", + "from keras import ops\n", "from keras import layers" ] }, @@ -75,7 +75,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -101,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -137,8 +137,7 @@ "downsample_factor = 4\n", "\n", "# Maximum length of any captcha in the dataset\n", - "max_length = max([len(label) for label in labels])\n", - "" + "max_length = max([len(label) for label in labels])\n" ] }, { @@ -152,7 +151,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -172,9 +171,9 @@ " # 1. Get the total size of the dataset\n", " size = len(images)\n", " # 2. Make an indices array and shuffle it, if required\n", - " indices = np.arange(size)\n", + " indices = ops.arange(size)\n", " if shuffle:\n", - " np.random.shuffle(indices)\n", + " keras.random.shuffle(indices)\n", " # 3. Get the size of training samples\n", " train_samples = int(size * train_size)\n", " # 4. Split data into training and validation sets\n", @@ -195,15 +194,14 @@ " # 3. Convert to float32 in [0, 1] range\n", " img = tf.image.convert_image_dtype(img, tf.float32)\n", " # 4. Resize to the desired size\n", - " img = tf.image.resize(img, [img_height, img_width])\n", + " img = ops.image.resize(img, [img_height, img_width])\n", " # 5. Transpose the image because we want the time\n", " # dimension to correspond to the width of the image.\n", - " img = tf.transpose(img, perm=[1, 0, 2])\n", + " img = ops.transpose(img, axes=[1, 0, 2])\n", " # 6. Map the characters in label to numbers\n", " label = char_to_num(tf.strings.unicode_split(label, input_encoding=\"UTF-8\"))\n", " # 7. Return a dict as our model is expecting two inputs\n", - " return {\"image\": img, \"label\": label}\n", - "" + " return {\"image\": img, \"label\": label}\n" ] }, { @@ -217,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -250,7 +248,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -281,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -289,13 +287,15 @@ "source": [ "\n", "def ctc_batch_cost(y_true, y_pred, input_length, label_length):\n", - " label_length = tf.cast(tf.squeeze(label_length, axis=-1), tf.int32)\n", - " input_length = tf.cast(tf.squeeze(input_length, axis=-1), tf.int32)\n", - " sparse_labels = tf.cast(ctc_label_dense_to_sparse(y_true, label_length), tf.int32)\n", + " label_length = ops.cast(ops.squeeze(label_length, axis=-1), dtype=\"int32\")\n", + " input_length = ops.cast(ops.squeeze(input_length, axis=-1), dtype=\"int32\")\n", + " sparse_labels = ops.cast(\n", + " ctc_label_dense_to_sparse(y_true, label_length), dtype=\"int32\"\n", + " )\n", "\n", - " y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon())\n", + " y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon())\n", "\n", - " return tf.expand_dims(\n", + " return ops.expand_dims(\n", " tf.compat.v1.nn.ctc_loss(\n", " inputs=y_pred, labels=sparse_labels, sequence_length=input_length\n", " ),\n", @@ -304,41 +304,43 @@ "\n", "\n", "def ctc_label_dense_to_sparse(labels, label_lengths):\n", - " label_shape = tf.shape(labels)\n", - " num_batches_tns = tf.stack([label_shape[0]])\n", - " max_num_labels_tns = tf.stack([label_shape[1]])\n", + " label_shape = ops.shape(labels)\n", + " num_batches_tns = ops.stack([label_shape[0]])\n", + " max_num_labels_tns = ops.stack([label_shape[1]])\n", "\n", " def range_less_than(old_input, current_input):\n", - " return tf.expand_dims(tf.range(tf.shape(old_input)[1]), 0) < tf.fill(\n", + " return ops.expand_dims(ops.arange(ops.shape(old_input)[1]), 0) < tf.fill(\n", " max_num_labels_tns, current_input\n", " )\n", "\n", - " init = tf.cast(tf.fill([1, label_shape[1]], 0), tf.bool)\n", + " init = ops.cast(tf.fill([1, label_shape[1]], 0), dtype=\"bool\")\n", " dense_mask = tf.compat.v1.scan(\n", " range_less_than, label_lengths, initializer=init, parallel_iterations=1\n", " )\n", " dense_mask = dense_mask[:, 0, :]\n", "\n", - " label_array = tf.reshape(\n", - " tf.tile(tf.range(0, label_shape[1]), num_batches_tns), label_shape\n", + " label_array = ops.reshape(\n", + " ops.tile(ops.arange(0, label_shape[1]), num_batches_tns), label_shape\n", " )\n", " label_ind = tf.compat.v1.boolean_mask(label_array, dense_mask)\n", "\n", - " batch_array = tf.transpose(\n", - " tf.reshape(\n", - " tf.tile(tf.range(0, label_shape[0]), max_num_labels_tns),\n", + " batch_array = ops.transpose(\n", + " ops.reshape(\n", + " ops.tile(ops.arange(0, label_shape[0]), max_num_labels_tns),\n", " tf.reverse(label_shape, [0]),\n", " )\n", " )\n", " batch_ind = tf.compat.v1.boolean_mask(batch_array, dense_mask)\n", - " indices = tf.transpose(\n", - " tf.reshape(tf.concat([batch_ind, label_ind], axis=0), [2, -1])\n", + " indices = ops.transpose(\n", + " ops.reshape(ops.concatenate([batch_ind, label_ind], axis=0), [2, -1])\n", " )\n", "\n", " vals_sparse = tf.compat.v1.gather_nd(labels, indices)\n", "\n", " return tf.SparseTensor(\n", - " tf.cast(indices, tf.int64), vals_sparse, tf.cast(label_shape, tf.int64)\n", + " ops.cast(indices, dtype=\"int64\"), \n", + " vals_sparse, \n", + " ops.cast(label_shape, dtype=\"int64\")\n", " )\n", "\n", "\n", @@ -350,12 +352,12 @@ " def call(self, y_true, y_pred):\n", " # Compute the training-time loss value and add it\n", " # to the layer using `self.add_loss()`.\n", - " batch_len = tf.cast(tf.shape(y_true)[0], dtype=\"int64\")\n", - " input_length = tf.cast(tf.shape(y_pred)[1], dtype=\"int64\")\n", - " label_length = tf.cast(tf.shape(y_true)[1], dtype=\"int64\")\n", + " batch_len = ops.cast(ops.shape(y_true)[0], dtype=\"int64\")\n", + " input_length = ops.cast(ops.shape(y_pred)[1], dtype=\"int64\")\n", + " label_length = ops.cast(ops.shape(y_true)[1], dtype=\"int64\")\n", "\n", - " input_length = input_length * tf.ones(shape=(batch_len, 1), dtype=\"int64\")\n", - " label_length = label_length * tf.ones(shape=(batch_len, 1), dtype=\"int64\")\n", + " input_length = input_length * ops.ones(shape=(batch_len, 1), dtype=\"int64\")\n", + " label_length = label_length * ops.ones(shape=(batch_len, 1), dtype=\"int64\")\n", "\n", " loss = self.loss_fn(y_true, y_pred, input_length, label_length)\n", " self.add_loss(loss)\n", @@ -441,7 +443,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -462,8 +464,7 @@ " validation_data=validation_dataset,\n", " epochs=epochs,\n", " callbacks=[early_stopping],\n", - ")\n", - "" + ")\n" ] }, { @@ -480,7 +481,7 @@ }, { "cell_type": "code", - "execution_count": 0, + "execution_count": null, "metadata": { "colab_type": "code" }, @@ -488,10 +489,10 @@ "source": [ "\n", "def ctc_decode(y_pred, input_length, greedy=True, beam_width=100, top_paths=1):\n", - " input_shape = tf.shape(y_pred)\n", + " input_shape = ops.shape(y_pred)\n", " num_samples, num_steps = input_shape[0], input_shape[1]\n", - " y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon())\n", - " input_length = tf.cast(input_length, tf.int32)\n", + " y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon())\n", + " input_length = ops.cast(input_length, dtype=\"int32\")\n", "\n", " if greedy:\n", " (decoded, log_prob) = tf.nn.ctc_greedy_decoder(\n", @@ -587,4 +588,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/examples/vision/md/captcha_ocr.md b/examples/vision/md/captcha_ocr.md index 3e51607591..deed00b23f 100644 --- a/examples/vision/md/captcha_ocr.md +++ b/examples/vision/md/captcha_ocr.md @@ -2,7 +2,7 @@ **Author:** [A_K_Nain](https://twitter.com/A_K_Nain)
**Date created:** 2020/06/14
-**Last modified:** 2020/06/26
+**Last modified:** 2024/03/13
**Description:** How to implement an OCR model using CNNs, RNNs and CTC loss. @@ -29,7 +29,6 @@ import os os.environ["KERAS_BACKEND"] = "tensorflow" -import os import numpy as np import matplotlib.pyplot as plt @@ -38,6 +37,7 @@ from collections import Counter import tensorflow as tf import keras +from keras import ops from keras import layers ``` @@ -131,9 +131,9 @@ def split_data(images, labels, train_size=0.9, shuffle=True): # 1. Get the total size of the dataset size = len(images) # 2. Make an indices array and shuffle it, if required - indices = np.arange(size) + indices = ops.arange(size) if shuffle: - np.random.shuffle(indices) + keras.random.shuffle(indices) # 3. Get the size of training samples train_samples = int(size * train_size) # 4. Split data into training and validation sets @@ -154,10 +154,10 @@ def encode_single_sample(img_path, label): # 3. Convert to float32 in [0, 1] range img = tf.image.convert_image_dtype(img, tf.float32) # 4. Resize to the desired size - img = tf.image.resize(img, [img_height, img_width]) + img = ops.image.resize(img, [img_height, img_width]) # 5. Transpose the image because we want the time # dimension to correspond to the width of the image. - img = tf.transpose(img, perm=[1, 0, 2]) + img = ops.transpose(img, axes=[1, 0, 2]) # 6. Map the characters in label to numbers label = char_to_num(tf.strings.unicode_split(label, input_encoding="UTF-8")) # 7. Return a dict as our model is expecting two inputs @@ -218,13 +218,15 @@ plt.show() ```python def ctc_batch_cost(y_true, y_pred, input_length, label_length): - label_length = tf.cast(tf.squeeze(label_length, axis=-1), tf.int32) - input_length = tf.cast(tf.squeeze(input_length, axis=-1), tf.int32) - sparse_labels = tf.cast(ctc_label_dense_to_sparse(y_true, label_length), tf.int32) + label_length = ops.cast(ops.squeeze(label_length, axis=-1), dtype="int32") + input_length = ops.cast(ops.squeeze(input_length, axis=-1), dtype="int32") + sparse_labels = ops.cast( + ctc_label_dense_to_sparse(y_true, label_length), dtype="int32" + ) - y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon()) + y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon()) - return tf.expand_dims( + return ops.expand_dims( tf.compat.v1.nn.ctc_loss( inputs=y_pred, labels=sparse_labels, sequence_length=input_length ), @@ -233,41 +235,43 @@ def ctc_batch_cost(y_true, y_pred, input_length, label_length): def ctc_label_dense_to_sparse(labels, label_lengths): - label_shape = tf.shape(labels) - num_batches_tns = tf.stack([label_shape[0]]) - max_num_labels_tns = tf.stack([label_shape[1]]) + label_shape = ops.shape(labels) + num_batches_tns = ops.stack([label_shape[0]]) + max_num_labels_tns = ops.stack([label_shape[1]]) def range_less_than(old_input, current_input): - return tf.expand_dims(tf.range(tf.shape(old_input)[1]), 0) < tf.fill( + return ops.expand_dims(ops.arange(ops.shape(old_input)[1]), 0) < tf.fill( max_num_labels_tns, current_input ) - init = tf.cast(tf.fill([1, label_shape[1]], 0), tf.bool) + init = ops.cast(tf.fill([1, label_shape[1]], 0), dtype="bool") dense_mask = tf.compat.v1.scan( range_less_than, label_lengths, initializer=init, parallel_iterations=1 ) dense_mask = dense_mask[:, 0, :] - label_array = tf.reshape( - tf.tile(tf.range(0, label_shape[1]), num_batches_tns), label_shape + label_array = ops.reshape( + ops.tile(ops.arange(0, label_shape[1]), num_batches_tns), label_shape ) label_ind = tf.compat.v1.boolean_mask(label_array, dense_mask) - batch_array = tf.transpose( - tf.reshape( - tf.tile(tf.range(0, label_shape[0]), max_num_labels_tns), + batch_array = ops.transpose( + ops.reshape( + ops.tile(ops.arange(0, label_shape[0]), max_num_labels_tns), tf.reverse(label_shape, [0]), ) ) batch_ind = tf.compat.v1.boolean_mask(batch_array, dense_mask) - indices = tf.transpose( - tf.reshape(tf.concat([batch_ind, label_ind], axis=0), [2, -1]) + indices = ops.transpose( + ops.reshape(ops.concatenate([batch_ind, label_ind], axis=0), [2, -1]) ) vals_sparse = tf.compat.v1.gather_nd(labels, indices) return tf.SparseTensor( - tf.cast(indices, tf.int64), vals_sparse, tf.cast(label_shape, tf.int64) + ops.cast(indices, dtype="int64"), + vals_sparse, + ops.cast(label_shape, dtype="int64") ) @@ -279,12 +283,12 @@ class CTCLayer(layers.Layer): def call(self, y_true, y_pred): # Compute the training-time loss value and add it # to the layer using `self.add_loss()`. - batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64") - input_length = tf.cast(tf.shape(y_pred)[1], dtype="int64") - label_length = tf.cast(tf.shape(y_true)[1], dtype="int64") + batch_len = ops.cast(ops.shape(y_true)[0], dtype="int64") + input_length = ops.cast(ops.shape(y_pred)[1], dtype="int64") + label_length = ops.cast(ops.shape(y_true)[1], dtype="int64") - input_length = input_length * tf.ones(shape=(batch_len, 1), dtype="int64") - label_length = label_length * tf.ones(shape=(batch_len, 1), dtype="int64") + input_length = input_length * ops.ones(shape=(batch_len, 1), dtype="int64") + label_length = label_length * ops.ones(shape=(batch_len, 1), dtype="int64") loss = self.loss_fn(y_true, y_pred, input_length, label_length) self.add_loss(loss) @@ -664,10 +668,10 @@ and try the demo on [Hugging Face Spaces](https://huggingface.co/spaces/keras-io ```python def ctc_decode(y_pred, input_length, greedy=True, beam_width=100, top_paths=1): - input_shape = tf.shape(y_pred) + input_shape = ops.shape(y_pred) num_samples, num_steps = input_shape[0], input_shape[1] - y_pred = tf.math.log(tf.transpose(y_pred, perm=[1, 0, 2]) + keras.backend.epsilon()) - input_length = tf.cast(input_length, tf.int32) + y_pred = ops.log(ops.transpose(y_pred, axes=[1, 0, 2]) + keras.backend.epsilon()) + input_length = ops.cast(input_length, dtype="int32") if greedy: (decoded, log_prob) = tf.nn.ctc_greedy_decoder(