Где в коде pytorch или huggingface / transformer метка "переименовывается" в метки? - PullRequest
1 голос
/ 17 июня 2020

мой вопрос касается примера, доступного в библиотеке great huggingface / transformers.

Я использую записную книжку, предоставленную создателями библиотеки, в качестве отправной точки для моего конвейера. В записной книжке ниже представлен процесс точной настройки BERT для классификации предложений в наборе данных Glue. https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/trainer/01_text_classification.ipynb#scrollTo = uBzDW1FO63pK
При входе в код я заметил очень странную вещь, которую я не могу объяснить.

В этом примере входные данные представлены в модели как экземпляры класса InputFeatures отсюда: https://github.com/huggingface/transformers/blob/011cc0be51cf2eb0a91333f1a731658361e81d89/src/transformers/data/processors/utils.py Этот класс имеет 4 атрибута, включая атрибут label :

class InputFeatures:
    ...
    input_ids: List[int]
    attention_mask: Optional[List[int]] = None
    token_type_ids: Optional[List[int]] = None
    label: Optional[Union[int, float]] = None

, которые передаются позже как словарь входных данных для метода forward() модели. Это выполняется классом Trainer, например в строках 573-576 здесь: https://github.com/huggingface/transformers/blob/edcb3ac59ab05d9afbc6b4f7bebfb2e5dfc662d2/src/transformers/trainer.py

    def _training_step(
        self, model: nn.Module, inputs: Dict[str, torch.Tensor], optimizer: torch.optim.Optimizer
    ) -> float:
        model.train()
        for k, v in inputs.items():
            inputs[k] = v.to(self.args.device)

        outputs = model(**inputs)  

Однако метод forward() ожидает меток (обратите внимание на форму множественного числа) входной параметр.

    def forward(
        self,
        input_ids=None,
        attention_mask=None,
        head_mask=None,
        inputs_embeds=None,
        labels=None,
        output_attentions=None,
    ):

(взято отсюда: https://huggingface.co/transformers/_modules/transformers/modeling_distilbert.html#DistilBertForSequenceClassification)

Итак, мой вопрос: где метка становится меткой в этом конвейере?

Чтобы дать некоторую дополнительную информацию по проблеме, я создал свой собственный конвейер, который не использует ничего, связанного с данными Glue и pipe, в основном он полагается только на класс трансформаторов Trainer. Я даже использую другую модель (Флобер). Я реплицировал класс InputFeature, и мой код работает для обоих приведенных ниже случаев:

class InputFeature:
    def __init__(self, text, label):
        self.input_ids = text
        self.label = label

class InputFeaturePlural:
    def __init__(self, text, label):
        self.input_ids = text
        self.labels = label

Но он не работает, если я назову второй атрибут self.labe или другими именами. Почему можно использовать оба имени атрибута?

В моем случае это не так важно, но мне неудобно передавать данные в переменной, которая «меняет имя» где-то по пути.

Спасибо за идеи

1 Ответ

1 голос
/ 17 июня 2020

Переименование происходит в collator. В трейнере init, когда data_collator равно None, используется значение по умолчанию:

class Trainer:
    # ...
    def __init__(...):
        # ...
        self.data_collator = data_collator if data_collator is not None else default_data_collator
        # ...

FYI, self.data_collator позже используется, когда вы получаете dataloader :

data_loader = DataLoader(
    self.train_dataset,
    batch_size=self.args.train_batch_size,
    sampler=train_sampler,
    collate_fn=self.data_collator,              # <-- here
    drop_last=self.args.dataloader_drop_last,
)

Подборщик по умолчанию имеет специальную обработку для меток , которая при необходимости выполняет это переименование:

# Special handling for labels.
# Ensure that tensor is created with the correct type
# (it should be automatically the case, but let's make sure of it.)
if hasattr(first, "label") and first.label is not None:
    if type(first.label) is int:
        labels = torch.tensor([f.label for f in features], dtype=torch.long)
    else:
        labels = torch.tensor([f.label for f in features], dtype=torch.float)
    batch = {"labels": labels}  # <-- here is where it happens
elif hasattr(first, "label_ids") and first.label_ids is not None:
    if type(first.label_ids[0]) is int:
        labels = torch.tensor([f.label_ids for f in features], dtype=torch.long)
    else:
        labels = torch.tensor([f.label_ids for f in features], dtype=torch.float)
    batch = {"labels": labels}
else:
    batch = {}
...