创建TensorFlow TimeDistributed层时触发floating point exception报错求解
问题情况
- 报错类型:floating point exception,无堆栈追踪
- 崩溃触发点:执行
distributed_cnn = tf.keras.layers.TimeDistributed(cnn_model)(input_layer)时,模型call函数运行两次后程序崩溃 - 完整代码如下:
import os import sys from typing import Counter import tensorflow as tf import numpy as np from tensorflow.keras import models, layers, callbacks from tensorflow.keras.utils import to_categorical from tensorflow.keras.optimizers import Adam from tensorflow.keras.datasets import mnist from matplotlib import pyplot as plt # Change this to the location of the database directories DB_DIR = os.path.dirname(os.path.realpath(__file__)) # Import databases sys.path.insert(1, DB_DIR) from db_utils import get_imdb_dataset, get_speech_dataset, get_single_digit_dataset def Secure_Voice_Channel(func): """Define Secure_Voice_Channel decorator.""" def execute_func(*args, **kwargs): print('Established Secure Connection.') returned_value = func(*args, **kwargs) print("Ended Secure Connection.") return returned_value return execute_func @Secure_Voice_Channel class generic_vns_function(tf.keras.Model): def __init__(self, input_shape, layers, layer_units): super().__init__() self.convolutions = [] # Dynamically create Convolutional layers and MaxPools for layer in range(len(layers)): self.convolutions.append(tf.keras.layers.Conv2D(layer, 3, padding="same", input_shape=input_shape, activation="relu")) # Add MaxPooling layer self.convolutions.append(tf.keras.layers.MaxPooling2D((2,2))) # Flatten self.flatten = tf.keras.layers.Flatten() # Dense layer self.dense1 = tf.keras.layers.Dense(1024, activation="relu") def call(self, input): x = input for layer in self.convolutions: x = layer(x) x = self.flatten(x) x = self.dense1(x) return x def train_model(model, epochs, batch_size, X_train, y_train, X_test, y_test): """Generic Deep Learning Model training function.""" cb = [callbacks.EarlyStopping(monitor='val_loss', patience=3)] model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=batch_size, verbose=1, callbacks=cb) scores = model.evaluate(X_test, y_test, verbose=2) print("Baseline Error: %.2f%%" % (100-scores[1]*100)) return model def choose_dataset(dataset_type): """Select dataset based on string variable.""" if dataset_type == "nlp": return get_imdb_dataset(dir=DB_DIR) elif dataset_type == "computer_vision": (X_train, y_train), (X_test, y_test) = mnist.load_data() elif dataset_type == "speech_recognition": # (X_train, y_train), (X_test, y_test), (_, _) = get_speech_dataset() (X_train, y_train), (X_test, y_test), (_, _) = get_single_digit_dataset(0) else: raise ValueError("Couldn't find dataset.") (X_train, X_test) = normalize_dataset(dataset_type, X_train, X_test) (X_train, y_train), (X_test, y_test) = reshape_dataset(X_train, y_train, X_test, y_test) return (X_train, y_train), (X_test, y_test) def normalize_dataset(string, X_train, X_test): """Normalize speech recognition and computer vision datasets.""" if string == "computer vision": X_train = X_train / 255 X_test = X_test / 255 else: mean = np.mean(X_train) std = np.std(X_train) X_train = (X_train-std)/mean X_test = (X_test-std)/mean return (X_train, X_test) def reshape_dataset(X_train, y_train, X_test, y_test): """Reshape Computer Vision and Speech datasets.""" y_train = to_categorical(y_train) y_test = to_categorical(y_test) return (X_train, y_train), (X_test, y_test) def create_LSTM(cnn_model, input_shape, num_classes): input_layer = layers.Input(shape=input_shape) distributed_cnn = tf.keras.layers.TimeDistributed(cnn_model)(input_layer) x, state_a, state_b = layers.LSTM(distributed_cnn) output = layers.Dense(num_classes, activation="softmax")(x) model = models.Model(inputs=input_layer, outputs=output) opt = Adam() model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) return model def main(): # Hyperparameters layers = [64, 32] layer_units = 1000 epochs = 10 batch_size = 200 lr = 0.001 filter = 64 kernal_size = 3 window = 3 dataset = "speech_recognition" # Import Datasets (X_train, y_train), (X_test, y_test) = choose_dataset(dataset) num_classes = y_train.shape[1] # Reshape both the train and test dataset X_train = X_train.reshape(X_train.shape[0], window, int(X_train.shape[1]/window), X_train.shape[2], 1) X_test = X_test.reshape(X_test.shape[0], window, int(X_test.shape[1]/window), X_test.shape[2], 1) # Generate CNN model cnn_model = generic_vns_function(X_train.shape[1:], layers, layer_units) print("Created generic CNN model") # Create the LSTM CNN with time distributed layer model = create_LSTM(cnn_model, X_train.shape[1:], num_classes) print("Created LST model") trained_model = train_model(model, epochs, batch_size, X_train, y_train, X_test, y_test) save_format="tf" # # Save model to h5 file trained_model.save(save_format, 'models/model_%s_a3.h5' % dataset) return None
问题根因分析
- 卷积层参数配置错误(核心触发浮点异常的原因)
generic_vns_function类初始化时,循环创建卷积层的参数写错:原代码循环用for layer in range(len(layers)):,传入Conv2D的第一个参数是循环变量layer,也就是当layers为[64,32]时,两次循环传入的滤波器数量是0、1,第一层卷积输出通道数为0,后续计算涉及除以通道数、矩阵维度匹配时直接触发除以0的浮点异常。 - LSTM层调用不符合API规范
layers.LSTM的第一个参数是隐藏层单元数(整数),原代码直接传入张量distributed_cnn作为初始化参数,属于API使用错误,会触发张量维度、参数类型异常。 - 数据归一化逻辑双重错误
- 字符串匹配错误:
choose_dataset传入的分类标识是computer_vision(下划线分隔),normalize_dataset中判断条件是computer vision(空格分隔),导致所有数据集都走标准差归一化逻辑 - 归一化公式错误:正确的Z-score标准化公式为
(样本值-均值)/标准差,原代码写为(样本值-标准差)/均值,同时未做标准差为0的防护,容易出现除0异常
- Keras模型子类被错误装饰
自定义模型类generic_vns_function被普通函数装饰器@Secure_Voice_Channel修饰,破坏了Keras Model类的继承链和内部初始化逻辑,导致张量追踪、前向传播调用出现未知异常。 - 模型保存API使用错误
model.save的第一个参数为保存路径,原代码将save_format="tf"作为第一个参数传入,参数顺序完全错误。
修复方案
- 修正卷积层参数:将卷积层创建代码改为
for i in range(len(layers)): self.convolutions.append(tf.keras.layers.Conv2D(layers[i], 3, padding="same", activation="relu"))
input_shape不需要给卷积层单独传,子类模型会自动推断输入形状。
- 修正LSTM层调用:将
create_LSTM中的LSTM部分改为
# 可根据需求调整units的数值 x = layers.LSTM(units=256)(distributed_cnn) # 若需返回状态则开启return_state参数 # x, state_a, state_b = layers.LSTM(units=256, return_state=True)(distributed_cnn)
- 修正归一化逻辑:
def normalize_dataset(string, X_train, X_test): """Normalize speech recognition and computer vision datasets.""" if string == "computer_vision": X_train = X_train / 255.0 X_test = X_test / 255.0 else: mean = np.mean(X_train) std = np.std(X_train) + 1e-8 # 加极小值避免除0 X_train = (X_train - mean) / std X_test = (X_test - mean) / std return (X_train, X_test)
- 移除模型类上的
@Secure_Voice_Channel装饰器,若需要安全日志可以在call方法首尾加打印语句,或者在模型训练/推理的调用外层加装饰器。 - 修正模型保存代码:
# 保存为h5格式 trained_model.save('models/model_%s_a3.h5' % dataset, save_format='h5') # 若保存为tf SavedModel格式 # trained_model.save('models/model_%s_a3_tf' % dataset, save_format='tf')
内容的提问来源于stack exchange,提问作者logankilpatrick
相关产品推荐
相关产品推荐

