Lutorpy is a libray built for deep learning with torch in python, by a two-way bridge between Python/Numpy and Lua/Torch, you can use any Torch modules(nn, rnn etc.) in python, and easily convert variables(array and tensor) between torch and numpy.
- import any lua/torch module to python and use it like python moduels
- use lua objects directly in python, conversion are done automatically
- create torch tensor from numpy array with
torch.fromNumpyArray(arr)
- use
tensor.asNumpyarray()
to convert a torch tensor to a numpy array with memory sharing - support zero-base indexing (lua uses 1-based indexing)
- automatic prepending self to function by
"._"
syntax, easily convert":"
operator in lua to python
-- lua code # python code (with lutorpy)
-- import lutorpy as lua
require "nn" ===> require("nn")
model = nn.Sequential() ===> model = nn.Sequential()
-- use ":" to access add ===> # use "._" to access add
model:add(nn.Linear(10, 3)) ===> model._add(nn.Linear(10, 3))
-- import numpy as np
x = torch.Tensor(10):zero() ===> arr = np.zeros(10)
-- torch style(painful?) ===> # numpy style(elegent?)
x:narrow(1, 2, 6):fill(1) ===> arr[1:7] = 1
-- # convert numpy array to a torch tensor
-- x = torch.fromNumpyArray(arr)
-- # or you can still use torch style
x:narrow(1, 7, 2):fill(2) ===> x._narrow(1, 7, 2)._fill(2)
-- 1-based index ===> # 0-based index
x[10] = 3 ===> x[9] = 3
y = model:forward(x) ===> y = model._forward(x)
-- # you can convert y to a numpy array
-- yArr = y.asNumpyArray()
import lutorpy as lua
import numpy as np
## use require("MODULE") to import lua modules
require("nn")
## run lua code in python with minimal modification: replace ":" to "._"
t = torch.DoubleTensor(10,3)
print(t._size()) # the corresponding lua version is t:size()
## or, you can use numpy array
xn = np.random.randn(100)
## convert the numpy array into torch tensor
xt = torch.fromNumpyArray(xn)
## convert torch tensor to numpy array
### Note: the underlying object are sharing the same memory, so the conversion is instant
arr = xt.asNumpyArray()
print(arr.shape)
## minimal example of multi-layer perception(without training code)
mlp = nn.Sequential()
mlp._add(nn.Linear(100, 30))
mlp._add(nn.Tanh())
mlp._add(nn.Linear(30, 10))
## generate a numpy array and convert it to torch tensor
xn = np.random.randn(100)
xt = torch.fromNumpyArray(xn)
## process with the neural network
yt = mlp._forward(xt)
print(yt)
## or for example, you can plot your result with matplotlib
yn = yt.asNumpyArray()
import matplotlib.pyplot as plt
plt.plot(yn)
import numpy as np
import lutorpy as lua
# load your torch file(for example xx.t7 containing the model and weights)
model = torch.load('PATH TO YOUR MODEL FILE')
# generate your input data with numpy
arr = np.random.randn(100)
# convert your numpy array into torch tensor
x = torch.fromNumpyArray(arr)
# apply model forward method with "._" syntax(which is equivalent to ":" in lua)
yt = model._forward(x)
# convert to numpy array
yn = yt.asNumpyArray()
You can also have a look at the step-by-step tutorial and more complete example.
You need to install torch before you start (only LuaJIT engine is supported for now)
# in a terminal, run the commands WITHOUT sudo
git clone https://github.com/torch/distro.git ~/torch --recursive
cd ~/torch
./clean.sh
bash install-deps
./install.sh
Then, you can use luarocks to install torch/lua modules
luarocks install nn
If you don't have numpy installed, install it by pip
sudo pip install numpy
Now, we are ready to install lutorpy, just use pip to install the released version:
sudo pip install lutorpy
Or, install from git repository:
git clone https://github.com/imodpasteur/lutorpy.git
cd lutorpy
sudo python setup.py install
if the setup script failed to detect your torch, it may related to: issue #38
import lutorpy as lua
# setup runtime and use zero-based index(optional, enabled by default)
lua.LuaRuntime(zero_based_index=True)
### note: zero-based index will only work getter operator such as "t[0]", for torch function like narrow, you still need 1-based indexing.
lua.execute(' greeting = "hello world" ')
print(greeting)
Note that if you do this, all the following code should change acorrdingly.
lua.LuaRuntime(zero_based_index=False)
a = lua.eval(' {11, 22} ') # define a lua table with two elements
print(a[0])
require("torch")
z = torch.Tensor(4,5,6,2)
print(torch.isTensor(z))
s = torch.LongStorage(6)
print(torch.type(s))
require('torch')
t = torch.randn(10,10)
print(t)
arr = t.asNumpyArray()
print(arr)
Note: both torch tensor and cuda tensor are supported.
arr = np.random.randn(100)
print(arr)
t = torch.fromNumpyArray(arr)
print(t)
require('cutorch')
cudat = torch.CudaTensor(10,10)
#convert cudaTensor to numpy array
arr = cudat.asNumpyArray()
print(arr)
arr = np.random.randn(100)
print(arr)
t = torch.fromNumpyArray(arr)
cudat = t._cuda()
print(cudat)
require("image")
img_rgb = image.lena()
print(img_rgb.size(img_rgb))
img = image.rgb2y(img_rgb)
print(img.size(img))
# use SpatialConvolution from nn to process the image
require("nn")
n = nn.SpatialConvolution(1,16,12,12)
res = n.forward(n, img)
print(res.size(res))
mlp = nn.Sequential()
module = nn.Linear(10, 5)
mlp.add(mlp, module)
print(module.weight)
print(module.bias)
print(module.gradWeight)
print(module.gradBias)
x = torch.Tensor(10) #10 inputs
# pass self to the function
y = mlp.forward(mlp, x)
print(y)
In lua, we use syntax like 'mlp:add(module)' to use a function without pass self to the function. But in python, it's done by default, there are two ways to prepend 'self' to a lua function in lutorpy.
The first way is inline prepending by add '_' to before any function name, then it will try to return a prepended version of the function:
mlp = nn.Sequential()
module = nn.Linear(10, 5)
# lua style
mlp.add(mlp, module)
# inline prepending
mlp._add(module) # equaliant to mlp:add(module) in lua
Train a model to perform XOR operation (see this torch tutorial).
require("nn")
mlp = nn.Sequential()
mlp._add(nn.Linear(2, 20)) # 2 input nodes, 20 hidden nodes
mlp._add(nn.Tanh())
mlp._add(nn.Linear(20, 1)) # 1 output nodes
criterion = nn.MSECriterion()
for i in range(2500):
# random sample
input= torch.randn(2) # normally distributed example in 2d
output= torch.Tensor(1)
if input[0]*input[1] > 0: # calculate label for XOR function
output[0] = -1 # output[0] = -1
else:
output[0] = 1 # output[0] = 1
# feed it to the neural network and the criterion
criterion._forward(mlp._forward(input), output)
# train over this example in 3 steps
# (1) zero the accumulation of the gradients
mlp._zeroGradParameters()
# (2) accumulate gradients
mlp._backward(input, criterion.backward(criterion, mlp.output, output))
# (3) update parameters with a 0.01 learning rate
mlp._updateParameters(0.01)
Train a model with nn trainer.
require("nn")
mlp = nn.Sequential()
mlp._add(nn.Linear(2, 20)) # 2 input nodes, 20 hidden nodes
mlp._add(nn.Tanh())
mlp._add(nn.Linear(20, 1)) # 1 output nodes
class DataSet():
def __init__(self):
self.data = []
for i in range(2500):
# random sample
input= torch.randn(2) # normally distributed example in 2d
output= torch.Tensor(1)
if input[0]*input[1] > 0: # calculate label for XOR function
output[0] = -1 # output[0] = -1
else:
output[0] = 1 # output[0] = 1
# here we need to add one empty column because lua index will start at 1
self.data.append((i, input,output))
def __getitem__(self, key):
if key == 'size':
return lambda x: len(self.data)
return self.data[key-1]
dataset = DataSet()
criterion = nn.MSECriterion()
trainer = nn.StochasticGradient(mlp, criterion)
trainer.learningRate = 0.01
trainer._train(dataset)
x = torch.Tensor(2)
x[0] = 0.5; x[1] = 0.5; print(mlp._forward(x))
x[0] = 0.5; x[1] = -0.5; print(mlp._forward(x))
x[0] = -0.5; x[1] = 0.5; print(mlp._forward(x))
x[0] = -0.5; x[1] = -0.5; print(mlp._forward(x))
-
For applying tensor.asNumpyArray() method to a torch tensor, if the tensor is contiguous, the memory will be shared between numpy array and torch tensor, if the tensor is not contiguous, a contiguous clone of the tensor will be used, so the created numpy array won't share memory with the old tensor.
-
For torch.fromNumpyArray(), there will be no memory sharing between the numpy array and the tenosr created.
Lutorpy is built upon lupa, there are more features provided by lupa could be also useful, please check it out.
- python2 and python3 are both supported
- unfortunately, OSX is not supported so far
Have a bug? Please create an issue here on GitHub at https://github.com/imodpasteur/lutorpy/issues.
Like lutorpy project? It solved your problem? Let us know by giving lutorpy project a star, so we know how many people are interested, thank you.
This is a project inspired by lunatic-python and lupa, and it's based on lupa.