Я пытаюсь решить проблему классификации текстов в мультиклассе. Из-за специфических требований 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, и я считаю, что мне не хватает чего-то действительно простого. Заранее большое спасибо!