Typo.
[dagnn.git] / test-dagnn.lua
1 #!/usr/bin/env luajit
2
3 --[[
4
5    Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
6    Written by Francois Fleuret <francois.fleuret@idiap.ch>
7
8    This file is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License version 3 as
10    published by the Free Software Foundation.
11
12    It is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this file.  If not, see <http://www.gnu.org/licenses/>.
19
20 ]]--
21
22 require 'torch'
23 require 'nn'
24 require 'dagnn'
25
26 torch.setdefaulttensortype('torch.DoubleTensor')
27 torch.manualSeed(1)
28
29 function checkGrad(model, criterion, input, target)
30    local params, gradParams = model:getParameters()
31
32    local epsilon = 1e-5
33
34    local output = model:forward(input)
35    local loss = criterion:forward(output, target)
36    local gradOutput = criterion:backward(output, target)
37    gradParams:zero()
38    model:backward(input, gradOutput)
39    local analyticalGradParam = gradParams:clone()
40
41    local err = 0
42
43    for i = 1, params:size(1) do
44       local x = params[i]
45
46       params[i] = x - epsilon
47       local output0 = model:forward(input)
48       local loss0 = criterion:forward(output0, target)
49
50       params[i] = x + epsilon
51       local output1 = model:forward(input)
52       local loss1 = criterion:forward(output1, target)
53
54       params[i] = x
55
56       local ana = analyticalGradParam[i]
57       local num = (loss1 - loss0) / (2 * epsilon)
58
59       if num ~= ana then
60          err = math.max(err, math.abs(num - ana) / math.abs(num))
61       end
62    end
63
64    return err
65 end
66
67 function printTensorTable(t)
68    if torch.type(t) == 'table' then
69       for i, t in pairs(t) do
70          print('-- ELEMENT [' .. i .. '] --')
71          printTensorTable(t)
72       end
73    else
74       print(tostring(t))
75    end
76 end
77
78 --               +-- Linear(10, 10) --> ReLU --> d -->
79 --              /                               /
80 --             /                               /
81 --  --> a --> b -----------> c ---------------+
82 --                            \
83 --                             \
84 --                              +--------------- e -->
85
86 dag = nn.DAG()
87
88 a = nn.Linear(50, 10)
89 b = nn.ReLU()
90 c = nn.Linear(10, 15)
91 d = nn.CMulTable()
92 e = nn.Mul(-1)
93
94 dag:connect(a, b, c)
95 dag:connect(b, nn.Linear(10, 15), nn.ReLU(), d)
96 dag:connect(c, d)
97 dag:connect(c, e)
98
99 dag:setInput(a)
100 dag:setOutput({ d, e })
101
102 -- Check the output of the dot file
103 print('Writing /tmp/graph.dot')
104 dag:saveDot('/tmp/graph.dot')
105
106 -- Let's make a model where the dag is inside another nn.Container.
107 model = nn.Sequential()
108    :add(nn.Linear(50, 50))
109    :add(dag)
110    :add(nn.CAddTable())
111
112 local input = torch.Tensor(30, 50):uniform()
113 local output = model:updateOutput(input):clone()
114 output:uniform()
115
116 -- Check that DAG:accGradParameters and friends work okay
117 print('Gradient estimate error ' .. checkGrad(model, nn.MSECriterion(), input, output))
118
119 -- Check that we can save and reload the model
120 model:clearState()
121 torch.save('/tmp/test.t7', model)
122 local otherModel = torch.load('/tmp/test.t7')
123 print('Gradient estimate error ' .. checkGrad(otherModel, nn.MSECriterion(), input, output))