pythontensorflowkerasnlpnamed-entity-recognition

Error when I trying to run a trained ner model on local pc



import re
import pickle
import keras
import tensorflow as tf
from keras.models import Sequential
from keras.layers import TFSMLayer
import numpy as np

class CustomNonPaddingTokenLoss(keras.losses.Loss):
    def __init__(self, reduction=tf.keras.losses.Reduction.AUTO, name="custom_ner_loss"):
        super().__init__(reduction=reduction, name=name)

    def call(self, y_true, y_pred):
        loss_fn = keras.losses.SparseCategoricalCrossentropy(
            from_logits=False, reduction=self.reduction
        )
        loss = loss_fn(y_true, y_pred)
        mask = tf.cast((y_true > 0), dtype=tf.float32)
        loss = loss * mask
        return tf.reduce_sum(loss) / tf.reduce_sum(mask)

def map_record_to_training_data(record):
    record = tf.strings.split(record, sep="\t")
    length = tf.strings.to_number(record[0], out_type=tf.int32)
    tokens = record[1 : length + 1]
    tags = record[length + 1 :]
    tags = tf.strings.to_number(tags, out_type=tf.int64)
    tags += 1
    return tokens, tags

def lookup(tokens):
    # Load the list from the file
    with open('./resources/vocabulary.pkl', 'rb') as f:
        loaded_list = pickle.load(f)
    # The StringLookup class will convert tokens to token IDs
    lookup_layer = keras.layers.StringLookup(vocabulary=loaded_list)

    # No need to lowercase Vietnamese characters
    return lookup_layer(tokens)

def format_datatype(data):
    tokens =  [re.sub(r'[;,]', '', d) for d in data.split(' ')]
    #default is 0, since is for prediction
    ner_tags = [0 for d in data.split(' ')]

    #tab to separate
    string_input = str(len(tokens))+ "\t"+ "\t".join(tokens)+ "\t"+ "\t".join(map(str, ner_tags))
    string_input = tf.data.Dataset.from_tensor_slices([string_input])

    
    finalize_input = (string_input.map(map_record_to_training_data)
                      .map(lambda x, y: (lookup(x),  y))
                      .padded_batch(1)
                      )

    return finalize_input

def prediction(data):
    # Register the custom loss function with TensorFlow
    tf.keras.utils.get_custom_objects()['CustomNonPaddingTokenLoss'] = CustomNonPaddingTokenLoss
    loaded_model = Sequential()
    loaded_model.add(TFSMLayer("./resources/ner_model", call_endpoint='serving_default'))


    all_predicted_tag_ids = []
    
    for x, _ in data:
        print("Input Tensor Info:")
        print("Data Type:", x.dtype)
        print("Shape:", x.shape)
        x = tf.cast(x, tf.int64)
        output = loaded_model(x, training=False)
        predictions = np.argmax(output, axis=-1)
        predictions = np.reshape(predictions, [-1])
        all_predicted_tag_ids.append(predictions)

    all_predicted_tag_ids = np.concatenate(all_predicted_tag_ids)

    ner_labels = ["[PAD]", "N", "M", "other"]
    mapping =  dict(zip(range(len(ner_labels)), ner_labels))
    predicted_tags = [mapping[tag] for tag in all_predicted_tag_ids]

    return predicted_tags

sample_input = "Hello world, my name is John, I live in New York, my birthday is 10/02/1990."

result = prediction(format_datatype(sample_input))
print(result)

I trained the model on google colab, and download the model and try to load in on my window pc. *It work fine on google colab, even when I restart and clear the terminal and just run this block of code, there are no error at all. When I move to pc, I found that I need to load the model with a lot of pre-step, unlike on google colab just a (model = load_model("xxx/xxx"))

I am encountering an issue while using the TFSMLayer in TensorFlow, where I receive the following error message

-----------------------------------------

tensorflow.python.framework.errors_impl.InvalidArgumentError: Exception encountered when calling TFSMLayer.call().

cannot compute __inference_signature_wrapper_1285 as input #0(zero-based) was expected to be a int64 tensor but is a float tensor [Op:__inference_signature_wrapper_1285]

-------------------------------------------

I'm trying to load a TensorFlow model that uses the TFSMLayer for inference, but it seems that the input tensor received by the TFSMLayer.call() method is of data type float32, while the model expects int64. This inconsistency leads to an error during computation.

I have already attempted to cast the input tensor to int64 using tf.cast before passing it to the loaded model, but the error persists.

I'm uncertain why the input tensor's data type is being converted to float32, and how to resolve this issue. Any insights or suggestions on how to debug and resolve this problem would be greatly appreciated. Thank you!


Solution

  • Turns out it might be tensorflow version issue. I try to uninstall tensorflow on pc (2.16.1) and install the same version as google colab (2.15.0) and the original code run smoothly.

    import re
    import pickle
    import keras
    import tensorflow as tf
    import numpy as np
    print(tf.__version__)
    class CustomNonPaddingTokenLoss(keras.losses.Loss):
        def __init__(self, reduction=tf.keras.losses.Reduction.AUTO, name="custom_ner_loss"):
            super().__init__(reduction=reduction, name=name)
    
        def call(self, y_true, y_pred):
            loss_fn = keras.losses.SparseCategoricalCrossentropy(
                from_logits=False, reduction=self.reduction
            )
            loss = loss_fn(y_true, y_pred)
            mask = tf.cast((y_true > 0), dtype=tf.float32)
            loss = loss * mask
            return tf.reduce_sum(loss) / tf.reduce_sum(mask)
    
    def map_record_to_training_data(record):
        record = tf.strings.split(record, sep="\t")
        length = tf.strings.to_number(record[0], out_type=tf.int32)
        tokens = record[1 : length + 1]
        tags = record[length + 1 :]
        tags = tf.strings.to_number(tags, out_type=tf.int64)
        tags += 1
        return tokens, tags
    
    def lookup(tokens):
        # Load the list from the file
        with open('./resources/vocabulary.pkl', 'rb') as f:
            loaded_list = pickle.load(f)
        # The StringLookup class will convert tokens to token IDs
        lookup_layer = keras.layers.StringLookup(vocabulary=loaded_list)
    
        # No need to lowercase Vietnamese characters
        return lookup_layer(tokens)
    
    def format_datatype(data):
        tokens =  [re.sub(r'[;,]', '', d) for d in data.split(' ')]
        #default is 0, since is for prediction
        ner_tags = [0 for d in data.split(' ')]
    
        #tab to separate
        string_input = str(len(tokens))+ "\t"+ "\t".join(tokens)+ "\t"+ "\t".join(map(str, ner_tags))
        string_input = tf.data.Dataset.from_tensor_slices([string_input])
    
        
        finalize_input = (string_input.map(map_record_to_training_data)
                          .map(lambda x, y: (lookup(x),  y))
                          .padded_batch(1)
                          )
    
        return finalize_input
    
    def prediction(data):
        # Register the custom loss function with TensorFlow
        tf.keras.utils.get_custom_objects()['CustomNonPaddingTokenLoss'] = CustomNonPaddingTokenLoss
        
        loaded_model = tf.keras.models.load_model("./resources/ner_model")
    
        all_predicted_tag_ids = []
        
        for x, _ in data:
            print("Input Tensor Info:")
            print("Data Type:", x.dtype)
            print("Shape:", x.shape)
            x = tf.cast(x, tf.int64)
            output = loaded_model(x, training=False)
            predictions = np.argmax(output, axis=-1)
            predictions = np.reshape(predictions, [-1])
            all_predicted_tag_ids.append(predictions)
    
        all_predicted_tag_ids = np.concatenate(all_predicted_tag_ids)
    
        ner_labels = ["[PAD]", "N", "M", "other"]
        mapping =  dict(zip(range(len(ner_labels)), ner_labels))
        predicted_tags = [mapping[tag] for tag in all_predicted_tag_ids]
    
        return predicted_tags
    
    sample_input = ""Hello world, my name is John, I live in New York, my birthday is 10/02/1990."
    
    result = prediction(format_datatype(sample_input))
    print(result)
    print(len(result))