0

I have an anonymous function with "_" as parameters, I don't know what it means and why it is used here.

and function is:

f = lambda _: model.loss(X, y)[0]

grad_num = eval_numerical_gradient(f, model.params[name], verbose=False, h=1e-5)

model.loss:

def loss(self, X, y=None):


    # Unpack variables from the params dictionary
    W1, b1 = self.params['W1'], self.params['b1']
    W2, b2 = self.params['W2'], self.params['b2']

    h1, h1_cache = affine_relu_forward(X, W1, b1)
    scores, h2_cache = affine_forward(h1, W2, b2)


    # If y is None then we are in test mode so just return scores
    if y is None:
        return scores

    loss, grads = 0, {}


    loss, dscores = softmax_loss(scores, y)
    loss = loss + 0.5*self.reg*(np.sum(W2**2) + np.sum(W1**2))
    dh1, grads['W2'], grads['b2'] = affine_backward(dscores,h2_cache)
    dX, grads['W1'], grads['b1'] = affine_relu_backward(dh1,h1_cache)
    grads['W1'] += self.reg*W1
    grads['W2'] += self.reg*W2

    return loss, grads

and the function eval_numerical_gradient:

def eval_numerical_gradient(f, x, verbose=True, h=0.00001):

    fx = f(x) # evaluate function value at original point
    grad = np.zeros_like(x)
    # iterate over all indexes in x
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:

        # evaluate function at x+h
        ix = it.multi_index
        oldval = x[ix]
        x[ix] = oldval + h # increment by h
        fxph = f(x) # evalute f(x + h)
        x[ix] = oldval - h
        fxmh = f(x) # evaluate f(x - h)
        x[ix] = oldval # restore

        # compute the partial derivative with centered formula
        grad[ix] = (fxph - fxmh) / (2 * h) # the slope
        if verbose:
            print(ix, grad[ix])
        it.iternext() # step to next dimension

    return grad

Loss function isn't complex, I want to know what the "_" represented and function in there.

DeepSpace
  • 65,330
  • 8
  • 79
  • 117
Zhengfang Xin
  • 367
  • 3
  • 13
  • This is typically used for anonymous variables that are required but of no use to the code. – Fourier Jul 25 '19 at 08:02
  • Isn't used ``_``, unused parameter. – deon cagadoes Jul 25 '19 at 08:02
  • You can omit it altogether: `f = lambda: model.loss(X, y)[0]` – Andriy Makukha Jul 25 '19 at 08:04
  • 9
    Possible duplicate of [What is the purpose of the single underscore "\_" variable in Python?](https://stackoverflow.com/questions/5893163/what-is-the-purpose-of-the-single-underscore-variable-in-python) Your case is #3 in the accepted answer. – Chillie Jul 25 '19 at 08:04
  • `_` is just a variable – nag Jul 25 '19 at 08:04
  • 1
    @Chillie It's definitely related but I'd not mark it as duplicated because of the specific use-case I describe in my answer. Without context the lambda in the OP could be implemented as `lambda: model.loss(X, y)[0]` but it can't, because the callback *will* pass an argument – DeepSpace Jul 25 '19 at 08:08
  • 1
    @AndriyMakukha He can't because `f` is used as a callback that will be passed an argument. See my answer – DeepSpace Jul 25 '19 at 08:10
  • There were plenty of similar questions asked before. Please, do some research next time before asking. For example: [Python's lambda with no variables?](https://stackoverflow.com/questions/29767310/pythons-lambda-with-no-variables) – Georgy Jul 25 '19 at 09:53

2 Answers2

4

It's a convention in Python to use _ for variables that are not going to be used later. There is no black magic involved and it is an ordinary variable name that behaves exactly as you'd expect.

In this case it is used because f is passed as a callback which will be passed an argument when it is called (fxph = f(x)).

If f would have been implemented as

f = lambda: model.loss(X, y)[0]

then a TypeError: <lambda>() takes 0 positional arguments but 1 was given error will be raised.

DeepSpace
  • 65,330
  • 8
  • 79
  • 117
  • So, f can be f(X,y) , also can be f(X), because pass parameter `y = None`? – Zhengfang Xin Jul 25 '19 at 08:17
  • 1
    @ZhengfangXin Yes, but it is not related. If the lambda would have not accepted `_` then the call `fxph = f(x)` would have failed with the error I show in my answer – DeepSpace Jul 25 '19 at 08:25
  • I confuse about `f = lambda x,y: x+y` , Okay,then I know I can call `f(1,2)`. If I use `f = lambda _:x+y`, how to call it? – Zhengfang Xin Jul 25 '19 at 08:32
  • 1
    @AzatIbrakov It is not a duplicate, let alone an "obvious" one. None of the answers there explain **why** it is used in the very specific use-case that this question shows – DeepSpace Jul 25 '19 at 08:35
  • @ZhengfangXin I don't understand your question. `f` is already called (`fxph = f(x)`) – DeepSpace Jul 25 '19 at 08:36
  • @DeepSpace if I use '_' for convenience, how IDE know which parameter I want to call for. Because, it has two pass parameters which can be passed in loss function. – Zhengfang Xin Jul 25 '19 at 08:41
  • 1
    @ZhengfangXin The IDE and the interpreter do not care. They do care that `f` will accept an argument. They do not care how `f` calls that argument internally or if it even using it. – DeepSpace Jul 25 '19 at 08:42
  • If I want to use `f = lambda _: x + y` for convenience and I call `f(1,2)`, it wil raise false. I still don't know how to use "_" in lambda function. – Zhengfang Xin Jul 25 '19 at 08:47
  • 1
    @ZhengfangXin There's nothing special about the name `_` in this context. It is the same as `f = lambda ignored_argument: x + y`. – Artyer Jul 25 '19 at 08:49
  • 1
    @ZhengfangXin Again. `_` means nothing special. `_ = 1` is exactly the same as `x = 1`. You get an error because you define a function that accepts a single argument but you pass it two arguments. – DeepSpace Jul 25 '19 at 08:51
  • @DeepSpace I got it !!!, it changes the `self.params` in mother class of `loss method`. Then recall the method again! Thank you so much for your teaching and patience!!! – Zhengfang Xin Jul 25 '19 at 08:56
2

In your case, it's a convention, telling that the lambda parameter is not used (the answer from DeepSpace explain why).

General use:

You can use _ when you have to get a value but you do not use it. It is a python convention, developers use it to make their code more readable to other developers. With _, you say that you are aware that the variable is not used. Some IDE like PyCharm warn you if you don't:

def test(s):
    print("foobar")


if __name__ == '__main__':
    test("barfoo")

Will result of a warning in Pycharm for example:

warning

But not with _:

def test(_):
    print("foobar")


if __name__ == '__main__':
    test("barfoo")

Result no warning:

no warning

Dorian Turba
  • 1,465
  • 1
  • 14
  • 21
  • Why can not just call `def test(): print('foobar')`? – Zhengfang Xin Jul 25 '19 at 08:34
  • Because of the example ! Of course you can, it's just an example to show your how your IDE will behave. A better example maybe is with for loop: `for _ in range(10): print('hello')`, but it take more line to do and I want the answer to be concise. – Dorian Turba Jul 25 '19 at 08:36
  • 1
    I didn't downvote but it is not true to say that you use `_` to tell your IDE something. `_` is a python convention, developers use it to make their code more readable to other developers and IDE have adapted to help them using this convention. – Corentin Limier Jul 25 '19 at 08:39
  • Ok, not exactly true, but still not false. If IDE warn you, it's because it's a python convention and developers use it etc. Thanks, I will edit the answer to be more clear. – Dorian Turba Jul 25 '19 at 08:41