ValueError: Cannot reshape a tensor (BERT - transfer learning)
ValueError: Cannot reshape a tensor (BERT - transfer learning)
我正在使用 HuggingFace 的变形金刚库、Keras 和 BERT 构建多class 文本class化模型。
为了将我的输入转换为所需的 bert 格式,我使用了 BertTokenizer class 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: Cannot reshape a tensor with 768 elements to shape
[1,1,128,1] (128 elements) for '{{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/embeddings/LayerNorm/Reshape/ReadVariableOp,
tf_bert_for_sequence_classification_3/bert/embeddings/LayerNorm/Reshape/shape)'
with input shapes: [768], [4] and with input tensors computed as
partial shapes: input1 = [1,1,128,1].
我知道 BERT 将每个标记转换为一个 768 值数组,但这是我对那个特定数字的唯一了解,所以我不知道如何继续。
如果有人有使用 HuggingFace 库的经验,我也很感谢您对 TFBertForSequenceClassification 是否适合段落 classification 的想法。
非常感谢。
万一其他人需要帮助,这是一个相当复杂的修复,但这是我所做的:
从使用 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)
根据文档,注意掩码和令牌类型 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)
希望这对您有所帮助。
我正在使用 HuggingFace 的变形金刚库、Keras 和 BERT 构建多class 文本class化模型。
为了将我的输入转换为所需的 bert 格式,我使用了 BertTokenizer class 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: Cannot reshape a tensor with 768 elements to shape [1,1,128,1] (128 elements) for '{{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/embeddings/LayerNorm/Reshape/ReadVariableOp, tf_bert_for_sequence_classification_3/bert/embeddings/LayerNorm/Reshape/shape)' with input shapes: [768], [4] and with input tensors computed as partial shapes: input1 = [1,1,128,1].
我知道 BERT 将每个标记转换为一个 768 值数组,但这是我对那个特定数字的唯一了解,所以我不知道如何继续。
如果有人有使用 HuggingFace 库的经验,我也很感谢您对 TFBertForSequenceClassification 是否适合段落 classification 的想法。
非常感谢。
万一其他人需要帮助,这是一个相当复杂的修复,但这是我所做的:
从使用 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)
根据文档,注意掩码和令牌类型 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)
希望这对您有所帮助。