0

I've been working on my code since yesterday and maybe I'm just tired but I'm stuck at a Name error and I can't understand why. What I'm trying to do is make a general neuran class and then a class for each type of neuron instantiated with an appropriate method for neuron type indicator. I'm not very fluent with classes and inheritance, maybe there's a cleaner and more Pythonic way to do it? But first why the error?:

class _Neuron(number, function, forwards_to=[] ):
    def __init__(self, number, function, forwards_to):
        self.number = number
        self.function = function
        self.forwards_to = forwards_to
        self.current_state = 0 #neurons may have any numeric state representing the sum of inputs from other neurons
        self.output = 0

    #whenever ready call to use up current state to calculate function output and restet the current state      
    def fire(self):
        self.output = function(self.current_state)
        self.current_state = 0
        
    #receices numeric values of outputs of other neurons and adds them to the sum of received signals   
    def receive_signal(self, input_signal):
        self.current_state+=input_signal
    
    #adds a forward connection
    def add_connection(self, neuron_number):
        if neuron_number not in self.forwards_to:
            self.forwards_to.append(neuron_number)
    #add multiple forward paths     
    def add_connections(self, **neuron_numbers):
            for neuron_number in neuron_numbers:
                self.add_connection(neuron_number)
            
    #remove a neuron connection
    def remove_connection(self, neuron_number):
        if neuron_number in self.forwards_to:
            self.forwars_to.remove(neuron_number)
    #remove multiple forward paths
    def remove_connections(self, **neuron_numbers):
            for neuron_number in neuron_numbers:
                self.remove_connection(neuron_number)
            
    def _make_deep(self):
        self.type = "deep"
        
    def _make_input(self):
        self.type = "input"
        
    def _make_output(self):
        self.type = "output"
        
    def get_number(self):
        return self.number
        
    def get_type(self):
        return self.type
        
    def get_connections(self):
        return self.forwards_to
        
    def get_current_state(self):
        return self.current_state
        
    def get_output(self):
        return self.output
        
#classes for declaring specific neuron types
#input neuron
class InputNeuron(_Neuron):
        def __init__(self, number, function, forwars_to=[]):
            super().__init__(number, function, forwars_to=[])
            self._make_input()
            
#output neuron
class OutputNeuron(_Neuron):
        def __init__(self, number, function, forwars_to=[]):
            super().__init__(number, function, forwars_to=[])
            self._make_output()
            
#deep neuron
class DeepNeuron(_Neuron):
        def __init__(self, number, function, forwars_to=[]):
            super().__init__(number, function, forwars_to=[])
            self._make_deep()
    
#tests      
f = lambda x: 1/x   
n1 = _Neuron(number=1, function=f)
n1._make_input()
n1.add_connections(1,2,3,4,5)
n1.receive_signal(100)
print(n1.get_type())
print(n1.get_number())
print(n1.get_connections())
print(n1.get_current_state())
print(n1.get_output())
n1.fire()
print(n1.get_connections())
print(n1.get_current_state())
print(n1.get_output())
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
lj h
  • 107
  • 1
  • 8

1 Answers1

1

I can see several errors:

the first to are in the init of your _Neuron class, should be something like this

  • 1: your initialization parameters you need to put them in the init not when you declare the class

  • 2 If you use a list as a default parameter you can have inspected result since this is declared when the class is read, and thus all instances will share the same list. Check this post for more info.

class _Neuron:
    def __init__(self, number, function, forwards_to=None):
        if not forwards_to:
            forwards_to = []
        self.number = number
        self.function = function
        self.forwards_to = forwards_to
        self.current_state = 0 #neurons may have any numeric state representing the sum of inputs from other neurons
        self.output = 0
  • 3 you are missing self.funtion in your method fire
     def fire(self):
        self.output = self.function(self.current_state)
        self.current_state = 0
  • 4 ** this operator is for unpacking mappers as a dictionary, you should use a single * for list add_connections and remove_connections method
    def add_connections(self, *neuron_numbers):
            for neuron_number in neuron_numbers:
                self.add_connection(neuron_number)

5 - this is not an error but Is how I would recommend to do what you are trying. If I'm not wrong, you want to declare a base _Neuron class to inherit for the rest, that is call an abstract class, and you can use the module abc to do this. Check here to learn more about it. Note an abstract class cannot be instatiated.

from abc import ABC, abstractmethod

class _Neuron(ABC):
    def __init__(self, number, function, forwards_to=None):
        super().__init__()
        if not forwards_to:
            forwards_to = []
        self.number = number
        self.function = function
        self.forwards_to = forwards_to
        self.current_state = 0 #neurons may have any numeric state representing the sum of inputs from other neurons
        self.output = 0
        self._make_type()

    #whenever ready call to use up current state to calculate function output and restet the current state      
    def fire(self):
        self.output = self.function(self.current_state)
        self.current_state = 0
        
    #receices numeric values of outputs of other neurons and adds them to the sum of received signals   
    def receive_signal(self, input_signal):
        self.current_state+=input_signal
    
    #adds a forward connection
    def add_connection(self, neuron_number):
        if neuron_number not in self.forwards_to:
            self.forwards_to.append(neuron_number)
    #add multiple forward paths     
    def add_connections(self, *neuron_numbers):
            for neuron_number in neuron_numbers:
                self.add_connection(neuron_number)
            
    #remove a neuron connection
    def remove_connection(self, neuron_number):
        if neuron_number in self.forwards_to:
            self.forwars_to.remove(neuron_number)
    #remove multiple forward paths
    def remove_connections(self, *neuron_numbers):
            for neuron_number in neuron_numbers:
                self.remove_connection(neuron_number)

    @abstractmethod        
    def _make_type(self):
        self.type = "deep"
        
    def get_number(self):
        return self.number
    
    def get_type(self):
        return self.type
        
    def get_connections(self):
        return self.forwards_to
        
    def get_current_state(self):
        return self.current_state
        
    def get_output(self):
        return self.output
        
#classes for declaring specific neuron types
#input neuron
class InputNeuron(_Neuron):
        def __init__(self, number, function, forwards_to=None):
            super().__init__(number, function, forwards_to=forwards_to)
        
        def _make_type(self):
            self.type = "input"
#output neuron
class OutputNeuron(_Neuron):
        def __init__(self, number, function, forwards_to=None):
            super().__init__(number, function, forwards_to=forwards_to)
        
        def _make_type(self):
            self.type = "output"
#deep neuron
class DeepNeuron(_Neuron):
        def __init__(self, number, function, forwards_to=None):
            super().__init__(number, function, forwards_to=forwards_to)
        
        def _make_type(self):
            self.type = "deep"
    
#tests      
f = lambda x: 1/x   
n1 = InputNeuron(number=1, function=f)
n1.add_connections(1,2,3,4,5)
n1.receive_signal(100)
print(n1.get_type())
print(n1.get_number())
print(n1.get_connections())
print(n1.get_current_state())
print(n1.get_output())
n1.fire()
print(n1.get_connections())
print(n1.get_current_state())
print(n1.get_output())
Lucas M. Uriarte
  • 2,403
  • 5
  • 19
  • Thank you so much, these are all great tips and advice. I will need to instantiate multiple neurons in my network. – lj h Nov 12 '22 at 12:31
  • Also will the _make_type(self) be called upon instantiation of any of the 3 neuron types - deep, output, input? Or will I have to call it manually? I would like my neuralnet manager to initialize network with functions such as make_input_neurons(number_of_inputs_to_make) and use the make_input in this case. – lj h Nov 12 '22 at 12:33
  • If you check the init of the abstract class, the last of it is self. _make_type() . That makes that all neurons that inherits from the abstract one will automatically call the _make_type(self) method. Since this method is different in each other each one will call it own method – Lucas M. Uriarte Nov 12 '22 at 14:40
  • Do I understand correct - _Neuron class becomes an abstract class, meaning it's a kind of a template on which other classes can be based. And I can instantiate other classes inheriting from the _Neuron abstract class (ie DeepNeuron), but not the abstract class itself.. Secondly the decorator @abstractmethod means that this is a method in the abstract class that should be overwritten by definition of the inheriting class? – lj h Nov 12 '22 at 15:18
  • 1
    That is completely correct. I'm glad you got everything so fast! – Lucas M. Uriarte Nov 12 '22 at 15:28
  • 1
    It's because you explained it so well. – lj h Nov 12 '22 at 16:26