You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tf.one_hot内存占用过高崩溃,求张量场景下的替代或优化方案

解决tf.one_hot内存过高问题,无需独热编码计算MRR

你的内存崩溃问题根源在于显式生成大规模密集独热张量——当y_pred被reshape成一维后,再做tf.one_hot会生成形状为[batch_size * MAX_LEN, 64]的巨大张量,内存占用随批量和序列长度线性增长,很容易超出显存。

同时你的代码存在潜在错误:y_pred是模型输出的softmax概率分布(形状[batch_size, MAX_LEN, vocab_size]),直接将其cast为int64会把0-1之间的浮点数强制转为0,完全无法得到有效的预测类别索引,正确做法是先取argmax得到预测类别。

下面提供两种更高效的解决方案,完全避免显式独热编码:


方案一:直接基于概率分布计算MRR(推荐)

MRR的核心是计算真实标签在预测概率排序中的倒数排名,完全不需要独热编码。重写MRR计算逻辑,直接用模型输出的概率张量计算:

修改后的代码

def mrr_metric(y_true, y_pred_probs):
    # y_true: 形状 [batch_size, MAX_LEN],稀疏整数标签
    # y_pred_probs: 形状 [batch_size, MAX_LEN, vocab_size],模型输出的softmax概率
    # 获取每个真实标签对应的预测概率
    true_probs = tf.gather(
        y_pred_probs, 
        tf.cast(y_true, tf.int32), 
        axis=-1, 
        batch_dims=2  # 匹配前两个维度(batch和序列长度)
    )
    # 计算每个位置中,概率大于等于真实标签概率的样本数,加1即为真实标签的排名(排名从1开始)
    ranks = tf.reduce_sum(tf.cast(y_pred_probs >= true_probs[..., tf.newaxis], tf.float32), axis=-1)
    # 计算倒数排名的平均值,即MRR
    mrr = tf.reduce_mean(1.0 / ranks)
    return mrr

def mrr_metric_fn(y_true, y_pred):
    # 直接传入模型输出的概率张量,无需reshape和独热
    return mrr_metric(y_true, y_pred)

# 模型创建和编译部分保持不变
def create_classifier_bert_model():    
    inputs = layers.Input((config.MAX_LEN,), dtype=tf.int64)
    sequence_output = pretrained_bert_model(inputs)
    outputs = layers.Dense(vectorize_layer.vocabulary_size(), activation="softmax")(sequence_output)
    classifer_model = keras.Model(inputs, outputs=[outputs], name="prediction")
    optimizer = keras.optimizers.Adam(learning_rate=config.LR)
    classifer_model.compile(
        optimizer=optimizer, 
        loss="sparse_categorical_crossentropy", 
        weighted_metrics=['sparse_categorical_accuracy', mrr_metric_fn]
    )
    return classifer_model

这个方案的优势:

  • 完全避免生成大尺寸独热张量,内存占用仅和原始概率张量一致
  • 基于概率计算排名比基于硬预测(argmax)更准确,能保留softmax的概率信息

方案二:用稀疏张量替代密集独热张量

如果必须保留基于类别索引的逻辑,可以用稀疏张量存储独热编码(仅存储非零元素),大幅降低内存占用:

修改后的代码

def mrr_metric_fn(y_true, y_pred):
    # 先获取预测类别索引(修正原来的错误)
    y_pred_idx = tf.argmax(y_pred, axis=-1)  # 形状 [batch_size, MAX_LEN]
    y_pred_revel = tf.reshape(y_pred_idx, [-1])  # 形状 [batch_size * MAX_LEN]
    
    # 创建稀疏独热张量,仅存储非零位置
    sparse_one_hot = tf.sparse.SparseTensor(
        indices=tf.stack([tf.range(tf.size(y_pred_revel)), y_pred_revel], axis=1),
        values=tf.ones(tf.size(y_pred_revel), dtype=tf.float32),
        dense_shape=[tf.size(y_pred_revel), 64]
    )
    # 如果原来的mrr_metric支持稀疏张量,直接传入;否则可转为密集张量(但仅在必要时)
    # sparse_one_hot_dense = tf.sparse.to_dense(sparse_one_hot)
    mrr = mrr_metric(y_true, sparse_one_hot)
    return mrr

注意:如果你的mrr_metric函数不支持稀疏张量,需要修改其逻辑适配稀疏输入,否则转成密集张量仍会有内存问题,因此方案一仍是最优选择。


内容的提问来源于stack exchange,提问作者Fraol Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:03:27