Lua Torch7 和 OpenResty:尝试索引一个 nil 值
Lua Torch7 & OpenResty: attempt to index a nil value
我有一个 Lusty(OpenResty 的框架)API,它包装了一个 Torch 分类器。到目前为止,我已经能够让一个请求工作,但是对 API 的每个后续请求都会触发以下错误,没有详细的堆栈跟踪:
attempt to index a nil value
当我调用时似乎抛出错误:
net:add(SpatialConvolution(3, 96, 7, 7, 2, 2))
成功完成第一个请求而每个其他请求都失败的行为是问题的线索。
我在下方粘贴了 app/requests/classify.lua 的完整代码。这似乎是某种变量 caching/initialization 问题,尽管我对 Lua 的有限了解并不能帮助我调试问题。我试过做很多事情,包括将我的导入更改为 local torch = require('torch')
等本地化变量,并将这些导入移动到 classifyImage()
函数内部。
torch = require 'torch'
nn = require 'nn'
image = require 'image'
ParamBank = require 'ParamBank'
label = require 'classifier_label'
torch.setdefaulttensortype('torch.FloatTensor')
function classifyImage()
local opt = {
inplace = false,
network = "big",
backend = "nn",
save = "model.t7",
img = context.input.image,
spatial = false,
threads = 4
}
torch.setnumthreads(opt.threads)
require(opt.backend)
local SpatialConvolution = nn.SpatialConvolutionMM
local SpatialMaxPooling = nn.SpatialMaxPooling
local ReLU = nn.ReLU
local SpatialSoftMax = nn.SpatialSoftMax
local net = nn.Sequential()
print('==> init a big overfeat network')
net:add(SpatialConvolution(3, 96, 7, 7, 2, 2))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(3, 3, 3, 3))
net:add(SpatialConvolution(96, 256, 7, 7, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(2, 2, 2, 2))
net:add(SpatialConvolution(256, 512, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(512, 512, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(512, 1024, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(1024, 1024, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(3, 3, 3, 3))
net:add(SpatialConvolution(1024, 4096, 5, 5, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(4096, 4096, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(4096, 1000, 1, 1, 1, 1))
net:add(nn.View(1000))
net:add(SpatialSoftMax())
-- print(net)
-- init file pointer
print('==> overwrite network parameters with pre-trained weigts')
ParamBank:init("net_weight_1")
ParamBank:read( 0, {96,3,7,7}, net:get(1).weight)
ParamBank:read( 14112, {96}, net:get(1).bias)
ParamBank:read( 14208, {256,96,7,7}, net:get(4).weight)
ParamBank:read( 1218432, {256}, net:get(4).bias)
ParamBank:read( 1218688, {512,256,3,3}, net:get(7).weight)
ParamBank:read( 2398336, {512}, net:get(7).bias)
ParamBank:read( 2398848, {512,512,3,3}, net:get(9).weight)
ParamBank:read( 4758144, {512}, net:get(9).bias)
ParamBank:read( 4758656, {1024,512,3,3}, net:get(11).weight)
ParamBank:read( 9477248, {1024}, net:get(11).bias)
ParamBank:read( 9478272, {1024,1024,3,3}, net:get(13).weight)
ParamBank:read( 18915456, {1024}, net:get(13).bias)
ParamBank:read( 18916480, {4096,1024,5,5}, net:get(16).weight)
ParamBank:read(123774080, {4096}, net:get(16).bias)
ParamBank:read(123778176, {4096,4096,1,1}, net:get(18).weight)
ParamBank:read(140555392, {4096}, net:get(18).bias)
ParamBank:read(140559488, {1000,4096,1,1}, net:get(20).weight)
ParamBank:read(144655488, {1000}, net:get(20).bias)
ParamBank:close()
-- load and preprocess image
print('==> prepare an input image')
local img = image.load(opt.img):mul(255)
-- use image larger than the eye size in spatial mode
if not opt.spatial then
local dim = (opt.network == 'small') and 231 or 221
local img_scale = image.scale(img, '^'..dim)
local h = math.ceil((img_scale:size(2) - dim)/2)
local w = math.ceil((img_scale:size(3) - dim)/2)
img = image.crop(img_scale, w, h, w + dim, h + dim):floor()
end
-- memcpy from system RAM to GPU RAM if cuda enabled
if opt.backend == 'cunn' or opt.backend == 'cudnn' then
net:cuda()
img = img:cuda()
end
-- save bare network (before its buffer filled with temp results)
print('==> save model to:', opt.save)
torch.save(opt.save, net)
-- feedforward network
print('==> feed the input image')
timer = torch.Timer()
img:add(-118.380948):div(61.896913)
local out = net:forward(img)
-- find output class name in non-spatial mode
local results = {}
local topN = 10
local probs, idxs = torch.topk(out, topN, 1, true)
for i=1,topN do
print(label[idxs[i]], probs[i])
local r = {}
r.label = label[idxs[i]]
r.prob = probs[i]
results[i] = r
end
return results
end
function errorHandler(err)
return tostring( err )
end
local success, result = xpcall(classifyImage, errorHandler)
context.template = {
type = "mustache",
name = "app/templates/layout",
partials = {
content = "app/templates/classify",
}
}
context.output = {
success = success,
result = result,
request = context.input
}
context.response.status = 200
感谢您的帮助!
更新 1
在 local net
前后以及我调用 net:add
之后添加了 print( net )
。每次 local net
初始化之前,它显示的值为 nil
。正如预期的那样,在初始化 net
之后,它显示了一个 torch 对象作为值。似乎 :add
调用中的某些内容正在创建错误,因此我在声明我的 classifyImage
函数后立即添加了以下内容:
print(tostring(torch))
print(tostring(nn))
print(tostring(net))
添加这些新的打印语句后,我在第一次请求时得到以下信息:
nil
nil
nil
然后在第二个请求中:
table: 0x41448a08
table: 0x413bdb10
nil
并且在第 3 个请求中:
table: 0x41448a08
table: 0x413bdb10
nil
这些看起来像是指向内存中对象的指针,因此可以安全地假设 Torch 正在创建自己的全局对象吗?
当需要 torch
及其模块时,它最终会创建一个自身的全局实例,该实例在进程的生命周期内保留在内存中。对我有用的修复方法是在 Lusty 的 app.lua
主文件中引用 Torch 并将以下内容粘贴到顶部:
require 'torch'
require 'nn'
image = require 'image'
ParamBank = require 'ParamBank'
label = require 'classifier_label'
torch.setdefaulttensortype('torch.FloatTensor')
torch.setnumthreads(4)
SpatialConvolution = nn.SpatialConvolutionMM
SpatialMaxPooling = nn.SpatialMaxPooling
ReLU = nn.ReLU
SpatialSoftMax = nn.SpatialSoftMax
变量在 classifyImage
的范围内,现在每个请求都会成功。这是一个肮脏的修复,但由于 Torch 正在维护自己的全局对象,我看不到解决它的方法。
我有一个 Lusty(OpenResty 的框架)API,它包装了一个 Torch 分类器。到目前为止,我已经能够让一个请求工作,但是对 API 的每个后续请求都会触发以下错误,没有详细的堆栈跟踪:
attempt to index a nil value
当我调用时似乎抛出错误:
net:add(SpatialConvolution(3, 96, 7, 7, 2, 2))
成功完成第一个请求而每个其他请求都失败的行为是问题的线索。
我在下方粘贴了 app/requests/classify.lua 的完整代码。这似乎是某种变量 caching/initialization 问题,尽管我对 Lua 的有限了解并不能帮助我调试问题。我试过做很多事情,包括将我的导入更改为 local torch = require('torch')
等本地化变量,并将这些导入移动到 classifyImage()
函数内部。
torch = require 'torch'
nn = require 'nn'
image = require 'image'
ParamBank = require 'ParamBank'
label = require 'classifier_label'
torch.setdefaulttensortype('torch.FloatTensor')
function classifyImage()
local opt = {
inplace = false,
network = "big",
backend = "nn",
save = "model.t7",
img = context.input.image,
spatial = false,
threads = 4
}
torch.setnumthreads(opt.threads)
require(opt.backend)
local SpatialConvolution = nn.SpatialConvolutionMM
local SpatialMaxPooling = nn.SpatialMaxPooling
local ReLU = nn.ReLU
local SpatialSoftMax = nn.SpatialSoftMax
local net = nn.Sequential()
print('==> init a big overfeat network')
net:add(SpatialConvolution(3, 96, 7, 7, 2, 2))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(3, 3, 3, 3))
net:add(SpatialConvolution(96, 256, 7, 7, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(2, 2, 2, 2))
net:add(SpatialConvolution(256, 512, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(512, 512, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(512, 1024, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(1024, 1024, 3, 3, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialMaxPooling(3, 3, 3, 3))
net:add(SpatialConvolution(1024, 4096, 5, 5, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(4096, 4096, 1, 1, 1, 1))
net:add(ReLU(opt.inplace))
net:add(SpatialConvolution(4096, 1000, 1, 1, 1, 1))
net:add(nn.View(1000))
net:add(SpatialSoftMax())
-- print(net)
-- init file pointer
print('==> overwrite network parameters with pre-trained weigts')
ParamBank:init("net_weight_1")
ParamBank:read( 0, {96,3,7,7}, net:get(1).weight)
ParamBank:read( 14112, {96}, net:get(1).bias)
ParamBank:read( 14208, {256,96,7,7}, net:get(4).weight)
ParamBank:read( 1218432, {256}, net:get(4).bias)
ParamBank:read( 1218688, {512,256,3,3}, net:get(7).weight)
ParamBank:read( 2398336, {512}, net:get(7).bias)
ParamBank:read( 2398848, {512,512,3,3}, net:get(9).weight)
ParamBank:read( 4758144, {512}, net:get(9).bias)
ParamBank:read( 4758656, {1024,512,3,3}, net:get(11).weight)
ParamBank:read( 9477248, {1024}, net:get(11).bias)
ParamBank:read( 9478272, {1024,1024,3,3}, net:get(13).weight)
ParamBank:read( 18915456, {1024}, net:get(13).bias)
ParamBank:read( 18916480, {4096,1024,5,5}, net:get(16).weight)
ParamBank:read(123774080, {4096}, net:get(16).bias)
ParamBank:read(123778176, {4096,4096,1,1}, net:get(18).weight)
ParamBank:read(140555392, {4096}, net:get(18).bias)
ParamBank:read(140559488, {1000,4096,1,1}, net:get(20).weight)
ParamBank:read(144655488, {1000}, net:get(20).bias)
ParamBank:close()
-- load and preprocess image
print('==> prepare an input image')
local img = image.load(opt.img):mul(255)
-- use image larger than the eye size in spatial mode
if not opt.spatial then
local dim = (opt.network == 'small') and 231 or 221
local img_scale = image.scale(img, '^'..dim)
local h = math.ceil((img_scale:size(2) - dim)/2)
local w = math.ceil((img_scale:size(3) - dim)/2)
img = image.crop(img_scale, w, h, w + dim, h + dim):floor()
end
-- memcpy from system RAM to GPU RAM if cuda enabled
if opt.backend == 'cunn' or opt.backend == 'cudnn' then
net:cuda()
img = img:cuda()
end
-- save bare network (before its buffer filled with temp results)
print('==> save model to:', opt.save)
torch.save(opt.save, net)
-- feedforward network
print('==> feed the input image')
timer = torch.Timer()
img:add(-118.380948):div(61.896913)
local out = net:forward(img)
-- find output class name in non-spatial mode
local results = {}
local topN = 10
local probs, idxs = torch.topk(out, topN, 1, true)
for i=1,topN do
print(label[idxs[i]], probs[i])
local r = {}
r.label = label[idxs[i]]
r.prob = probs[i]
results[i] = r
end
return results
end
function errorHandler(err)
return tostring( err )
end
local success, result = xpcall(classifyImage, errorHandler)
context.template = {
type = "mustache",
name = "app/templates/layout",
partials = {
content = "app/templates/classify",
}
}
context.output = {
success = success,
result = result,
request = context.input
}
context.response.status = 200
感谢您的帮助!
更新 1
在 local net
前后以及我调用 net:add
之后添加了 print( net )
。每次 local net
初始化之前,它显示的值为 nil
。正如预期的那样,在初始化 net
之后,它显示了一个 torch 对象作为值。似乎 :add
调用中的某些内容正在创建错误,因此我在声明我的 classifyImage
函数后立即添加了以下内容:
print(tostring(torch))
print(tostring(nn))
print(tostring(net))
添加这些新的打印语句后,我在第一次请求时得到以下信息:
nil
nil
nil
然后在第二个请求中:
table: 0x41448a08
table: 0x413bdb10
nil
并且在第 3 个请求中:
table: 0x41448a08
table: 0x413bdb10
nil
这些看起来像是指向内存中对象的指针,因此可以安全地假设 Torch 正在创建自己的全局对象吗?
当需要 torch
及其模块时,它最终会创建一个自身的全局实例,该实例在进程的生命周期内保留在内存中。对我有用的修复方法是在 Lusty 的 app.lua
主文件中引用 Torch 并将以下内容粘贴到顶部:
require 'torch'
require 'nn'
image = require 'image'
ParamBank = require 'ParamBank'
label = require 'classifier_label'
torch.setdefaulttensortype('torch.FloatTensor')
torch.setnumthreads(4)
SpatialConvolution = nn.SpatialConvolutionMM
SpatialMaxPooling = nn.SpatialMaxPooling
ReLU = nn.ReLU
SpatialSoftMax = nn.SpatialSoftMax
变量在 classifyImage
的范围内,现在每个请求都会成功。这是一个肮脏的修复,但由于 Torch 正在维护自己的全局对象,我看不到解决它的方法。