【问题标题】:ValueError: Cannot reshape a tensor (BERT - transfer learning)ValueError:无法重塑张量(BERT - 迁移学习)
【发布时间】:2020-07-23 01:16:19
【问题描述】:

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

为了将我的输入转换为所需的 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 个元素) for '{{node tf_bert_for_sequence_classification_3/bert/embeddings/LayerNorm/Reshape}} = 重塑[T=DT_FLOAT, Tshape=DT_INT32](tf_bert_for_sequence_classification_3/bert/embeddings/LayerNorm/Reshape/ReadVariableOp, tf_bert_for_sequence_classification_3/bert/embeddings/LayerNorm/Reshape/shape)' 输入形状:[768],[4],输入张量计算为 部分形状:输入1 = [1,1,128,1]。

我知道 BERT 将每个标记转换为 768 值数组,但这是我对该特定数字的唯一了解,所以我不知道如何继续。

如果有人对 HuggingFace 库有经验,我也会感谢您对 TFBertForSequenceClassification 是否适合段落分类的想法。

非常感谢。

【问题讨论】:

    标签: python machine-learning keras tensorflow2.0


    【解决方案1】:

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

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

    我认为这不是完全必要的,所以如果您仍然使用 numpy 数组,那么请忽略这一段并相应地更改下面的 reshape 函数(从 tf.reshape 到 np reshape 方法)

    发件人:

    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)

    根据文档,注意掩码和令牌类型 ID 对于 BERT 是可选的。在这个例子中,我只使用了 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) )
    

    将标签转换为张量

    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)
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-27
      • 2020-10-31
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2019-09-19
      • 1970-01-01
      • 2017-09-14
      相关资源
      最近更新 更多