首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Torch:集合垃圾()不释放torch张量的内存

Torch:集合垃圾()不释放torch张量的内存
EN

Stack Overflow用户
提问于 2016-10-14 05:04:20
回答 3查看 967关注 0票数 0

我正在运行一个具有以下结构的代码:

代码语言:javascript
复制
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

我期望Collect垃圾()将释放所有由ip_1、ip_2和ip持有的内存。但是我可以看到内存没有被释放。这会导致内存泄漏。我想知道发生了什么事。有没有人能帮我理解一下集合体垃圾()的奇怪行为,并修复内存泄漏。

我真的很抱歉,我不能添加完整的代码。希望我添加的代码片段足以理解我的代码流程,我的网络训练代码非常类似于标准的CNN训练代码。

编辑:

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

代码语言:javascript
复制
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
EN

回答 3

Stack Overflow用户

发布于 2016-10-14 08:22:42

正如@Adam在评论中所说,in_1in_2变量继续被引用,它们的值不能被垃圾收集。即使您将它们更改为局部变量,它们也不会在此时被垃圾回收,因为定义它们的块还没有关闭。

您可以做的是在调用collectgarbage之前将in_1in_2的值设置为nil,这将使先前分配的值不可用,并符合垃圾收集的条件。只有当没有其他变量可能存储相同的值时,这才会起作用。

票数 4
EN

Stack Overflow用户

发布于 2016-10-14 10:49:57

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

票数 0
EN

Stack Overflow用户

发布于 2016-10-14 14:42:52

您可以创建全局变量来存储值。因此,此变量将始终可用。因此,在重写这些值之前,这样的vars gc无法收集它们。只需将vars设为本地并从作用域中调用gc即可。此外,第一个GC周期可能只调用finalizer和第二个空闲内存。但对此并不确定。因此,您可以尝试调用gc两次。

代码语言:javascript
复制
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。 in在Lua中不是有效的变量名

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40030968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档