2015-08-24 1 views
3

J'ai un tenseur 2x16x3x10x10 que je nourris dans mon réseau. Mon réseau comporte deux parties qui fonctionnent en parallèle. La première partie prend la matrice 16x3x10x10 et calcule la somme sur les deux dernières dimensions, en retournant un tenseur de 16x3. La deuxième partie est un réseau de neurones convolutionnels qui produit un tenseur 16x160. Chaque fois que je tente de lancer ce modèle, je reçois l'erreur suivante:Attendre une erreur tensorielle contiguë avec nn.Sum

...903/nTorch/Torch7/install/share/lua/5.1/torch/Tensor.lua:457: expecting a contiguous tensor 
stack traceback: 
[C]: in function 'assert' 
...903/nTorch/Torch7/install/share/lua/5.1/torch/Tensor.lua:457: in function 'view' 
...8/osu7903/nTorch/Torch7/install/share/lua/5.1/nn/Sum.lua:26: in function 'updateGradInput' 
...03/nTorch/Torch7/install/share/lua/5.1/nn/Sequential.lua:40: in function 'updateGradInput' 
...7903/nTorch/Torch7/install/share/lua/5.1/nn/Parallel.lua:52: in function 'updateGradInput' 
...su7903/nTorch/Torch7/install/share/lua/5.1/nn/Module.lua:30: in function 'backward' 
...03/nTorch/Torch7/install/share/lua/5.1/nn/Sequential.lua:73: in function 'backward' 
./train_v2_with_batch.lua:144: in function 'opfunc' 
...su7903/nTorch/Torch7/install/share/lua/5.1/optim/sgd.lua:43: in function 'sgd' 
./train_v2_with_batch.lua:160: in function 'train' 
run.lua:93: in main chunk 
[C]: in function 'dofile' 
...rch/Torch7/install/lib/luarocks/rocks/trepl/scm-1/bin/th:131: in main chunk 
[C]: at 0x00405800 

Voici la partie pertinente du modèle:

local first_part = nn.Parallel(1,2) 
local CNN = nn.Sequential() 

local sums = nn.Sequential() 
sums:add(nn.Sum(3)) 
sums:add(nn.Sum(3)) 
first_part:add(sums) 

-- stage 1: conv+max 
CNN:add(nn.SpatialConvolutionMM(nfeats, convDepth_L1,receptiveFieldWidth_L1,receptiveFieldHeight_L1)) 
-- Since the default stride of the receptive field is 1, then 
-- (assuming receptiveFieldWidth_L1 = receptiveFieldHeight_L1 = 3) the number of receptive fields is (10-3+1)x(10-3+1) or 8x8 
-- so the output volume is (convDepth_L1 X 8 X 8) or 10 x 8 x 8 

--CNN:add(nn.Threshold()) 
CNN:add(nn.ReLU()) 
CNN:add(nn.SpatialMaxPooling(poolsize,poolsize,poolsize,poolsize)) 
-- if poolsize=2, then the output of this is 10x4x4 

CNN:add(nn.Reshape(convDepth_L1*outputWdith_L2*outputWdith_L2,true)) 
first_part:add(CNN) 

Le code fonctionne lorsque le tenseur d'entrée est 2x1x3x10x10, mais pas lorsque le tenseur est 2x16x3x10x10. Edit: Je viens juste de réaliser que cela arrive quand je modélise: en arrière et non en modèle: en avant. Voici le code correspondant:

local y = model:forward(x) 
local E = loss:forward(y,yt) 

-- estimate df/dW 
local dE_dy = loss:backward(y,yt) 
print(dE_dy) 
model:backward(x,dE_dy) 

x est un tenseur 2x16x3x10x10 et dE_dy est 16x2.

Répondre

4

Ceci est une faille dans la bibliothèque torch.nn. Pour effectuer un pas en arrière, nn.Parallel sépare gradOutput il reçoit du module supérieur en morceaux et les envoie à ses sous-modules parallèles. Le fractionnement est effectué efficacement sans copier la mémoire, et donc ces pièces sont non-contiguous (à moins que vous ne fassiez une division sur la 1ère dimension).

local first_part = nn.Parallel(1,2) 
--        ^
--     Merging on the 2nd dimension; 
--  Chunks of splitted gradOutput will not be contiguous 

Le problème est que nn.Sum peut ne pas fonctionner avec gradOutput non contiguës. Je n'ai pas une meilleure idée que d'y apporter des modifications:

Sum_nc, _ = torch.class('nn.Sum_nc', 'nn.Sum') 
function Sum_nc:updateGradInput(input, gradOutput) 
    local size = input:size() 
    size[self.dimension] = 1 
    -- modified code: 
    if gradOutput:isContiguous() then 
     gradOutput = gradOutput:view(size) -- doesn't work with non-contiguous tensors 
    else 
     gradOutput = gradOutput:resize(size) -- slower because of memory reallocation and changes gradOutput 
     -- gradOutput = gradOutput:clone():resize(size) -- doesn't change gradOutput; safer and even slower 
    end 
    -- 
    self.gradInput:resizeAs(input) 
    self.gradInput:copy(gradOutput:expandAs(input)) 
    return self.gradInput 
end 

[...] 

sums = nn.Sequential() 
sums:add(nn.Sum_nc(3)) -- <- will use torch.view 
sums:add(nn.Sum_nc(3)) -- <- will use torch.resize 
+1

Merci! Ça fonctionne maintenant. – notacreditcard

+0

J'ai une autre question. Serait-il possible de calculer la somme de manière externe et de la transmettre en tant que paramètre au réseau avec une image. Ou y a-t-il un moyen pour moi d'avoir deux tenseurs de tailles différentes sur différentes parties du réseau parallèle? – notacreditcard