Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lua 如何为最简单的函数识别培训LSTM_Lua_Neural Network_Torch_Lstm_Recurrent Neural Network - Fatal编程技术网

Lua 如何为最简单的函数识别培训LSTM

Lua 如何为最简单的函数识别培训LSTM,lua,neural-network,torch,lstm,recurrent-neural-network,Lua,Neural Network,Torch,Lstm,Recurrent Neural Network,我正在学习LSTM网络,并决定尝试综合测试。我希望由一些点(x,y)供电的LSTM网络能够区分三个基本功能: 行:y=k*x+b 抛物线:y=k*x^2+b sqrt:y=k*sqrt(x)+b 我用的是lua+火炬 数据集是完全虚拟的-它是在“数据集”对象上动态创建的。当训练周期要求另一小批样本时,函数mt.\uu index返回动态创建的样本。它随机选择所描述的三个函数中的一个,并为它们选择一些随机点 这个想法是,LSTM网络将学习一些特征来识别最后一个点属于哪种函数 完整但简单的源脚本

我正在学习LSTM网络,并决定尝试综合测试。我希望由一些点(x,y)供电的LSTM网络能够区分三个基本功能:

  • 行:y=k*x+b
  • 抛物线:y=k*x^2+b
  • sqrt:y=k*sqrt(x)+b
我用的是lua+火炬

数据集是完全虚拟的-它是在“数据集”对象上动态创建的。当训练周期要求另一小批样本时,函数mt.\uu index返回动态创建的样本。它随机选择所描述的三个函数中的一个,并为它们选择一些随机点

这个想法是,LSTM网络将学习一些特征来识别最后一个点属于哪种函数

完整但简单的源脚本包括:

require "torch"
require "nn"
require "rnn"

-- hyper-parameters 
batchSize = 8
rho = 5 -- sequence length
hiddenSize = 100
outputSize = 3
lr = 0.001

-- Initialize synthetic dataset
-- dataset[index] returns table of the form: {inputs, targets}
-- where inputs is a set of points (x,y) of a randomly selected function: line, parabola, sqrt
-- and targets is a set of corresponding class of a function (1=line, 2=parabola, 3=sqrt)
local dataset = {}
dataset.size = function (self)
  return 1000
end
local mt = {}
mt.__index = function (self, i)
  local class = math.random(3)

  local t = torch.Tensor(3):zero()
  t[class] = 1
  local targets = {}
  for i = 1,batchSize do table.insert(targets, class) end

  local inputs = {}
  local k = math.random()
  local b = math.random()*5

  -- Line
  if class == 1 then
    for i = 1,batchSize do
      local x = math.random()*10 + 5
      local y = k*x + b
      input = torch.Tensor(2)
      input[1] = x
      input[2] = y
      table.insert(inputs, input)
    end

  -- Parabola
  elseif class == 2 then
    for i = 1,batchSize do
      local x = math.random()*10 + 5
      local y = k*x*x + b
      input = torch.Tensor(2)
      input[1] = x
      input[2] = y
      table.insert(inputs, input)
    end

  -- Sqrt
  else
    for i = 1,batchSize do
      local x = math.random()*5 + 5
      local y = k*math.sqrt(x) + b
      input = torch.Tensor(2)
      input[1] = x
      input[2] = y
      table.insert(inputs, input)
    end
  end

  return { inputs, targets }
end -- dataset.__index meta function
setmetatable(dataset, mt)

-- Initialize random number generator
math.randomseed( os.time() )

-- build simple recurrent neural network
local model = nn.Sequencer(
  nn.Sequential()
    :add( nn.LSTM(2, hiddenSize, rho) )
    :add( nn.Linear(hiddenSize, outputSize) )
    :add( nn.LogSoftMax() )
)

print(model)

-- build criterion
local criterion = nn.SequencerCriterion( nn.ClassNLLCriterion() )

-- training
model:training()

local epoch = 1
while true do

  print ("Epoch "..tostring(epoch).." started")

  for iteration = 1, dataset:size() do
    -- 1. Load minibatch of samples
    local sample = dataset[iteration] -- pick random sample (dataset always returns random set)
    local inputs = sample[1]
    local targets = sample[2]

    -- 2. Perform forward run and calculate error
    local outputs = model:forward(inputs)
    local err = criterion:forward(outputs, targets)

    print(string.format("Epoch %d Iteration %d Error = %f", epoch, iteration, err))

    -- 3. Backward sequence through model(i.e. backprop through time)
    local gradOutputs = criterion:backward(outputs, targets)
    -- Sequencer handles the backwardThroughTime internally
    model:backward(inputs, gradOutputs)
    model:updateParameters(lr)
    model:zeroGradParameters()     

  end -- for dataset

  epoch = epoch + 1
end -- while epoch
问题是:网络不收敛。
你能告诉我我做错了什么吗?

这种方法是完全错误的。由于许多原因,以这种方式学习LSTM将无法学习您想要的内容。我将陈述其中两项:

  • 假设从
    (-1,1)
    统一绘制
    x
    。然后,函数
    |x |
    0.5x+0.5
    将提供与
    y
    完全相同的分布。这表明您使用的方法不是函数识别的最佳方法

  • LSTM中至关重要的是,它的内存允许您在输入之间存储信息。这与独立地绘制点序列(在脚本中执行的操作)完全不同。在你的方法中学习到的每一种记忆关联都可能是虚假的


  • 我决定发布自己的答案,因为我解决了这个问题并收到了很好的结果

    首先是关于LSTM对此类任务的适用性。如上所述,LSTM适合处理时间序列。您还可以将直线、抛物线和sqrt视为一种时间函数。所以LSTM在这里是完全适用的。假设你正在接收实验结果,一个向量一个向量,你想知道什么样的函数可以描述你的序列

    有人可能会说,在上面的代码中,我们总是得到具有固定点数的feed NN(即批大小)。那么为什么要使用LSTM呢?也许试着用线性或卷积网络来代替

    别忘了,这是一个综合测试。在实际应用程序中,您可能会向NN提供大量数据点,并期望它能够识别函数的形式

    例如,在下面的代码中,我们一次用8个点训练NN(批量大小),但当我们测试NN时,我们只使用4个点(测试大小

    我们得到了非常好的结果:经过大约1000次迭代,NN给出了99%的正确答案

    但一层NN不是魔术师。如果我们在每次迭代中更改函数的形式,它就无法了解任何特性。即,在原始代码中,kb在每次请求时都会更改为数据集。我们应该做的是在启动时生成它们,并且不进行更改

    因此,工作代码如下:

    require "torch"
    require "nn"
    require "rnn"
    
    -- Initialize random number generator
    math.randomseed( os.time() )
    
    -- hyper-parameters 
    batch_size = 8
    test_size = 4
    rho = 5 -- sequence length
    hidden_size = 100
    output_size = 3
    learning_rate = 0.001
    
    -- Initialize synthetic dataset
    -- dataset[index] returns table of the form: {inputs, targets}
    -- where inputs is a set of points (x,y) of a randomly selected function: line, parabola, sqrt
    -- and targets is a set of corresponding class of a function (1=line, 2=parabola, 3=sqrt)
    local dataset = {}
    dataset.k = math.random()
    dataset.b = math.random()*5
    dataset.size = function (self)
      return 1000
    end
    local mt = {}
    mt.__index = function (self, i)
      local class = math.random(3)
    
      local t = torch.Tensor(3):zero()
      t[class] = 1
      local targets = {}
      for i = 1,batch_size do table.insert(targets, class) end
    
      local inputs = {}
      local k = self.k
      local b = self.b
    
      -- Line
      if class == 1 then
        for i = 1,batch_size do
          local x = math.random()*10 + 5
          local y = k*x + b
          input = torch.Tensor(2)
          input[1] = x
          input[2] = y
          table.insert(inputs, input)
        end
    
      -- Parabola
      elseif class == 2 then
        for i = 1,batch_size do
          local x = math.random()*10 + 5
          local y = k*x*x + b
          input = torch.Tensor(2)
          input[1] = x
          input[2] = y
          table.insert(inputs, input)
        end
    
      -- Sqrt
      else
        for i = 1,batch_size do
          local x = math.random()*5 + 5
          local y = k*math.sqrt(x) + b
          input = torch.Tensor(2)
          input[1] = x
          input[2] = y
          table.insert(inputs, input)
        end
      end
    
      return { inputs, targets }
    end -- dataset.__index meta function
    setmetatable(dataset, mt)
    
    
    -- build simple recurrent neural network
    local model = nn.Sequencer(
      nn.Sequential()
        :add( nn.LSTM(2, hidden_size, rho) )
        :add( nn.Linear(hidden_size, output_size) )
        :add( nn.LogSoftMax() )
    )
    
    print(model)
    
    -- build criterion
    local criterion = nn.SequencerCriterion( nn.ClassNLLCriterion() )
    
    
    local epoch = 1
    local err = 0
    local pos = 0
    local N = math.floor( dataset:size() * 0.1 )
    
    while true do
    
      print ("Epoch "..tostring(epoch).." started")
    
      -- training
      model:training()
      for iteration = 1, dataset:size() do
        -- 1. Load minibatch of samples
        local sample = dataset[iteration] -- pick random sample (dataset always returns random set)
        local inputs = sample[1]
        local targets = sample[2]
    
        -- 2. Perform forward run and calculate error
        local outputs = model:forward(inputs)
        local _err = criterion:forward(outputs, targets)
    
        print(string.format("Epoch %d (pos=%f) Iteration %d Error = %f", epoch, pos, iteration, _err))
    
        -- 3. Backward sequence through model(i.e. backprop through time)
        local gradOutputs = criterion:backward(outputs, targets)
        -- Sequencer handles the backwardThroughTime internally
        model:backward(inputs, gradOutputs)
        model:updateParameters(learning_rate)
        model:zeroGradParameters()     
    
      end -- for training
    
      -- Testing
      model:evaluate()
      err = 0
      pos = 0
      for iteration = 1, N do
        -- 1. Load minibatch of samples
        local sample = dataset[ math.random(dataset:size()) ]
        local inputs = sample[1]
        local targets = sample[2]
        -- Drop last points to reduce to test_size
        for i = #inputs, test_size, -1 do
          inputs[i] = nil
          targets[i] = nil
        end
    
        -- 2. Perform forward run and calculate error
        local outputs = model:forward(inputs)
        err = err + criterion:forward(outputs, targets)
    
        local p = 0
        for i = 1, #outputs do
          local _, oi = torch.max(outputs[i], 1)
          if oi[1] == targets[i] then p = p + 1 end
        end
        pos = pos + p/#outputs
    
      end -- for testing
      err = err / N
      pos = pos / N
      print(string.format("Epoch %d testing results: pos=%f err=%f", epoch, pos, err))
    
      if (pos > 0.95) then break end
    
      epoch = epoch + 1
    end -- while epoch
    

    谢谢你,马辛。我想我现在明白了。此外,所讨论的代码在每次迭代时生成随机的k和b,这使得NN没有机会学习任何特性。我看到两种可能的解决方案:1。启动时仅生成一次k和b。这意味着我们得到了一些固定线,抛物线和sqrt。2.按顺序生成输入点。尽管(2.)是可选的。我试着去实现(1),结果成功了!经过1000次迭代,NN能够以99%的准确率识别函数!