You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

TensorFlow多标签分类:所有测试数据预测结果一致问题求助

排查LSTM多标签分类预测结果完全一致的问题

嘿,我帮你拆解下这个问题——所有测试样本预测结果一模一样,这在序列模型训练里是很典型的“训练失效”表现,咱们从代码和数据的几个关键点逐一排查:

一、训练数据加载的致命错误

你看你的训练循环里,每次迭代都调用data_preprocessing.get_train_data(),这意味着每一轮迭代都在训练同一批数据!模型根本没法学到不同样本的特征差异,只会机械地记住这一批数据的模式,甚至会因为重复训练导致梯度爆炸/消失,最后收敛到一个固定的输出值。

解决方案:

先一次性加载所有训练数据,然后做打乱、分batch的操作,而不是每次迭代都重新获取全部数据:

# 提前加载并预处理所有训练数据
all_train_inputs = data_preprocessing.get_train_data()['input']
all_train_labels = data_preprocessing.get_train_data()['labels']

# 训练循环中,每个epoch先打乱数据,再按batch切片
for i in range(epoch):
    # 每个epoch打乱一次数据,避免顺序偏见
    shuffle_indices = np.random.permutation(len(all_train_inputs))
    shuffled_inputs = all_train_inputs[shuffle_indices]
    shuffled_labels = all_train_labels[shuffle_indices]
    
    for j in range(iteration):
        start_idx = j * batch
        end_idx = start_idx + batch
        # 处理最后一个batch可能不足batch_size的情况
        if end_idx > len(shuffled_inputs):
            end_idx = len(shuffled_inputs)
        batch_x = shuffled_inputs[start_idx:end_idx]
        batch_y = shuffled_labels[start_idx:end_idx]
        
        # 传入当前batch的数据进行训练
        fina_out = sess.run(model.out, feed_dict={
            model.placeholder['input']: batch_x,
            model.placeholder['output']: batch_y
        })

二、模型输出层的特征利用问题

你的模型只取了LSTM最后一个时间步的输出(batch_major[-1])来计算logits,但103步的序列里,最后一步的信息可能不足以区分14个类别的差异,导致模型输出趋同。

解决方案:

尝试利用整个序列的特征,比如对所有时间步的输出做平均池化或最大池化:

# 替换原来的batch_major[-1],改用所有时间步的平均值
sequence_avg = tf.reduce_mean(model, axis=1)  # axis=1是时间步维度
logits = tf.matmul(sequence_avg, weights) + bias

三、初始化与训练稳定性问题

  1. 权重初始化范围太小:你用的tf.random_uniform_initializer(-0.01,0.01)会导致初始权重非常小,模型的梯度信号太弱,训练初期就“动不起来”,最后收敛到固定输出。
    • 改用更适合的初始化方式,比如Xavier/Glorot初始化:
    weights = tf.get_variable(
        name='weights',
        shape=[100,14],
        initializer=tf.keras.initializers.GlorotUniform(),
        dtype=tf.float32
    )
    bias = tf.get_variable(
        name='bias',
        shape=[14],
        initializer=tf.keras.initializers.Zeros(),  # 偏置初始化为0更稳妥
        dtype=tf.float32
    )
    
  2. Dropout测试时未关闭:你在LSTM上加了DropoutWrapper,但测试时没有把output_keep_prob设为1.0,导致测试时也随机丢弃神经元,可能加剧输出的一致性问题。
    • 把Dropout的保留概率改成可传入的占位符:
    self.keep_prob = tf.placeholder(dtype=tf.float32, name='keep_prob')
    dropout_wrapper = rnn.DropoutWrapper(cell, output_keep_prob=self.keep_prob)
    
    • 训练时传入0.5,测试时传入1.0
    # 训练时
    fina_out = sess.run(model.out, feed_dict={
        model.placeholder['input']: batch_x,
        model.placeholder['output']: batch_y,
        model.keep_prob: 0.5
    })
    # 测试时
    test_out = sess.run(model.test, feed_dict={
        model.placeholder['input']: test_inputs,
        model.keep_prob: 1.0
    })
    

四、数据预处理与标签问题

  1. 输入数据未归一化:你提供的原始数据数值范围不一,LSTM对未归一化的数据非常敏感,容易导致梯度不稳定,模型收敛到次优解。
    • 对输入数据做标准化(0均值,1方差)或归一化(缩放到[-1,1]或[0,1]):
    from sklearn.preprocessing import StandardScaler
    # 假设输入数据形状是(样本数, 序列长度, 特征数)
    scaler = StandardScaler()
    # 先把序列展开成(样本数*序列长度, 特征数),拟合后再恢复形状
    flattened_inputs = all_train_inputs.reshape(-1, all_train_inputs.shape[-1])
    scaler.fit(flattened_inputs)
    normalized_inputs = scaler.transform(flattened_inputs).reshape(all_train_inputs.shape)
    
  2. 标签类别不平衡:检查你的14维标签是否存在某个类别占比极高(比如大部分样本的标签都是[0,1,1,...]),模型会偷懒一直预测这个占比最高的模式。如果是这种情况,需要用类别权重、过采样/欠采样等方式处理。

五、训练循环的逻辑修正

你的iteration=int(2175//100)计算的是21,但实际应该是(2175 + batch -1) // batch来确保所有样本都被训练到。另外,测试时不需要循环30次,一次性加载全部测试数据即可,避免重复加载带来的冗余。


内容的提问来源于stack exchange,提问作者Aaditya Ura

火山引擎 最新活动