Что может быть причиной увеличения потерь на валидацию и сохранения точности до нуля при уменьшении потерь на поезд? - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь решить проблему классификации текстов в мультиклассе. Из-за специфических требований c из моего проекта я пытаюсь использовать скорч (https://skorch.readthedocs.io/en/stable/index.html), чтобы обернуть pytorch для конвейера sklearn. То, что я пытаюсь сделать, это настроить предварительно обученную версию BERT из Huggingface (https://huggingface.co) с моим набором данных. Насколько я знаю, я пытался следовать инструкциям Скорча о том, как мне следует вводить свои данные, структурировать модель et c. Тем не менее, во время обучения потери поезда уменьшаются до 8-й эпохи, когда они начинают колебаться, все время, пока потери проверки с самого начала увеличиваются, а точность проверки остается постоянной до нуля. Мой конвейер настроен на

    from sklearn.pipeline import Pipeline


    pipeline = Pipeline(
    [
        ("tokenizer", Tokenizer()),
        ("classifier", _get_new_transformer())
    ]

, в котором я использую класс токенизатора для предварительной обработки набора данных, токенизации его для BERT и создания масок внимания. Это выглядит так:

    import torch
    from transformers import AutoTokenizer, AutoModel
    from torch import nn
    import torch.nn.functional as F
    from sklearn.base import BaseEstimator, TransformerMixin
    from tqdm import tqdm
    import numpy as np


    class Tokenizer(BaseEstimator, TransformerMixin):
        def __init__(self):
            super(Tokenizer, self).__init__()

            self.tokenizer = AutoTokenizer.from_pretrained(/path/to/model)

        def _tokenize(self, X, y=None):
            tokenized = self.tokenizer.encode_plus(X, max_length=20, add_special_tokens=True, pad_to_max_length=True)
            tokenized_text = tokenized['input_ids']
            attention_mask = tokenized['attention_mask']
            return np.array(tokenized_text), np.array(attention_mask)


        def fit(self, X, y=None):
            return self

        def transform(self, X, y=None):
            word_tokens, attention_tokens = np.array([self._tokenize(string)[0] for string in tqdm(X)]), \
                                    np.array([self._tokenize(string)[1] for string in tqdm(X)])
            X = word_tokens, attention_tokens
            return X

        def fit_transform(self, X, y=None, **fit_params):
            self = self.fit(X, y)
            return self.transform(X, y)

, затем я инициализирую модель, которую я хочу настроить, как

    class Transformer(nn.Module):
        def __init__(self, num_labels=213, dropout_proba=.1):
            super(Transformer, self).__init__()

            self.num_labels = num_labels
            self.model = AutoModel.from_pretrained(/path/to/model)
            self.dropout = torch.nn.Dropout(dropout_proba)
            self.classifier = torch.nn.Linear(768, num_labels)


        def forward(self, X, **kwargs):
            X_tokenized, attention_mask = torch.stack([x.unsqueeze(0) for x in X[0]]),\
                                  torch.stack([x.unsqueeze(0) for x in X[1]])
            _, X = self.model(X_tokenized.squeeze(), attention_mask.squeeze())
            X = F.relu(X)
            X = self.dropout(X)
            X = self.classifier(X)
            return X

Я инициализирую модель и создаю классификатор с помощью скорч, как показано ниже

    from skorch import NeuralNetClassifier
    from skorch.dataset import CVSplit
    from skorch.callbacks import ProgressBar
    import torch
    from transformers import AdamW


    def _get_new_transformer() -> NeuralNetClassifier:
        transformer = Transformer()
        net = NeuralNetClassifier(
            transformer,
            lr=2e-5,
            max_epochs=10,
            criterion=torch.nn.CrossEntropyLoss,
            optimizer=AdamW,
            callbacks=[ProgressBar(postfix_keys=['train_loss', 'valid_loss'])],
            train_split=CVSplit(cv=2, random_state=0)
            )
            return net

, и я использую fit следующим образом:

   pipeline.fit(X=dataset.training_samples, y=dataset.training_labels)

, в котором мои обучающие примеры - это списки строк, а мои метки - это массив, содержащий индексы каждого класса, как того требует pytorch.

Это пример того, что происходит

история тренировок

Я пытался тренировать только полностью подключенный слой, а не BERT, но у меня та же проблема снова. Я также проверил точность поезда после тренировочного процесса, и она составила всего 0,16%. Буду благодарен за любые советы или советы о том, как решить мою проблему! Я довольно новичок с Скорч и не очень комфортно с Pytorch, и я считаю, что мне не хватает чего-то действительно простого. Заранее большое спасибо!

...