ML.Neural.Network

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

# Source Code for Module ML.Neural.Network

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