2016-04-25 14 views
-1

私はLSTMネットワークを学習し、合成テストを試みることにしました。最も簡単な機能認識のためにLSTMを学習する方法

  • ライン:Y = K * X + B
  • 放物線:Y = K * X^2 + B
  • 私はいくつかの点(X、Y)によって供給されるLSTMネットワークは、3つの基本的な機能を区別します
  • SQRT:Y = K *のSQRT(X)+ B

IはLUA +トーチを使用しています。

データセットは完全に仮想です。これは、「データセット」オブジェクトでオンザフライで作成されます。トレーニングサイクルがサンプルの別のminibatchを要求すると、関数mt .__ indexは動的に作成されたsampleを返します。記述された3つの関数の中からランダムに選択し、ランダムな点を選択します。

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 

問題がある:ネットワークが収束しません。 私が間違っているアイディアを共有できますか?

答えて

0

私は問題を解決して良い結果を得たので、私自身の答えを投稿することに決めました。

まず、この種のタスクに対するLSTMの適用性について説明します。前述のように、LSTMは時系列を処理するのに適しています。また、line、parabola、sqrtを一種の時間関数と考えることもできます。だからLSTMは完全にここに適用可能です。実験結果を受け取っているとしたら、あなたのシリーズをどのような機能で表現できるかを知りたいのですか?

上記のコードでは、固定数のポイント(つまり、batch_size)で常にフィードNNを取得すると主張する人もいます。なぜLSTMを使うのですか?おそらくリニアまたはコンボリューションネットワークの代わりに使用しようとしますか?

よく、忘れないでください。これは合成テストです。実際のアプリケーションでは、かなりの量のデータポイントをNNに送り、関数の形式を認識することが期待されます。一度に8点(BATCH_SIZE)と我々列車 NN以下のコードで例えば

、我々は試験 NN我々は唯一の4点(test_size)を使用します。

私たちはかなり良い結果を得ています。約1000回反復した後、NNは正しい答えの99%を与えます。

しかし、1層は、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 
1

このアプローチは完全に間違っています。 LSTMをこのように学習することは、多くの理由からあなたが望むものを学習しません。私はそれらのうち2つを述べるだろう。

  1. はあなたが(-1, 1)から均等にあなたのxを引くと仮定しよう。次に、関数|x|0.5x + 0.5は、yというまったく同じ分布を与えます。これは、使用する方法が機能認識には最適ではないことを示しています。

  2. LSTMで重要なのは、入力間に情報を格納できるメモリです。ポイントのシーケンスを独立して描くことから、あなたのスクリプトで何をするのかはまったく違っています。あなたの方法で学習されるすべてのメモリ相関は偽りに過ぎません。

+0

は、マルチン、ありがとうございました。私は今それを得ると思います。さらに、問題のコードは、反復ごとにランダムなkとbを生成するため、NNが任意のフィーチャを学習する機会はありません。私は2つの可能な解決法を見ています:1.起動時にkとbを一度だけ生成します。つまり、固定線、放物線、およびsqrtを取得します。 2.入力ポイントを順次生成する。 (2.)はオプションですが。私は(1.)を実装しようとした - それは働いた!唯一の千回の反復後NNは、99%の精度で機能を認識することができます! –

関連する問題