Recurrent visual attention

本文将深度学习与聚焦机制和强化学习结合起来,通过学习本篇文献,可以:

  • 理解聚焦机制中较简单的hard attention

  • 了解增强学习的基本流程

(1)注意力机制(Attention)

以物体识别为例,在进行分类的时候,不是一次对一张大图进行估计,而是分多次观察小部分图像,首先初始化一个图像坐标点l,以该坐标点为中心提取小部分图像,并通过一个Gilpse网络图区该部分的图像特征向量,将该部分的图像的特征向量输入到RNN中,将RNN输出输入到一个location网络中,得到下次要提取的图像的坐标点,以该坐标点为中心提取小部分图像,并再Gilpse网络图区该部分的图像特征向量,再将其输入RNN中,如此步骤循环steptimes次,将最后一次的RNN输出结果输入到一个softmax中,估计分类结果。引入Attention,每次只对局部区域的图像进行处理,一方面可以减少图像其他区域的非必要信息的干扰,从而降低噪声的影响,另一方面还可以减少计算量。

(2)强化学习

由于我们每次只是观察到局部区域的图像,因此需要额外的信息来辅助如何进行有效的分类。本文引入了一个action网络,如果分类正确,则会对该行为进行奖励,网络训练的目标就是使奖励最大化。

RAM网络整体结构如下图所示:
这里写图片描述

上图中,A用于提取局部区域块,即attention机制,具体来说就是在t时刻,只取以t时刻的中心坐标点 lt1 为中心的局部块作为后续网络的输入,输出为以该坐标点 lt1 为中心的提取的N个局部块的平均 p(xt,lt1) ;B为整个Glimpse Network,提取得到局部块 p(xt,lt1) 后,需要提取该局部块的特征向量 gt ,作为RNN的输入。C部分为整体模型,将t时候Glimpse Network输出的图像块的特征向量 gt 输入到RNN中,得到t时刻的隐藏层输出 ht ;得到t时刻的隐藏层输出后,我们就可以通过action网络 fa(θa) 可能会影响环境状态的环境动作 at 。并通过location 网络 fl(θl) 得到t+1时刻的局部块的中心坐标点 lt

Glimpse网络:

A部分为attention机制,具体为根据输入t时刻的为局部块的中心坐标点,以该坐标点为中心,提取大小为[w0,w0]的图像块,提取到局部块之后,可以将输入两个全连接层,得到特征向量,中心坐标点输入另一个包含两个全连接层的网络,得到特征向量,最后由这两个特征向量得到图像局部块的特征向量表示 gt 。公式如下:

g=Rect(Linear(hg)+Linear(hl))

式中, hg=Rect(Linear(p(x,l)))
注意本文中 Linear 函数公式为:
Linear(x)=Wx+b ,且 Rect(x)=max(x,0)

此部分代码如下:

def __call__(self, loc):
    glimpse_input = self.get_glimpse(loc)#以loc为中心,提取局部区域块
    glimpse_input = tf.reshape(glimpse_input,
                               (tf.shape(loc)[0], self.sensor_size))
    g = tf.nn.relu(tf.nn.xw_plus_b(glimpse_input, self.w_g0, self.b_g0))#w_g0=(64,128)
    g = tf.nn.xw_plus_b(g, self.w_g1, self.b_g1)#w_g1=(128,256)
    l = tf.nn.relu(tf.nn.xw_plus_b(loc, self.w_l0, self.b_l0))#w_l0=(2,128)
    l = tf.nn.xw_plus_b(l, self.w_l1, self.b_l1)#w_l0=(128,256)
    g = tf.nn.relu(g + l)#得到最终的 glimpse feature vector
    return g

rnn部分网络:

得到t时刻的输入图像的特征向量 gt 后,将 gt 和t-1时刻的RNN输出 ht1 输入到RNN中,便可以得到t时刻的RNN输出 ht ,公式为:

ht=fh(ht1)=Rect(Linear(ht1+Linear(gt)))

(1)location 网络 fl(θl)

得到局部块的特征向量 gt 后,将其输入到rnn中,得到隐藏层输出ht,将ht输入location 网络 fl(θl) ,则可以得到 t+1 时刻的局部块坐标中心点 lt ,公式如下:

lt=fl(ht)=Linear(ht)

此部分代码如下:


  def __call__(self, input):#input为rnn隐藏层的输出,(,n_hidden),w为(n_hidden,2)
    mean = tf.clip_by_value(tf.nn.xw_plus_b(input, self.w, self.b), -1., 1.)#将input转换为大小为2的坐标点,即(,2)
    mean = tf.stop_gradient(mean)#阻止对mean反向传播
    if self._sampling:
      loc = mean + tf.random_normal(
          (tf.shape(input)[0], self.loc_dim), stddev=self.loc_std)#随机取样,(,2)
      loc = tf.clip_by_value(loc, -1., 1.)
    else:
      loc = mean
    loc = tf.stop_gradient(loc)
    return loc, mean
(2)action网络 fa(θa)

将rnn最后一个隐藏层的输出output输入一个action网络,则可以根据网络的任务执行对应的动作。在执行完一个动作后,会得到奖励信号 rt 。例如在目标识别场景中,action网络 fa(θa) 的作用是执行一个分类操作,如果分类正确,就奖励1分,否则不奖励。action网络 fa(θa) 的操作公式如下:

fa(h)=exp(Linear(h))/Z

式中,Z表示归一化操作。

如果rnn的最后一个隐藏层输出为output,将其输入到一个分类网络中,代码如下:


# Build classification network.分类
with tf.variable_scope('cls'):
  w_logit = weight_variable((config.cell_output_size, config.num_classes))#w_logit=(256,10)
  b_logit = bias_variable((config.num_classes,))
logits = tf.nn.xw_plus_b(output, w_logit, b_logit)
logits = tf.nn.softmax(logits)
#预测输出标签pred_labels = tf.argmax(logits, 1)# 0/1 reward.#分类正确则奖励1reward = tf.cast(tf.equal(pred_labels, labels_ph), tf.float32)#ypred equal to yin ,then the reward is 1rewards = tf.expand_dims(reward, 1)#[batch_sz, 1]rewards = tf.tile(rewards, (1, config.num_glimpses))# [batch_sz, timesteps]

从而可以得到输出每个标签的概率分布logits,和输出分类pred_labels,如果输出分类pred_labels与输入分类y相等,则reward+1分,否则reward+0分。

模型训练

action网络训练目标就是学习到一种策略使得总的奖励达到最大。奖励目标函数为基本的强化学习公式:

loss2=1MMi=1Tt=1θlogπ(uit|si1:t;θ)(Ritbt)

上式中, Rt 为rewards, bt 为reinfocement baseline,即偏置项,可以由输入序列的RNN隐藏层输出到一个Linear层得到, π 本文中为高斯函数。
总的损失函数为RNN预测分类结果的交叉损失熵loss1,即使分类尽量准确;加上奖励目标函数loss2,即使奖励最大;最后加上loss3为奖励 Rt 与偏置项 bt 的差的平方,即使奖励 Rt 与偏置项 bt 尽量接近。
下面给出整个模型代码:
完整代码连接:https://github.com/zhongwen/RAM

rnn_cell = tf.nn.rnn_cell
seq2seq = tf.nn.seq2seq

mnist = input_data.read_data_sets('MNIST_data', one_hot=False)

config = Config()
n_steps = config.step

loc_mean_arr = []#mean为坐标点
sampled_loc_arr = []#sample为mean加上随机取值


def get_next_input(output,i):
  loc, loc_mean = loc_net(output)#output为rnn隐藏层输出ht
  gl_next = gl(loc)
  loc_mean_arr.append(loc_mean)
  sampled_loc_arr.append(loc)
  return gl_next

# placeholders
images_ph = tf.placeholder(tf.float32,
                           [None, config.original_size * config.original_size *
                            config.num_channels])#input image size is 28*28*1
labels_ph = tf.placeholder(tf.int64, [None])

# Build the aux nets.
with tf.variable_scope('glimpse_net'):
  gl = GlimpseNet(config, images_ph)
with tf.variable_scope('loc_net'):
  loc_net = LocNet(config)

# number of examples
N = tf.shape(images_ph)[0]#batch_size
init_loc = tf.random_uniform((N, 2), minval=-1, maxval=1)#对每张输入图像初始化一个点l
init_glimpse = gl(init_loc)
# Core network.
lstm_cell = rnn_cell.LSTMCell(config.cell_size, state_is_tuple=True)
init_state = lstm_cell.zero_state(N, tf.float32)
inputs = [init_glimpse]
inputs.extend([0] * (config.num_glimpses))#输入为rnn序列为[init_glimpse,0,0,0,0,0,0]
outputs, _ = seq2seq.rnn_decoder(
    inputs, init_state, lstm_cell, loop_function=get_next_input)#在rnn中,上一个隐藏层的输出输入get_next_input得到下一个隐藏层的输入

# Time independent baselines
with tf.variable_scope('baseline'):
  w_baseline = weight_variable((config.cell_output_size, 1))#w_baseline=(256,1)
  b_baseline = bias_variable((1,))
baselines = []
for t, output in enumerate(outputs[1:]):
  baseline_t = tf.nn.xw_plus_b(output, w_baseline, b_baseline)#get the reward
  baseline_t = tf.squeeze(baseline_t)
  baselines.append(baseline_t)
baselines = tf.pack(baselines)  # [timesteps, batch_sz]
baselines = tf.transpose(baselines)  # [batch_sz, timesteps]

# Take the last step only.
output = outputs[-1]
# Build classification network.分类
with tf.variable_scope('cls'):
  w_logit = weight_variable((config.cell_output_size, config.num_classes))#w_logit=(256,10)
  b_logit = bias_variable((config.num_classes,))
logits = tf.nn.xw_plus_b(output, w_logit, b_logit)
logits = tf.nn.softmax(logits)

# cross-entropy.,
xent = tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels_ph)
xent = tf.reduce_mean(xent)#使分类的准确度最高
#预测输出标签
pred_labels = tf.argmax(logits, 1)
# 0/1 reward.
#分类正确则奖励1
reward = tf.cast(tf.equal(pred_labels, labels_ph), tf.float32)#ypred equal to yin ,then the reward is 1
rewards = tf.expand_dims(reward, 1)#[batch_sz, 1]
rewards = tf.tile(rewards, (1, config.num_glimpses))# [batch_sz, timesteps]
#logll大小为[batch_sz, timesteps]
logll = loglikelihood(loc_mean_arr, sampled_loc_arr, config.loc_std)#利用均值和方差求取高斯函数,在求去输入为sampled_loc_arr的高斯函数的值
advs = rewards - tf.stop_gradient(baselines)#Rt-bt

#学习使rewards最大
logllratio = tf.reduce_mean(logll * advs)#equaltion 2
reward = tf.reduce_mean(reward)
#learning the baselines
baselines_mse = tf.reduce_mean(tf.square((rewards - baselines)))#square of Rt-bt
var_list = tf.trainable_variables()
# hybrid loss,总的损失函数
loss = -logllratio + xent + baselines_mse  # `-` for minimize
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值