For Assignment 2, Exercise 2 I’m seeing that some functions calls have a double parenthesis while others have single parenthesis. Trying to understand when to use one over the other. My understanding until now is that you use double parens
()() when you need to call a function that returns another function (i.e. higher order function).
However, in the Exercise 2
alpaca_model there are situations such as
x = tfl.GlobalAveragePooling2D()(x)that are double parens and others such as
inputs = tf.keras.Input(shape=input_shape) and I’m not totally sure why. I understand why.
GlobalAveragePooling2D()() example above
x is suppose to present the dataset but how does it know that
x is the dataset if it’s not one of the parameters in the method? See tf.keras.layers.GlobalAveragePooling2D | TensorFlow v2.14.0 You will see that x is not listed as a param. Thanks for your help.
Please read about functional api
Short and simplified description (not necessarily 100% technically correct):
When you see double parens, the first set applies to the functional layer definition (that’s where you put any arguments for that layer), and the second set is where you would put any data is passed to that layer.
You don’t need the second set of parens when you use a Sequential model, because the data is passed automatically between layers when the model is trained.
In addition to the links and explanations from Tom and Balaji, here’s a thread that gives a nice explanation of the Sequential and Functional APIs.
Notice at the TensorFlow doc you linked that Python class inheritance is in play. Look also at the signatures for Layer base class methods, esp init()
I am not sure I’d say ()() is necessarily indicating a function that returns a function. I think it is a pattern or style of exploiting Python treating everything as a first class object. In this case, the first () returns an instance of a Layer class, which in turn supports a method that accepts the Layer input as a parameter. Thoughts?
Thanks @ai_curious I read your other post discussing difference between functional and sequential APIs (very helpful btw), so it seems the difference of using double parens versus single comes down to the difference in syntax where functional APIs treat whatever you pass into the trailing paren as the input by default. What made it confusing was that it wasn’t mentioned in the documentation of the different methods (i.e. Dense, MaxPool, etc. ) Also, I don’t see where init() is listed in the “Inherit From:” Global Average Max Pool 2D layer links and even if it was I’m not sure I understand how
init() is related to the input. Not an experienced programmer but just looked up what
init()is and it seems it means it’s used to initialize objects of a class but I’m kind of lost after that. Does initialize objects of a class mean that it assigns values to the object? If yes, then I guess we’re just suppose to know that passing
x to the trailing paren means only the input by definition of the syntax and that init() is “under the hood” function that does it for you.
I Thank you any help with additional clarification.
Since Layer is the base class, its init() is also called whenever a subclass is instantiated. Most of the attributes and capabilities, such as to carry and manipulate a collection of weights, comes from the base. Only sub-class-specifics, like the actual pooling algorithm, are implemented in the sub class.
If you look at the example code in the Layer class doc page, you can see where the ()() is broken out into two Python expressions, which I think I also gave an example of in my Tips… thread. The first () is the call to the sub-class instance constructor, which in turn calls the base class. Any parameters in the first () go to init(). The second () is the sub-class call() method, which accepts the layer inputs as a parameter. This interface ie method signature is again derived from the Layer base class. It is part of the Object-Oriented programming infrastructure leveraged extensively in both Python and TensorFlow (and Java and C++ …)
More elaboration here…