在本地PC上运行训练好的NER模型时出错

0 投票
1 回答
32 浏览
提问于 2025-04-13 14:02

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)

我在谷歌Colab上训练了一个模型,然后下载了这个模型,想在我的Windows电脑上加载它。
在谷歌Colab上运行得很好,即使我重启并清空终端,只要运行这段代码,就没有任何错误。
但在电脑上,我发现需要进行很多准备步骤才能加载模型,而在谷歌Colab上只需要一行代码(model = load_model("xxx/xxx"))。

我在使用TFSMLayer时遇到了一个问题,收到以下错误信息:

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

tensorflow.python.framework.errors_impl.InvalidArgumentError: 调用 TFSMLayer.call() 时遇到异常。

无法计算 __inference_signature_wrapper_1285,因为输入 #0(从零开始)预期是一个 int64 张量,但实际上是一个 float 张量 [Op:__inference_signature_wrapper_1285]

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

我正在尝试加载一个使用TFSMLayer进行推理的TensorFlow模型,但似乎TFSMLayer.call()方法接收到的输入张量数据类型是float32,而模型期望的是int64。这种不一致导致了计算时的错误。

我已经尝试在将输入张量传递给加载的模型之前,使用tf.cast将其转换为int64,但错误依然存在。

我不确定为什么输入张量的数据类型会被转换为float32,也不知道该如何解决这个问题。如果有任何建议或调试的方法,我将非常感激。谢谢!

1 个回答

0

结果发现可能是tensorflow版本的问题。我尝试在电脑上卸载tensorflow(2.16.1),然后安装和Google Colab一样的版本(2.15.0),这样原来的代码就能顺利运行了。

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))

撰写回答