Torch and lua learning FAQ (focus on nn module compilation and torch compilation)

1. The difference between dots and colons in function calls
http://blog.csdn.net/wangbin_jxust/article/details/12170233 According to the description of this blog, it can be found that the colon just omits the passed first parameter self The role of the dot number needs to be specific to pass the actual parameters of an object. Let's do an experiment and use torch

x = torch.Tensor(5):zero()

At this time, the Tensor of length 5 is output with all 0s

x = torch.Tensor(5).zero()

[string "x = torch.Tensor(5).zero()"]:1: invalid arguments: no arguments provided
expected arguments: *DoubleTensor*
stack traceback:
        [C]: in function 'zero'
        [string "x = torch.Tensor(5).zero()"]:1: in main chunk
        [C]: in function 'xpcall'
        /home/lzhou/torch/install/share/lua/5.1/trepl/init.lua:679: in function 'repl'
        ...zhou/torch/install/lib/luarocks/rocks/trepl/scm-1/bin/th:204: in main chunk
        [C]: at 0x004064f0

At this time, the program reported an error, because the actual parameter object must be passed in when the dot call is made. Change
the code to

x = torch.Tensor(5)
x = x.zero(x)

That's it for now! The dot call must pass in the actual parameter

y = torch.Tensor(5)
z = torch.Tensor(5)
z = z.zero(y)

The output z and y are both 0

2. The c interface problem in torch Come
from the introduction of the official website, in the MSECriterion.lua file there are

   input.THNN.MSECriterion_updateOutput(
      input:cdata(),
      target:cdata(),
      self.output_tensor:cdata(),
      self.sizeAverage
   )

The syntax of input.THNN.MSECriterion_updateOutput is very strange. Let's take a look at the example on the official website.
The official website uses threshold.lua in ">http://torch.ch/docs/developer-docs.html# as an example to explain.
write picture description here
The input.nn.threshold_updataOutput function here is also a very strange syntax, let's take a look The explanation on the official website.
write picture description here
This sentence actually calls the function u in threshold.c, but why go back and call this function? Because in the next few lines, this function will be registered in the table of input.nn. , so this function will be called.
write picture description here
This allows us to write arbitrary functions for any Tensor, without the need for very complex functions to be dynamically allocated.
Finally, look at which files they are included in
init.lua
write picture description here
init.c
write picture description here
write picture description here
write picture description here

http://blog.hanschen.site/2016/09/07/lua-and-c.html
But we study and observe the new version of torch, it seems that it is not like the one given by the official website, why? The link given on the official website is the link of the torch a long time ago. In the new version of torch, the Lua C API is no longer used for the interaction between lua and c. Of course, this is only for the nn module. The basic torch part is actually implemented by the Lua C API. , then in the new version of torch, we will take MSECriterion as an example for a detailed introduction.
First of all, there is a MSECriterion.lua file
write picture description here
in /extra/nn/. There is no such function as luaT_pushmetatable in the whole file, that is, there is no such interface as Lua API C. Instead, it is a very simple function , what replaces the traditional method of communication, is the FFI module of LuaJIT, which is used to communicate with c.
The above code has

input.THNN.MSECriterion_updateOutput(...)

The above sentence is very vague. What is going on and how is it called? Let's take a look at the compilation process of the nn module
1) Below the extra/nn directory is a series of lua functions, which is the external interface part
2) extra/nn/lib/THNN/generic The following is the implementation of c
corresponding . There will be a corresponding CMakelist.txt file under each directory, which is used to compile the c file in the corresponding directory, so that the corresponding LibTHNN.so file will be generated, and the corresponding path is in torch/install/lib/lua/5.1.

After C compilation, the functions encapsulated at the bottom layer are placed in the dynamic link library LibTHNN.so. The next thing is how to remove these C functions from the lua interface. If you use the old version of the official website, it must be done in the way of Lua C API, but this method is too cumbersome. The emergence of FFI has changed this state. For the introduction of FFI, see FFI Introduction
FFI can simplify the communication between LUA and c, so how does torch do it?
In the torch/extra/nn folder, there are a lot of lua, how are these lua arranged?
Under this folder, the first is init.lua, which defines a table such as nn's global. Then there are two functions, THNN.lua and THNN_H.lua. How are they implemented? Take a look at THNN.lua specifically

local ffi = require 'ffi'

local THNN = {}


local generic_THNN_h = require 'nn.THNN_h'
-- strip all lines starting with #
-- to remove preprocessor directives originally present
-- in THNN.h
generic_THNN_h = generic_THNN_h:gsub("\n#[^\n]*", "")
generic_THNN_h = generic_THNN_h:gsub("^#[^\n]*\n", "")

Find the corresponding c module through the dynamic function library specified by cpath.

THNN.C = ffi.load(package.searchpath('libTHNN', package.cpath))

The first is to add it to the ffi module, define THNN, and add it to THNN_h and THNN_h to declare a series of C functions in lua, which is convenient for FFI to call.
Next, there will be two paragraphs when ffi calls c.

ffi.cdef(base_declarations)

Define the two data structures of c

for i=1,#replacements do
   local r = replacements[i]
   local s = preprocessed
   for k,v in pairs(r) do
      s = string.gsub(s, k, v)
   end
   ffi.cdef(s)
end

In this case, all the c function definitions are added with ffi, that is, the cdef function, which is a very critical function for the communication between lua and c.
So far , we already know how lua communicates with c. But how to interpret the form of input.THNN.function() at the beginning? see the code below

local function_names = extract_function_names(generic_THNN_h)

THNN.kernels = {}
THNN.kernels['torch.FloatTensor'] = THNN.bind(THNN.C, function_names, 'Float', THNN.getState)
THNN.kernels['torch.DoubleTensor'] = THNN.bind(THNN.C, function_names, 'Double', THNN.getState)

torch.getmetatable('torch.FloatTensor').THNN = THNN.kernels['torch.FloatTensor']
torch.getmetatable('torch.DoubleTensor').THNN = THNN.kernels['torch.DoubleTensor']

torch.getmetatable('torch.FloatTensor').THNN = THNN.kernels['torch.FloatTensor'] loads the metatable of FloatTensor and adds the THNN function. There are many previously defined c functions in THNN, and that's it A tensor such as input can easily get the corresponding function through THNN. The details are in the code, which explains why input.THNN.function is legal. Similar implementation routines are also used for cunn, as are other modules.

However, through the above code, it is found that torch must be installed in advance, otherwise torch.getmetatable is not feasible, where is torch installed?
Now go to the /torch/pkg/torch folder. The torch folder is mainly to implement some basic operations such as timer, file and Tensor. Let's see how it is organized.
The entry is still init.c under the folder

#include "general.h"
#include "utils.h"

extern void torch_utils_init(lua_State *L);
extern void torch_random_init(lua_State *L);
extern void torch_File_init(lua_State *L);
extern void torch_DiskFile_init(lua_State *L);
extern void torch_MemoryFile_init(lua_State *L);
extern void torch_PipeFile_init(lua_State *L);
extern void torch_Timer_init(lua_State *L);

extern void torch_ByteStorage_init(lua_State *L);
extern void torch_CharStorage_init(lua_State *L);
extern void torch_ShortStorage_init(lua_State *L)
...
...

Start by declaring a series of functions

LUA_EXTERNC DLL_EXPORT int luaopen_libtorch(lua_State *L);

int luaopen_libtorch(lua_State *L)
{

  lua_newtable(L);
  lua_pushvalue(L, -1);
  lua_setglobal(L, "torch");

  torch_utils_init(L);
  torch_File_init(L);

  torch_ByteStorage_init(L);
  torch_CharStorage_init(L);
  torch_ShortStorage_init(L);
  torch_IntStorage_init(L);
  torch_LongStorage_init(L);
  torch_FloatStorage_init(L);
  torch_DoubleStorage_init(L);
  torch_HalfStorage_init(L);

  torch_ByteTensor_init(L);
  ...
  ...
  luaT_newmetatable(L, "torch.Allocator", NULL, NULL, NULL, NULL);
  return 1;

First, a global table such as torch will be set up, and a method will be added to the meta table at a time. Here, the standard LUA C API method is used, and the virtual stack is used instead of the FFI form
. First look at the first one

torch_utils_init(L);

This function looks for utils.c in the current directory. The most critical part of the code is

static int torch_updateerrorhandlers(lua_State *L)
{
  THSetErrorHandler(luaTorchErrorHandlerFunction, L);
  THSetArgErrorHandler(luaTorchArgErrorHandlerFunction, L);
  return 0;
}

static const struct luaL_Reg torch_utils__ [] = {
  {"getdefaulttensortype", torch_lua_getdefaulttensortype},
  {"isatty", torch_isatty},
  {"tic", torch_lua_tic},
  {"toc", torch_lua_toc},
  {"setnumthreads", torch_setnumthreads},
  {"getnumthreads", torch_getnumthreads},
  {"getnumcores", torch_getnumcores},
  {"factory", luaT_lua_factory},
  {"getconstructortable", luaT_lua_getconstructortable},
  {"typename", luaT_lua_typename},
  {"isequal", luaT_lua_isequal},
  {"getenv", luaT_lua_getenv},
  {"setenv", luaT_lua_setenv},
  {"newmetatable", luaT_lua_newmetatable},
  {"setmetatable", luaT_lua_setmetatable},
  {"getmetatable", luaT_lua_getmetatable},
  {"metatype", luaT_lua_metatype},
  {"pushudata", luaT_lua_pushudata},
  {"version", luaT_lua_version},
  {"pointer", luaT_lua_pointer},
  {"setheaptracking", torch_setheaptracking},
  {"updateerrorhandlers", torch_updateerrorhandlers},
  {NULL, NULL}
};

void torch_utils_init(lua_State *L)
{
  torch_updateerrorhandlers(L);
  luaT_setfuncs(L, torch_utils__, 0);
}

Plug functions into the torch table, all the above functions can be called through
torch.function Let's see

extern void torch_Timer_init(lua_State *L);
static const struct luaL_Reg torch_Timer__ [] = {
  {"reset", torch_Timer_reset},
  {"stop", torch_Timer_stop},
  {"resume", torch_Timer_resume},
  {"time", torch_Timer_time},
  {"__tostring__", torch_Timer___tostring__},
  {NULL, NULL}
};

void torch_Timer_init(lua_State *L)
{
  luaT_newmetatable(L, "torch.Timer", NULL, torch_Timer_new, torch_Timer_free, NULL);
  luaT_setfuncs(L, torch_Timer__, 0);
  lua_pop(L, 1);
}

The first thing here is to insert functions into the meta table of torch.Timer, so this part of the call
write picture description here
is slightly different from the previous one. The two auxiliary functions are finished, and the other auxiliary functions are similar, but the operations such as pushing the stack in the Tensor part need to be done. Find it in generic/Tensor.c

static const struct luaL_Reg torch_Tensor_(_) [] = {
  {"retain", torch_Tensor_(retain)},
  {"free", torch_Tensor_(free)},
  {"contiguous", torch_Tensor_(contiguous)},
  {"size", torch_Tensor_(size)},
  {"elementSize", torch_Tensor_(elementSize)},
  {"__len__", torch_Tensor_(size)},
  {"stride", torch_Tensor_(stride)},
  {"dim", torch_Tensor_(nDimension)},
  {"nDimension", torch_Tensor_(nDimension)},
  {"set", torch_Tensor_(set)},
  {"storage", torch_Tensor_(storage)},
  {"storageOffset", torch_Tensor_(storageOffset)},
  {"clone", torch_Tensor_(clone)},
  {"contiguous", torch_Tensor_(contiguous)},
  {"resizeAs", torch_Tensor_(resizeAs)},
  {"resize", torch_Tensor_(resize)},
  {"narrow", torch_Tensor_(narrow)},
  {"sub", torch_Tensor_(sub)},
  {"select", torch_Tensor_(select)},
#ifndef TH_REAL_IS_HALF
  {"index", torch_Tensor_(indexSelect)},
  {"indexCopy", torch_Tensor_(indexCopy)},
  {"indexAdd", torch_Tensor_(indexAdd)},
  {"indexFill", torch_Tensor_(indexFill)},
  {"maskedSelect", torch_Tensor_(maskedSelect)},
  {"maskedCopy", torch_Tensor_(maskedCopy)},
  {"maskedFill", torch_Tensor_(maskedFill)},
#endif
  {"transpose", torch_Tensor_(transpose)},
  {"t", torch_Tensor_(t)},
  {"unfold", torch_Tensor_(unfold)},
  {"isContiguous", torch_Tensor_(isContiguous)},
  {"isSameSizeAs", torch_Tensor_(isSameSizeAs)},
  {"isSetTo", torch_Tensor_(isSetTo)},
  {"isSize", torch_Tensor_(isSize)},
  {"nElement", torch_Tensor_(nElement)},
  {"copy", torch_Tensor_(copy)},
#ifndef TH_REAL_IS_HALF
  {"apply", torch_Tensor_(apply)},
  {"map", torch_Tensor_(map)},
  {"map2", torch_Tensor_(map2)},
#endif
  {"read", torch_Tensor_(read)},
  {"write", torch_Tensor_(write)},
  {"__index__", torch_Tensor_(__index__)},
  {"__newindex__", torch_Tensor_(__newindex__)},
  {NULL, NULL}
};

void torch_Tensor_(init)(lua_State *L)
{
  luaT_newmetatable(L, torch_Tensor, NULL,
                    torch_Tensor_(new), torch_Tensor_(free), torch_Tensor_(factory));
  luaT_setfuncs(L, torch_Tensor_(_), 0);
  lua_pop(L, 1);
#ifndef TH_REAL_IS_HALF
  THVector_(vectorDispatchInit)();
#endif
}

Is the above code familiar? Yes, these are the basic operations of Tensor. torch7 obtains the global control of torch by compiling the corresponding c and lua under the folder, and the next step is the compilation process.
In init.lua, it will first be added to libtorch to obtain the concept of global torch, and the next step is to use torch to perform various operations, common torch., etc.

Summary: The torch part of torch7 is in the form of LUA C API, and torch has its own implementation, namely LuaT, the specific content is in luaT
, and the additional packages such as nn and cunn are loaded in the form of ffi

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325742700&siteId=291194637