ValueError: Невозможно изменить тензор (BERT - передача обучения) - PullRequest
1 голос
/ 10 апреля 2020

Я строю мультиклассовую модель классификации текста, используя библиотеку трансформеров HuggingFace, используя Keras и BERT.

Чтобы преобразовать мои входные данные в требуемый формат bert, я использую метод encode_plus, найденный в Класс BertTokenizer найден здесь

Данные представляют собой абзац предложений для функции и имеют одну метку (всего 45 меток)

Код для преобразуйте входные данные:

def create_input_array(df, tokenizer):
sentences = df.text.values
labels = df.label.values

input_ids = []
attention_masks = []
token_type_ids = []

# For every sentence...
for sent in sentences:
    # `encode_plus` will:
    #   (1) Tokenize the sentence.
    #   (2) Prepend the `[CLS]` token to the start.
    #   (3) Append the `[SEP]` token to the end.
    #   (4) Map tokens to their IDs.
    #   (5) Pad or truncate the sentence to `max_length`
    #   (6) Create attention masks for [PAD] tokens.

    encoded_dict = tokenizer.encode_plus(
        sent,  # Sentence to encode.
        add_special_tokens=True,  # Add '[CLS]' and '[SEP]'
        max_length=128,  # Pad & truncate all sentences.
        pad_to_max_length=True,
        return_attention_mask=True,  # Construct attn. masks.
        return_tensors='tf',  # Return tf tensors.
    )

    # Add the encoded sentence to the list.
    input_ids.append(encoded_dict['input_ids'])

    # And its attention mask (simply differentiates padding from non-padding).
    attention_masks.append(encoded_dict['attention_mask'])

    token_type_ids.append(encoded_dict['token_type_ids'])

return [np.asarray(input_ids, dtype=np.int32),
        np.asarray(attention_masks, dtype=np.int32),
        np.asarray(token_type_ids, dtype=np.int32)]

Модель в самой базовой форме c, которая по-прежнему воспроизводит ошибку:

model = TFBertForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels = labellen,
output_attentions = False, 
output_hidden_states = False
)

Компилировать и подгонять:

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3, epsilon=1e-08, clipnorm=1.0)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
model.compile(optimizer=optimizer, loss=loss, metrics=[metric])
model.fit(x_train, y[:100], epochs=1, batch_size=3)

Ошибка при запуске:

ValueError: Невозможно изменить тензор с 768 элементами для формирования [1,1,128,1] (128 элементов) для '{{node tf_bert_for_sequence_classification_3 / bert / embeddings / LayerNorm / Reshape}} = Reshape [T = DT_FLOAT, Tshape = DT_INT32] (tf_bert_for_sequence_classification_3 / bert / embNN / Layer ReadOn / переменная / встраиваемая / Layer Read / Layer Read / Layer Read / Layer Read / Layer Read / Layer Read / , tf_bert_for_sequence_classific ation_3 / bert / embeddings / LayerNorm / Reshape / shape) 'с входными формами: [768], [4] и с входными тензорами, вычисленными как частичные формы: input 1 = [1,1,128,1].

Я понимаю, что BERT преобразует каждый токен в массив значений 768, но это единственное, что я знаю об этом конкретном числе, поэтому я застрял в том, как действовать.

Если у кого-то есть опыт работы с библиотекой HuggingFace, я также буду признателен за ваши мысли о том, подходит ли TFBertForSequenceClassification для классификации абзацев.

Большое спасибо.

1 Ответ

0 голосов
/ 14 апреля 2020

В случае, если кому-то еще нужна помощь с этим, это было довольно сложное исправление, но вот что я сделал:

Изменено использование numpy массивов для наборов данных tf

Я не думаю, что это совершенно необходимо, поэтому, если вы все еще используете numpy массивы, тогда проигнорируйте этот абзац и соответственно измените приведенные ниже функции изменения формы (от tf.reshape до методов преобразования np)

С:

return [np.asarray(input_ids, dtype=np.int32),
         np.asarray(attention_masks, dtype=np.int32),
         np.asarray(token_type_ids, dtype=np.int32)]

До:

input_ids = tf.convert_to_tensor(input_ids)
attention_masks = tf.convert_to_tensor(attention_masks)

 return input_ids, attention_masks

(поэтому списки преобразуются в тензор)

Функция преобразования входных вызовов (обратите внимание на пропуск token_type_ids)

Из документации маски внимания и идентификаторы типа токена являются необязательными для BERT. В этом примере я использую только input_ids и Внимание_Маски

 train_ids, train_masks = create_input_array(df[:], tokenizer=tokenizer)

Изменение формы ввода

train_ids = tf.reshape(train_ids, (-1, 128, 1) )
train_masks = tf.reshape(train_masks, (-1, 128, 1) )

Преобразование меток в тензор

labels = tf.convert_to_tensor(y[:])
n_classes = np.unique(y).max() + 1

Импорт всех тензоров в набор данных tf

dataset = tf.data.Dataset.from_tensors(( (train_ids, train_masks), labels ))

Загрузите модель BERT и добавьте слои

Прежде чем все, что у меня было была однострочная модель = TFBert ... теперь я создаю входной слой для каждого из input_ids и масок, возвращая только первый вывод из слоя bert, сглаживаю, а затем добавляю плотный слой.

model = TFBertForSequenceClassification.from_pretrained('bert-base-uncased', trainable=False)

# Input layers
input_layer = Input(shape=(128, ), dtype=np.int32)
input_mask_layer = Input(shape=(128, ), dtype=np.int32)

# Bert layer, return first output
bert_layer = model([input_layer, input_mask_layer])[0]

# Flatten layer
flat_layer = Flatten() (bert_layer)

# Dense layer
dense_output = Dense(n_classes, activation='softmax') (flat_layer)

model_ = Model(inputs=[input_layer, input_mask_layer], outputs=dense_output)

Скомпилировать модель

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3, epsilon=1e-08, clipnorm=1.0)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
model_.compile(optimizer=optimizer, loss=loss, metrics=[metric])

Здесь весь набор данных передается в качестве первого аргумента, который также содержит метки.

model_.fit(dataset, epochs=4, batch_size=4, verbose=1)

Надеюсь, это помогает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...