2015-06-11 6 views
2

Я пытался реализовать сиамскую нейронную сеть в Torch/Lua, как I already explained here. Теперь у меня есть моя первая реализация, которую я считаю хорошей.Torch Lua: Почему мой градиентный спуск не оптимизирует ошибку?

К сожалению, у меня возникла проблема: во время тренировки назад распространение, градиентный спуск не обновляет ошибку. То есть, он всегда вычисляет одно и то же значение (то есть +1 или -1), не меняя его. В правильной реализации ошибка должна идти от +1 до -1 или от -1 до +1. В моем случае он просто застрял в верхнем значении и ничего не меняется.

Почему? Я действительно ищу кого-то, кто мог бы дать мне несколько намеков.

Вот мой рабочий код, который вы могли бы попытаться запустить:

LEARNING_RATE_CONST = 0.01; 
output_layer_number = 1; 
MAX_ITERATIONS_CONST = 10; 

require 'os' 
require 'nn' 

-- rounds a real number num to the number having idp values after the dot 
function round(num, idp) 
    local mult = 10^(idp or 0) 
    return math.floor(num * mult + 0.5)/mult 
end 

-- gradient update for the siamese neural network 
function gradientUpdate(perceptron, dataset_vector, targetValue, learningRate, max_iterations) 

print('gradientUpdate()\n') 

    for i = 1, max_iterations do 

     predictionValue = perceptron:forward(dataset_vector)[1] 
     sys.sleep(0.2) 
     gradientWrtOutput = torch.Tensor({-targetValue}); 

     perceptron:zeroGradParameters() 
     perceptron:backward(dataset_vector, gradientWrtOutput) -- 

     perceptron:updateParameters(learningRate) 

     predictionValue = perceptron:forward(dataset_vector)[1] 
     io.write("i="..i..") optimization predictionValue= "..predictionValue.."\n"); 

     if(predictionValue==targetValue) then 
     io.write("\[email protected]@@ (i="..i..") optimization predictionValue "..predictionValue.." @@@\n"); 
     break 
    end 

    end 
    return perceptron; 
end 

input_number = 6; -- they are 6 
dim = 10 
hiddenUnits = 3 

trueTarget=1; falseTarget=-trueTarget; 

trainDataset = {}; targetDataset = {}; 
for i=1, dim do 
    trainDataset[i]={torch.rand(input_number), torch.rand(input_number)} 
    if i%2==0 then targetDataset[i] = trueTarget 
    else targetDataset[i] = falseTarget 
    end 
     -- print('targetDataset['..i..'] '..targetDataset[i]); 
     -- sys.sleep(0.2) 
end 

for i=1, dim do 
    for j=1, input_number do 
    print(round(trainDataset[i][1][j],2)..' '..round(trainDataset[i][2][j],2)); 
    end 
end 

-- imagine we have one network we are interested in, it is called "perceptronUpper" 
    perceptronUpper= nn.Sequential() 
    print('input_number='..input_number..'\thiddenUnits='..hiddenUnits); 
    perceptronUpper:add(nn.Linear(input_number, hiddenUnits)) 
    perceptronUpper:add(nn.Tanh()) 
    if dropOutFlag==TRUE then perceptronUpper:add(nn.Dropout()) end 

    perceptronUpper:add(nn.Linear(hiddenUnits,output_layer_number)) 
    perceptronUpper:add(nn.Tanh()) 

    perceptronLower = perceptronUpper:clone('weight', 'gradWeight', 'gradBias', 'bias') 

    parallel_table = nn.ParallelTable() 
    parallel_table:add(perceptronUpper) 
    parallel_table:add(perceptronLower) 

    perceptron= nn.Sequential() 
    perceptron:add(parallel_table) 
    perceptron:add(nn.CosineDistance()) 

    max_iterations = MAX_ITERATIONS_CONST; 
    learnRate = LEARNING_RATE_CONST; 


    -- # TRAINING: 
    for k=1, dim do 
     print('\n[k='..k..'] gradientUpdate()'); 
     perceptron = gradientUpdate(perceptron, trainDataset[k], targetDataset[k], learnRate, max_iterations) 
    end 

Возникает вопрос: почему переменная predictionValue всегда то же самое? Почему он не получает обновления?

EDIT: Теперь я понял, что проблема в том, что я использовал только 1 размер выходного слоя. Я переместил его на 6, но, к сожалению, у меня возникла новая проблема. Градиент не обновляется в правильном направлении. Например, вот что происходит, используя мой предыдущий код с output_layer_number = 6

i=1) predictionValue=0.99026757478549 target=-1 
i=2) predictionValue=0.9972249767451 target=-1 
i=3) predictionValue=0.95910828489725 target=-1 
i=4) predictionValue=0.98960431921481 target=-1 
i=5) predictionValue=0.9607511165448 target=-1 
i=6) predictionValue=0.7774414068913 target=-1 
i=7) predictionValue=0.78994300446018 target=-1 
i=8) predictionValue=0.96893163039218 target=-1 
i=9) predictionValue=0.99786687264848 target=-1 
i=10) predictionValue=0.92254348014872 target=-1 
i=11) predictionValue=0.84935926907926 target=-1 
i=12) predictionValue=0.93696147024616 target=-1 
i=13) predictionValue=0.93469525917962 target=-1 
i=14) predictionValue=0.9584800936415 target=-1 
i=15) predictionValue=0.99376832219916 target=-1 
i=16) predictionValue=0.97381161559835 target=-1 
i=17) predictionValue=0.94124227912993 target=-1 
i=18) predictionValue=0.94947181918451 target=-1 
i=19) predictionValue=0.9946839455962 target=-1 
i=20) predictionValue=0.9637013147803 target=-1 
i=21) predictionValue=0.94853981221519 target=-1 
i=22) predictionValue=0.95441294067747 target=-1 
i=23) predictionValue=0.99999485148281 target=-1 
i=24) predictionValue=0.9900480694373 target=-1 
i=25) predictionValue=0.99316158138794 target=-1 

То есть, predictionValue никогда не идет к -1. Зачем?

ответ

3

Почему переменная predictionValue всегда одна и та же? Почему он не получает обновления?

Прежде всего, вы должны выполнить обратное распространение только если predictionValue*targetValue < 1, чтобы убедиться, что вы обратно распространяться только если пары должны быть сдвинуты (targetValue = 1) или разрываются (targetValue = -1).

См. Также этот факел/nn official example, который иллюстрирует это.

Это, как говорится, есть только 1 мощность unit (output_layer_number = 1). Это означает, что каждая ветвь вашей сиамской сети создает единый скаляр, соответственно. u и v. Эта пара скаляров затем сравниваются расстоянием косинус:

C(u,v) = cosine(u, v) = (u/|u|) x (v/|v|) 

Примечание: этот критерий может принимать только два значения здесь: 1 или -1 (см ниже синим цветом).

Когда пришло время для обратного распространения, вы вычисляете производные этого критерия относительно входов, то есть dC/du и dC/dv. Но эти производные равны нулю и неопределенными в 0 (см ниже красным цветом):

enter image description here

Вот почему обратного распространения не делает ничего здесь, т.е.он остается статичным (и вы можете проверить это на практике, распечатав нормы этих производных).

+0

Спасибо @deltheil. Это изменило значения оптимизации, но, к сожалению, оно не обновляется в правильном направлении. Я обновил вопрос, не могли бы вы взглянуть на обновление? благодаря –

 Смежные вопросы

  • Нет связанных вопросов^_^