Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TemporalConvolution.lua - github.com/soumith/cudnn.torch.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 36a55b7793876c376a44bc6fca4f1ba365111b1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
local TemporalConvolution, parent =
    torch.class('cudnn.TemporalConvolution', 'nn.TemporalConvolution')
--use cudnn to perform temporal convolutions
--note: if padH parameter is not passed, no padding will be performed, as in parent TemporalConvolution
--however, instead of separately padding data, as is required now for nn.TemporalConvolution,
--it is recommended to pass padding parameter to this routine and use cudnn implicit padding facilities.
--limitation is that padding will be equal on both sides.

function TemporalConvolution:__init(inputFrameSize, outputFrameSize,
                            kH, dH, padH)
    local delayedReset = self.reset
    local kW = inputFrameSize
    local nInputPlane = 1 -- single channel
    local nOutputPlane = outputFrameSize
    self.inputFrameSize = inputFrameSize
    self.outputFrameSize = outputFrameSize
    cudnn.SpatialConvolution.__init(self, nInputPlane, nOutputPlane, kW, kH, 1, dH,0,padH)
    self.weight = self.weight:view(nOutputPlane,inputFrameSize*kH)
    self.gradWeight = self.gradWeight:view(outputFrameSize, inputFrameSize*kH)
--self.dW and self.kW now have different meaning than in nn.TemporalConvolution, because
--W and H are switched in temporal and spatial
end

function TemporalConvolution:createIODescriptors(input)
    local sizeChanged = false
    if not self.iDesc or not self.oDesc or
        input:size(1) ~= self.iSize[1] or input:size(2) ~= self.iSize[2]
    or input:size(3) ~= self.iSize[3] or input:size(4) ~= self.iSize[4] then
       sizeChanged = true
    end
    cudnn.SpatialConvolution.createIODescriptors(self,input)
    if sizeChanged then
       self.oSize = self.output:size()
    end
end

function TemporalConvolution:fastest(mode)
    self = cudnn.SpatialConvolution.fastest(self,mode)
    return self
end

function TemporalConvolution:resetWeightDescriptors()
    cudnn.SpatialConvolution.resetWeightDescriptors(self)
end

local function inputview(input)
   local _input = input
   if input:dim()==2 then
      _input = input:view(1,input:size(1),input:size(2))
   end
   return _input:view(_input:size(1),1,_input:size(2),_input:size(3))
end

function TemporalConvolution:updateOutput(input)
   local _input = inputview(input)
   assert(_input:size(4) == self.inputFrameSize,'invalid input frame size')
   self.buffer = self.buffer or torch.CudaTensor()
   self._output = self._output or torch.CudaTensor()
   if self.output:storage() then self._output:set(self.output:storage()) else self._output = self.output end
   if self.buffer:storage() then self.output:set(self.buffer:storage(), 1, self.output:size()) else self.output = self.buffer end
   cudnn.SpatialConvolution.updateOutput(self,_input)
   self.buffer = self.output:view(self.oSize):transpose(2,3)
   self.output  = self._output:resize(self.buffer:size()):copy(self.buffer)
   -- self.output here is always 4D, use input dimensions to properly view output
   if input:dim()==3 then
     self.output=self.output:view(self.oSize[1], self.oSize[3],self.oSize[2])
   else
     self.output=self.output:view(self.oSize[3], self.oSize[2])
   end
   return self.output
end

local function transposeGradOutput(src,dst)
    assert(src:dim() == 2 or src:dim() == 3, 'gradOutput has to be 2D or 3D');
    local srctransposed = src:transpose(src:dim(),src:dim()-1)
    dst:resize(srctransposed:size())
    dst:copy(srctransposed)
    if src:dim()==3 then
      dst = dst:view(dst:size(1),dst:size(2),dst:size(3),1)
    else
      dst = dst:view(dst:size(1),dst:size(2),1)
    end
    return dst
end

function TemporalConvolution:updateGradInput(input, gradOutput)
   if not self.gradInput then return end
   local _gradOutput = transposeGradOutput(gradOutput,self.buffer)
   local _input = inputview(input)
   self.gradInput = cudnn.SpatialConvolution.updateGradInput(self,_input, _gradOutput)
   if input:dim()==3 then
      self.gradInput = self.gradInput:view(self.iSize[1],self.iSize[3],self.iSize[4])
   else
      self.gradInput = self.gradInput:view(self.iSize[3],self.iSize[4])
   end
   return self.gradInput
end

function TemporalConvolution:accGradParameters(input,gradOutput,scale)
--2d (4d) view of input
    local _input = inputview(input)
-- transpose gradOutput (it will likely be transposed twice, hopefully, no big deal
    local _gradOutput = transposeGradOutput(gradOutput,self.buffer)
    cudnn.SpatialConvolution.accGradParameters(self,_input,_gradOutput,scale)
end

function TemporalConvolution:clearDesc()
  self.buffer = nil
  self._output = nil
  self.oSize = nil
end

function TemporalConvolution:write(f)
  self:clearDesc()
  cudnn.SpatialConvolution.clearDesc(self)
    local var = {}
    for k,v in pairs(self) do
        var[k] = v
    end
    f:writeObject(var)
end

function TemporalConvolution:clearState()
   self:clearDesc()
   nn.utils.clear(self, '_input', '_gradOutput')
   return parent.clearState(self)
end