代码之家  ›  专栏  ›  技术社区  ›  harmegiddo

如何在Keras中使用卷积LSTM实现位置估计?

  •  0
  • harmegiddo  · 技术社区  · 8 年前

    我在Keras和Tensorflow中使用了LSTM。

    我想实现位置估计。

    我想输入电影(1个场景是15帧)并估计移动方块在电影中的位置。

    输入为15帧。输出为2个变量(x,y)。

    在以下代码中,估计精度太差。我该怎么办? 而且,我不理解AveragePoolG3D/重塑(没有这个,它将无法执行)。

    # 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 回复  |  直到 8 年前
        1
  •  0
  •   Daniel Möller    8 年前

    查看您的 seq.summary() 了解形状。

    您的最后一个 ConvLSTM2D 图层正在输出具有形状的内容

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

    要使密集层工作,需要保持“电影”和“长度”维度,并将其他维度合并为一个维度。

    请注意,尺寸标注 40 (通道)很重要,因为它代表不同的“概念”,而 80 s(边)纯粹是二维位置。

    由于您不想触及“长度”维度,因此需要 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-net”,并尝试在那里创建类似U-net的东西。

    推荐文章