我目前正在阅读Joel Grus的《数据科学》一书,我遇到了一个我不太理解的功能:
def safe(f):
def safe_f(*args, **kwargs):
try:
return f(*args, **kwargs)
except:
return float('inf')
return safe_f
在梯度下降算法中调用安全函数来删除无穷大的值。
def minimize_batch(target_fn, gradient_fn, theta_0, tolerance=0.000001):
step_sizes = [100, 10, 1, 0.1, 0.001, 0.0001, 0.00001]
theta = theta_0
target_fn = safe(target_fn)
value = target_fn(theta)
while True:
gradient = gradient_fn(theta)
next_thetas = [step(theta, gradient, -step_size) for step_size in step_sizes]
next_theta = min(next_thetas, key=target_fn)
next_value = target_fn(next_theta)
if abs(value - next_value) < tolerance:
return theta
else:
theta, value = next_theta, next_value
我知道保险箱在做什么,但我不明白它是怎么做的。例如,如果没有目标的输入,SAFE如何评估目标的价值?安全的做法是什么?它知道如何删除无穷大的值?
撇开梯度下降不谈,这个安全函数是否适用于在很多地方都没有定义的疯狂函数?
它看起来不像是在删除无穷大的值。它看起来是在添加无穷大的值,而不是引发异常。例如,当x为零时,EDOCX1的不安全版本(0)会引发ZeroDivisionError;安全修饰版本不会引发异常,而是返回无穷大。
如果您知道safe是一个修饰函数,并且可以通过一个闭包在safe_f内部访问f,那么它可能有助于查找有关此的信息。
如果我们逐步替换变量名,可能有助于您理解:
target_fn = safe(target_fn)
指safe中的f为target_fn:
def safe(target_fn):
def safe_f(*args, **kwargs):
try:
return target_fn(*args, **kwargs)
except:
return float('inf')
return safe_f
还有:
target_fn = safe_f
也就是说,我们将最初绑定到target_fn的函数替换为刚才在decorator函数safe中创建的函数safe_f,通过一个闭包保留对原始函数f的访问。
所以这些参数是通过*args, **kwargs传递的(见**(双星)和*(星)对参数做了什么?):
next_value = target_fn(next_theta)
决定:
def safe_f(next_theta):
try:
return target_fn(next_theta)
except:
return float('inf')
也就是说,用参数next_theta返回调用原始target_fn的结果,或者如果执行此操作时出现错误,返回float('inf')。
would this safe function work on a crazy functions that was undefined at uncountably many places?
因为它使用*args, **kwargs,所以您可以使用它来包装任何函数,它会悄悄地抑制函数产生的任何错误并返回float('inf')—不过,这并不总是可取的!decorator函数还有许多其他用途,这些用途通常使用@decorator语法(例如,用于类和类上的静态方法和属性);请参见例如,python decorator有哪些常见用途?