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
三、初始化与训练稳定性问题
- 权重初始化范围太小:你用的
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 ) - 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 })
四、数据预处理与标签问题
- 输入数据未归一化:你提供的原始数据数值范围不一,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) - 标签类别不平衡:检查你的14维标签是否存在某个类别占比极高(比如大部分样本的标签都是[0,1,1,...]),模型会偷懒一直预测这个占比最高的模式。如果是这种情况,需要用类别权重、过采样/欠采样等方式处理。
五、训练循环的逻辑修正
你的iteration=int(2175//100)计算的是21,但实际应该是(2175 + batch -1) // batch来确保所有样本都被训练到。另外,测试时不需要循环30次,一次性加载全部测试数据即可,避免重复加载带来的冗余。
内容的提问来源于stack exchange,提问作者Aaditya Ura




