使用后在分配过程中删除变量

时间:2019-02-28 06:52:56

标签: python python-3.x neural-network deep-learning

在查看单独的一行时,我倾向于看到不清楚您在计算中的位置的代码。例如:

def forward(self, X):
    X = layer(X)
    X = activation(X)
    X = layer(X)
    X = activation(X)
    return X

很明显,第2行和第4行以及第3行和第5行是彼此无法区分的。

我宁愿编写更具可读性的代码,当查看特定的代码行时,很明显您在计算中的位置。例如(使用吴安国的符号):

def forward(self, X):
    A0 = X
    Z1 = layer(A0)
    A1 = activation(Z1)
    Z2 = layer(A1)
    A2 = activation(Z2)
    return A2

但是给定较大的变量,这可能会导致内存错误,因此可能有必要执行以下操作...

def forward(self, X):
    A0 = X
    Z1 = layer(A0); del A0
    A1 = activation(Z1); del Z1
    Z2 = layer(A1); del A1
    A2 = activation(Z2); del Z2
    return A2

但是,这损害了可读性,没有利用垃圾收集器属性。我不确定这种选择是否会有所作为。

如果A0,Z1,A1,Z2,A2的大小都相同,那么理想的解决方案就是只占用内存中最多两个变量的大小。

在计算左侧后,是否有Python方式删除右侧使用的所有变量,或者有类似的效果?或者,您是否可以创建一个执行删除和分配(给定作用域限制)的函数,效率折衷是什么?

1 个答案:

答案 0 :(得分:2)

  

理想的解决方案是只占用内存中最多两个变量的大小。

del在Python中并不经常需要。重复是一种代码气味。不要重复自己(DRY原理)。您可以使用循环删除重复项。

def forward(self, A):
    for _ in range(2):
        Z = layer(A)
        A = activation(Z)
    return A

您将重新使用两个变量AZ

您可以通过嵌套调用来进一步压缩它,从而完全删除Z

def forward(self, A):
    for _ in range(2):
        A = activation(layer(A))
    return A

如果您在功能上倾向于倾斜,则此模式称为“减少”(有时也称为“折叠”)。这可能不太像“ Pythonic”,但是在Python代码中仍然很常用该功能样式。

from functools import reduce

def forward(self, X):
    return reduce(lambda A, _: activation(layer(A)), range(2), X)

甚至,

def forward(self, X):
    return reduce(lambda x, f: f(x), [layer, activation]*2, X)

流行的toolz库也实现了这种模式

from toolz.functoolz import thread_first

def forward(self, X):
    return thread_first(X, layer, activation, layer, activation)

不需要中间变量,但是如果您觉得更好,可以添加注释。

def forward(self, X):
    return thread_first(
        X,  # A0
        layer, # Z1
        activation, # A1
        layer,  # Z2
        activation,  # A2
    )

这些都没有执行。


事实上,除了参数之外,根本不需要变量。

def forward(self, X):
    return activate(layer(activate(layer(X))))

函数实际上就是这么简单,关于变量名的麻烦似乎使它过于复杂。

对于仅两层来说,这可能还可以,但是循环/缩减版本使以后通过更新range()参数(甚至可能是.forward()的另一个参数)来添加更多层变得更加容易。方法。


  

您能创建一个执行删除和分配(给定作用域限制)的函数吗,效率折衷是什么?

除非使用del(或当它们超出范围时),否则您不能真正删除本地人。但是您可以使用自己的名称空间来代替本地人。这是由dict所支持的,该dict的效率仅比Local稍低,在这里并不重要。

from types import SimpleNamespace

class MonoNamespace(SimpleNamespace):
    """A namespace that holds only one attribute at a time."""
    def __setattr__(self, name, value):
        vars(self).clear()
        vars(self)[name] = value

def forward(self, X):
    ns = MonoNamespace(A0=X)
    ns.Z1 = layer(ns.A0)
    ns.A1 = activation(ns.Z1)
    ns.Z2 = layer(ns.A1)
    ns.A2 = activation(ns.Z2)
    return ns.A2