Daniel Voigt Godoy - Deep Learning with PyTorch Step-by-Step A Beginner’s Guide-leanpub

peiying410632
from peiying410632 More from this publisher
22.02.2024 Views

Higher-Order FunctionsAlthough this is more of a coding topic, I believe it is necessary to have a goodgrasp on how higher-order functions work to fully benefit from Python’scapabilities and make the best out of our code.I will illustrate higher-order functions with an example so that you can gain aworking knowledge of it, but I am not delving any deeper into the topic, as itis outside the scope of this book.Let’s say we’d like to build a series of functions, each performing anexponentiation to a given power. The code would look like this:def square(x):return x ** 2def cube(x):return x ** 3def fourth_power(x):return x ** 4# and so on and so forth...Well, clearly there is a higher structure to this:• every function takes a single argument x, which is the number we’d liketo exponentiate• every function performs the same operation, an exponentiation, buteach function has a different exponentOne way of solving this is to make the exponent an explicit argument, justlike the code below:def generic_exponentiation(x, exponent):return x ** exponentRethinking the Training Loop | 127

That’s perfectly fine, and it works quite well. But it also requires that youspecify the exponent every time you call the function. There must be anotherway! Of course, there is; that’s the purpose of this section!We need to build another (higher-order) function to build those functions(square, cube, etc.) for us. The (higher-order) function is just a functionbuilder. But how do we do that?First, let’s build the "skeleton" of the functions we are trying to generate; theyall take a single argument x, and they all perform an exponentiation, eachusing a different exponent.Fine. It should look like this:def skeleton_exponentiation(x):return x ** exponentIf you try calling this function with any x, say, skeleton_exponentiation(2),you’ll get the following error:skeleton_exponentiation(2)OutputNameError: name 'exponent' is not definedThis is expected: Your "skeleton" function has no idea what the variableexponent is! And that’s what the higher-order function is going toaccomplish.We "wrap" our skeleton function with a higher-order function (which willbuild the desired functions). Let’s call it, rather unimaginatively,exponentiation_builder(). What are its arguments, if any? Well, we’retrying to tell our skeleton function what its exponent should be, so let’sstart with that!128 | Chapter 2: Rethinking the Training Loop

That’s perfectly fine, and it works quite well. But it also requires that you

specify the exponent every time you call the function. There must be another

way! Of course, there is; that’s the purpose of this section!

We need to build another (higher-order) function to build those functions

(square, cube, etc.) for us. The (higher-order) function is just a function

builder. But how do we do that?

First, let’s build the "skeleton" of the functions we are trying to generate; they

all take a single argument x, and they all perform an exponentiation, each

using a different exponent.

Fine. It should look like this:

def skeleton_exponentiation(x):

return x ** exponent

If you try calling this function with any x, say, skeleton_exponentiation(2),

you’ll get the following error:

skeleton_exponentiation(2)

Output

NameError: name 'exponent' is not defined

This is expected: Your "skeleton" function has no idea what the variable

exponent is! And that’s what the higher-order function is going to

accomplish.

We "wrap" our skeleton function with a higher-order function (which will

build the desired functions). Let’s call it, rather unimaginatively,

exponentiation_builder(). What are its arguments, if any? Well, we’re

trying to tell our skeleton function what its exponent should be, so let’s

start with that!

128 | Chapter 2: Rethinking the Training Loop

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!