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

Source Code for Module rdkit.ML.Neural.Network

  1  ## Automatically adapted for numpy.oldnumeric Jun 27, 2008 by -c 
  2   
  3  # 
  4  #  Copyright (C) 2000-2008  greg Landrum 
  5  # 
  6  """ Contains the class _Network_ which is used to represent neural nets 
  7   
  8  **Network Architecture:** 
  9   
 10    A tacit assumption in all of this stuff is that we're dealing with 
 11    feedforward networks. 
 12   
 13    The network itself is stored as a list of _NetNode_ objects.  The list 
 14    is ordered in the sense that nodes in earlier/later layers than a 
 15    given node are guaranteed to come before/after that node in the list. 
 16    This way we can easily generate the values of each node by moving 
 17    sequentially through the list, we're guaranteed that every input for a 
 18    node has already been filled in. 
 19   
 20    Each node stores a list (_inputNodes_) of indices of its inputs in the 
 21    main node list. 
 22   
 23  """ 
 24  from __future__ import print_function 
 25  import numpy 
 26  import random 
 27   
 28  from rdkit.six.moves import xrange 
 29  from rdkit.ML.Neural import NetNode, ActFuncs 
 30   
 31  # FIX: this class has not been updated to new-style classes 
 32  # (RD Issue380) because that would break all of our legacy pickled 
 33  # data. Until a solution is found for this breakage, an update is 
 34  # impossible. 
35 -class Network:
36 """ a neural network 37 38 """
39 - def ConstructRandomWeights(self,minWeight=-1,maxWeight=1):
40 """initialize all the weights in the network to random numbers 41 42 **Arguments** 43 44 - minWeight: the minimum value a weight can take 45 46 - maxWeight: the maximum value a weight can take 47 48 """ 49 for node in self.nodeList: 50 inputs = node.GetInputs() 51 if inputs: 52 weights = [random.uniform(minWeight,maxWeight) for x in range(len(inputs))] 53 node.SetWeights(weights)
54 55
56 - def FullyConnectNodes(self):
57 """ Fully connects each layer in the network to the one above it 58 59 60 **Note** 61 this sets the connections, but does not assign weights 62 63 """ 64 nodeList = range(self.numInputNodes) 65 nConnections = 0 66 for layer in xrange(self.numHiddenLayers): 67 for i in self.layerIndices[layer+1]: 68 self.nodeList[i].SetInputs(nodeList) 69 nConnections = nConnections + len(nodeList) 70 nodeList = self.layerIndices[layer+1] 71 72 for i in self.layerIndices[-1]: 73 self.nodeList[i].SetInputs(nodeList) 74 nConnections = nConnections + len(nodeList) 75 self.nConnections = nConnections
76
77 - def ConstructNodes(self,nodeCounts,actFunc,actFuncParms):
78 """ build an unconnected network and set node counts 79 80 **Arguments** 81 82 - nodeCounts: a list containing the number of nodes to be in each layer. 83 the ordering is: 84 (nInput,nHidden1,nHidden2, ... , nHiddenN, nOutput) 85 86 """ 87 self.nodeCounts = nodeCounts 88 self.numInputNodes = nodeCounts[0] 89 self.numOutputNodes = nodeCounts[-1] 90 self.numHiddenLayers = len(nodeCounts)-2 91 self.numInHidden = [None]*self.numHiddenLayers 92 for i in xrange(self.numHiddenLayers): 93 self.numInHidden[i] = nodeCounts[i+1] 94 95 numNodes = sum(self.nodeCounts) 96 self.nodeList = [None]*(numNodes) 97 for i in xrange(numNodes): 98 self.nodeList[i] = NetNode.NetNode(i,self.nodeList, 99 actFunc=actFunc, 100 actFuncParms=actFuncParms) 101 102 self.layerIndices = [None]*len(nodeCounts) 103 start = 0 104 for i in xrange(len(nodeCounts)): 105 end = start + nodeCounts[i] 106 self.layerIndices[i] = range(start,end) 107 start = end
108
109 - def GetInputNodeList(self):
110 """ returns a list of input node indices 111 """ 112 return self.layerIndices[0]
113 - def GetOutputNodeList(self):
114 """ returns a list of output node indices 115 """ 116 return self.layerIndices[-1]
117 - def GetHiddenLayerNodeList(self,which):
118 """ returns a list of hidden nodes in the specified layer 119 """ 120 return self.layerIndices[which+1]
121
122 - def GetNumNodes(self):
123 """ returns the total number of nodes 124 """ 125 return sum(self.nodeCounts)
126
127 - def GetNumHidden(self):
128 """ returns the number of hidden layers 129 """ 130 return self.numHiddenLayers
131
132 - def GetNode(self,which):
133 """ returns a particular node 134 """ 135 return self.nodeList[which]
136 - def GetAllNodes(self):
137 """ returns a list of all nodes 138 """ 139 return self.nodeList
140
141 - def ClassifyExample(self,example,appendExamples=0):
142 """ classifies a given example and returns the results of the output layer. 143 144 **Arguments** 145 146 - example: the example to be classified 147 148 **NOTE:** 149 150 if the output layer is only one element long, 151 a scalar (not a list) will be returned. This is why a lot of the other 152 network code claims to only support single valued outputs. 153 154 """ 155 if len(example) > self.numInputNodes: 156 if len(example)-self.numInputNodes > self.numOutputNodes: 157 example = example[1:-self.numOutputNodes] 158 else: 159 example = example[:-self.numOutputNodes] 160 assert len(example) == self.numInputNodes 161 totNumNodes = sum(self.nodeCounts) 162 results = numpy.zeros(totNumNodes,numpy.float64) 163 for i in xrange(self.numInputNodes): 164 results[i] = example[i] 165 for i in xrange(self.numInputNodes,totNumNodes): 166 self.nodeList[i].Eval(results) 167 self.lastResults = results[:] 168 if self.numOutputNodes == 1: 169 return results[-1] 170 else: 171 return results
172
173 - def GetLastOutputs(self):
174 """ returns the complete list of output layer values from the last time this node classified anything""" 175 return self.lastResults
176
177 - def __str__(self):
178 """ provides a string representation of the network """ 179 outStr = 'Network:\n' 180 for i in xrange(len(self.nodeList)): 181 outStr = outStr + '\tnode(% 3d):\n'%i 182 outStr = outStr + '\t\tinputs: %s\n'%(str(self.nodeList[i].GetInputs())) 183 outStr = outStr + '\t\tweights: %s\n'%(str(self.nodeList[i].GetWeights())) 184 185 outStr = outStr + 'Total Number of Connections: % 4d'%self.nConnections 186 return outStr
187
188 - def __init__(self,nodeCounts,nodeConnections=None, 189 actFunc=ActFuncs.Sigmoid,actFuncParms=(), 190 weightBounds=1):
191 """ Constructor 192 193 This constructs and initializes the network based upon the specified 194 node counts. 195 196 A fully connected network with random weights is constructed. 197 198 **Arguments** 199 200 - nodeCounts: a list containing the number of nodes to be in each layer. 201 the ordering is: 202 (nInput,nHidden1,nHidden2, ... , nHiddenN, nOutput) 203 204 - nodeConnections: I don't know why this is here, but it's optional. ;-) 205 206 - actFunc: the activation function to be used here. Must support the API 207 of _ActFuncs.ActFunc_. 208 209 - actFuncParms: a tuple of extra arguments to be passed to the activation function 210 constructor. 211 212 - weightBounds: a float which provides the boundary on the random initial weights 213 214 215 216 """ 217 self.ConstructNodes(nodeCounts,actFunc,actFuncParms) 218 self.FullyConnectNodes() 219 self.ConstructRandomWeights(minWeight=-weightBounds,maxWeight=weightBounds) 220 self.lastResults = []
221 222 if __name__ == '__main__': 223 224 print('[2,2,2]') 225 net = Network([2,2,2]) 226 print(net) 227 228 print('[2,4,1]') 229 net = Network([2,4,1]) 230 print(net) 231 232 print('[2,2]') 233 net = Network([2,2]) 234 print(net) 235 input = [1,0] 236 res = net.ClassifyExample(input) 237 print(input,'->',res) 238 input = [0,1] 239 res = net.ClassifyExample(input) 240 print(input,'->',res) 241 input = [.5,.5] 242 res = net.ClassifyExample(input) 243 print(input,'->',res) 244