Keras中Transformer模型加权与普通准确率不一致问题排查
时间序列分类模型加权准确率异常问题
问题背景
训练时间序列分类Transformer模型,以“以上一个目标值作为下一个预测结果”的Baseline模型做对比基准。为处理不平衡数据集,采用数据生成器+sample_weights样本加权方案。
将所有sample_weights设为1测试时,Baseline模型的加权准确率与普通准确率结果完全一致(符合预期);但Transformer模型的两者差异显著:普通准确率归一化到[0,1]区间,加权准确率却归一化到[0,100]区间,需排查原因。
相关代码
数据生成器样本权重获取函数
def get_sample_weights(self, inputs, labels): ''' Obtains sample weights for any number of classes. NOTE: sample_weights pertain a weighting to each label ''' # 初始化样本权重为1 sample_weights = tf.ones_like(labels, dtype=tf.float64) # 获取类别及对应样本数 class_counts = np.bincount(self.train_df.price_change) total = class_counts.sum() n_classes = len(class_counts) # 强制所有类别权重为1 weights = tf.constant([1, 1, 1], dtype=tf.float64) for idx, count in enumerate(class_counts): weight = weights[idx] # 更新对应类别的样本权重 sample_weights = tf.where(tf.equal(labels, float(idx)), weight, sample_weights) return inputs, labels, sample_weights
Baseline模型配置与评估代码
baseline = Baseline(label_index=single_gen.column_indices['price_change']) baseline.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'], weighted_metrics=['accuracy']) train_metrics = baseline.evaluate(single_gen.train) val_metrics = baseline.evaluate(single_gen.valid)
Transformer模型配置与评估代码
transformer_model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(), optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), metrics=['sparse_categorical_accuracy'], weighted_metrics=['sparse_categorical_accuracy']) history = transformer_model.fit(aapl_gen.train, epochs=2, validation_data=aapl_gen.valid) train_metrics = transformer_model.evaluate(data_gen.train) val_metrics = transformer_model.evaluate(data_gen.valid)
原因分析与解决方法
核心原因:指标计算逻辑差异
问题根源在于**accuracy与sparse_categorical_accuracy作为加权指标时的计算逻辑不一致**:
accuracy(对应稀疏任务的SparseCategoricalAccuracy)作为加权指标时,会自动对样本权重做归一化(将权重总和缩放到1),因此结果范围与普通准确率一致([0,1])。- 部分TensorFlow版本中,
sparse_categorical_accuracy作为加权指标时,未正确执行权重归一化,直接返回加权正确样本数(而非除以总权重),导致结果范围变为[0,样本总数],表现为与普通准确率差100倍的现象。
解决方案
统一指标类型
将Transformer模型的指标替换为accuracy,与Baseline保持一致:transformer_model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(), optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), metrics=['accuracy'], weighted_metrics=['accuracy'])验证样本权重正确性
在get_sample_weights函数末尾添加验证代码,确认所有样本权重确实为1:print("样本权重唯一值:", tf.reduce_unique(sample_weights).numpy())手动计算验证指标
手动计算普通准确率与加权准确率,对比模型返回结果,定位问题:y_true, y_pred, weights = [], [], [] for x, y, w in data_gen.train: y_true.extend(y.numpy()) y_pred.extend(tf.argmax(transformer_model.predict(x), axis=1).numpy()) weights.extend(w.numpy()) # 普通准确率 regular_acc = sum(t == p for t, p in zip(y_true, y_pred)) / len(y_true) # 加权准确率 weighted_acc = sum(w for t, p, w in zip(y_true, y_pred, weights) if t == p) / sum(weights) print(f"手动计算普通准确率: {regular_acc:.4f}") print(f"手动计算加权准确率: {weighted_acc:.4f}")升级TensorFlow版本
若使用旧版本TensorFlow,升级至最新稳定版,修复指标计算的潜在bug。
内容的提问来源于stack exchange,提问作者Isaac Berrios
相关产品推荐
相关产品推荐

