本周工作进展
经过两周心酸的调试,在省略了回归操作的情况下依旧失败了无数遍,今天我终于跑出了第一个能看的 CTPN 模型。这篇博客就作为我 CTPN 之旅的完结总结,虽然全连接后的分支只剩分类了,虽然文本框合并也没有。
详细工作内容
① 模型设计
首先,输入图片经过 VGG16,长宽缩小到原来 1/16,得到 feature map, 所以 feature map 的一个像素对应原图的 16*16 像素,这也是为什么 anchor 的宽度要固定为 16。
接着,feature map 的每个像素点都取包括周围的九个像素点拼接,每个像素点通道数为 c,则可以拼接成一个 9c 通道数的像素。实际操作中,可以用 1*1 卷积代替。
逐行将新 feature map 的像素输入双向 LSTM,找到 anchor 间水平的序列关系。
每个 feature map 输入全连接层,在分别输出 2k 个分数(最后我只做了这个),2k 个定位,k 个边缘提纯。
# 去掉全连接的 vgg16 网络
def vgg16_no_tail():
# 注意一定要把 include_top 设为 false,
# 否则 input_shape 默认为 224*224,会出错
vgg = keras.applications.VGG16(include_top=False)
vgg_no_tail = keras.Model(
inputs=vgg.input,
outputs=vgg.get_layer("block5_conv3").output)
return vgg_no_tail
# 生成训练模型
def ctpn_model(h=600, w=900, k=10, anchor_size=16):
conv_h = h // anchor_size
conv_w = w // anchor_size
input_layer = vgg16_no_tail(None)
layer = input_layer.output
# 卷积代替
layer = keras.layers.Convolution2D(
512 * 9, (3, 3),
activation='relu',
padding='same',
name='cnn2rnn')(layer)
# 变形,用于找到像素的水平关联
layer = keras.layers.Reshape((-1, 512 * 9))(layer)
# bi-lstm
layer = keras.layers.Bidirectional(
keras.layers.LSTM(128, return_sequences=True))(layer)
# 恢复形状
layer = keras.layers.Reshape((conv_h, conv_w, 256))(layer)
# FC
layer = keras.layers.Convolution2D(512, (1, 1), activation='r