加速 Theano 中的 reduce 操作
Speedup for the reduce operation in Theano
编辑:
很抱歉,事实证明我在进行测试时在我的 GPU 上有其他进程 运行,我已经更新了空闲 GPU 上的计时结果,对于较大的矩阵,加速变得很明显。
原文Post:
如 中所述,L
是一个矩阵列表,其中每个项目 M
是一个 x*n
矩阵(x
是一个变量, n
固定)。
我想为 L
中的所有项目计算 M'*M
的总和(M'
是 M
的 t运行spose)作为以下 Python 代码确实如此。
for M in L:
res += np.dot(M.T, M)
以下是 Numpy 和 Theano 实现的一些示例(对于可执行脚本,请参阅@DanielRenshaw 对 的回答)。
def numpy_version1(*L):
n = L[0].shape[1]
res = np.zeros((n, n), dtype=L[0].dtype)
for M in L:
res += np.dot(M.T, M)
return res
def compile_theano_version1(number_of_matrices, n, dtype):
L = [tt.matrix() for _ in xrange(number_of_matrices)]
res = tt.zeros(n, dtype=dtype)
for M in L:
res += tt.dot(M.T, M)
return theano.function(L, res)
def compile_theano_version2(number_of_matrices, n):
L = theano.typed_list.TypedListType(tt.TensorType(theano.config.floatX, broadcastable=(None, None)))()
res, _ = theano.reduce(fn=lambda i, tmp: tmp+tt.dot(L[i].T, L[i]),
outputs_info=tt.zeros((n, n), dtype=theano.config.floatX),
sequences=[theano.tensor.arange(number_of_matrices, dtype='int64')])
return theano.function([L], res)
我 运行 CPU 上的 Numpy 版本和不同设置的 GPU 上的 Theano 版本,似乎 Theano 版本总是按比例比 Numpy 版本慢(无论数量和矩阵的大小)。
但我期待可能会有一些优化 w.r.t GPU,因为它是一个简单的 reduce 操作。
有人可以帮助我了解幕后发生的事情吗?
编辑:
以下是用于生成数据的脚本(来自@DanielRenshaw)、我已经厌倦的设置和结果。
L = [np.random.standard_normal(size=(x, n)).astype(dtype)
for x in range(min_x, number_of_matrices + min_x)]
dtype = 'float32'
theano.config.floatX = dtype
iteration_count = 10
min_x = 20
# base case:
# numpy_version1 0.100589990616
# theano_version1 0.243968963623
# theano_version2 0.198153018951
number_of_matrices = 200
n = 100
# increase matrix size:
# numpy_version1 4.90120816231
# theano_version1 0.984472036362
# theano_version2 3.56008815765
number_of_matrices = 200
n = 1000
# increase number of matrices:
# numpy_version1 5.11445093155
# theano_version1 compilation error
# theano_version2 6.54448604584
number_of_matrices = 2000
n = 100
您遇到的问题不是矩阵的数量,而是矩阵的大小。
您的测试示例根据您拥有的矩阵数量创建大小矩阵,因此,您拥有的矩阵越多,矩阵越大,但 python 循环开销也越大(在减少操作),因此,检测速度改进变得更加困难。
为了进行一些新的测试,我已经仔细修改了你的矩阵生成:
S = 1000 # Size of the matrices
N = 10 # Number of matrices
L = [np.random.standard_normal(size=(np.random.randint(S//2, S*2), S)).astype(np.float32) for _ in range(N)]
这仅生成 10 个大小为 (x, 1000)
的矩阵,其中 x
是 [S//2, S*2] == [500, 2000]
.
范围内的某个值
f1 = compile_theano_version1(N, S, np.float32)
f2 = compile_theano_version2(N, S)
- 现在用
N = 10
个大矩阵进行一些测试:
对于S = 1000
,N = 10
:
%timeit numpy_version1(*L) # 10 loops, best of 3: 131 ms per loop
%timeit f1(*L) # 10 loops, best of 3: 37.3 ms per loop
%timeit f2(L) # 10 loops, best of 3: 68.7 ms per loop
其中 theano 函数在具有相当不错 i7
和不错的 NVIDIA 860M 的笔记本电脑中具有 x4
和 x2
加速(这意味着您应该在这里获得更好的加速).
对于S = 5000
,N = 10
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 4 s per loop
%timeit f1(*L) # 1 loops, best of 3: 907 ms per loop
%timeit f2(L) # 1 loops, best of 3: 1.77 s per loop
因此,总的来说,在这种设置下,S
越大,theano 相对于 CPU 的加速就越大。
- 一些
N = 100
大矩阵的测试:theano 似乎更快
对于S = 1000
,N = 100
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 1.46 s per loop
%timeit f1(*L) # 1 loops, best of 3: 408 ms per loop
%timeit f2(L) # 1 loops, best of 3: 724 s per loop
对于S = 2000
,N = 100
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 11.3 s per loop
%timeit f1(*L) # 1 loops, best of 3: 2.72 s per loop
%timeit f2(L) # 1 loops, best of 3: 4.01 s per loop
- 使用
N = 100
小矩阵进行测试:numpy 似乎更快
对于S = 50
,N = 100
:
%timeit numpy_version1(*L) # 100 loops, best of 3: 1.17 ms per loop
%timeit f1(*L) # 100 loops, best of 3: 4.21 ms per loop
%timeit f2(L) # 100 loops, best of 3: 7.42 ms per loop
测试规范:
- 处理器:i7 4710HQ
- 显卡:NVIDIA GeForce GTX 860M
- Numpy:版本 1.10.2 使用 intel MKT 构建
- Theano:版本 0.70; floatX = float32;使用 GPU
编辑:
很抱歉,事实证明我在进行测试时在我的 GPU 上有其他进程 运行,我已经更新了空闲 GPU 上的计时结果,对于较大的矩阵,加速变得很明显。
原文Post:
如 L
是一个矩阵列表,其中每个项目 M
是一个 x*n
矩阵(x
是一个变量, n
固定)。
我想为 L
中的所有项目计算 M'*M
的总和(M'
是 M
的 t运行spose)作为以下 Python 代码确实如此。
for M in L:
res += np.dot(M.T, M)
以下是 Numpy 和 Theano 实现的一些示例(对于可执行脚本,请参阅@DanielRenshaw 对
def numpy_version1(*L):
n = L[0].shape[1]
res = np.zeros((n, n), dtype=L[0].dtype)
for M in L:
res += np.dot(M.T, M)
return res
def compile_theano_version1(number_of_matrices, n, dtype):
L = [tt.matrix() for _ in xrange(number_of_matrices)]
res = tt.zeros(n, dtype=dtype)
for M in L:
res += tt.dot(M.T, M)
return theano.function(L, res)
def compile_theano_version2(number_of_matrices, n):
L = theano.typed_list.TypedListType(tt.TensorType(theano.config.floatX, broadcastable=(None, None)))()
res, _ = theano.reduce(fn=lambda i, tmp: tmp+tt.dot(L[i].T, L[i]),
outputs_info=tt.zeros((n, n), dtype=theano.config.floatX),
sequences=[theano.tensor.arange(number_of_matrices, dtype='int64')])
return theano.function([L], res)
我 运行 CPU 上的 Numpy 版本和不同设置的 GPU 上的 Theano 版本,似乎 Theano 版本总是按比例比 Numpy 版本慢(无论数量和矩阵的大小)。
但我期待可能会有一些优化 w.r.t GPU,因为它是一个简单的 reduce 操作。
有人可以帮助我了解幕后发生的事情吗?
编辑:
以下是用于生成数据的脚本(来自@DanielRenshaw)、我已经厌倦的设置和结果。
L = [np.random.standard_normal(size=(x, n)).astype(dtype)
for x in range(min_x, number_of_matrices + min_x)]
dtype = 'float32'
theano.config.floatX = dtype
iteration_count = 10
min_x = 20
# base case:
# numpy_version1 0.100589990616
# theano_version1 0.243968963623
# theano_version2 0.198153018951
number_of_matrices = 200
n = 100
# increase matrix size:
# numpy_version1 4.90120816231
# theano_version1 0.984472036362
# theano_version2 3.56008815765
number_of_matrices = 200
n = 1000
# increase number of matrices:
# numpy_version1 5.11445093155
# theano_version1 compilation error
# theano_version2 6.54448604584
number_of_matrices = 2000
n = 100
您遇到的问题不是矩阵的数量,而是矩阵的大小。
您的测试示例根据您拥有的矩阵数量创建大小矩阵,因此,您拥有的矩阵越多,矩阵越大,但 python 循环开销也越大(在减少操作),因此,检测速度改进变得更加困难。
为了进行一些新的测试,我已经仔细修改了你的矩阵生成:
S = 1000 # Size of the matrices
N = 10 # Number of matrices
L = [np.random.standard_normal(size=(np.random.randint(S//2, S*2), S)).astype(np.float32) for _ in range(N)]
这仅生成 10 个大小为 (x, 1000)
的矩阵,其中 x
是 [S//2, S*2] == [500, 2000]
.
f1 = compile_theano_version1(N, S, np.float32)
f2 = compile_theano_version2(N, S)
- 现在用
N = 10
个大矩阵进行一些测试:
对于S = 1000
,N = 10
:
%timeit numpy_version1(*L) # 10 loops, best of 3: 131 ms per loop
%timeit f1(*L) # 10 loops, best of 3: 37.3 ms per loop
%timeit f2(L) # 10 loops, best of 3: 68.7 ms per loop
其中 theano 函数在具有相当不错 i7
和不错的 NVIDIA 860M 的笔记本电脑中具有 x4
和 x2
加速(这意味着您应该在这里获得更好的加速).
对于S = 5000
,N = 10
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 4 s per loop
%timeit f1(*L) # 1 loops, best of 3: 907 ms per loop
%timeit f2(L) # 1 loops, best of 3: 1.77 s per loop
因此,总的来说,在这种设置下,S
越大,theano 相对于 CPU 的加速就越大。
- 一些
N = 100
大矩阵的测试:theano 似乎更快
对于S = 1000
,N = 100
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 1.46 s per loop
%timeit f1(*L) # 1 loops, best of 3: 408 ms per loop
%timeit f2(L) # 1 loops, best of 3: 724 s per loop
对于S = 2000
,N = 100
:
%timeit numpy_version1(*L) # 1 loops, best of 3: 11.3 s per loop
%timeit f1(*L) # 1 loops, best of 3: 2.72 s per loop
%timeit f2(L) # 1 loops, best of 3: 4.01 s per loop
- 使用
N = 100
小矩阵进行测试:numpy 似乎更快
对于S = 50
,N = 100
:
%timeit numpy_version1(*L) # 100 loops, best of 3: 1.17 ms per loop
%timeit f1(*L) # 100 loops, best of 3: 4.21 ms per loop
%timeit f2(L) # 100 loops, best of 3: 7.42 ms per loop
测试规范:
- 处理器:i7 4710HQ
- 显卡:NVIDIA GeForce GTX 860M
- Numpy:版本 1.10.2 使用 intel MKT 构建
- Theano:版本 0.70; floatX = float32;使用 GPU