Keras官方自带了很多实用的模型教程,地址在https://github.com/keras-team/keras/tree/master/examples,这里主要是conv_lstm.py的基础上进行了一定修改,来实现一个非常简单的运动预测模型。
首先导入库函数:
from keras.models import Sequential
from keras.layers import Dropout
from keras.layers.convolutional import Conv3D
from keras.layers.convolutional_recurrent import ConvLSTM2D
from keras.layers.normalization import BatchNormalization
import numpy as np
import pylab as plt
之后可以开始架网络了。个人觉得卷积LSTM对于图片序列中每一张图片的处理可以等效于卷积层,同时具备LSTM对序列信息的处理能力。网络其他结构的处理和一般的卷积神经网络基本相同,因为网络是对序列中各图片进行依次处理。网络结构如下:
seq = Sequential()
seq.add(ConvLSTM2D(filters=16, kernel_size=(3, 3),
input_shape=(None, 16, 16, 1),
padding='same', return_sequences=True))
seq.add(BatchNormalization())
seq.add(Dropout(0.3))
seq.add(ConvLSTM2D(filters=32, kernel_size=(3, 3),
padding='same', return_sequences=True))
seq.add(BatchNormalization())
seq.add(Dropout(0.3))
seq.add(ConvLSTM2D(filters=32, kernel_size=(3, 3),
padding='same', return_sequences=True))
seq.add(BatchNormalization())
seq.add(Dropout(0.5))
seq.add(Conv3D(filters=1, kernel_size=(3, 3, 3),
activation='sigmoid',
padding='same', data_format='channels_last'))
seq.compile(loss='binary_crossentropy', optimizer='nadam')
seq.summary()
可以看到就是把常规的卷积网络中Conv2D换成ConvLSTM2D,其他的区别不大。
之后按照官方提供的方法生成数据,这里相比官方文档把图像缩小,并且不生成噪声数据,方便处理了:
def generate_movies(n_samples=1200, n_frames=15):
row = 32
col = 32
shifted_movies = np.zeros((n_samples, n_frames, row, col, 1),
dtype=np.float)
for i in range(n_samples):
# Add 3 to 7 moving squares
n = np.random.randint(3, 8)
for j in range(n):
# Initial position
xstart = np.random.randint(8, 24)
ystart = np.random.randint(8, 24)
# 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
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
shifted_movies = shifted_movies[::, ::, 8:24, 8:24, ::]
shifted_movies[shifted_movies >= 1] = 1
return shifted_movies
shifted_movies = generate_movies(n_samples=1200)
之后用生成的前1000组数据作为训练集,后200组作为测试集。每组数据的前10帧作为已知的输入,6~15帧作为需要预测的输出,对网络进行训练:
seq.fit(shifted_movies[:1000, 0:10], shifted_movies[:1000, 5:15], batch_size=10,
epochs=20, validation_split=0.05)
训练完成之后,查看网络在测试集上的表现即可:
y_pred = seq.predict(shifted_movies[1000:, 0:10])
该网络对测试集的预测结果如下所示:
输入数据:
真实输出:
预测输出:
可以看到,网络输出结果与真实结果之间差别不大,基本能够实现对运动状态的预测。
当然,在实际应用时,完全可以对视频流中每一张图片首先使用卷积神经网络提取出特征图,再用特征图对卷积LSTM进行学习,通过输出的特征图来反推出目标的位置即可。