Package rdkit :: Package ML :: Package Neural :: Module Trainers
[hide private]
[frames] | no frames]

Source Code for Module rdkit.ML.Neural.Trainers

  1  ## Automatically adapted for numpy.oldnumeric Jun 27, 2008 by -c 
  2   
  3  # 
  4  #  Copyright (C) 2000-2008  greg Landrum 
  5  # 
  6  """ Training algorithms for feed-forward neural nets 
  7   
  8    Unless noted otherwise, algorithms and notation are taken from: 
  9    "Artificial Neural Networks: Theory and Applications", 
 10      Dan W. Patterson, Prentice Hall, 1996 
 11     
 12  """ 
 13  from __future__ import print_function 
 14  import numpy 
 15   
 16  from rdkit.six.moves import xrange 
 17     
18 -class Trainer(object):
19 """ "virtual base class" for network trainers 20 21 """ 22 pass
23
24 -class BackProp(Trainer):
25 """implement back propagation (algorithm on pp 153-154 of Patterson) 26 27 I don't *think* that I've made any assumptions about the connectivity of 28 the net (i.e. full connectivity between layers is not required). 29 30 **NOTE:** this code is currently making the assumption that the activation 31 functions on the nodes in the network are capable of calculating their 32 derivatives using only their values (i.e. a DerivFromVal method should 33 exist). This shouldn't be too hard to change. 34 35 """
36 - def StepUpdate(self,example,net,resVect=None):
37 """ does a BackProp step based upon the example 38 39 **Arguments** 40 41 - example: a 2-tuple: 42 1) a list of variable values values 43 2) a list of result values (targets) 44 45 - net: a _Network_ (or something supporting the same API) 46 47 - resVect: if this is nonzero, then the network is not required to 48 classify the _example_ 49 50 **Returns** 51 52 the backprop error from _network_ **before the update** 53 54 **Note** 55 56 In case it wasn't blindingly obvious, the weights in _network_ are modified 57 in the course of taking a backprop step. 58 59 """ 60 totNumNodes = net.GetNumNodes() 61 if self.oldDeltaW is None: 62 self.oldDeltaW = numpy.zeros(totNumNodes,numpy.float64) 63 outputNodeList = net.GetOutputNodeList() 64 nOutput = len(outputNodeList) 65 targetVect = numpy.array(example[-nOutput:],numpy.float64) 66 trainVect = example[:-nOutput] 67 if resVect is None: 68 # classify the example 69 net.ClassifyExample(trainVect) 70 resVect = net.GetLastOutputs() 71 outputs = numpy.take(resVect,outputNodeList) 72 errVect = targetVect - outputs 73 74 delta = numpy.zeros(totNumNodes,numpy.float64) 75 # start with the output layer 76 for i in xrange(len(outputNodeList)): 77 idx = outputNodeList[i] 78 node = net.GetNode(idx) 79 # the deltas here are easy 80 delta[idx] = errVect[i]*node.actFunc.DerivFromVal(resVect[idx]) 81 # use these results to start working on the deltas of the preceding layer 82 inputs = node.GetInputs() 83 weights = delta[idx]*node.GetWeights() 84 for j in xrange(len(inputs)): 85 idx2 = inputs[j] 86 delta[idx2] = delta[idx2] + weights[j] 87 88 # now propagate the deltas backwards 89 for layer in xrange(net.GetNumHidden()-1,-1,-1): 90 nodesInLayer = net.GetHiddenLayerNodeList(layer) 91 for idx in nodesInLayer: 92 node = net.GetNode(idx) 93 # start by finishing off the error term for this guy 94 delta[idx] = delta[idx]*node.actFunc.DerivFromVal(resVect[idx]) 95 96 # and then propagate our errors to the preceding layer 97 if layer != 0: 98 inputs = node.GetInputs() 99 weights = delta[idx]*node.GetWeights() 100 for i in xrange(len(inputs)): 101 idx2 = inputs[i] 102 delta[idx2] = delta[idx2] + weights[i] 103 104 # okey dokey... we've now got the deltas for each node, use those 105 # to update the weights (whew!) 106 nHidden = net.GetNumHidden() 107 for layer in xrange(0,nHidden+1): 108 if layer == nHidden: 109 idxList = net.GetOutputNodeList() 110 else: 111 idxList = net.GetHiddenLayerNodeList(layer) 112 for idx in idxList: 113 node = net.GetNode(idx) 114 dW = self.speed * delta[idx] * numpy.take(resVect,node.GetInputs()) 115 newWeights = node.GetWeights() + dW 116 node.SetWeights(newWeights) 117 118 # return the RMS error from the OLD network 119 return numpy.sqrt(errVect*errVect)[0]
120 121
122 - def TrainOnLine(self,examples,net,maxIts=5000,errTol=0.1,useAvgErr=1, 123 silent=0):
124 """ carries out online training of a neural net 125 126 The definition of online training is that the network is updated after 127 each example is presented. 128 129 **Arguments** 130 131 - examples: a list of 2-tuple: 132 1) a list of variable values values 133 2) a list of result values (targets) 134 135 - net: a _Network_ (or something supporting the same API) 136 137 - maxIts: the maximum number of *training epochs* (see below for definition) to be 138 run 139 140 - errTol: the tolerance for convergence 141 142 - useAvgErr: if this toggle is nonzero, then the error at each step will be 143 divided by the number of training examples for the purposes of checking 144 convergence. 145 146 - silent: controls the amount of visual noise produced as this runs. 147 148 149 **Note** 150 151 a *training epoch* is one complete pass through all the training examples 152 153 """ 154 nExamples = len(examples) 155 converged = 0 156 cycle = 0 157 158 while (not converged) and (cycle < maxIts): 159 maxErr = 0 160 newErr = 0 161 #print('bp: ',cycle) 162 for example in examples: 163 localErr = self.StepUpdate(example,net) 164 newErr += localErr 165 if localErr > maxErr: 166 maxErr = localErr 167 if useAvgErr == 1: 168 newErr = newErr / nExamples 169 else: 170 newErr = maxErr 171 #print('\t',newErr,errTol) 172 173 if newErr <= errTol: 174 converged = 1 175 176 # if cycle % 10 == 0 and not silent: 177 if not silent: 178 print('epoch %d, error: % 6.4f'%(cycle,newErr)) 179 180 cycle = cycle + 1 181 if not silent: 182 if converged: 183 print('Converged after %d epochs.'%cycle) 184 else: 185 print('NOT Converged after %d epochs.'%cycle) 186 print('final error: % 6.4f'%newErr)
187
188 - def __init__(self,speed=0.5,momentum=0.7):
189 """ Constructor 190 191 **Arguments** 192 193 - speed: the speed parameter for back prop training 194 195 - momentum: the momentum term for back prop training 196 *Not currently used* 197 198 """ 199 self.speed = speed 200 self.momentum = momentum 201 self.oldDeltaW = None
202 203 204 205 if __name__ == '__main__': 206 from rdkit.ML.Neural import Network 207
208 - def testAnd():
209 examples = [ 210 [[0,0,1], [0.1]], 211 [[0,1,1], [.1]], 212 [[1,0,1], [.1]], 213 [[1,1,1], [.9]] 214 ] 215 net = Network.Network([3,1]) 216 t = BackProp() 217 t.TrainOnLine(examples,net) 218 return net
219
220 - def testOr():
221 examples = [ 222 [[0,0,1], [0.1]], 223 [[0,1,1], [.9]], 224 [[1,0,1], [.9]], 225 [[1,1,1], [.9]] 226 ] 227 net = Network.Network([3,1]) 228 t = BackProp() 229 t.TrainOnLine(examples,net,maxIts=1000,useAvgErr=0) 230 print('classifications:') 231 for example in examples: 232 res = net.ClassifyExample(example[0]) 233 print('%f -> %f'%(example[1][0],res)) 234 235 return net
236
237 - def testXor():
238 examples = [ 239 [[0,0,1], [.1]], 240 [[0,1,1], [.9]], 241 [[1,0,1], [.9]], 242 [[1,1,1], [.1]] 243 ] 244 net = Network.Network([3,3,1]) 245 246 t = BackProp(speed=.8) 247 t.TrainOnLine(examples,net,errTol=0.2) 248 return net
249 250
251 - def testLinear():
252 examples = [ 253 [.1,.1], 254 [.2,.2], 255 [.3,.3], 256 [.4,.4], 257 [.8,.8], 258 ] 259 net = Network.Network([1,2,1]) 260 t = BackProp(speed=.8) 261 t.TrainOnLine(examples,net,errTol=0.1,useAvgErr=0) 262 print('classifications:') 263 for example in examples: 264 res = net.ClassifyExample(example[:-1]) 265 print('%f -> %f'%(example[-1],res)) 266 267 return net
268
269 - def runProfile(command):
270 import random 271 random.seed(23) 272 import profile,pstats 273 datFile = '%s.prof.dat'%(command) 274 profile.run('%s()'%command,datFile) 275 stats = pstats.Stats(datFile) 276 stats.strip_dirs() 277 stats.sort_stats('time').print_stats()
278 279 if 0: 280 net = testXor() 281 print('Xor:', net) 282 from rdkit.six.moves import cPickle 283 outF = open('xornet.pkl','wb+') 284 cPickle.dump(net,outF) 285 outF.close() 286 else: 287 #runProfile('testLinear') 288 net = testLinear() 289 #net = testOr() 290