Как разделить вход на разные каналы в керасе - PullRequest
0 голосов
/ 05 июня 2018

У меня есть 20 канальных данных, каждое из которых содержит 5000 значений (всего более 150 000 записей, хранящихся в виде файлов .npy на жестком диске).

Я следую учебному пособию keras fit_generator, доступному на https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly.html длячитать данные (каждая запись читается как (5000, 20) массив NumPy типа float32.

Сети, которые я теоретизировал, имеют параллельные сверточные сети для каждого канала, которые объединяются в конце и, следовательно, должныпараллельная подача данных. Считывание и передача только одного канала из данных и подача в одну сеть успешна

def __data_generation(self, list_IDs_temp):
    'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
    # Initialization
    if(self.n_channels == 1):
        X = np.empty((self.batch_size, *self.dim))
    else:
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
    y = np.empty((self.batch_size), dtype=int)

    # Generate data
    for i, ID in enumerate(list_IDs_temp):
        # Store sample
        d = np.load(self.data_path + ID + '.npy')
        d = d[:, self.required_channel]
        d = np.expand_dims(d, 2)
        X[i,] = d

        # Store class
        y[i] = self.labels[ID]

    return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

Однако при чтении всей записи и попытке передать ее в сеть с помощью нарезки с помощью лямбдыя получаю слои

Чтение всей записи

 X[i,] = np.load(self.data_path + ID + '.npy')

Использование реализации Lambda Slicing Layer доступно по адресу: https://github.com/keras-team/keras/issues/890 и вызов

input = Input(shape=(5000, 20))
slicedInput = crop(2, 0, 1)(input)

IЯ могу скомпилировать модель и показать ожидаемые размеры слоев.

Когда данные поступают в эту сеть, я получаю

ValueError: could not broadcast input array from shape (5000,20) into shape (5000,1)

AЛюбая помощь будет высоко ценится ....

1 Ответ

0 голосов
/ 05 июня 2018

Как упомянуто в Github thread , на который вы ссылаетесь, Lambda layer может возвращать только один вывод, и, таким образом, предлагаемый crop(dimension, start, end) возвращает только один "Tensor наданное измерение от начала до конца ".

Я считаю, что то, чего вы хотите достичь, может быть сделано таким образом:

from keras.layers import Dense, Concatenate, Input, Lambda
from keras.models import Model

num_channels = 20
input = Input(shape=(5000, num_channels))

branch_outputs = []
for i in range(num_channels):
    # Slicing the ith channel:
    out = Lambda(lambda x: x[:, i])(input)

    # Setting up your per-channel layers (replace with actual sub-models):
    out = Dense(16)(out)
    branch_outputs.append(out)

# Concatenating together the per-channel results:
out = Concatenate()(branch_outputs)

# Adding some further layers (replace or remove with your architecture):
out = Dense(10)(out)

# Building model:
model = Model(inputs=input, outputs=out)    
model.compile(optimizer=keras.optimizers.Adam(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])

# --------------
# Generating dummy data:
import numpy as np
data = np.random.random((64, 5000, num_channels))
targets = np.random.randint(2, size=(64, 10))

# Training the model:
model.fit(data, targets, epochs=2, batch_size=32)
# Epoch 1/2
# 32/64 [==============>...............] - ETA: 1s - loss: 37.1219 - acc: 0.1562
# 64/64 [==============================] - 2s 27ms/step - loss: 38.4801 - acc: 0.1875
# Epoch 2/2
# 32/64 [==============>...............] - ETA: 0s - loss: 38.9541 - acc: 0.0938
# 64/64 [==============================] - 0s 4ms/step - loss: 36.0179 - acc: 0.1875
...