Image captioning(二)

来源:互联网 发布:effective java 知乎 编辑:程序博客网 时间:2024/06/08 13:16

技术上来说

  • 往粗了讲,大家听到的是:RNN,CNN,ATTENTION,Embedding 比较有名的名词。
  • 往细了讲:卷积,max/min/avg pooling, self-attention, gated-weight,sigmod weight,softmax weight等这些具体的技术细节可能在你构建graph的时候都会或多或少的使用,万变不离其宗,熟悉使用这些东西,后面在遇到各种模型,业务应用的时候就很容易掌握。
  • 还有正则化(regularization),归一化(normalization)是很有用的东西,特别是dropout在模型层面防止过拟合,normalization用来平衡各层级的单元的影响范围这些都有很有用的效果。

什么场景用什么技术

我举几个例子:

  • 就图像上面来说,附近的点应该是很相关的,所以一个区域附近的点其实可以做sample,平均,max等,所以这是卷积层能够在图像处理里面获得很好收益的基础。
  • 同样传统nlp里面常用的ngram处理技术,很和卷积层的处理有类似之处,特别是类似电商商品标题,或者网页seo优化过的描述,其实他们算不上真正意义上的句子或者有逻辑的语句,可能更多的是名词形容词的堆砌,邻近的词表达的是类似的意思,这个使用卷积做encoder也可以取得不错的效果。

  • 对于RNN来说,它训练的是一个有逻辑的序列,当处理每个元素的时候,它应该记住什么,忘记什么,最终一个序列在不断的记住和忘记之后,生成最终的内容。RNN比较复杂,它的变形也很多,具体可以参见我以往的微文,可以根据具体的东西来修改RNN结构。

  • 对于Attention的应用,更好直观的解释,我们在处理这个任务的时候是不是要聚焦在某个点上面,比如:在看长颈鹿在吃树叶的时候,当我们生成长颈鹿的时候我们聚焦的是图片中的长颈鹿部分,当我们生成树叶的时候我们聚焦的是树叶区域,其他的诸如天空,草地我们其实是没有关注的,对于attention用到的技术,大家也千万不要觉得有多高大上,就是各种求解权重的技巧,求解权重最终一般会落到sigmod或者softmax,关键词是找到重要性的业务逻辑。

模型

回归我们的image caption的模型,简单描述这个模型就是:
利用CNN网络讲图像encoder成一个固定维度的向量,然后这个向量作为RNN输入序列的第一个元素(后面的元素是描述caption序列)来做迭代生成模型训练。

对于生成模型的每一步(生成到序列中的元素),和encoder-decoder里面的decoder模型基本一致,只是我们这里的第一个输入元素是图片encoder向量I,我们给一个生成概率:

logp(S|I)=t=0Nlogp(St|I,S0,S1,...,St1)

S0,S1,...,SN是RNN的输入序列,I是图像信息
当前字符st的生成和图像信息和历史输入序列都有关。

理论逻辑只有上面这么多,是一个很简单的模型,能够通俗理解。

我们给出论文的 graph 结构如下:

这里写图片描述

这个结构看起来复杂,其实原理很简单:

  1. 首先左边是一个CNN encoder结构 I,它的目的就是要将图片encoder成一个固定向量,这里用的CNN结构,可以使用当前比较流行的,比如inception,ResNet等。考虑到一方面由于图像的训练本身需要大量的数据,资源,时间;另一方面图像的描述相对来说是独立的,不应该收到caption生成的影响。所以,这里的图像graph参数需要提前做训练,也可以用其他人已经训练好的模型。
  2. 然后I作为LSTM的第一个输入input,这里是作为第一个输入,而不是直接作为state,这样输入层就会对图像的结果进行过滤。两外一个注意的是,I作为第一个输入就可以了,不必要在后面每一个都输入,不然会因为图像的噪音造成过拟合。
  3. 后续就是caption序列生成模型,首先对输入的图像向量I,会生成状态state0,然后s0是一个开始标志比如:这样的字符,然后s0经过LSTM Cell之后,会得到一个output向量输出O1,然后O1经过softmax后会得到每一个term的生成概率, 然后不带迭代这个步骤,直到每个词都生成,这里注意结尾也会加一个标志字符, 比如这种,模型就知道什么词之后最大概率就ende了。
  4. BeamSearch: 上面说的生成模型是一个迭代的模型,每次生成一个词是一个局部的概率,每个局部词的概率最大不意味着整句话生成的概率最大。这里常用的是BeamSearch递归查询。它的原理是:假设对步骤t,已经生成k个历史最高的结果的序列[s0,s1,...,sk],然后对这k个结果,分别生成N个, 然后对 N*K个结果生成top K个结果,这样增加必要的搜索空间。

结合代码

图片encoder

我们可以从google 模型链接里面下载已经训练好的模型, 比如Inception v3(附件一)。
在代码中,我们直接加载就可以了:
首先记载Inception V3 的训练好的模型文件:

saver = tf.train.Saver(self.inception_variables)saver.restore(sess, self.config.inception_checkpoint_file)

对于输入的images, 我们的目标是获得一个固定维度的tensor

这里直接用tensorflow的graph build,然后经过一个pooling层,
这样每一个图片经过处理后得到一个512维的向量I:

from tensorflow.contrib.slim.python.slim.nets.inception_v3 import inception_v3_basenet, end_points = inception_v3_base(images, scope=scope)with tf.variable_scope("logits"):  shape = net.get_shape()  net = slim.avg_pool2d(net, shape[1:3], padding="VALID", scope="pool")  net = slim.dropout(      net,      keep_prob=dropout_keep_prob,      is_training=is_inception_model_training,      scope="dropout")  net = slim.flatten(net, scope="flatten")I = net

sequence decoder

  • 首先我们初始化一个带droupout的LSTM Cell:
lstm_cell = tf.contrib.rnn.BasicLSTMCell(    num_units=512,     state_is_tuple=True)lstm_cell = tf.contrib.rnn.DropoutWrapper(    lstm_cell,    input_keep_prob=0.7,    output_keep_prob=0.7)
  • 然后图像的encoder向量I作为第一个元素经过Cell
# init zero statezero_state = lstm_cell.zero_state(    batch_size=batch_size,     dtype=tf.float32)# fist element_, initial_state = lstm_cell(I, zero_state)
  • 后续的词开始一次经过LSTM Cell
lstm_outputs, _ = tf.nn.dynamic_rnn(cell=lstm_cell,                                    inputs=seq_input_embedding,                                    sequence_length=sequence_length,                                    initial_state=initial_state,                                    dtype=tf.float32)  
  • 经过Cell的词xi经过Cell后得到一个decoder的向量,然后需要对这个向量经过一个全联接层后利用softmax得到预测的词yi
logits = tf.contrib.layers.fully_connected(    inputs=lstm_outputs,    num_outputs=vocab_size)

如果是生成过程:这个已经足够了,只用用logits经过softmax后,得到概率最大的几个词就是生成的下一个词的候选集:
如果是train的过程,生成的概率最大的词是predict yi,label是下一个词xi+1,这样可以利用predict和label得到loss,从而进行优化。

防止过拟合

由于这种监督训练比分类任务更加复杂,需要极大的数据量,而我们的训练数据只有不到10w的数据,所以极易造成过拟合

  1. CNN模型的参数需要预先训练,比如应用到ImageNet的模型,这里可以用一个训练的比较完整的模型参数,并且保持这些参数在训练的时候不变,这个作用非常大。
  2. 词向量可以提前训练,但是实时表明这个收益不是很大。
  3. 模型层面的防止过拟合:dropout,或者ensembling模型(主要是权衡模型隐藏层的宽度和整体的深度)

问题
数据的不可迁移性,不同的数据集很难迁移数据
描述的多样性,一个图片生成的话很多,很难以评估生成效果的好差。

附件一:
https://github.com/tensorflow/models/tree/master/research/slim#pre-trained-models

阅读全文
0 0