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

基于HuggingFace预训练BERT微调时遇AttributeError问题求助

问题原因分析

错误核心在于:HuggingFace的BERT模型返回的是BaseModelOutputWithPoolingAndCrossAttentions对象(包含last_hidden_state、pooler_output等属性),而fastai的损失函数期望接收PyTorch张量,直接调用transpose方法会因对象类型不匹配报错。此外还有两个潜在问题:

  • 自定义Tokenizer实现存在缺陷
  • 标准TextDataBunch无法提供BERT所需的attention_mask等输入参数

解决方案

1. 封装BERT模型,返回张量输出

创建自定义模型类,包裹HuggingFace的BERT模型,提取任务所需的张量(如分类任务的logits)返回给fastai:

import torch.nn as nn
from transformers import BertModel

class BertForFastAI(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        self.bert = BertModel.from_pretrained("bert-base-uncased")
        # 根据任务定义分类头,这里以二分类为例
        self.classifier = nn.Linear(self.bert.config.hidden_size, num_classes)
    
    def forward(self, input_ids, attention_mask=None):
        # 获取BERT输出对象
        outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
        # 使用pooler_output作为句子表征
        pooled_output = outputs.pooler_output
        # 计算分类logits并返回张量
        logits = self.classifier(pooled_output)
        return logits

2. 修正Tokenizer实现

替换自定义Tokenizer为fastai兼容的版本,确保正确添加BERT要求的[CLS]和[SEP]标记:

from fastai.text import Tokenizer, Vocab
from transformers import BertTokenizer
from fastai.text.transform import BaseTokenizer

class CustomBertTokenizer(BaseTokenizer):
    def __init__(self, pretrained_tokenizer, max_seq_len=128, **kwargs):
        self.tokenizer = pretrained_tokenizer
        self.max_seq_len = max_seq_len
    
    def tokenize(self, t):
        # 添加CLS和SEP标记,并限制序列长度
        tokens = ["[CLS]"] + self.tokenizer.tokenize(t)[:self.max_seq_len-2] + ["[SEP]"]
        return tokens

# 初始化预训练Tokenizer
bert_tok = BertTokenizer.from_pretrained("bert-base-uncased")
# 创建fastai兼容的Tokenizer
tokenizer = Tokenizer(tok_func=CustomBertTokenizer(bert_tok, max_seq_len=128), pre_rules=[], post_rules=[])
# 复用BERT的词汇表
vocab = Vocab(list(bert_tok.vocab.keys()))

3. 构建包含Attention Mask的DataBunch

标准TextDataBunch无法生成BERT所需的attention_mask,需要自定义数据处理流程:

from fastai.data_block import DataBunch, ItemList
import torch

def get_attention_mask(input_ids, pad_token_id=0):
    # 生成attention_mask:1表示有效token,0表示padding
    return (input_ids != pad_token_id).long()

# 自定义ItemList处理文本数据
class BertTextItemList(ItemList):
    def __init__(self, items, tokenizer, vocab, max_seq_len=128, **kwargs):
        super().__init__(items, **kwargs)
        self.tokenizer = tokenizer
        self.vocab = vocab
        self.max_seq_len = max_seq_len
    
    def get(self, i):
        text = self.items[i]
        tokens = self.tokenizer.tokenize(text)
        # 转换为数字id
        input_ids = self.vocab.numericalize(tokens)
        # 补全到max_seq_len
        input_ids = torch.cat([input_ids, torch.zeros(self.max_seq_len - len(input_ids), dtype=torch.long)])
        # 生成attention_mask
        attention_mask = get_attention_mask(input_ids, pad_token_id=self.vocab.stoi["[PAD]"])
        return (input_ids, attention_mask)

# 构建DataBunch
train_list = BertTextItemList(train_df['text'], tokenizer=tokenizer, vocab=vocab)
valid_list = BertTextItemList(val_df['text'], tokenizer=tokenizer, vocab=vocab)
test_list = BertTextItemList(test_df['text'], tokenizer=tokenizer, vocab=vocab)

# 绑定标签
train_list = train_list.label_from_df(train_df, cols='label')
valid_list = valid_list.label_from_df(val_df, cols='label')
test_list = test_list.label_from_df(test_df, cols='label')

# 创建DataBunch
data_bunch = DataBunch.create(train_list, valid_list, test_list, bs=8)

4. 初始化Learner并启动训练

from fastai.basic_train import Learner
from fastai.metrics import accuracy

# 初始化模型,假设是二分类任务
model = BertForFastAI(num_classes=2)
# 创建Learner,指定损失函数
learner = Learner(data_bunch, model, loss_func=nn.CrossEntropyLoss(), metrics=[accuracy])

# 启动训练
learner.fit_one_cycle(1)

关键说明
  • 必须将HuggingFace模型的输出对象转换为张量,才能被fastai的损失函数处理
  • BERT模型需要attention_mask区分有效token和padding,这是标准文本DataBunch缺失的
  • Tokenizer必须正确添加[CLS]和[SEP]标记,符合BERT的输入格式要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:56:52