Neural network Caffe的LSTM模块

Neural network Caffe的LSTM模块,neural-network,deep-learning,caffe,lstm,recurrent-neural-network,Neural Network,Deep Learning,Caffe,Lstm,Recurrent Neural Network,有人知道Caffe是否有一个好的LSTM模块吗?我从russel91的github帐户中找到了一个,但很明显,包含示例和解释的网页消失了(以前-->它现在只重定向到不再有示例或解释的页面)。我知道使用Caffe处理LSTM模型。在2015年CVPR期间,他还做了一次精彩的演讲。他与RNN和LSTM有联系 更新:有一个由Jeff Donahue编写的版本,包括RNN和LSTM。该PR于2016年6月合并为master。事实上,经常性网络培训通常通过展开网络来完成。也就是说,在时间步长上复制网络(在

有人知道Caffe是否有一个好的LSTM模块吗?我从russel91的github帐户中找到了一个,但很明显,包含示例和解释的网页消失了(以前-->它现在只重定向到不再有示例或解释的页面)。

我知道使用Caffe处理LSTM模型。在2015年CVPR期间,他还做了一次精彩的演讲。他与RNN和LSTM有联系


更新:有一个由Jeff Donahue编写的版本,包括RNN和LSTM。该PR于2016年6月合并为master。

事实上,经常性网络培训通常通过展开网络来完成。也就是说,在时间步长上复制网络(在时间步长上共享权重),并在展开的模型上简单地进行前后传递

要展开LSTM(或任何其他单元),不必使用的递归分支,而是使用
NetSpec()
显式展开模型

下面是一个简单的例子:

from caffe import layers as L, params as P, to_proto
import caffe

# some utility functions
def add_layer_to_net_spec(ns, caffe_layer, name, *args, **kwargs):
  kwargs.update({'name':name})
  l = caffe_layer(*args, **kwargs)
  ns.__setattr__(name, l)
  return ns.__getattr__(name)
def add_layer_with_multiple_tops(ns, caffe_layer, lname, ntop, *args, **kwargs):    
  kwargs.update({'name':lname,'ntop':ntop})
  num_in = len(args)-ntop # number of input blobs
  tops = caffe_layer(*args[:num_in], **kwargs)
  for i in xrange(ntop):
      ns.__setattr__(args[num_in+i],tops[i])
  return tops

# implement single time step LSTM unit
def single_time_step_lstm( ns, h0, c0, x, prefix, num_output, weight_names=None):
  """
  see arXiv:1511.04119v1
  """
  if weight_names is None:
      weight_names = ['w_'+prefix+nm for nm in ['Mxw','Mxb','Mhw']]
  # full InnerProduct (incl. bias) for x input
  Mx = add_layer_to_net_spec(ns, L.InnerProduct, prefix+'lstm/Mx', x,
                    inner_product_param={'num_output':4*num_output,'axis':2,
                                           'weight_filler':{'type':'uniform','min':-0.05,'max':0.05},
                                           'bias_filler':{'type':'constant','value':0}},
                    param=[{'lr_mult':1,'decay_mult':1,'name':weight_names[0]},
                           {'lr_mult':2,'decay_mult':0,'name':weight_names[1]}])
  Mh = add_layer_to_net_spec(ns, L.InnerProduct, prefix+'lstm/Mh', h0,
                    inner_product_param={'num_output':4*num_output, 'axis':2, 'bias_term': False,
                                       'weight_filler':{'type':'uniform','min':-0.05,'max':0.05},
                                       'bias_filler':{'type':'constant','value':0}},
                    param={'lr_mult':1,'decay_mult':1,'name':weight_names[2]})
  M = add_layer_to_net_spec(ns, L.Eltwise, prefix+'lstm/Mx+Mh', Mx, Mh,
                          eltwise_param={'operation':P.Eltwise.SUM})
  raw_i1, raw_f1, raw_o1, raw_g1 = \
  add_layer_with_multiple_tops(ns, L.Slice, prefix+'lstm/slice', 4, M,
                             prefix+'lstm/raw_i', prefix+'lstm/raw_f', prefix+'lstm/raw_o', prefix+'lstm/raw_g',
                             slice_param={'axis':2,'slice_point':[num_output,2*num_output,3*num_output]})
  i1 = add_layer_to_net_spec(ns, L.Sigmoid, prefix+'lstm/i', raw_i1, in_place=True)
  f1 = add_layer_to_net_spec(ns, L.Sigmoid, prefix+'lstm/f', raw_f1, in_place=True)
  o1 = add_layer_to_net_spec(ns, L.Sigmoid, prefix+'lstm/o', raw_o1, in_place=True)
  g1 = add_layer_to_net_spec(ns, L.TanH, prefix+'lstm/g', raw_g1, in_place=True)
  c1_f = add_layer_to_net_spec(ns, L.Eltwise, prefix+'lstm/c_f', f1, c0, eltwise_param={'operation':P.Eltwise.PROD})
  c1_i = add_layer_to_net_spec(ns, L.Eltwise, prefix+'lstm/c_i', i1, g1, eltwise_param={'operation':P.Eltwise.PROD})
  c1 = add_layer_to_net_spec(ns, L.Eltwise, prefix+'lstm/c', c1_f, c1_i, eltwise_param={'operation':P.Eltwise.SUM})
  act_c = add_layer_to_net_spec(ns, L.TanH, prefix+'lstm/act_c', c1, in_place=False) # cannot override c - it MUST be preserved for next time step!!!
  h1 = add_layer_to_net_spec(ns, L.Eltwise, prefix+'lstm/h', o1, act_c, eltwise_param={'operation':P.Eltwise.PROD})
  return c1, h1, weight_names
一旦你有了单一的时间步,你可以展开它很多次你想

def exmaple_use_of_lstm():
  T = 3 # number of time steps
  B = 10 # batch size
  lstm_output = 500 # dimension of LSTM unit

  # use net spec
  ns = caffe.NetSpec()

  # we need initial values for h and c
  ns.h0 = L.DummyData(name='h0', dummy_data_param={'shape':{'dim':[1,B,lstm_output]},
                               'data_filler':{'type':'constant','value':0}})

  ns.c0 = L.DummyData(name='c0', dummy_data_param={'shape':{'dim':[1,B,lstm_output]},
                                   'data_filler':{'type':'constant','value':0}})

  # simulate input X over T time steps and B sequences (batch size)
  ns.X = L.DummyData(name='X', dummy_data_param={'shape': {'dim':[T,B,128,10,10]}} )
  # slice X for T time steps
  xt = L.Slice(ns.X, name='slice_X',ntop=T,slice_param={'axis':0,'slice_point':range(1,T)})
  # unroling
  h = ns.h0
  c = ns.c0
  lstm_weights = None
  tops = []
  for t in xrange(T):
    c, h, lstm_weights = single_time_step_lstm( ns, h, c, xt[t], 't'+str(t)+'/', lstm_output, lstm_weights)
    tops.append(h)
    ns.__setattr__('c'+str(t),c)
    ns.__setattr__('h'+str(t),h)
  # concat all LSTM tops (h[t]) to a single layer
  ns.H = L.Concat( *tops, name='concat_h',concat_param={'axis':0} )
  return ns
编写prototxt:

ns = exmaple_use_of_lstm()
with open('lstm_demo.prototxt','w') as W:
  W.write('name: "LSTM using NetSpec example"\n')
  W.write('%s\n' % ns.to_proto())
生成的展开网络(三个时间步)如下所示


您试过了吗?我找不到关于如何使用该模块的详细说明。在github讨论的轨道上有一个玩具示例,但并不完全是不言自明的(甚至连我都找不到了)。您提到的教程只是一般性地谈论LSTM。@mcExchange我没有尝试过,谢谢您的教程。幻灯片非常好,但比不上视频演示。我是LSTM网络的新手。如果有人在上面的例子中解释“记忆”单元是如何写入、擦除和读取的,那就太棒了。@auro这一点太宽泛了,无法发表评论。试着问新问题谢谢你提醒我们要具体。具体问题与Jeff Donahue幻灯片中提到的“cont”(continuation)标记有关,在其他地方也被称为clip标记。这通常标志着句子的开头(BoS)或视频剪辑的开头。该输入在LSTM中的方式和位置?它是否直接连接到遗忘门以基本上“重置”内存?@auro在这个LSTM示例中,没有重置LSTM的
“cont”
信号。而是一个“硬编码”输入
c0
层设置为常数零。@Jan因为你在时间上展开,你需要有三个
Mx
内积层的实例:
t0/Mx
t1/Mx
t2/Mx
,但是,如果你探索得到的
prototxt
,你会注意到
参数{name:…}
的所有实例都指向相同的名称-即,所有临时副本共享相同的实际参数。