Как я могу использовать Convolutional LSTM в Keras для оценки местоположения? - PullRequest
0 голосов
/ 25 апреля 2018

Я использовал LSTM в Керасе с Tensorflow.

Я хотел бы реализовать оценку позиции.

Я хочу ввести фильм (1 сцена - 15 кадров) и оценить положение движенияквадрат в фильме.

Ввод 15 кадров.Выходное значение равно 2 переменным (x, y).

В следующем коде точность оценки слишком низкая.Что я должен делать?И я не понимаю AveragePooling3D / Reshape (без этого он не будет работать.).

# We create a layer which take as input movies of shape
# (n_frames, width, height, channels) and returns a movie
# of identical shape.

seq = Sequential()
seq.add(ConvLSTM2D(filters=40, kernel_size=(3, 3),
                   input_shape=(None, 80, 80, 1),
                   padding='same', return_sequences=True))
seq.add(BatchNormalization())

seq.add(ConvLSTM2D(filters=40, kernel_size=(3, 3),
                   padding='same', return_sequences=True))
seq.add(BatchNormalization())

seq.add(ConvLSTM2D(filters=40, kernel_size=(3, 3),
                   padding='same', return_sequences=True))
seq.add(BatchNormalization())

seq.add(ConvLSTM2D(filters=40, kernel_size=(3, 3),
                   padding='same', return_sequences=True))
seq.add(BatchNormalization())

#seq.add(Flatten())
seq.add(AveragePooling3D((1, 80, 80)))

seq.add(Reshape((-1, 40)))

seq.add(Dense(2))

#seq.add(Conv3D(filters=1, kernel_size=(3, 3, 3),
#               activation='sigmoid',
#               padding='same', data_format='channels_last'))

seq.compile(loss='mean_squared_error', optimizer='adam')
def generate_movies(n_samples=1200, n_frames=15):
    row = 80
    col = 80
    noisy_movies = np.zeros((n_samples, n_frames, row, col, 1), dtype=np.float)
    shifted_movies = np.zeros((n_samples, n_frames, row, col, 1),
                              dtype=np.float)
    square_x_y = np.zeros((n_samples, n_frames, 2), dtype=np.float)

    for i in range(n_samples):
        for j in range(1):
            # Initial position
            xstart = np.random.randint(20, 60)
            ystart = np.random.randint(20, 60)
            # Direction of motion
            directionx = np.random.randint(0, 3) - 1
            directiony = np.random.randint(0, 3) - 1

            # Size of the square
            w = np.random.randint(2, 4)

            for t in range(n_frames):
                x_shift = xstart + directionx * t
                y_shift = ystart + directiony * t
                noisy_movies[i, t, x_shift - w: x_shift + w,
                             y_shift - w: y_shift + w, 0] += 1

                # Make it more robust by adding noise.
                # The idea is that if during inference,
                # the value of the pixel is not exactly one,
                # we need to train the network to be robust and still
                # consider it as a pixel belonging to a square.
                if np.random.randint(0, 2):
                    noise_f = (-1)**np.random.randint(0, 2)
                    noisy_movies[i, t,
                                 x_shift - w - 1: x_shift + w + 1,
                                 y_shift - w - 1: y_shift + w + 1,
                                 0] += noise_f * 0.1

                # Shift the ground truth by 1
                x_shift = xstart + directionx * (t + 1)
                y_shift = ystart + directiony * (t + 1)
                shifted_movies[i, t, x_shift - w: x_shift + w,
                               y_shift - w: y_shift + w, 0] += 1

                square_x_y[i, t, 0] = x_shift/row
                square_x_y[i, t, 1] = y_shift/col

    # Cut to a 40x40 window
    #noisy_movies = noisy_movies[::, ::, 20:60, 20:60, ::]
    #shifted_movies = shifted_movies[::, ::, 20:60, 20:60, ::]
    #noisy_movies[noisy_movies >= 1] = 1
    #shifted_movies[shifted_movies >= 1] = 1
    return noisy_movies, shifted_movies, square_x_y

# Train the network
noisy_movies, shifted_movies, sq_x_y = generate_movies(n_samples = 1200)
seq.fit(noisy_movies[:1000], sq_x_y[:1000], batch_size=10,
        epochs=1, validation_split=0.05)

1 Ответ

0 голосов
/ 25 апреля 2018

См. Ваш seq.summary(), чтобы понять формы.

Ваш последний ConvLSTM2D слой выводит что-то с формой

  • (movies, length, side1, side2, channels)
  • (None, None, 80, 80, 40)

Чтобы плотный слой работал, вам нужно сохранить размерность «фильмы» и «длина», а остальные свести в одно целое.

Обратите внимание, что размер 40 (каналы) важен, поскольку он представляет разные "концепции", тогда как 80 s (стороны) являются чисто 2D-позиционными.

Поскольку вы не хотите прикасаться к измерению «длина», вам нужен AveragePooling2D (не 3D). Но так как вы собираетесь обнаружить очень четкую позиционную особенность и ее местоположение , я предлагаю вам вообще не сворачивать пространственные измерения. Лучше просто изменить форму и добавить Dense, который будет учитывать эти позиции.

Так что вместо AveragePooling я предлагаю вам использовать:

seq.add(Reshape((-1, 80*80*40)) #new shape is = (movies, length, 80*80*40)

Затем вы добавляете Плотный слой, у которого все еще есть понятие позиций:

seq.add(Dense(2)) #output shape is (movies, length, 2)

Это не гарантирует, что ваша модель будет работать хорошо, но я считаю, что "лучше".

Другие вещи, которые вы можете сделать, это добавить более плотные слои и плавно перейти от 80 * 80 * 40 функций к 2.

Это более сложно, но вы можете изучить функциональную модель API, узнать о "U-сетях" и попытаться создать что-то вроде сети.

...