koraykv / unsup

Some unsupervised learning modules using Torch
86 stars 36 forks source link

Making an autoencoder use CUDA? #30

Open daviddoria opened 9 years ago

daviddoria commented 9 years ago

I've tried setting the encoder, decoder, the autoencoder itself, and the data to cuda using:

autoencoderModel:cuda() autoencoderModel.encoder:cuda() autoencoderModel.decoder:cuda() samples.cuda()

but I get this error:

bad argument #1 to 'set' (expecting number or Tensor or storage)
stack traceback:
[C]: in function 'set'
...torch7/share/lua/5.1/nn/Module.lua:201: in function 'flatten'
...torch7/share/lua/5.1/nn/Module.lua:243: in function 'getParameters'

Is it possible to make these autoencoders work with CUDA?

mdushkoff commented 9 years ago

I figured out how to do this recently actually after building an autoencoder from scratch. What you have to do is simple, after you make an autoencoder model, maybe it's named autoencoderModel.

You have to move the following onto your GPU:

autoencoderModel.encoder:cuda()
autoencoderModel.decoder:cuda()
autoencoderModel.loss:cuda()

After you do this, you should be able to forward any torch.CudaTensor through the autoencoder model with no issues as long as your input dimensions match.

You would probably expect autoencoderModel:cuda() to do this by itself, but this behavior is not what actually occurs.

The loss function has to be put on as well or else your loss will complain that it is not receiving the correct type of Tensor, however it looks like your issue might be slightly different...

daviddoria commented 9 years ago

Hm, it doesn't seem like "loss" is a member of the autoencoder?

Here is the error: "attempt to index field 'loss' (a nil value)"

And the code that produced it:

  local autoencoder = unsup.PSD(encoder, decoder, beta)

  if opt.type == 'cuda' then
    autoencoder.encoder:cuda()
    autoencoder.decoder:cuda()
    autoencoder.loss:cuda()

end

mdushkoff commented 9 years ago

The PSD module utilizes a field called predcost instead of loss so you would do:

local autoencoder = unsup.PSD(encoder, decoder, beta)

if opt.type == 'cuda' then
    autoencoder.encoder:cuda()
    autoencoder.decoder:cuda()
    autoencoder.predcost:cuda()
end

Hopefully that works, but I have not tested it. Also there is an error using CUDA when computing the diagonal Hessian components which I have yet to figure out yet which might also prevent this from working (you could always just disable that).

daviddoria commented 9 years ago

Have you used the convolutional autoencoder classes with CUDA? It looks like SpatialConvFistaL1 and ConvPsd? I am getting an "Inconsistent parameter types. torch.FloatTensor ~= torch.CudaTensor" error when trying to use those classes with CUDA.

koraykv commented 9 years ago

This relates to my last comment in issue #31 . I have written these classes a long time ago and have not been maintaining lately. The modules and custom classes most probably have to be modified to be able to work with cuda.

erosennin commented 9 years ago

I'm currently trying to make ConvPsd work with CUDA. There is no CUDA implementation of nn.SpatialConvolutionMap AFAIK, so I've replaced it with nn.SpatialConvolution:

--- a/ConvPsd.lua
+++ b/ConvPsd.lua
@@ -14,6 +14,7 @@ function ConvPSD:__init(conntable, kw, kh, iw, ih, lambda, beta, params)
    local decodertable = conntable:clone()
    decodertable:select(2,1):copy(conntable:select(2,2))
    decodertable:select(2,2):copy(conntable:select(2,1))
+   local inputFeatures = conntable:select(2,1):max()
    local outputFeatures = conntable:select(2,2):max()

    -- decoder is L1 solution
@@ -26,15 +27,15 @@ function ConvPSD:__init(conntable, kw, kh, iw, ih, lambda, beta, params)
    self.params.encoderType = params.encoderType or 'linear'

    if params.encoderType == 'linear' then
-      self.encoder = nn.SpatialConvolutionMap(conntable, kw, kh, 1, 1)
+      self.encoder = nn.SpatialConvolution(inputFeatures, outputFeatures, kw, kh, 1, 1)
    elseif params.encoderType == 'tanh' then
       self.encoder = nn.Sequential()
-      self.encoder:add(nn.SpatialConvolutionMap(conntable, kw, kh, 1, 1))
+      self.encoder:add(nn.SpatialConvolution(inputFeatures, outputFeatures, kw, kh, 1, 1))
       self.encoder:add(nn.Tanh())
       self.encoder:add(nn.Diag(outputFeatures))
    elseif params.encoderType == 'tanh_shrink' then
       self.encoder = nn.Sequential()
-      self.encoder:add(nn.SpatialConvolutionMap(conntable, kw, kh, 1, 1))
+      self.encoder:add(nn.SpatialConvolution(inputFeatures, outputFeatures, kw, kh, 1, 1))
       self.encoder:add(nn.TanhShrink())
       self.encoder:add(nn.Diag(outputFeatures))
    else

In theory, this should work exactly the same way, but It does not. I'm getting an error message about negative second derivatives:

$ luajit  demo_psd_conv.lua
<...>
Starting Training
Computing Hessian
Min Hessian=0.02 Max Hessian=500
luajit: ...a/src/torch/install/share/lua/5.1/unsup/UnsupTrainer.lua:106: Negative ddx
stack traceback:
        [C]: in function 'error'
        ...a/src/torch/install/share/lua/5.1/unsup/UnsupTrainer.lua:106: in function 'computeDiagHessian'
        ...a/src/torch/install/share/lua/5.1/unsup/UnsupTrainer.lua:36: in function 'train'
        demo_psd_conv.lua:181: in function 'train'
        demo_psd_conv.lua:192: in main chunk
        [C]: at 0x00406690

Any ideas, why simply replacing nn.SpatialConvolutionMap with nn.SpatialConvolution makes such a difference? Where should I look?

viorik commented 9 years ago

I managed to get conv_psd run with CUDA, if anyone is interested https://github.com/viorik/unsupgpu

soumith commented 9 years ago

@viorik that's nice. you should consider adding a link to the cheatsheet, where the unsup entry is.

viorik commented 9 years ago

@soumith ok, I'll do that; also I am making now few more changes to make it run on mini-batches, otherwise running with cuda is not very useful.

johnyboyoh commented 9 years ago

@viorik sounds good. BTW, I failed to install your package as it appears to be unknown to luarocks.

viorik commented 9 years ago

Right, that's because I haven't submitted a rockspec for inclusion in the rocks server. I am newbie, so I am still in the experimental stage :). But if you git clone my repo, you should be able to do luarocks make locally and use it.