Torch中的Reinforcement Learning的底层实现

  • 原理篇
  • 实现篇
      • nnReinforceCategorical
      • nnReinforce

强化学习已经成为大家关注的点,至少据我了解世界顶级名校CV的实验室都在做这方面的工作。最近也在做相关的Research,正好遇到了在Torch中的RL实现,发现没有什么可以参考的中文资料,只能试着来解释一下Torch中的RL实现。

原理篇

在Torch中的RL【2】实现参考的是论文【1】的方法实现。实现的也是比较简单的immediate RL。在【1】中提出了immediate RL,也是类似于associative reward-inaction AR-I的方法。

假设输出是一个向量,那么第i和输出的计算如下:
首先是为了计算出 si
这里写图片描述

再用mass function对 si 进行处理得到 pi
这里写图片描述

这里的 fi 可以使用logistic function计算:
这里写图片描述

假设输出符合伯努利分布,那么对于输出为0或者1的概率分别为:
这里写图片描述

在进行训练计算BP更新w:
这里写图片描述

首先是 αij 可以是一个常数,也可以是:
这里写图片描述

对于 eij 的计算首先是表示mass probability function:
这里写图片描述
然后可以进行求导表示为如下方式:(有点儿cross-entropy的感觉)
这里写图片描述
然后 pi si 进行求导:
这里写图片描述
这里写图片描述
然后 si wij 进行求导:
这里写图片描述

把这些乘起来就是 eij
这里写图片描述
这里写图片描述

把reward, α 加上就是最终的梯度:(baseline reward为0的时候)
这里写图片描述

和一个叫做associative reward-inaction对比:(取 λ 为0即可)
这里写图片描述

然后在推出来的导数中加入baseline reward,就可以得到:
这里写图片描述
这里有一个estimate reward:通过以下公式得到。
这里写图片描述

实现篇

Torch的代码实现在这里:【2】,是集合了目前Torch有实现的RL方法。是根据【1】实现的。这次要讲的是ReinforceCategorical【3】这部分的代码。

nn.ReinforceCategorical

module = nn.ReinforceCategorical([stochastic])

这个类是继承了nn.Reinforce,实现的是针对一个sample的Multinomial distribution的分类。输入时multinomial distribution,比如从Softmax的输出获取的就是一个multinomial distribution(概率和为1),得到的输出就是一个one-hot coding,也就是输出的vector只有一个为1,其余为0,这样的结构用于做分类再合适不过了。在训练的时候,输入可以是batch size,也就是可以进行batch gradient training。

在进行evaluation的时候,若stochastic=false,那么输入等于输出。其实nn.ReinforceCategorical继承于nn.Reinforce,主要定义了updateGradInput和updateOutput这两个函数。

函数中有如下变量:

f:对于输入的概率进行另外一种变化的函数,比如sigmoid。
y:对某个sample的index表示,采用one-hot code表示。
p:输入的概率分布,(p[1],p[2],p[3]...)

计算对weight的e(ij)进行更新的公式的时候采用如下:
d ln(f(y,p))     1/p[i]    if i = y  
------------ =   
    d p          0         otherwise

ReinforceCategorical.lua代码解释:

local ReinforceCategorical, parent = torch.class("nn.ReinforceCategorical", "nn.Reinforce")

-- 根据输入input的概率分布,进行一次采样,把采样的index的输出设置为1,其余为0
function ReinforceCategorical:updateOutput(input)
   self.output:resizeAs(input)
   self._index = self._index or ((torch.type(input) == 'torch.CudaTensor') and torch.CudaTensor() or torch.LongTensor())
   if self.stochastic or self.train ~= false then
      -- sample from categorical with p = input
      self._input = self._input or input.new()
      -- prevent division by zero error (see updateGradInput)
      self._input:resizeAs(input):copy(input):add(0.00000001) 
      input.multinomial(self._index, input, 1)
      -- one hot encoding
      self.output:zero()
      self.output:scatter(2, self._index, 1)
   else
      -- use p for evaluation
      self.output:copy(input)
   end
   return self.output
end

-- 计算需要进行更新的weight的梯度,self.gradInput
-- 先是初始化为上面函数的one-hot uotput,然后除以input,为了防止除0错误,加了一个小数。然后乘以reward,乘以-1。
function ReinforceCategorical:updateGradInput(input, gradOutput)
   -- Note that gradOutput is ignored
   -- f : categorical probability mass function
   -- x : the sampled indices (one per sample) (self.output)
   -- p : probability vector (p[1], p[2], ..., p[k]) 
   -- derivative of log categorical w.r.t. p
   -- d ln(f(x,p))     1/p[i]    if i = x  
   -- ------------ =   
   --     d p          0         otherwise
   self.gradInput:resizeAs(input):zero()
   self.gradInput:copy(self.output)
   self._input = self._input or input.new()
   -- prevent division by zero error
   self._input:resizeAs(input):copy(input):add(0.00000001) 
   self.gradInput:cdiv(self._input)

   -- multiply by reward 
   self.gradInput:cmul(self:rewardAs(input))
   -- multiply by -1 ( gradient descent on input )
   self.gradInput:mul(-1)
   return self.gradInput
end

-- 设置parent类型并且把self._index置为nil
function ReinforceCategorical:type(type, tc)
   self._index = nil
   return parent.type(self, type, tc)
end

所以可以看出ReinforceCategorical计算的是用于训练时的output以及具体的gradient,另外的函数也就是在mass function上以及表示输出output的方式不同。还有类似的函数有: ReinforceBernoulli,ReinforceNormal,ReinforceGamma。

在代码里面有scatter【5】和multinomial【6】这两个函数,其实一眼看去这个意思是很明确,scatter是把一个数组的值或者是value填到一个Tensor里面。multinomial是根据给出的概率分布,进行采样。比如给出[0.1,0.2,0.7],然后就会进行采用,返回的是index,比如采集5次,可能会得到3,3,3,1,3这样的序列。使用multinomial的时候要主要,不要让分布为0,否则报错。为0的时候无法进行采样。

在scatter中,接口如下:

[Tensor] scatter(dim, index, src|val)

例子如下:

x = torch.rand(2, 5)
> x
 0.3227  0.4294  0.8476  0.9414  0.1159
 0.7338  0.5185  0.2947  0.0578  0.1273
[torch.DoubleTensor of size 2x5]

y = torch.zeros(3, 5):scatter(1, torch.LongTensor{{1, 2, 3, 1, 1}, {3, 1, 1, 2, 3}}, x)
> y
 0.3227  0.5185  0.2947  0.9414  0.1159
 0.0000  0.4294  0.0000  0.0578  0.0000
 0.7338  0.0000  0.8476  0.0000  0.1273
[torch.DoubleTensor of size 3x5]
填充的时候,首先看第一个参数为1,那么说明是以第一维(列)为单位的。那么第一列,填充的位置分别是{13},那么x[1,1]和x[2,1]分别放在y[1,1],y[3,1]。到了第二列就是{2,1},那么x[1,2],x[2,2]分别放在y[2,2],y[1,2]。依次类推。

z = torch.zeros(2, 4):scatter(2, torch.LongTensor{{3}, {4}}, 1.23)
> z
 0.0000  0.0000  1.2300  0.0000
 0.0000  0.0000  0.0000  1.2300
[torch.DoubleTensor of size 2x4]
填充的时候,因为是根据第二维(行)的进行填充,那么填的第一元素就是z[1,3],另外一个元素就在z[2,4]

nn.Reinforce

这是简单的RL实现,由论文【10】通过一些改变得到,基本上是一样的,除了多了别的mass function以外。

module = nn.Reinforce([stochastic])

stochastic=flase的时候只在训练的时候进行stochastic(不确定的,概率),evaluation的时候不需要。默认为false。计算reward的方式和VRClassReward【7】类似。

reward = a*(R - b)
a在论文中是一个常数或者是用某个计算式计算(看上面的论文介绍)。R就是(通常 0 或者 1), b是基准reward(baseline reward), 是对R的预测,用到了上一个时刻的reward以及上一个时刻的预测,看上面的论文解释。
------------------------------------------------------------------------
--[[ Reinforce ]]--
-- Ref A. http://incompleteideas.net/sutton/williams-92.pdf
-- Abstract class for modules that use the REINFORCE algorithm (ref A).
-- The reinforce(reward) method is called by a special Reward Criterion.
-- After which, when backward is called, the reward will be used to 
-- generate gradInputs. The gradOutput is usually ignored.
------------------------------------------------------------------------
local Reinforce, parent = torch.class("nn.Reinforce", "nn.Module")

function Reinforce:__init(stochastic)
   parent.__init(self)
   -- true makes it stochastic during evaluation and training
   -- false makes it stochastic only during training
   self.stochastic = stochastic
end

-- 这个reward来自于parent的reinforce计算reward,具体计算在VRClassReward里面【11】。
-- a Reward Criterion will call this
function Reinforce:reinforce(reward)
   parent.reinforce(self, reward)
   self.reward = reward
end

-- 在子类中实现
function Reinforce:updateOutput(input)
   self.output:set(input)
end

-- 在子类中实现,被子类调用用来计算梯度
function Reinforce:updateGradInput(input, gradOutput)
   local reward = self:rewardAs(input)
   self.gradInput:resizeAs(reward):copy(reward)
end

-- 计算的是input的reward,在这里需要注意的是训练的时候可能是batch traning,所以要考虑input size的问题(这一部分不能确定,还需要在研究一下)
-- this can be called by updateGradInput
function Reinforce:rewardAs(input)
   assert(self.reward:dim() == 1)
   if input:isSameSizeAs(self.reward) then
      return self.reward
   else
      if self.reward:size(1) ~= input:size(1) then
         -- assume input is in online-mode
         input = self:toBatch(input, input:dim())
         assert(self.reward:size(1) == input:size(1), self.reward:size(1).." ~= "..input:size(1))
      end
      self._reward = self._reward or self.reward.new()
      self.__reward = self.__reward or self.reward.new()
      local size = input:size():fill(1):totable()
      size[1] = self.reward:size(1)
      self._reward:view(self.reward, table.unpack(size))
      self.__reward:expandAs(self._reward, input)
      return self.__reward
   end
end

另外,对于reward函数,nn中也有更加专业的模块:【7】。如果想要了解完整的强化学习的内容,可以看这个example【8】,来源于Google Attention的论文复现。我目前看到整个网络远比这个大得多,等有空再把【8】介绍一下。

在RL里面,经常用到ArgMax.lua,用来计算每一维的最大输出【12】。nn.Collapse对Tensor大小进行改变【13】。

【1】RL 论文: http://www-anw.cs.umass.edu/~barto/courses/cs687/williams92simple.pdf
【2】Torch中的RL代码: https://github.com/nicholas-leonard/dpnn#nn.ReinforceCategorical
【3】Torch中的RL ReinforceCategorical代码: https://github.com/Element-Research/dpnn/blob/master/ReinforceCategorical.lua
【4】Torch中别的RL ReinforceCategorical实现: https://github.com/shubhtuls/volumetricPrimitives/blob/master/modules/ReinforceCategorical.lua
【5】Torch scatter: https://github.com/torch/torch7/blob/master/doc/tensor.md
【6】Torch Multinomial: https://github.com/torch/torch7/blob/master/doc/maths.md
【7】VRClassReward: https://github.com/nicholas-leonard/dpnn#nn.Module.reinforce
【8】RL Example: https://github.com/nicholas-leonard/dpnn/blob/master/Reinforce.lua
【9】Visual Attention: http://papers.nips.cc/paper/5542-recurrent-models-of-visual-attention.pdf
【10】RL class code: https://github.com/nicholas-leonard/dpnn/blob/master/Reinforce.lua
【11】VRClass Reward: https://github.com/nicholas-leonard/dpnn/blob/master/VRClassReward.lua
【12】nn.ArgMax: https://github.com/Element-Research/dpnn/blob/master/ArgMax.lua
【13】nn.Collapse: https://github.com/torch/nn/blob/master/Collapse.lua

转载请注明出处:
http://blog.csdn.net/c602273091/article/details/78966962

你可能感兴趣的:(RL,&,DL,&,SLAM,Torch,RL)