1

I'm trying to set up a Functions class that will handle functions for my NN projects. I've figured out I'd like the list of functions to be somewhat flexible (easily add, or remove functions used).

I've created a list of functions, defined a bunch of lambda functions, added a method that adds all the functions in the body to the list. When I try to check the length of the list it shows the correct number, but when I try to retrieve a function into a variable and pass it an argument I get an information that lambda takes 1 argument and I gave it 2. I don't understand what is the second argument.


import numpy as np

class Functions():
    f0 = identity = lambda x: x
    f1 = linear_step = lambda x: 1 if x > 0 else 0
    f2 = sigmoid = lambda x: 1/(1+np.exp(-x))
    f3 = tanh = lambda x: np.tanh(x)
    f4 = swish = lambda x: x/(1+np.exp(-x))
    f5 = absolute = lambda x: abs(x)
    f6 = cubic = lambda x: x**3
    f7 = square = lambda x: x**2
    f8 = sinusoid = lambda x: np.sin(x)
    f9 = square_root = lambda x: np.sqrt(x)
    f10 = cubic_root = lambda x: np.cbrt(x)
    f11 = opposite = lambda x: -x
    f12 = inverse = lambda x: 1/x
    f13 = exponential = lambda x: np.exp(x)
    
    def __init__(self): #constructor
        self._functions = []
        self.add_functions(self.f0, self.f1, self.f2, self.f3, self.f4, self.f5, self.f6, self.f7, self.f8, self.f9, self.f10, self.f11, self.f12, self.f13)

    #add a fyunction to the list, if it is not already there
    def _add_function(self, function):
        if function not in self._functions:
            self._functions.append(function)
            #print(f"Added function: {function.__name__}")
            return True
        else:
            #print(f"Function: {function.__name__} already exists at index: {functions.index(function)}")
            return False
        
    #add multiple functions to the list
    def add_functions(self, *args):
        for function in args:
            self._add_function(function)
            
    #get the number of functions in the list
    def number_of_functions(self):
        return len(self._functions)


    #return the function at the given index
    def get_function(self, index):
        try:
            return self._functions[index]
        except IndexError:
            print("Index out of range");
            return None
    
    def get_all_functions(self):
        return self._functions
        
        

functs = Functions()

print(f"number of functions {functs.number_of_functions()}")

iden = functs.get_function(0)
print(f"identity of one is {iden(1)}")

What's causing the issue? Alternatively what would be a better way to have an enumerable data structure to store and load the activation functions?

8
  • 1
    You're forgetting about self. Commented Nov 11, 2022 at 13:36
  • in which place should I add the self Commented Nov 11, 2022 at 13:37
  • 1
    Just use lambda self, x or lambda _,x if you aren't using the self argument. Commented Nov 11, 2022 at 13:40
  • 1
    Like @12944qwerty said, I believe the issue occur because f1 only accept x, but you called self.f1, so it accepted self as x parameter, and you tried to assign (1) at the last line of your code to f1, so Python read it as you tried to input self and 1 into f1 Commented Nov 11, 2022 at 13:43
  • 1
    Your _add_function method isn't going to work the way you intend. Functions cannot be compared for equality; (lambda x: x) == (lambda x: x) will evaluate to false. Even though the functions are equivalent, they are not the same function value. Commented Nov 11, 2022 at 14:08

2 Answers 2

3

When you do self.f1, you create a bound method, taking one less parameter than f1 did. This is how methods work in Python, so that you don't have to do self.foo(self, ...) all the time. You're encountering an unfortunate consequence of this generally reasonable decision.

There are several ways you could fix this. The easiest is probably to rewrite __init__ as follows.

    def __init__(self): #constructor
        self._functions = []
        cls = type(self)
        self.add_functions(cls.f0, cls.f1, cls.f2, cls.f3, cls.f4, cls.f5, cls.f6, cls.f7, cls.f8, cls.f9, cls.f10, cls.f11, cls.f12, cls.f13)

But, really, I doubt this is the right way to store these functions. I'd put them into a list and pass that to the class upon instantiation. Or just ditch the class and use a dictionary.

Sign up to request clarification or add additional context in comments.

Comments

2

All these functions behave the same as add_function, __init__, and number_of_functions. They are secretly being passed self. I have shown two fixes below:

class Functions:
    f0 = identity = lambda self, x: x
    f1 = linear_step = lambda self, x: 1 if x > 0 else 0
    f2 = sigmoid = lambda self, x: 1 / (1 + np.exp(-x))
    f3 = tanh = lambda self, x: np.tanh(x)
    # ...

class Functions:
    f0 = identity = staticmethod(lambda x: x)
    f1 = linear_step = staticmethod(lambda x: 1 if x > 0 else 0)
    f2 = sigmoid = staticmethod(lambda x: 1 / (1 + np.exp(-x)))
    f3 = tanh = staticmethod(lambda x: np.tanh(x))
    # ...

1 Comment

The second solution is probably the correct one. Nothing about the class indicates an instance of Functions is necessary (which calls into question the need for a class, rather than a list or dict, in the first place).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.