TensorFlow下HuggingFace自定义数据集微调报dtype属性错误求助
问题根因
这个报错是Transformers 3.2.0版本与TensorFlow 2.3+版本的兼容性问题,和数据集内容、自定义逻辑无关,官方原始示例在版本不匹配的环境下运行会100%复现该错误。
具体触发点有两个:
- 官方示例中
model.compile(optimizer=optimizer, loss=model.compute_loss)的写法,在高版本TensorFlow下初始化损失函数时,无法正确读取标签张量的dtype属性,拿到None值后调用属性直接报错 - 构造
tf.data.Dataset时直接传入Python原生列表格式的标签,没有显式指定张量类型,会进一步放大类型推断的兼容性问题
额外提示:原示例中
labels.append(0 if label_dir is "neg" else 1)的写法存在语法不规范问题,Python中判断字符串值相等应当使用==而非is,避免不同环境下字符串驻留机制差异导致标签赋值错误。
单标签示例修复方案
不需要降级环境,修改两处代码即可跑通官方IMDB分类示例:
- 构造数据集时,将标签显式转换为
tf.int32类型的张量,不要直接传入Python原生列表 - 替换直接传入
model.compute_loss的写法,显式定义匹配分类任务的损失函数,注意分类头输出的是未经过激活的logits,损失函数要指定from_logits=True
修复后的核心代码段:
import tensorflow as tf # 构造数据集时显式指定标签类型 train_dataset = tf.data.Dataset.from_tensor_slices(( dict(train_encodings), tf.constant(train_labels, dtype=tf.int32) )) val_dataset = tf.data.Dataset.from_tensor_slices(( dict(val_encodings), tf.constant(val_labels, dtype=tf.int32) )) test_dataset = tf.data.Dataset.from_tensor_slices(( dict(test_encodings), tf.constant(test_labels, dtype=tf.int32) )) from transformers import TFDistilBertForSequenceClassification # 加载模型时显式指定单标签分类的类别数 model = TFDistilBertForSequenceClassification.from_pretrained( 'distilbert-base-uncased', num_labels=2 ) optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5) # 替换原loss传参,单标签分类用稀疏分类交叉熵 loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy']) model.fit( train_dataset.shuffle(1000).batch(16), epochs=3, validation_data=val_dataset.batch(16) )
多标签文本分类适配方案
针对自有隐私数据集的多标签分类需求,在上述修复基础上额外调整4处逻辑即可:
- 标签预处理:将每个样本的标签转换为与类别总数等长的0/1向量,例:总共有4个类别,某样本同时属于第0类和第2类,对应标签为
[1,0,1,0] - 数据集构造:标签张量类型改为
tf.float32 - 模型加载:
num_labels参数设置为实际的多标签类别总数 - 训练配置:损失函数替换为适用于多标签任务的二分类交叉熵,评估指标切换为多标签场景下的准确率、AUC等指标
多标签场景核心代码示例:
# 替换为实际的类别总数 NUM_LABELS = 自定义类别数 # 提前将标签处理为NUM_LABELS长度的0/1向量列表 # train_labels形状: (样本数, NUM_LABELS) train_dataset = tf.data.Dataset.from_tensor_slices(( dict(train_encodings), tf.constant(train_labels, dtype=tf.float32) )) val_dataset = tf.data.Dataset.from_tensor_slices(( dict(val_encodings), tf.constant(val_labels, dtype=tf.float32) )) model = TFDistilBertForSequenceClassification.from_pretrained( 'distilbert-base-uncased', num_labels=NUM_LABELS ) optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5) # 多标签任务用二分类交叉熵损失 loss = tf.keras.losses.BinaryCrossentropy(from_logits=True) model.compile( optimizer=optimizer, loss=loss, metrics=[ tf.keras.metrics.BinaryAccuracy(), tf.keras.metrics.AUC(multi_label=True) ] ) model.fit( train_dataset.shuffle(1000).batch(16), epochs=3, validation_data=val_dataset.batch(16) )
内容的提问来源于stack exchange,提问作者Olive Yew
相关产品推荐
相关产品推荐

