Memory leaks Torch:collectgarbage()未释放Torch张量的内存

Memory leaks Torch:collectgarbage()未释放Torch张量的内存,memory-leaks,lua,garbage-collection,torch,Memory Leaks,Lua,Garbage Collection,Torch,我运行的代码具有以下结构: network = createNetwork() -- loading a pre-trained network. function train() for i=1,#trainingsamples do local ip = loadInput() local ip_1 = someImageProcessing(ip) local ip_2 = someImageProcessing(ip)

我运行的代码具有以下结构:

network = createNetwork() -- loading a pre-trained network. 
function train()
    for i=1,#trainingsamples do
        local ip = loadInput()
        local ip_1 = someImageProcessing(ip)
        local ip_2 = someImageProcessing(ip)
        network:forward( ...some manipulation on ip_1,ip_2...)
        network:backward()
        collectgarbage('collect')
        print debug.getlocal -- all local variables.
        end
end
我希望collectgarbage()将释放ip_1、ip_2和ip所持有的所有内存。但是我可以看到记忆没有被释放。这会导致内存泄漏。我想知道发生了什么事。有人能帮我理解collectgarbage()的奇怪行为并修复内存泄漏吗

很抱歉,我无法添加完整的代码。希望我添加的代码片段足以理解我的代码流程,我的网络培训代码与标准CNN培训代码非常相似

编辑:

很抱歉,没有提到这些变量被声明为局部变量,并且在示例代码段中使用了一个关键字作为变量。我现在已经编辑过了。唯一的全局变量是在列车功能外声明的网络,我将ip_1、ip_2作为网络输入。另外,我在下面添加了实际代码的修剪版本

network = createNetwork()

function trainNetwork()

local parameters,gradParameters = network:getParameters()
network:training()    -- set flag for dropout

local bs = 1 

local lR = params.learning_rate / torch.sqrt(bs) 
local optimConfig = {learningRate = params.learning_rate,
                   momentum = params.momentum,
                   learningRateDecay = params.lr_decay,
                   beta1 = params.optim_beta1,
                   beta2 = params.optim_beta2,
                   epsilon = params.optim_epsilon}

 local nfiles = getNoofFiles('train')

 local weights = torch.Tensor(params.num_classes):fill(1)

 criterion =  nn.ClassNLLCriterion(weights)

for ep=1,params.epochs do


IMAGE_SEQ = 1

while (IMAGE_SEQ <= nfiles) do

  xlua.progress(IMAGE_SEQ, nfiles)
  local input, inputd2
  local color_image, depth_image2, target_image


  local nextInput = loadNext('train')
  color_image = nextInput.data.rgb
  depth_image2 = nextInput.data.depth
  target_image = nextInput.data.labels

  input = network0:forward(color_image)       -- process RGB
  inputd2 = networkd:forward(depth_image2):squeeze()   -- HHA

  local input_concat = torch.cat(input,inputd2,1):squeeze()  -- concat RGB,  HHA
  collectgarbage('collect')


  target = target_image:reshape(params.imWidth*params.imHeight) -- reshape target as vector


  -- create closure to evaluate f(X) and df/dX
  local loss = 0
  local feval = function(x)
    -- get new parameters
  if x ~= parameters then parameters:copy(x) end
    collectgarbage()

    -- reset gradients
    gradParameters:zero()
    -- f is the average of all criterions
    -- evaluate function for complete mini batch


    local output = network:forward(input_concat)    -- run forward pass
    local err = criterion:forward(output, target)   -- compute loss

    loss = loss + err


-- estimate df/dW
    local df_do = criterion:backward(output, target)

    network:backward(input_concat, df_do)           -- update parameters

      local _,predicted_labels = torch.max(output,2)
      predicted_labels = torch.reshape(predicted_labels:squeeze():float(),params.imHeight,params.imWidth)


    return err,gradParameters
  end -- feval

  pm('Training loss: '.. loss, 3)

  _,current_loss = optim.adam(feval, parameters, optimConfig)
  print ('epoch / current_loss ',ep,current_loss[1])

  os.execute('cat /proc/$PPID/status | grep RSS')

  collectgarbage('collect')

  -- for memory leakage debugging

  print ('locals')
  for x, v in pairs(locals()) do
      if type(v) == 'userdata' then
        print(x, v:size())
      end
  end

  print ('upvalues')
  for x,v in pairs(upvalues()) do
     if type(v) == 'userdata' then
        print(x, v:size())
      end
  end

end -- ii

print(string.format('Loss: %.4f  Epoch: %d   grad-norm: %.4f',
current_loss[1], ep, torch.norm(parameters)/torch.norm(gradParameters)))

if (current_loss[1] ~= current_loss[1] or gradParameters ~= gradParameters) then
    print ('nan loss or gradParams. quiting...')
    abort()
end

 -- some validation code here
 end --epochs
 print('Training completed')

 end
network=createNetwork()
函数trainNetwork()
本地参数,gradParameters=网络:getParameters()
网络:training()--设置辍学标志
本地bs=1
本地lR=参数学习率/torch.sqrt(bs)
局部最优配置={learningRate=params.learning\u rate,
动量=参数动量,
learningRateDecay=参数lr_decay,
beta1=参数optim_beta1,
beta2=参数optim_beta2,
epsilon=params.optim_epsilon}
本地nfiles=getNoofFiles(“火车”)
局部权重=火炬张量(参数num_类):填充(1)
标准=nn.ClassNLL标准(权重)
对于ep=1,参数为
图像顺序=1

尽管(IMAGE_SEQ如@Adam在评论中所说,
in_1
in_2
变量继续被引用,它们的值不能被垃圾收集。即使你将它们更改为局部变量,它们也不会在该点被垃圾收集,因为定义它们的块尚未关闭


您可以做的是在调用
collectgarbage
之前,将\u 1
中的
和\u 2
中的
值设置为
nil
,这将使以前分配的值不可访问并符合垃圾收集的条件。只有在没有其他变量存储相同的值时,这才起作用。

正如@Adam所说在注释中,
in_1
in_2
变量继续被引用,它们的值不能被垃圾收集。即使您将它们更改为本地变量,它们也不会在此时被垃圾收集,因为定义它们的块尚未关闭


您可以做的是在调用
collectgarbage
之前,将\u 1
中的
和\u 2
中的
值设置为
nil
,这将使以前分配的值不可访问并符合垃圾收集的条件。这仅在没有其他变量存储相同的值时才起作用。

+1到Paul's回答上面的问题;但请注意“应该”这个词。几乎所有的时候你都会很好。但是,如果你的代码变得更复杂(你开始传递内存对象并处理它们),你可能会发现Lua gc有时可能会决定保留内存对象的时间比预期的要长一点。但是不要担心(或者浪费时间试图找出原因),最终所有未使用的内存OBJ都将由Lua gc收集。垃圾收集器是一个复杂的算法,有时会显得有点不确定。

+1参考Paul的上述答案;但请注意“应该”一词。几乎所有时间都可以。但是,如果您的代码变得更复杂(并且您开始传递内存对象并对其进行处理),您可能会发现偶尔Lua gc可能会决定保留内存对象的时间比预期的稍长。但不要担心(或浪费时间试图找出原因),最终所有未使用的内存OBJ将由Lua gc收集。垃圾收集器是一个复杂的算法,有时可能会出现一些不确定性。

您创建全局变量来存储值。因此,这些变量将始终可用。因此,除非您重写值,否则vars gc无法收集它们。 只需将vars设置为本地,并从作用域中调用gc。 同样,GC的第一个周期可能只调用终结器,第二个周期调用空闲内存。 但不确定。所以你可以试着打两次电话给gc

function train()
  do
    local in = loadInput()
    local in_1 = someImageProcessing(in)
    local in_2 = someImageProcessing(in)
    network:forward( ...some manipulation on in_1,in_2...)
    network:backward()
  end
    collectgarbage('collect')
    collectgarbage('collect')
    print debug.getlocal -- all local variables.

PS.
中的
在Lua中是无效的变量名

您创建全局变量来存储值。因此此变量将始终可用。因此,在您重写值之前,此类变量gc无法收集它们。 只需将vars设置为本地,并从作用域中调用gc。 同样,GC的第一个周期可能只调用终结器,第二个周期调用空闲内存。 但不确定。所以你可以试着打两次电话给gc

function train()
  do
    local in = loadInput()
    local in_1 = someImageProcessing(in)
    local in_2 = someImageProcessing(in)
    network:forward( ...some manipulation on in_1,in_2...)
    network:backward()
  end
    collectgarbage('collect')
    collectgarbage('collect')
    print debug.getlocal -- all local variables.

PS.
中的
在Lua中是无效的变量名

您在_1
和_2
中创建了
作为全局变量,为什么希望它们是垃圾?另外,
中的
是一个变量,不能用作名称。作为指向全局变量和垃圾收集的参考链接:“对于Lua,存储在全局变量中的任何对象都不是垃圾,即使您的程序将永远不再使用它。"抱歉,忘了在代码段中提到。变量实际上声明为本地变量。你看到我的答案了吗。你必须从变量范围中调用GC。但是在你的第一个示例中,GC应该能够清除所有
ip
变量。当然,它也可能取决于
someImageProcessing
代码。感谢大家关注这个问题。最终很快我找到了问题。问题与我的代码无关。它在Torch matio库中。matio的加载函数在循环中使用时会泄漏内存。这里讨论了这个问题。在我的代码中,loadNext()使用matio加载输入文件。现在我将所有mat文件转换为.t7 fl