2016-07-22 2 views
0

Je dirige un morceau de code, train.lua, trouvé ici: https://github.com/karpathy/char-rnn/blob/master/train.lualuajit/lua5.1/lua5.2/numéro de mémoire lua5.3 pour le code RNN

C'est une prédiction de langage caractère sage modèle basé sur les SRNN/LSTM. Cela fonctionnait parfaitement sur OSX avec CPU jusqu'à ce que j'aie essayé d'implémenter un modèle de prédiction par mots. A savoir, le réseau prédit le mot suivant, par opposition à l'alphabet suivant. Le nombre de vocabulaire (résultats possibles) est passé à 13320 et le nombre de paramètres a également augmenté à 39963. Avec Luajit, j'ai reçu un message d'erreur "pas assez de mémoire", et je cherchais une solution. J'ai trouvé la question de la limite de mémoire sur Luajit soulevée ici: https://github.com/karpathy/char-rnn/issues/80

J'ai donc retiré la torche et installé lua lisse. Toutefois, ni LUA51, LUA52 ni LUA53 n'ont fonctionné. J'ai rencontré le même problème de mémoire. Il dit juste "Kill: 9" chaque fois que je cours le code d'entraînement. En particulier, le problème survient lorsque je l'obtiens pour créer des calques cachés T (la longueur de séquence ou les pas de temps), qui partagent les mêmes poids, en utilisant la fonction "model_utils.clone_many_times" dans le fichier util/model_utils.lua. Dans mon cas, la fonction s'exécute au point où elle clone 7 couches cachées, et tue le processus là. J'ai mis le rnn_size et le batch_size à la fois 1. Bien sûr, je veux courir des réseaux beaucoup plus grands, mais le code échoue toujours avec cette petite taille.

Mise à jour: Voici la solution de contournement sur laquelle je travaille.

Le processus de clonage semble quelque peu redondant car il stocke des couches cachées. Peut-être que nous pouvons changer la fonction d'une manière qui ne porte que des activations dans les unités, par opposition aux couches entières, à travers des pas de temps T. Je pense que le seul problème est backprop. Les niveaux d'activation des unités masquées sont reportés par la table, init_state_global, d'un lot à l'autre. Nous avons donc besoin d'établir une rétropropagation sur plusieurs lots.

+0

À quelle étape s'arrête-t-il exactement? Pouvez-vous expliquer quel appel de fonction ne fonctionne pas? – Fabich

+0

Lua 5.3 utilise moins de mémoire. Essayez-le. – lhf

Répondre

0

Voici une solution de contournement que j'ai trouvée. Tout le reste égal, les résultats que j'ai obtenus étaient presque les mêmes que ceux d'origine, à l'exception de quelques erreurs de précision flottantes pour une raison quelconque. Il économise de la mémoire (seq_length n'affecte même pas la taille de la mémoire). Je place le nombre de clones dans la fonction "model_utils.clone_many_times" à 1 (donc nous n'avons probablement plus besoin de cette fonction qui consomme de la mémoire), et stocke juste l'activation des unités cachées pour backprop.

function feval(x) 
if x ~= params then 
    params:copy(x) 
end 
grad_params:zero() 

------------------ get minibatch ------------------- 
local x, y = loader:next_batch(1) 
x,y = prepro(x,y) -- seq_length by batch_size tensor 
------------------- forward pass ------------------- 
local rnn_state = {[0] = init_state_global} 
local predictions = {}   -- softmax outputs 
local loss = 0 
local hidden_units = {} 

for t=1,opt.seq_length do 
    clones.rnn[1]:training() -- make sure we are in correct mode (this is cheap, sets flag) 
    local lst = clones.rnn[1]:forward{x[t], unpack(rnn_state[t-1])} 
    rnn_state[t] = {} 
    for i=1,#init_state do table.insert(rnn_state[t], lst[i]) end -- extract the state, without output 
    hidden_units[t] = {} 
    local j = 1 
    for k = 1, #clones.rnn[1].modules do 
     if clones.rnn[1].modules[k].output then 
      if not (type(clones.rnn[1].modules[k].output) == 'table') then 
       hidden_units[t][j] = clones.rnn[1].modules[k].output:clone() 
      else 
       hidden_units[t][j] = {} 
       for l=1, #clones.rnn[1].modules[k].output do 
        hidden_units[t][j][l] = clones.rnn[1].modules[k].output[l]:clone() 
       end 
      end 
      j = j+1 

     end 
    end 

    predictions[t] = lst[#lst] -- last element is the prediction 
    loss = loss + clones.criterion[1]:forward(predictions[t], y[t]) 
end 
loss = loss/opt.seq_length 

------------------ backward pass ------------------- 
-- initialize gradient at time t to be zeros (there's no influence from future) 
local drnn_state = {[opt.seq_length] = clone_list(init_state, true)} -- true also zeros the clones 
for t=opt.seq_length,1,-1 do 
    -- backprop through loss, and softmax/linear 
    local j = 1 

    for k = 1, #clones.rnn[1].modules do 
     if clones.rnn[1].modules[k].output then 
      clones.rnn[1].modules[k].output = hidden_units[t][j] 
      j = j+1 
     end 
    end 

    local doutput_t = clones.criterion[1]:backward(predictions[t], y[t]) 
    table.insert(drnn_state[t], doutput_t) 
    local dlst = clones.rnn[1]:backward({x[t], unpack(rnn_state[t-1])}, drnn_state[t]) 
    drnn_state[t-1] = {} 
    for k,v in pairs(dlst) do 
     for k=1, #clones.rnn[1].modules[k].output do 
       hidden_units[t][j][k] = clones.rnn[1].modules[k].output:clone() 
       end 
      end 
      j = j+1 

     end 
    end 

    predictions[t] = lst[#lst] -- last element is the prediction 
    loss = loss + clones.criterion[1]:forward(predictions[t], y[t]) 
end 
loss = loss/opt.seq_length 
------------------ backward pass ------------------- 
-- initialize gradient at time t to be zeros (there's no influence from future) 
local drnn_state = {[opt.seq_length] = clone_list(init_state, true)} -- true also zeros the clones 
for t=opt.seq_length,1,-1 do 
    -- backprop through loss, and softmax/linear 
    local j = 1 

    for k = 1, #clones.rnn[1].modules do 
     if clones.rnn[1].modules[k].output then 
      clones.rnn[1].modules[k].output = hidden_units[t][j] 
      j = j+1 
     end 
    end 

    local doutput_t = clones.criterion[1]:backward(predictions[t], y[t]) 
    table.insert(drnn_state[t], doutput_t) 
    local dlst = clones.rnn[1]:backward({x[t], unpack(rnn_state[t-1])}, drnn_state[t]) 
    drnn_state[t-1] = {} 
      for k = 1, #clones.rnn[1].modules do 
     if clones.rnn[1].modules[k].output then 
      clones.rnn[1].modules[k].output = hidden_units[t][j] 
      j = j+1 
     end 
    end 

    local doutput_t = clones.criterion[1]:backward(predictions[t], y[t]) 
    table.insert(drnn_state[t], doutput_t) 
    local dlst = clones.rnn[1]:backward({x[t], unpack(rnn_state[t-1])}, drnn_state[t]) 
    drnn_state[t-1] = {} 
    for k,v in pairs(dlst) do 
     if k > 1 then -- k == 1 is gradient on x, which we dont need 
      -- note we do k-1 because first item is dembeddings, and then follow the 
      -- derivatives of the state, starting at index 2. I know... 
      drnn_state[t-1][k-1] = v 
     end 
    end 
end 
------------------------ misc ---------------------- 
-- transfer final state to initial state (BPTT) 
init_state_global = rnn_state[#rnn_state] -- NOTE: I don't think this needs to be a clone, right? 
-- grad_params:div(opt.seq_length) -- this line should be here but since we use rmsprop it would have no effect. Removing for efficiency 
-- clip gradient element-wise 
--Lets not clip gradient this time grad_params:clamp(-opt.grad_clip, opt.grad_clip) 
return loss, grad_params 
end