我目前正在研究卷积神经网络的开发,该网络有效地涉及多达5或6个维数组。
我知道许多用于卷积神经网络的工具并没有真正处理ND卷积,所以我决定尝试编写Helix Convolution的实现,从而可以将卷积视为大型的一维卷积(有关该概念的更多详细信息,请参阅参考文献1.http://sepwww.stanford.edu/public/docs/sep95/jon1/paper_html/node2.html,参考文献2 https://sites.ualberta.ca/~mostafan/Files/Papers/md_convolution_TLE2009.pdf(。
我这样做是基于(可能不正确的(假设,即大型单维卷积在 GPU 上可能比多维卷积更容易,并且该方法可以简单地扩展到 N 维。
特别是,引用参考文献2.指出:
我们没有发现N-D标准卷积与使用N-D标准卷积之间的计算效率显着提高 文中描述的算法。然而,我们发现 使用所描述的编写地震数据正则化代码 技巧导致可以轻松处理正则化的算法 任意数量的空间维度问题(纳吉扎德( 和萨基,2009 年(。
我已经编写了以下函数的实现,与signal.fftconvolve
.与此功能相比,它在 CPU 上的速度较慢,但我仍然想看看它在 PyTorch 中的 GPU 上作为前向卷积层的表现如何。
有人可以帮我把这段代码移植到 PyTorch 上,这样我就可以验证它的行为方式吗?
"""
HELIX CONVOLUTION FUNCTION
Shrink:
CROPS THE SIZE OF THE CONVOLVED SIGNAL DOWN TO THE ORIGINAL SIZE OF THE ORIGINAL.
Pad:
PADS THE DIFFERENCE BETWEEN THE ORIGINAL SHAPE AND THE DESIRED, CONVOLVED SHAPE FOR KERNEL AND SIGNAL.
GetLength:
EXTRACTS THE LENGTH OF THE UNWOUND STRIP OF THE SIGNAL AND KERNEL THAT IS TO BE CONVOLVED.
FFTConvolve:
USES THE NUMPY FFT PACKAGE TO PERFORM FAST FOURIER CONVOLUTION ON THE SIGNALS
Convolve:
USES HELIX CONVOLUTION ON AN INPUT ARRAY AND KERNEL.
"""
import numpy as np
from numpy import *
from scipy import signal
import operator
import time
class HelixCPU:
@classmethod
def Shrink(cls,array, bounding):
start = tuple(map(lambda a, da: (a-da)//2, array.shape, bounding))
end = tuple(map(operator.add, start, bounding))
slices = tuple(map(slice, start, end))
return array[slices]
@classmethod
def Pad(cls,array, target_shape):
diff = target_shape-array.shape
padder=[(0,val) for val in diff]
padded = np.pad(array, padder, 'constant')
return padded
@classmethod
def GetLength(cls,array_shape, padded_shape):
temp=1
steps=np.zeros_like(array_shape)
for i, entry in enumerate(padded_shape[::-1]):
if(i==len(padded_shape)-1):
steps[i]=1
else:
temp=entry*temp
steps[i]=temp
steps=np.roll(steps, 1)
steps=steps[::-1]
ones=np.ones_like(array_shape)
ones[-1]=0
out=np.multiply(steps,array_shape - ones)
length = np.sum(out)
return length
@classmethod
def FFTConvolve(cls, in1, in2, len1, len2):
s1 = len1
s2 = len2
shape = s1 + s2 - 1
fsize = 2 ** np.ceil(cp.log2(shape)).astype(int)
fslice = slice(0, shape)
conv = np.fft.ifft(np.fft.fft(in1, int(fsize)) * np.fft.fft(in2, int(fsize)))[fslice].copy()
return conv
@classmethod
def Convolve(cls,array, kernel):
m = array.shape
n = kernel.shape
mn = np.add(m, n)
mn = mn-np.ones_like(mn)
k_pad=cls.Pad(kernel, mn)
a_pad=cls.Pad(array, mn)
length_k = cls.GetLength(kernel.shape, k_pad.shape);
length_a = cls.GetLength(array.shape, a_pad.shape);
k_flat = k_pad.flatten()[0:length_k]
a_flat = a_pad.flatten()[0:length_a]
conv = cls.FFTConvolve(a_flat, k_flat)
conv = np.resize(conv,mn)
conv = cls.Shrink(conv, m)
return conv
def main():
array=np.random.rand(25,25,41,51)
kernel=np.random.rand(10, 10, 10, 10)
start2 =time.process_time()
test2 = HelixCPU.Convolve(array, kernel)
end2=time.process_time()
start1= time.process_time()
test1 = signal.fftconvolve(array, kernel, "same")
end1= time.process_time()
print ("")
print ("========================")
print ("SOME LARGE CONVOLVED RANDOM ARRAYS. ")
print ("========================")
print("")
print ("Random Calorimeter Image of Size {0} Created".format(array.shape))
print ("Random Kernel of Size {0} Created".format(kernel.shape))
print("")
print ("ValuetOriginaltHelix")
print ("Time Taken [s]t{0}t{1}t{2}".format( (end1-start1), (end2-start2), (end2-start2)/(end1-start1) ))
print ("Maximum Valuet{:03.2f}t{:13.2f}".format( np.max(test1), np.max(test2) ))
print ("Matrix Norm t{:03.2f}t{:13.2f}".format( np.linalg.norm(test1), np.linalg.norm(test2) ))
print ("All Close?t{0}".format(np.allclose(test1, test2)))
抱歉,由于代表次数少,我无法添加评论,所以我提出我的问题作为答案,希望可以回答您的问题。
螺旋卷积是指将卷积运算定义为单个矩阵乘法吗?如果是这样,我过去确实尝试过这个,但它的实用性确实是内存效率低下的。