无法将输入数组从形状 (27839,1) 广播到形状 (27839)
Posted
技术标签:
【中文标题】无法将输入数组从形状 (27839,1) 广播到形状 (27839)【英文标题】:could not broadcast input array from shape (27839,1) into shape (27839) 【发布时间】:2020-10-06 15:05:59 【问题描述】:我正在为一个在链中使用 Keras 二进制分类器模型的多类问题构建一个链分类器。我有 17 个标签作为分类目标,X_train 的形状是 (111300,107),y_train 是 (111300,17)。训练后,我在预测方法中得到了以下错误;
*could not broadcast input array from shape (27839,1) into shape (27839)*
我的代码在这里:
def create_model():
input_size=length_long_sentence
embedding_size=128
lstm_size=64
output_size=len(unique_tag_set)
#----------------------------Model--------------------------------
current_input=Input(shape=(input_size,))
emb_current = Embedding(vocab_size, embedding_size, input_length=input_size)(current_input)
out_current=Bidirectional(LSTM(units=lstm_size))(emb_current )
#out_current = Reshape((1,2*lstm_size))(out_current)
output = Dense(units=1, activation= 'sigmoid')(out_current)
#output = Dense(units=1, activation='softmax')(out_current)
model = Model(inputs=current_input, outputs=output)
#-------------------------------compile-------------
model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])
return model
model = KerasClassifier(build_fn=create_model, epochs=1,batch_size=256, shuffle = True, verbose = 1,validation_split=0.2)
chain=ClassifierChain(model, order='random', random_state=42)
history=chain.fit(X_train, y_train)
chain.classes_ 的结果如下:
[array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8),
array([0, 1], dtype=uint8)]
然后尝试预测测试数据:
Y_pred_chain = chain.predict(X_test)
模型总结如下:
这里有完整的错误跟踪:
109/109 [==============================] - 22s 202ms/step
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-28-34a25ad06cd4> in <module>()
----> 1 Y_pred_chain = chain.predict(X_test)
/usr/local/lib/python3.6/dist-packages/sklearn/multioutput.py in predict(self, X)
523 else:
524 X_aug = np.hstack((X, previous_predictions))
--> 525 Y_pred_chain[:, chain_idx] = estimator.predict(X_aug)
526
527 inv_order = np.empty_like(self.order_)
ValueError: could not broadcast input array from shape (27839,1) into shape (27839)
谁能帮忙解决这个错误?
【问题讨论】:
我会仔细检查 X_test 的形状。 X_test 的形状是 (27839, 107)。 训练结束后,能不能打印chain.classes_
并写出它的输出?
我在主帖中添加了chain.classes_的输出。
这有点远,但我有一个类似的问题,我通过使用np.array(X_test)
作为输入解决了这个问题。我认为这与X_test
的指针是否实际“控制”内存有关
【参考方案1】:
第一阶段
按照问题中发布的模型摘要,我从107
的输入大小开始,输出大小为1
(二进制分类任务)
让我们把它分解成碎片并理解。
模型架构
input_size = 107
# define the model
def create_model():
global input_size
embedding_size=128
lstm_size=64
output_size=1
vocab_size = 100
current_input=Input(shape=(input_size,))
emb_current = Embedding(vocab_size, embedding_size, input_length=input_size)(current_input)
out_current=Bidirectional(LSTM(units=lstm_size))(emb_current )
output = Dense(units=output_size, activation= 'sigmoid')(out_current)
model = Model(inputs=current_input, outputs=output)
model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])
return model
一些虚拟数据
X = np.random.randint(0,100,(111, 107))
y = np.random.randint(0,2,(111,1)) # NOTE: The y should have two dimensions
让我们直接测试 keras 模型
model = KerasClassifier(build_fn=create_model, epochs=1, batch_size=8, shuffle = True, verbose = 1,validation_split=0.2)
model.fit(X, y)
y_hat = model.predict(X)
输出:
Train on 88 samples, validate on 23 samples
Epoch 1/1
88/88 [==============================] - 2s 21ms/step - loss: 0.6951 - accuracy: 0.4432 - val_loss: 0.6898 - val_accuracy: 0.5652
111/111 [==============================] - 0s 2ms/step
(111, 1)
哒哒!它有效
现在让它们链接并运行
model=KerasClassifier(build_fn=create_model, epochs=1, batch_size=8, shuffle=True, verbose=1,validation_split=0.2)
chain=ClassifierChain(model, order='random', random_state=42)
chain.fit(X, y)
print (chain.predict(X).shape)
哎呀!它训练但预测失败,因为 OP 指出 错误:
ValueError: could not broadcast input array from shape (111,1) into shape (111)
问题
这个错误是因为sklearn中的以下行
--> 525 Y_pred_chain[:, chain_idx] = estimator.predict(X_aug)
这是因为分类器链一次运行一个估计器,并将每个估计器的预测保存在估计器索引处的Y_pred_chain
中(由order
参数确定)。它假设估计器以一维数组的形式返回预测。但是 keras 模型返回形状为 batch_size x output_size
的输出,在我们的例子中是 111 x 1
。
解决办法
我们需要一种方法来重塑形状的预测 111 X 1
到 111
或一般 batch_size x 1
到 batch_size
。让我们依靠 OOPS 的概念,重载 KerasClassifier
的 predict 方法
class MyKerasClassifier(KerasClassifier):
def __init__(self, **args):
super().__init__(**args)
def predict(self, X):
return super().predict(X).reshape(len(X)) # Here we are flattening 2D array to 1D
model=MyKerasClassifier(build_fn=create_model, epochs=1, batch_size=8, shuffle=True, verbose=1,validation_split=0.2)
chain=ClassifierChain(model, order='random', random_state=42)
chain.fit(X, y)
print (chain.predict(X).shape)
输出:
Epoch 1/1
88/88 [==============================] - 2s 19ms/step - loss: 0.6919 - accuracy: 0.5227 - val_loss: 0.6892 - val_accuracy: 0.5652
111/111 [==============================] - 0s 3ms/step
(111, 1)
哒哒!它有效
第二阶段
让我们深入了解ClassifierChain 类
一种将二元分类器排列成链的多标签模型。
每个模型按照链指定的顺序进行预测 使用提供给模型的所有可用功能以及 链中较早的模型的预测。
所以我们真正需要的是一个形状为111 X 17
的y
,以便链包含17 个估计器。来试试吧
真正的分类器链
y = np.random.randint(0,2,(111,17))
model=MyKerasClassifier(build_fn=create_model, epochs=1, batch_size=8, shuffle=True, verbose=1,validation_split=0.2)
chain=ClassifierChain(model, order='random', random_state=42)
chain.fit(X, y)
输出:
ValueError: Error when checking input: expected input_62 to have shape (107,) but got array with shape (108,)
无法训练模型;原因很简单。该链首先训练具有107
功能的第一个估计器,并且工作正常。接下来,链选择下一个估计器,然后使用107
特征 + 前一个估计器的单个输出 (=108) 对其进行训练。但是由于我们的模型的输入大小为107
,因此它会失败,因此会出现错误消息。每个估计器将获得107
输入特征 + 所有先前估计器的输出。
解决方案 [hacky]
我们需要一种方法来更改模型的input_size
,因为它们是从ClassifierChain
创建的。 ClassifierChain
似乎没有回调或挂钩,所以我有一个 hacky 解决方案。
input_size = 107
# define the model
def create_model():
global input_size
embedding_size=128
lstm_size=64
output_size=1
vocab_size = 100
current_input=Input(shape=(input_size,))
emb_current = Embedding(vocab_size, embedding_size, input_length=input_size)(current_input)
out_current=Bidirectional(LSTM(units=lstm_size))(emb_current )
output = Dense(units=output_size, activation= 'sigmoid')(out_current)
model = Model(inputs=current_input, outputs=output)
model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])
input_size += 1 # <-- This does the magic
return model
X = np.random.randint(0,100,(111, 107))
y = np.random.randint(0,2,(111,17))
model=MyKerasClassifier(build_fn=create_model, epochs=1, batch_size=8, shuffle=True, verbose=1,validation_split=0.2)
chain=ClassifierChain(model, order='random', random_state=42)
chain.fit(X, y)
print (chain.predict(X).shape)
输出:
Train on 88 samples, validate on 23 samples
Epoch 1/1
88/88 [==============================] - 2s 22ms/step - loss: 0.6901 - accuracy: 0.6023 - val_loss: 0.7002 - val_accuracy: 0.4783
Train on 88 samples, validate on 23 samples
Epoch 1/1
88/88 [==============================] - 2s 22ms/step - loss: 0.6976 - accuracy: 0.5000 - val_loss: 0.7070 - val_accuracy: 0.3913
Train on 88 samples, validate on 23 samples
Epoch 1/1
----------- [Output truncated] ----------------
111/111 [==============================] - 0s 3ms/step
111/111 [==============================] - 0s 3ms/step
(111, 17)
正如预期的那样,它训练 17
估计器,predict
方法返回形状为 111 x 17
的输出,每列对应于相应估计器所做的预测。
【讨论】:
感谢您提供非常详细的回答。让我试试看。 我解决了输入大小的问题,将其设为无,因此它不会像我们的例子中的 107 那样被修复。 感谢您的回答。它通过自定义 keras 分类器和重载预测方法来工作。谢谢 自定义 kerasclassifier 预测方法在 google colab notebook 上工作,但是当我尝试在服务器上运行它时,它给了我这个错误'模型对象没有属性,'predict_classes'。有什么想法吗?【参考方案2】:这里是一个完整的工作示例...
我使用顺序模型和 softmax 作为最后一次激活来解决
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.models import *
from sklearn.multioutput import ClassifierChain
n_sample = 20
vocab_size = 33
input_size = 100
X = np.random.randint(0,vocab_size, (n_sample,input_size))
y = np.random.randint(0,2, (n_sample,17))
def create_model():
global input_size
embedding_size = 128
lstm_size = 64
model = Sequential([
Embedding(vocab_size, embedding_size, input_length=input_size),
Bidirectional(LSTM(units=lstm_size)),
Dense(units=2, activation= 'softmax')
])
model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])
input_size += 1
return model
model = tf.keras.wrappers.scikit_learn.KerasClassifier(build_fn=create_model, epochs=1, batch_size=256,
shuffle = True, verbose = 1, validation_split=0.2)
chain = ClassifierChain(model, order='random', random_state=42)
chain.fit(X, y)
chain.predict_proba(X)
这里是运行代码:https://colab.research.google.com/drive/1aVjjh6VPmAyBddwU4ff2w9y_LmmC02W_?usp=sharing
【讨论】:
以上是关于无法将输入数组从形状 (27839,1) 广播到形状 (27839)的主要内容,如果未能解决你的问题,请参考以下文章
Mask-RCNN,ValueError:无法将输入数组从形状(70)广播到形状(1)
如何将 RGB ImageItem 添加到 pyqtgraph ViewBox? ValueError:无法将输入数组从形状(256,256,4)广播到形状(256,256)