如何在lua中读取大文件(> 1GB)?

时间:2016-06-03 12:29:54

标签: lua torch luajit

我是Lua的新手(将其用于Torch7框架)。我有一个输入功能文件,大小约为1.4GB(文本文件)。简单的io.open函数在尝试打开此文件时抛出错误“内存不足”。在浏览用户组和文档时,我发现它的可能是一个Lua限制。这有解决方法吗?或者我在阅读文件时做错了什么?

local function parse_file(path)
    -- read file
    local file = assert(io.open(path,"r"))
    local content = file:read("*all")
    file:close()

    -- split on start/end tags.
    local sections = string.split(content, start_tag)
    for j=1,#sections do
        sections[j] = string.split(sections[j],'\n')
        -- remove the end_tag
        table.remove(sections[j], #sections[j])
    end 
    return sections
end

local train_data = parse_file(file_loc .. '/' .. train_file)

编辑:我想要阅读的输入文件包含我想训练模型的图像功能。这个文件是有序的({start-tag} ... contents ... {end-tag} {start-tag} ...等等...),所以如果我可以加载这些文件就可以了部分(开始标记到结束标记)一次一个。但是,我希望将所有这些部分加载到内存中。

2 个答案:

答案 0 :(得分:2)

事实证明,加载大文件问题的最简单方法是将Torch升级到Lua5.2或更高版本!正如Torch的开发人员对torch7-google-group所做的那样。

cd ~/torch
./clean.sh
TORCH_LUA_VERSION=LUA52 ./install.sh

从5.2版开始,内存限制不存在!我测试了这个,它工作得很好!

参考:https://groups.google.com/forum/#!topic/torch7/fi8a0RTPvDo

另一种可能的解决方案(更优雅,类似于@Adam在他的回答中建议的)是使用逐行读取文件并使用张量或tds来存储数据,因为它使用了以外的内存Luajit。由于Vislab,代码示例如下所示。

local ffi = require 'ffi'
-- this function loads a file line by line to avoid having memory issues
local function load_file_to_tensor(path)
  -- intialize tensor for the file
  local file_tensor = torch.CharTensor()

  -- Now we must determine the maximum size of the tensor in order to allocate it into memory.
  -- This is necessary to allocate the tensor in one sweep, where collumns correspond to letters and rows correspond to lines in the text file.

  --[[ get  number of rows/collumns ]]
  local file = io.open(path, 'r') -- open file
  local max_line_size = 0
  local number_of_lines = 0
  for line in file:lines() do
    -- get maximum line size
    max_line_size = math.max(max_line_size, #line +1) -- the +1 is important to correctly fetch data

    -- increment the number of lines counter
    number_of_lines = number_of_lines +1
  end
  file:close() --close file

  -- Now that we have the maximum size of the vector, we just have to allocat memory for it (as long there is enough memory in ram)
  file_tensor = file_tensor:resize(number_of_lines, max_line_size):fill(0)
  local f_data = file_tensor:data()

  -- The only thing left to do is to fetch data into the tensor. 
  -- Lets open the file again and fill the tensor using ffi
  local file = io.open(path, 'r') -- open file
  for line in file:lines() do
    -- copy data into the tensor line by line
    ffi.copy(f_data, line)
    f_data = f_data + max_line_size
  end
  file:close() --close file

  return file_tensor
end

从张量读取数据简单快捷。例如,如果您想要读取文件中的第10行(将在张量的第10个位置),您可以简单地执行以下操作:

local line_string = ffi.string(file_tensor[10]:data()) -- this will convert into a string var

警告:这将在内存中占用更多空间,并且对于某些行比另一行更长的情况可能不是最佳的。但是如果你没有内存问题,甚至可以忽略这一点,因为当将文件中的张量加载到内存中时,速度非常快,并且可能会在此过程中为您节省一些白发。

参考:https://groups.google.com/forum/#!topic/torch7/fi8a0RTPvDo

答案 1 :(得分:0)

我从来没有需要读取如此大的文件,但如果你的内存不足,你可能需要逐行阅读。经过一些快速研究后,我从lua网站上找到了这个:

buff = buff..line.."\n"
     

buff是一个包含50,020字节的新字符串,而现在的旧字符串是>垃圾。在两个循环周期之后,buff是一个50,040字节的字符串,并且有两个旧字符串总共产生超过100千字节的垃圾。因此,Lua非常正确地决定,它是运行垃圾收集器的好时机,因此它可以释放那些100 KB。问题是这将每两个周期发生一次,因此Lua将在完成循环之前运行其垃圾收集器两千次。即使完成所有这些工作,其内存使用量也将是文件大小的三倍。更糟糕的是,每个连接必须将整个字符串内容(50千字节和增长)复制到新字符串中。

所以看起来加载大文件会使用疯狂的内存量,即使你逐行读取它并且每次都使用连接:

local buff = ""  
while 1 do  
    local line = read()  
    if line == nil then break end  
    buff = buff..line.."\n"  
end  

然后他们提出了更多的记忆保存过程:

  function newBuffer ()
      return {n=0}     -- 'n' counts number of elements in the stack
  end  

  function addString (stack, s)
    table.insert(stack, s)       -- push 's' into the top of the stack
    for i=stack.n-1, 1, -1 do
      if string.len(stack[i]) > string.len(stack[i+1]) then break end
      stack[i] = stack[i]..table.remove(stack)
    end
  end

  function toString (stack)
    for i=stack.n-1, 1, -1 do
      stack[i] = stack[i]..table.remove(stack)
    end
    return stack[1]
  end

这比以前占用更少的内存。所有信息来自: http://www.lua.org/notes/ltn009.html
希望有所帮助。