test_module.py 6.22 KB
Newer Older
Hang Zhang's avatar
test  
Hang Zhang committed
1
2
3
4
5
6
7
8
9
10
##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
## Created by: Hang Zhang
## ECE Department, Rutgers University
## Email: zhang.hang@rutgers.edu
## Copyright (c) 2017
##
## This source code is licensed under the MIT-style license found in the
## LICENSE file in the root directory of this source tree 
##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Zhang's avatar
Zhang committed
11
import numpy as np
Hang Zhang's avatar
sync BN  
Hang Zhang committed
12

Hang Zhang's avatar
test  
Hang Zhang committed
13
14
15
import torch
from torch.autograd import Variable, gradcheck

Zhang's avatar
Zhang committed
16
import encoding
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
17

Zhang's avatar
v0.4.2  
Zhang committed
18
19
EPS = 1e-3
ATOL = 1e-3
Zhang's avatar
Zhang committed
20
21
22

def _assert_tensor_close(a, b, atol=ATOL, rtol=EPS):
    npa, npb = a.cpu().numpy(), b.cpu().numpy()
Zhang's avatar
v0.4.2  
Zhang committed
23
    assert np.allclose(npa, npb, rtol=rtol, atol=atol), \
Zhang's avatar
Zhang committed
24
25
        'Tensor close check failed\n{}\n{}\nadiff={}, rdiff={}'.format(
            a, b, np.abs(npa - npb).max(), np.abs((npa - npb) / np.fmax(npa, 1e-5)).max())
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
26

Hang Zhang's avatar
Hang Zhang committed
27
def test_aggregate():
Hang Zhang's avatar
test  
Hang Zhang committed
28
29
30
31
32
33
34
35
    B,N,K,D = 2,3,4,5
    A = Variable(torch.cuda.DoubleTensor(B,N,K).uniform_(-0.5,0.5), 
        requires_grad=True)
    X = Variable(torch.cuda.DoubleTensor(B,N,D).uniform_(-0.5,0.5), 
        requires_grad=True)
    C = Variable(torch.cuda.DoubleTensor(K,D).uniform_(-0.5,0.5), 
        requires_grad=True)
    input = (A, X, C)
Zhang's avatar
Zhang committed
36
    test = gradcheck(encoding.functions.aggregate, input, eps=EPS, atol=ATOL)
Hang Zhang's avatar
Hang Zhang committed
37
    print('Testing aggregate(): {}'.format(test))
Hang Zhang's avatar
test  
Hang Zhang committed
38
39


Hang Zhang's avatar
Hang Zhang committed
40
def test_scaledL2():
Hang Zhang's avatar
test  
Hang Zhang committed
41
42
43
44
45
46
47
48
    B,N,K,D = 2,3,4,5
    X = Variable(torch.cuda.DoubleTensor(B,N,D).uniform_(-0.5,0.5), 
        requires_grad=True)
    C = Variable(torch.cuda.DoubleTensor(K,D).uniform_(-0.5,0.5), 
        requires_grad=True)
    S = Variable(torch.cuda.DoubleTensor(K).uniform_(-0.5,0.5), 
        requires_grad=True)
    input = (X, C, S)
Zhang's avatar
Zhang committed
49
    test = gradcheck(encoding.functions.scaledL2, input, eps=EPS, atol=ATOL)
Hang Zhang's avatar
Hang Zhang committed
50
    print('Testing scaledL2(): {}'.format(test))
Hang Zhang's avatar
test  
Hang Zhang committed
51
52
53
54
55
56
57


def test_encoding():
    B,C,H,W,K = 2,3,4,5,6
    X = Variable(torch.cuda.DoubleTensor(B,C,H,W).uniform_(-0.5,0.5), 
        requires_grad=True)
    input = (X,)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
58
    layer = encoding.nn.Encoding(C,K).double().cuda()
Zhang's avatar
Zhang committed
59
    test = gradcheck(layer, input, eps=EPS, atol=ATOL)
Hang Zhang's avatar
test  
Hang Zhang committed
60
    print('Testing encoding(): {}'.format(test))
Hang Zhang's avatar
sync BN  
Hang Zhang committed
61

Hang Zhang's avatar
test  
Hang Zhang committed
62
63

def test_sum_square():
Zhang's avatar
Zhang committed
64
65
    B,C,H = 2,3,4
    X = Variable(torch.cuda.DoubleTensor(B,C,H).uniform_(-0.5,0.5), 
Hang Zhang's avatar
test  
Hang Zhang committed
66
67
        requires_grad=True)
    input = (X,)
Zhang's avatar
Zhang committed
68
    test = gradcheck(encoding.functions.sum_square, input, eps=EPS, atol=ATOL)
Hang Zhang's avatar
test  
Hang Zhang committed
69
70
71
    print('Testing sum_square(): {}'.format(test))


Hang Zhang's avatar
sync BN  
Hang Zhang committed
72
73
74
75
76
def test_all_reduce():
    ngpu = torch.cuda.device_count()
    X = [torch.DoubleTensor(2,4,4).uniform_(-0.5,0.5).cuda(i) for i in range(ngpu)]
    for x in X:
        x.requires_grad = True
Hang Zhang's avatar
Hang Zhang committed
77
    Y = encoding.parallel.allreduce(1, *X)
Hang Zhang's avatar
sync BN  
Hang Zhang committed
78
    assert (len(X) == len(Y))
Zhang's avatar
Zhang committed
79
80
81
82
    for i in range(1, ngpu):
        _assert_tensor_close(Y[i].data, Y[0].data)
    input = (1, *X)
    test = gradcheck(encoding.parallel.allreduce, input, eps=EPS, atol=ATOL)
Zhang's avatar
v0.4.2  
Zhang committed
83
    print('Testing allreduce(): {}'.format(test))
Zhang's avatar
Zhang committed
84

Zhang's avatar
v0.4.2  
Zhang committed
85
86
87

def test_syncbn():
    train_mode=True
Zhang's avatar
Zhang committed
88
89
90
91
92
93
    # generate input
    B,C,H,W = 8,3,4,5
    X = Variable(torch.cuda.DoubleTensor(B,C,H,W).uniform_(-0.5,0.5), 
                 requires_grad=True)
    input = (X,)
    # SyncBN using DataParallel
Zhang's avatar
v0.4.2  
Zhang committed
94
    layer = encoding.nn.BatchNorm2d(C)
Zhang's avatar
Zhang committed
95
    model = torch.nn.DataParallel(layer).double().cuda()
Zhang's avatar
v0.4.2  
Zhang committed
96
    encoding.parallel.patch_replication_callback(model)
Zhang's avatar
Zhang committed
97
98
99
    layer.train(train_mode)
    # grad check
    test = gradcheck(model, input, eps=EPS, atol=ATOL)
Zhang's avatar
v0.4.2  
Zhang committed
100
    print('Testing BatchNorm2d(): {}'.format(test))
Zhang's avatar
Zhang committed
101
102


Zhang's avatar
v0.4.2  
Zhang committed
103
def test_syncbn_func():
Zhang's avatar
Zhang committed
104
105
106
107
    # generate input
    B, C, H = 2, 3, 4
    X = Variable(torch.cuda.DoubleTensor(B,C,H).uniform_(-0.5, 0.5), 
        requires_grad=True)
Zhang's avatar
v0.4.2  
Zhang committed
108
109
110
111
    gamma = Variable(torch.cuda.DoubleTensor(C).uniform_(-0.5, 0.5), requires_grad=True)
    beta = Variable(torch.cuda.DoubleTensor(C).uniform_(-0.5, 0.5), requires_grad=True)
    mean = Variable(torch.cuda.DoubleTensor(C).uniform_(-0.5, 0.5), requires_grad=True)
    std = Variable(torch.cuda.DoubleTensor(C).uniform_(-0.5, 0.5), requires_grad=True)
Zhang's avatar
Zhang committed
112
    N = B * H
Zhang's avatar
v0.4.2  
Zhang committed
113
    inputs = (X, mean, std, gamma, beta)
Zhang's avatar
Zhang committed
114
    # grad check
Zhang's avatar
v0.4.2  
Zhang committed
115
    test = gradcheck(encoding.functions.batchnormtrain, inputs, eps=EPS, atol=ATOL)
Zhang's avatar
Zhang committed
116
117
118
    print('Testing batchnorm(): {}'.format(test))


Zhang's avatar
v0.4.2  
Zhang committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def testSyncBN():
    def _checkBatchNormResult(bn1, bn2, input, is_train, cuda=False):
        def _find_bn(module):
            for m in module.modules():
                if isinstance(m, (torch.nn.BatchNorm1d, torch.nn.BatchNorm2d,
                                  encoding.nn.BatchNorm1d, encoding.nn.BatchNorm2d)):
                    return m
        def _syncParameters(bn1, bn2):
            bn1.reset_parameters()
            bn2.reset_parameters()
            if bn1.affine and bn2.affine:
                bn2.weight.data.copy_(bn1.weight.data)
                bn2.bias.data.copy_(bn1.bias.data)
                bn2.running_mean.copy_(bn1.running_mean)
                bn2.running_var.copy_(bn1.running_var)

        bn1.train(mode=is_train)
        bn2.train(mode=is_train)

        if cuda:
            input = input.cuda()
        # using the same values for gamma and beta
        _syncParameters(_find_bn(bn1), _find_bn(bn2))

        input1 = Variable(input.clone().detach(), requires_grad=True)
        input2 = Variable(input.clone().detach(), requires_grad=True)
        output1 = bn1(input1)
        output2 = bn2(input2)
        # assert forwarding
        _assert_tensor_close(input1.data, input2.data)
        _assert_tensor_close(output1.data, output2.data)
        if not is_train:
            return
        (output1 ** 2).sum().backward()
        (output2 ** 2).sum().backward()
        _assert_tensor_close(input1.grad.data, input2.grad.data)
        _assert_tensor_close(_find_bn(bn1).running_mean, _find_bn(bn2).running_mean)
        _assert_tensor_close(_find_bn(bn1).running_var, _find_bn(bn2).running_var)
Zhang's avatar
Zhang committed
157
158
159


    bn = torch.nn.BatchNorm2d(10).cuda().double()
Zhang's avatar
v0.4.2  
Zhang committed
160
    sync_bn = encoding.nn.BatchNorm2d(10).double()
Zhang's avatar
Zhang committed
161
    sync_bn = torch.nn.DataParallel(sync_bn).cuda()
Zhang's avatar
v0.4.2  
Zhang committed
162
    encoding.parallel.patch_replication_callback(sync_bn)
Zhang's avatar
Zhang committed
163
164
    # check with unsync version
    for i in range(10):
Zhang's avatar
v0.4.2  
Zhang committed
165
        print(i)
Zhang's avatar
Zhang committed
166
167
        _checkBatchNormResult(bn, sync_bn, torch.rand(16, 10, 16, 16).double(), True, cuda=True)
        _checkBatchNormResult(bn, sync_bn, torch.rand(16, 10, 16, 16).double(), False, cuda=True)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
168

Hang Zhang's avatar
test  
Hang Zhang committed
169
if __name__ == '__main__':
Hang Zhang's avatar
sync BN  
Hang Zhang committed
170
171
    import nose
    nose.runmodule()