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

Source Code for Module rdkit.ML.Neural.Trainers

  1  # 
  2  #  Copyright (C) 2000-2008  greg Landrum 
  3  # 
  4  """ Training algorithms for feed-forward neural nets 
  5   
  6    Unless noted otherwise, algorithms and notation are taken from: 
  7    "Artificial Neural Networks: Theory and Applications", 
  8      Dan W. Patterson, Prentice Hall, 1996 
  9   
 10  """ 
 11  from __future__ import print_function 
 12   
 13  import numpy 
 14   
 15   
16 -class Trainer(object):
17 """ "virtual base class" for network trainers 18 19 """ 20 pass
21 22
23 -class BackProp(Trainer):
24 """implement back propagation (algorithm on pp 153-154 of Patterson) 25 26 I don't *think* that I've made any assumptions about the connectivity of 27 the net (i.e. full connectivity between layers is not required). 28 29 **NOTE:** this code is currently making the assumption that the activation 30 functions on the nodes in the network are capable of calculating their 31 derivatives using only their values (i.e. a DerivFromVal method should 32 exist). This shouldn't be too hard to change. 33 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 range(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 range(len(inputs)): 85 idx2 = inputs[j] 86 delta[idx2] = delta[idx2] + weights[j] 87 88 # now propagate the deltas backwards 89 for layer in range(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 range(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 range(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 - def TrainOnLine(self, examples, net, maxIts=5000, errTol=0.1, useAvgErr=1, silent=0):
122 """ carries out online training of a neural net 123 124 The definition of online training is that the network is updated after 125 each example is presented. 126 127 **Arguments** 128 129 - examples: a list of 2-tuple: 130 1) a list of variable values values 131 2) a list of result values (targets) 132 133 - net: a _Network_ (or something supporting the same API) 134 135 - maxIts: the maximum number of *training epochs* (see below for definition) to be 136 run 137 138 - errTol: the tolerance for convergence 139 140 - useAvgErr: if this toggle is nonzero, then the error at each step will be 141 divided by the number of training examples for the purposes of checking 142 convergence. 143 144 - silent: controls the amount of visual noise produced as this runs. 145 146 147 **Note** 148 149 a *training epoch* is one complete pass through all the training examples 150 151 """ 152 nExamples = len(examples) 153 converged = 0 154 cycle = 0 155 156 while (not converged) and (cycle < maxIts): 157 maxErr = 0 158 newErr = 0 159 # print('bp: ',cycle) 160 for example in examples: 161 localErr = self.StepUpdate(example, net) 162 newErr += localErr 163 if localErr > maxErr: 164 maxErr = localErr 165 if useAvgErr == 1: 166 newErr = newErr / nExamples 167 else: 168 newErr = maxErr 169 # print('\t',newErr,errTol) 170 171 if newErr <= errTol: 172 converged = 1 173 174 # if cycle % 10 == 0 and not silent: 175 if not silent: 176 print('epoch %d, error: % 6.4f' % (cycle, newErr)) 177 178 cycle = cycle + 1 179 if not silent: 180 if converged: 181 print('Converged after %d epochs.' % cycle) 182 else: 183 print('NOT Converged after %d epochs.' % cycle) 184 print('final error: % 6.4f' % newErr)
185
186 - def __init__(self, speed=0.5, momentum=0.7):
187 """ Constructor 188 189 **Arguments** 190 191 - speed: the speed parameter for back prop training 192 193 - momentum: the momentum term for back prop training 194 *Not currently used* 195 196 """ 197 self.speed = speed 198 self.momentum = momentum 199 self.oldDeltaW = None
200 201 if __name__ == '__main__': # pragma: nocover 202 from rdkit.ML.Neural import Network 203
204 - def testAnd():
205 examples = [[[0, 0, 1], [0.1]], [[0, 1, 1], [.1]], [[1, 0, 1], [.1]], [[1, 1, 1], [.9]]] 206 net = Network.Network([3, 1]) 207 t = BackProp() 208 t.TrainOnLine(examples, net) 209 return net
210
211 - def testOr():
212 examples = [[[0, 0, 1], [0.1]], [[0, 1, 1], [.9]], [[1, 0, 1], [.9]], [[1, 1, 1], [.9]]] 213 net = Network.Network([3, 1]) 214 t = BackProp() 215 t.TrainOnLine(examples, net, maxIts=1000, useAvgErr=0) 216 print('classifications:') 217 for example in examples: 218 res = net.ClassifyExample(example[0]) 219 print('%f -> %f' % (example[1][0], res)) 220 221 return net
222
223 - def testXor():
224 examples = [[[0, 0, 1], [.1]], [[0, 1, 1], [.9]], [[1, 0, 1], [.9]], [[1, 1, 1], [.1]]] 225 net = Network.Network([3, 3, 1]) 226 227 t = BackProp(speed=.8) 228 t.TrainOnLine(examples, net, errTol=0.2) 229 return net
230
231 - def testLinear():
232 examples = [ 233 [.1, .1], 234 [.2, .2], 235 [.3, .3], 236 [.4, .4], 237 [.8, .8], 238 ] 239 net = Network.Network([1, 2, 1]) 240 t = BackProp(speed=.8) 241 t.TrainOnLine(examples, net, errTol=0.1, useAvgErr=0) 242 print('classifications:') 243 for example in examples: 244 res = net.ClassifyExample(example[:-1]) 245 print('%f -> %f' % (example[-1], res)) 246 247 return net
248
249 - def runProfile(command):
250 import random 251 random.seed(23) 252 import profile 253 import pstats 254 datFile = '%s.prof.dat' % (command) 255 profile.run('%s()' % command, datFile) 256 stats = pstats.Stats(datFile) 257 stats.strip_dirs() 258 stats.sort_stats('time').print_stats()
259 260 if 0: 261 net = testXor() 262 print('Xor:', net) 263 from rdkit.six.moves import cPickle 264 outF = open('xornet.pkl', 'wb+') 265 cPickle.dump(net, outF) 266 outF.close() 267 else: 268 # runProfile('testLinear') 269 net = testLinear() 270 # net = testOr() 271