Этап 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
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)
Ta-da! это работает
Этап 2
Давайте глубже рассмотрим ClassifierChain class
Модель с несколькими метками, которая объединяет двоичные классификаторы в цепочку.
Каждая модель делает прогноз в порядке, указанном цепочкой, используя все доступные функции, предоставленные модели, плюс прогнозы моделей, которые находятся ранее в цепочке.
Итак что нам действительно нужно, так это y
формы 111 X 17
, чтобы цепочка содержала 17 оценок. Давайте попробуем
Настоящая ClassifierChain
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
входных характеристик + результат всех предыдущих оценщиков.
Решение [хакерское]
Нам нужен способ изменить input_size
модели, поскольку они созданы из ClassifierChain
. Кажется, что в ClassifierChain
нет обратных вызовов или перехватов, поэтому у меня есть хакерское решение.
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
каждого столбца, соответствующего прогнозам, сделанным соответствующим оценщиком.