0

我正在实现输入和输出矩阵非常大的神经网络,所以我使用 dask 数组来存储它们。

X是 32000 x 7500 的输入矩阵,y是相同维度的输出矩阵。

下面是具有 1 个隐藏层的神经网络代码:

class Neural_Network(object):
    def __init__(self,i,j,k):
        #define hyperparameters
        self.inputLayerSize = i
        self.outputLayerSize = j
        self.hiddenLayerSize = k
        #weights
        self.W1 = da.random.normal(0.5,0.5,size =(self.inputLayerSize,self.hiddenLayerSize),chunks=(1000,1000))
        self.W2 = da.random.normal(0.5,0.5,size =(self.hiddenLayerSize,self.outputLayerSize),chunks=(1000,1000))
        self.W1 = self.W1.astype('float96')
        self.W2 = self.W2.astype('float96')

    def forward(self,X):
        self.z2 = X.dot(self.W1)
        self.a2 = self.z2.map_blocks(self.sigmoid)
        self.z3 = self.a2.dot(self.W2)
        yhat = self.z3.map_blocks(self.sigmoid)
        return yhat

    def exp(z):
        return np.exp(z)

    def sigmoid(self,z):
        #sigmoid function
##        return 1/(1+np.exp(-z))
        return 1/(1+(-z).map_blocks(self.exp))

    def sigmoidprime(self,z):
        ez = (-z).map_blocks(self.exp)
        return ez/(1+ez**2)

    def costFunction (self,X,y):
        self.yHat = self.forward(X)
        return 1/2*sum((y-self.yHat)**2)

    def costFunctionPrime (self,X,y):
        self.yHat = self.forward(X)
        self.error = -(y - self.yHat)
        self.delta3 = self.error*self.z3.map_blocks(self.sigmoidprime)
        dJdW2 = self.a2.transpose().dot(self.delta3)
        self.delta2 = self.delta3.dot(self.W2.transpose())*self.z2.map_blocks(self.sigmoidprime)
        dJdW1 = X.transpose().dot(self.delta2)
        return dJdW1 , dJdW2

现在我尝试降低功能成本,如下所示:

>>> n = Neural_Network(7420,7420,5000)
>>> for i in range(0,500):
    cost1,cost2 = n.costFunctionPrime(X,y)
    n.W1 = n.W1 -3*cost1
    n.W2 = n.W2 -3*cost2
    if i%5==0:
        print (i*100/500,'%')

但是当i达到 120 左右时,它给了我错误:

    File "<pyshell#127>", line 3, in <module>
    n.W1 = n.W1 -3*cost1
  File "c:\python34\lib\site-packages\dask\array\core.py", line 1109, in __sub__
    return elemwise(operator.sub, self, other)
  File "c:\python34\lib\site-packages\dask\array\core.py", line 2132, in elemwise
    dtype=dt, name=name)
  File "c:\python34\lib\site-packages\dask\array\core.py", line 1659, in atop
    return Array(merge(dsk, *dsks), out, chunks, dtype=dtype)
  File "c:\python34\lib\site-packages\toolz\functoolz.py", line 219, in __call__
    return self._partial(*args, **kwargs)
  File "c:\python34\lib\site-packages\toolz\curried\exceptions.py", line 20, in merge
    return toolz.merge(*dicts, **kwargs)
  File "c:\python34\lib\site-packages\toolz\dicttoolz.py", line 39, in merge
    rv.update(d)
MemoryError

MemoryError当我这样做时它也会给出nn.W1.compute()

4

1 回答 1

0

这看起来像是在构建图形时失败,而不是在计算期间。想到两件事:

避免过度循环

for 循环的每次迭代都可能将数百万个任务转储到任务图中。每个任务可能占用大约 100B 到 1kB 的空间。当这些加起来时,它们很容易使您的机器不堪重负。

在典型的深度学习库中,比如 Theano,你会使用这样的scan操作。Dask.array 没有这样的操作。

避免将图表插入图表

您在本身调用 map_blocks 的函数上调用 map_blocks。

self.delta2 = self.delta3.dot(self.W2.transpose())*self.z2.map_blocks(self.sigmoidprime)

def sigmoidprime(self,z):
    ez = (-z).map_blocks(self.exp)
    return ez/(1+ez**2)

相反,您可能只是制作一个 sigmoid 素数函数

def sigmoidprime(z):
    ez = np.exp(-z)
    return ez / (1 + ez ** 2)

然后映射该功能

self.z2.map_blocks(sigmoidprime)

深度学习很棘手

一般来说,做好深度学习往往需要专业化。出于某种原因,旨在很好地做到这一点的库通常不是通用的。像 dask.array 这样的通用库可能很有用,但可能永远无法实现像 Theano 这样的库的平稳运行。

一种可能的方法

您可以尝试构建一个只需一步的函数。它将从磁盘读取,执行所有点积、转置和正常计算,然后显式存储到磁盘数据集中。然后,您将多次调用此函数。即使这样,我也不相信 dask.array 背后的调度策略可以很好地做到这一点。

于 2016-03-29T15:15:04.773 回答