ValueError:无法重塑张量(BERT-转移学习)

时间:2020-04-10 09:49:33

标签: python machine-learning keras tensorflow2.0

我正在使用Keras和BERT使用HuggingFace的转换器库构建多类文本分类模型。

要将输入转换为所需的bert格式,我使用BertTokenizer类found here中的encode_plus方法

数据是每个功能的句子段落,并且具有单个标签(总共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)]

最基本形式的模型仍然会重现错误:

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 / embedddings / LayerNorm / Reshape / ReadVariableOp, tf_bert_for_sequence_classification_3 / bert / embedddings / LayerNorm / Reshape / shape)' 输入形状为[768],[4],输入张量计算为 部分形状:input 1 = [1,1,128,1]。

我了解到BERT会将每个令牌转换为768个值数组,但这是我对那个特定数字的唯一了解,所以我坚持如何进行。

如果任何人都有使用HuggingFace库的经验,也希望您考虑到TFBertForSequenceClassification是否适合段落分类。

非常感谢。

1 个答案:

答案 0 :(得分:1)

万一其他人需要帮助,这是一个相当复杂的修复程序,但这是我所做的:

从使用numpy数组更改为tf数据集

我不认为这是完全必要的,因此,如果您仍使用numpy数组,则仍然可以忽略此段并相应地更改下面的重塑函数(从tf.reshape更改为np reshape方法)

发件人:

with

收件人:

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

(因此列表已被转换为张量)

调用转换输入功能(注意省略token_type_ids)

在文档中,注意掩码和令牌类型ID对于BERT是可选的。在此示例中,我仅使用input_ids和tention_masks

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

 return input_ids, attention_masks

重塑输入

 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) )

将所有张量导入到tf数据集

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

加载BERT模型并添加图层

在我之前只有一线模型= TFBert ... 现在,我为每个input_id和masks创建一个输入层,仅返回bert层的第一个输出,展平,然后添加一个密集层。

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

编译模型

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])

希望这会有所帮助。