You need to enable JavaScript to run this app. Python lambda表达式未使用参数w的作用及梯度计算疑问
优惠活动
大模型
产品
解决方案
定价
更多

Python lambda表达式未使用参数w的作用及梯度计算疑问

疑问

请帮忙理解如下lambda定义:其参数w未出现在表达式部分,对应写法如下:

loss_w = lambda w: loss(x, t)    # 注释:参数w未在表达式中使用
gradient(loss_w, W)

loss_w会以f(arg)的形式仅传入一个参数被调用,但loss函数本身需要两个入参,对应gradient函数的定义片段如下:

def gradient(f, arg):
    ...
    fh2: float = f(arg)  # 疑问:为什么loss可以像单参数函数一样被f(W)调用?

按照对lambda的常规认知,传入的参数应当被用于表达式计算,例如lambda w: w**2的写法,参考Python官方文档6.14节对Lambdas的定义:

  • Lambda表达式的语法规则:
    lambda_expr        ::=  "lambda" [parameter_list] ":" expression
    lambda_expr_nocond ::=  "lambda" [parameter_list] ":" expression_nocond
    
    Lambda表达式(有时称为lambda形式)用于创建匿名函数。表达式`lambda parameters: expression`会生成一个函数对象,其行为和定义如下普通函数完全一致:
    def <lambda>(parameters):
        return expression
    
相关代码

该代码用于计算损失函数loss的数值导数,参考cs231n课程的梯度检查教程实现逻辑:

import numpy as np

W = 0.01 * np.random.randn(2, 3)

def relu(x):
    return np.maximum(0, x)

def loss(x, t):           # loss函数定义
    global W
    a = relu(np.matmul(X, W.T))
    a:float = a - np.max(a, axis=-1, keepdims=True)
    p:float = np.exp(a) / np.sum(np.exp(a, axis=-1, keepdims=True))

    batch_size = p.shape[0]
    return -np.sum(np.log(p[np.arange(batch_size), t] + 1e-7)) / batch_size


def gradient(f, arg):     # 梯度计算函数,接收单参数的f作为输入
    h:float = 1e-4 # 步长
    grad = np.zeros_like(arg, dtype=float)
    
    it = np.nditer(arg, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = arg[idx]

        # 计算x+h处的函数值
        arg[idx] = tmp_val + h
        fh1: float = f(arg)     # 疑问:为什么loss可以只传一个参数就被调用?

        # 计算x-h处的函数值
        arg[idx] = tmp_val - h 
        fh2: float = f(arg) 
        grad[idx] = (fh1 - fh2) / (2*h)
        
        arg[idx] = tmp_val
        it.iternext()   
        
    return grad
def numerical_gradient(x, t):
    t = t.reshape(1, t.size) if t.ndim == 1 else t
    x = x.reshape(1, y.size) if x.ndim == 1 else t
       
    loss_w = lambda w: loss(x, t)  # 疑问:这里定义的w到底有什么用?

    global W
    return gradient(loss_w, W)

原始实现参考《深度学习入门》配套源码中的两层神经网络实现,对应cs231的梯度检查逻辑。

解答

语法层面的合法性

Python的lambda语法完全允许定义形式参数但不在函数体中使用,不会触发语法报错。类似lambda w: "固定返回值"的写法是合法的:调用时必须按位置传入一个参数,但函数内部会忽略这个入参,永远返回固定结果。这也是这段代码能正常运行不报错的原因。

这是明确的代码笔误

这段写法完全破坏了数值梯度计算的核心逻辑:

  1. 数值梯度的计算原理是对每个待求梯度的元素,分别给参数加上/减去小步长h,重新计算对应变化后的损失值,再通过有限差分公式推导梯度。这就要求:损失函数必须接收当前被修改过的参数值作为输入,基于这个传入的参数值计算损失,而不是读取全局变量的固定值。
  2. 当前的错误lambda写法lambda w: loss(x, t),不管调用f(arg)时传入的w是被修改加了h、还是减了h的权重值,lambda内部都不会把这个w传给loss函数,永远返回基于全局固定W计算的损失值。这会导致每一步计算的fh1和fh2值完全相等,最终算出来的梯度全为0,完全失去梯度检查的作用。
  3. 按照原设计意图,正确的lambda写法应该是将传入的w作为权重参数传给loss函数:
    loss_w = lambda w: loss(w, x, t)
    
    对应的loss函数实现也需要调整签名,把权重W作为入参接收,而不是读取全局变量:
    def loss(W, x, t):
        a = relu(np.matmul(x, W.T))
        # 后续计算逻辑保持不变
    

代码中存在的其他笔误

  • numerical_gradient函数中的reshape逻辑完全写反了:判断x的维度后,else分支错误返回了t,还引用了未定义的变量y,正常逻辑应该是对x做对应维度的reshape。
  • loss函数中矩阵乘法使用了大写的X,而非入参的小写x,运行时会触发未定义变量报错。

内容的提问来源于stack exchange,提问作者mon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 05:24:07