Switch to unified view

a b/src/LiviaNet/LiviaNet3DConvLayer.py
1
""" 
2
Copyright (c) 2016, Jose Dolz .All rights reserved.
3
4
Redistribution and use in source and binary forms, with or without modification,
5
are permitted provided that the following conditions are met:
6
7
    1. Redistributions of source code must retain the above copyright notice,
8
       this list of conditions and the following disclaimer.
9
    2. Redistributions in binary form must reproduce the above copyright notice,
10
       this list of conditions and the following disclaimer in the documentation
11
       and/or other materials provided with the distribution.
12
13
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
    OTHER DEALINGS IN THE SOFTWARE.
21
22
Jose Dolz. Dec, 2016.
23
email: jose.dolz.upv@gmail.com
24
LIVIA Department, ETS, Montreal.
25
"""
26
27
28
import theano
29
import theano.tensor as T
30
from theano.tensor.nnet import conv2d
31
import theano.tensor.nnet.conv3d2d
32
import pdb
33
34
import sys
35
import os
36
import numpy as np
37
import numpy
38
import random
39
40
from Modules.General.Utils import initializeWeights
41
from Modules.NeuralNetwork.ActivationFunctions import *
42
from Modules.NeuralNetwork.layerOperations import *
43
44
#################################################################
45
#                         Layer Types                           #
46
#################################################################
47
48
class LiviaNet3DConvLayer(object):
49
    """Convolutional Layer of the Livia network """
50
    def __init__(self,
51
                 rng,
52
                 layerID,
53
                 inputSample_Train, 
54
                 inputSample_Test,
55
                 inputToLayerShapeTrain,
56
                 inputToLayerShapeTest,
57
                 filterShape,
58
                 useBatchNorm, 
59
                 numberEpochApplyRolling, 
60
                 maxPoolingParameters,
61
                 weights_initMethodType,
62
                 weights,
63
                 activationType,
64
                 dropoutRate=0.0) :
65
        
66
        self.inputTrain = None
67
        self.inputTest = None
68
        self.inputShapeTrain = None
69
        self.inputShapeTest = None
70
       
71
        self._numberOfFeatureMaps = 0
72
        self._maxPoolingParameters = None
73
        self._appliedBnInLayer = None
74
        self.params = [] 
75
        self.W = None 
76
        self._gBn = None 
77
        self._b = None 
78
        self._aPrelu = None 
79
        self.numberOfTrainableParams = 0
80
        
81
        self.muBatchNorm = None 
82
        self._varBnsArrayForRollingAverage = None 
83
        self.numberEpochApplyRolling = numberEpochApplyRolling
84
        self.rollingIndex = 0 
85
        self._sharedNewMu_B = None 
86
        self._sharedNewVar_B = None
87
        self._newMu_B = None
88
        self._newVar_B = None
89
        
90
        self.outputTrain = None
91
        self.outputTest = None
92
        self.outputShapeTrain = None
93
        self.outputShapeTest = None
94
95
        # === After all the parameters has been initialized, create the layer 
96
        # Set all the inputs and parameters
97
        self.inputTrain = inputSample_Train
98
        self.inputTest = inputSample_Test
99
        self.inputShapeTrain = inputToLayerShapeTrain
100
        self.inputShapeTest = inputToLayerShapeTest
101
        
102
        self._numberOfFeatureMaps = filterShape[0] 
103
        assert self.inputShapeTrain[1] == filterShape[1]
104
        self._maxPoolingParameters = maxPoolingParameters
105
106
        print(" --- [STATUS]  --------- Creating layer {} --------- ".format(layerID))
107
        
108
         ## Process the input layer through all the steps over the block
109
             
110
        (inputToConvTrain,
111
         inputToConvTest) = self.passInputThroughLayerElements(inputSample_Train,
112
                                                               inputToLayerShapeTrain,
113
                                                               inputSample_Test,
114
                                                               inputToLayerShapeTest,
115
                                                               useBatchNorm, 
116
                                                               numberEpochApplyRolling, 
117
                                                               activationType,
118
                                                               weights,  
119
                                                               dropoutRate,
120
                                                               rng
121
                                                               )         
122
        # input shapes for the convolutions
123
        inputToConvShapeTrain = inputToLayerShapeTrain
124
        inputToConvShapeTest  = inputToLayerShapeTest
125
        
126
        # --------------  Weights initialization -------------
127
        # Initialize weights with random weights if W is empty
128
        # Otherwise, use loaded weights
129
130
        self.W = initializeWeights(filterShape,
131
                                   weights_initMethodType,
132
                                   weights)
133
134
        self.params = [self.W] + self.params
135
        self.numberOfTrainableParams += 1
136
        
137
        ##---------- Convolve --------------
138
        (convolvedOutput_Train, convolvedOutputShape_Train) = convolveWithKernel(self.W, filterShape, inputToConvTrain, inputToConvShapeTrain) 
139
        (convolvedOutput_Test, convolvedOutputShape_Test)   = convolveWithKernel(self.W , filterShape, inputToConvTest, inputToConvShapeTest) 
140
        
141
        self.outputTrain = convolvedOutput_Train
142
        self.outputTest = convolvedOutput_Test
143
        self.outputShapeTrain = convolvedOutputShape_Train
144
        self.outputShapeTest = convolvedOutputShape_Test
145
        
146
    
147
    def updateLayerMatricesBatchNorm(self):
148
149
        if self._appliedBnInLayer :
150
            muArrayValue = self.muBatchNorm.get_value()
151
            muArrayValue[self.rollingIndex] = self._sharedNewMu_B.get_value()
152
            self.muBatchNorm.set_value(muArrayValue, borrow=True)
153
            
154
            varArrayValue = self._varBnsArrayForRollingAverage.get_value()
155
            varArrayValue[self.rollingIndex] = self._sharedNewVar_B.get_value()
156
            self._varBnsArrayForRollingAverage.set_value(varArrayValue, borrow=True)
157
            self.rollingIndex = (self.rollingIndex + 1) % self.numberEpochApplyRolling
158
            
159
    def getUpdatesForBnRollingAverage(self) :
160
        if self._appliedBnInLayer :
161
            return [(self._sharedNewMu_B, self._newMu_B),
162
                    (self._sharedNewVar_B, self._newVar_B) ]
163
        else :
164
            return []
165
    
166
167
    def passInputThroughLayerElements(self,
168
                                      inputSample_Train,
169
                                      inputSampleShape_Train,
170
                                      inputSample_Test,
171
                                      inputSampleShape_Test,
172
                                      useBatchNorm,
173
                                      numberEpochApplyRolling,
174
                                      activationType,
175
                                      weights,
176
                                      dropoutRate,
177
                                      rndState):
178
        """ Through each block the following steps are applied, according to Kamnitsas:
179
            1 - Batch Normalization or biases
180
            2 - Activation function
181
            3 - Dropout
182
            4 - (Optional) Max pooling
183
184
            Ref:   He et al "Identity Mappings in Deep Residual Networks" 2016 
185
            https://github.com/KaimingHe/resnet-1k-layers/blob/master/resnet-pre-act.lua """
186
            
187
        # ________________________________________________________
188
        #      1 :  Batch Normalization 
189
        # ________________________________________________________
190
        """ Implemenation taken from Kamnitsas work.
191
        
192
        A batch normalization implementation in TensorFlow:
193
194
        http://r2rt.com/implementing-batch-normalization-in-tensorflow.html
195
196
        "Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift",
197
         Proceedings of the 32nd International Conference on Machine Learning, Lille, France, 2015.
198
         Journal of Machine Learning Research: W&CP volume 37
199
        """
200
        if useBatchNorm > 0 :
201
           
202
            self._appliedBnInLayer = True
203
            
204
            (inputToNonLinearityTrain,
205
            inputToNonLinearityTest,
206
            self._gBn,
207
            self._b,
208
            self.muBatchNorm,
209
            self._varBnsArrayForRollingAverage,
210
            self._sharedNewMu_B,
211
            self._sharedNewVar_B,
212
            self._newMu_B,
213
            self._newVar_B) = applyBn( numberEpochApplyRolling,
214
                                       inputSample_Train,
215
                                       inputSample_Test,
216
                                       inputSampleShape_Train)
217
                         
218
            self.params = self.params + [self._gBn, self._b]
219
        else : 
220
            self._appliedBnInLayer = False
221
            numberOfInputFeatMaps = inputSampleShape_Train[1]
222
223
            b_values = np.zeros( (self._numberOfFeatureMaps), dtype = 'float32')
224
            self._b = theano.shared(value=b_values, borrow=True)
225
    
226
            inputToNonLinearityTrain = applyBiasToFeatureMaps( self._b, inputSample_Train )
227
            inputToNonLinearityTest = applyBiasToFeatureMaps( self._b, inputSample_Test )
228
229
            self.params = self.params + [self._b]
230
            
231
        # ________________________________________________________
232
        #      2 :  Apply the corresponding activation function 
233
        # ________________________________________________________
234
        def Linear():
235
            print " --- Activation function: Linear"
236
            self.activationFunctionType = "Linear"
237
            output_Train = inputToNonLinearityTrain
238
            output_Test = inputToNonLinearityTest
239
            return (output_Train, output_Test)
240
            
241
        def ReLU():
242
            print " --- Activation function: ReLU"
243
            self.activationFunctionType = "ReLU"
244
            output_Train = applyActivationFunction_ReLU_v1(inputToNonLinearityTrain)
245
            output_Test = applyActivationFunction_ReLU_v1(inputToNonLinearityTest)
246
            return (output_Train, output_Test)
247
        
248
        def PReLU():
249
            print " --- Activation function: PReLU"
250
            self.activationFunctionType = "PReLU"
251
            numberOfInputFeatMaps = inputSampleShape_Train[1]
252
            PReLU_Values = np.ones( (numberOfInputFeatMaps), dtype = 'float32' )*0.01 
253
            self._aPrelu = theano.shared(value=PReLU_Values, borrow=True) 
254
255
            output_Train = applyActivationFunction_PReLU(inputToNonLinearityTrain, self._aPrelu)
256
            output_Test  = applyActivationFunction_PReLU(inputToNonLinearityTest, self._aPrelu)
257
            self.params = self.params + [self._aPrelu]
258
            self.numberOfTrainableParams += 1
259
            return (output_Train,output_Test)
260
        
261
        def LeakyReLU():
262
            print " --- Activation function: Leaky ReLU "
263
            self.activationFunctionType = "Leky ReLU"
264
            leakiness = 0.2 # TODO. Introduce this value in the config.ini
265
            output_Train = applyActivationFunction_LeakyReLU(inputToNonLinearityTrain,leakiness)
266
            output_Test = applyActivationFunction_LeakyReLU(inputToNonLinearityTest,leakiness)
267
            return (output_Train, output_Test)
268
                
269
        optionsActFunction = {0 : Linear,
270
                              1 : ReLU,
271
                              2 : PReLU,
272
                              3 : LeakyReLU}
273
274
        (inputToDropout_Train, inputToDropout_Test) = optionsActFunction[activationType]()
275
            
276
        # ________________________________________________________
277
        #      3 :  Apply Dropout
278
        # ________________________________________________________
279
        output_Train = apply_Dropout(rndState,dropoutRate,inputSampleShape_Train,inputToDropout_Train, 0)
280
        output_Test  = apply_Dropout(rndState,dropoutRate,inputSampleShape_Train,inputToDropout_Test, 1)
281
          
282
        # ________________________________________________________
283
        #      This will go as input to the convolutions
284
        # ________________________________________________________   
285
286
        return (output_Train, output_Test)
287
        
288