来自:http://deeplearning.net/software/theano/tutorial/using_gpu.html
using the GPU
想要看GPU的介绍性的讨论和对密集并行计算的使用,查阅:GPGPU.
theano设计的一个目标就是在一个抽象层面上进行特定的计算,所以内部的函数编译器需要灵活的处理这些计算,其中一个灵活性体现在可以在显卡上进行计算。
当前有两种方式来使用gpu,一种只支持NVIDIA cards (CUDA backend) ;另一种,还在开发中,可以支持任何 OpenCL设备,就像和NVIDIA cards (GpuArray Backend)一样。
一、CUDA backend
如果你没有准备好,那么就需要安装Nvidia 的 GPU编程工具链 (CUDA),然后配置好 Theano。我们提供了安装指南 Linux , MacOS and Windows .(我的安装)。1.1 测试theano和GPU
为了检查你的GPU是否启用了,可以剪切下面的代码然后保存成一个文件,运行看看。
from theano import function, config, shared, sandbox
import theano.tensor as T
import numpy
import time
vlen = 10 * 30 * 768 # 10 x #cores x # threads per core
iters = 1000
rng = numpy.random.RandomState(22)
x = shared(numpy.asarray(rng.rand(vlen), config.floatX))
f = function([], T.exp(x))
print f.maker.fgraph.toposort()
t0 = time.time()
for i in xrange(iters):
r = f()
t1 = time.time()
print 'Looping %d times took' % iters, t1 - t0, 'seconds'
print 'Result is', r
if numpy.any([isinstance(x.op, T.Elemwise) for x in f.maker.fgraph.toposort()]):
print 'Used the cpu'
else:
print 'Used the gpu'
该程序会计算一堆随机数的exp() 。注意到我们使用了 shared 函数来确保输入的x 是存储在显卡设备上的。
如果运行该程序(保存文件名为check1.py),而且device=cpu, 那么计算机将会花费大约 3 ;而在GPU 上,只需要0.64秒。不过 GPU不会一直生成完全和CPU一致的浮点数。 作为一个基准来说,调用numpy.exp(x.get_value()) 的一个循环会花费大约 46秒。
$ THEANO_FLAGS=mode=FAST_RUN,device=cpu,floatX=float32 python check1.py
[Elemwise{exp,no_inplace}()]
Looping 1000 times took 3.06635117531 seconds
Result is [ 1.23178029 1.61879337 1.52278066 ..., 2.20771813 2.29967761
1.62323284]
Used the cpu
$ THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python check1.py
Using gpu device 0: GeForce GTX 580
[GpuElemwise{exp,no_inplace}(), HostFromGpu(GpuElemwise{exp,no_inplace}.0)]
Looping 1000 times took 0.638810873032 seconds
Result is [ 1.23178029 1.61879349 1.52278066 ..., 2.20771813 2.29967761
1.62323296]
Used the gpu
注意到在theano中GPU的操作在目前来说,只支持 floatX 为 float32类型。
1.2 返回设备分配数据的句柄
在前面的例子中,加速并没有那么明显,这是因为函数返回的结果是作为一个 NumPy ndarray,而为了方便,已经从设备复制到主机上了。这就是为什么在device=gpu下很容易交换的原因,不过如果你不建议更少的可移植性,可以通过改变graph来用GPU的存储结果表示一个计算的过程来得到更大的加速。 gpu_from_host 操作也就是说“将输入从主机复制到GPU上”,然后在T.exp(x)被GPU版本的exp()替换后进行优化。
from theano import function, config, shared, sandbox
import theano.sandbox.cuda.basic_ops
import theano.tensor as T
import numpy
import time
vlen = 10 * 30 * 768 # 10 x #cores x # threads per core
iters = 1000
rng = numpy.random.RandomState(22)
x = shared(numpy.asarray(rng.rand(vlen), config.floatX))
f = function([], sandbox.cuda.basic_ops.gpu_from_host(T.exp(x)))
print f.maker.fgraph.toposort()
t0 = time.time()
for i in xrange(iters):
r = f()
t1 = time.time()
print 'Looping %d times took' % iters, t1 - t0, 'seconds'
print 'Result is', r
print 'Numpy result is', numpy.asarray(r)
if numpy.any([isinstance(x.op, T.Elemwise) for x in f.maker.fgraph.toposort()]):
print 'Used the cpu'
else:
print 'Used the gpu'
输出结果为:
$ THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python check2.py
Using gpu device 0: GeForce GTX 580
[GpuElemwise{exp,no_inplace}()]
Looping 1000 times took 0.34898686409 seconds
Result is
Numpy result is [ 1.23178029 1.61879349 1.52278066 ..., 2.20771813 2.29967761
1.62323296]
Used the gpu
这里我们通过简单的不要将结果数组复制回主机的方式省掉了大约50%的运行时间。通过每次的函数调用返回的对象不是一个NumPy array,而是一个 “CudaNdarray”,后者可以通过正常的Numpy casting机制(例如numpy.asarray())来转换成一个NumPy ndarray。
对更对你可以使用borrow flag加速的资料,查阅:Borrowing when Constructing Function Objects.
1.3 在GPU上加速的是什么?
在当我们接着优化我们的实现的时候,效果的特性也会改变,而且在从设备到设备之间会有所变化,不过现在还是给出一个粗略的想法吧:
- 只有float32 的数据类型的计算可以加速。针对float64的更好的支持期待将来的硬件,不过在目前(2010年1月)float64还是相当慢的。
- 当参数是足够大而保持30个处理器都工作的时候,矩阵乘法,卷积和大型的逐元素计算可以加速大概5-50x。
- 索引、维度重排和常量时间的reshaping在gpu和cpu上一样块。
- 在张量上基于行/列的求和在gpu上可能会比cpu上慢一点。
- 设备与主机之间大量的数据的复制是相当慢的,通常会抵消掉在数据上一两个加速函数的大部分优势。让gpu取得性能上的提升的关键取决于数据传输到设备上的时间消耗。
1.4 在gpu上提升效果的提示
- 考虑将floatX=float32 加到你的 .theanorc 文件中。
- 使用theano flag allow_gc=False. 见 GPU Async capabilities
- 推荐使用构造器,如matrix, vector 和 scalar 来替换dmatrix, dvector 和 dscalar。因为前者当设定floatX = float32 的时候回使用float32类型的变量。
- 确保你的输出变量为float32 dtype而不是float64。在graph中更多的float32变量会让你将更多的工作放在gpu上实现。
- 使用shared float32变量存储频繁访问的数据(见shared())来最大程度的减少转移到gpu设备上花费的时间。当使用gpu的时候,float32 张量共享变量存储在gpu上,并默认的使用这些变量来消除到gpu上的传输时间。(这里的意思应该是创建的时候就放在gpu上,而无需每次调用都从cpu上传给gpu,从而这份数据能够一直保持在gpu上,减少多次的传输)。
- 如果你对你得到的效果不满意,试着用 mode='ProfileMode'来建立你的函数。这在程序终止的时候,会打印出一些时间信息。如果一个op或者apply花费了它共享还多的时间,那么如果你知道一些gpu变成,就可以看看在theano.sandbox.cuda上它是怎么实现的。检查下载cpu上花费的时间比例Xs(X%) ,和在gpu上花费的时间比例 Xs(X%) 和在传输操作上花费的时间比例 Xs(X%) 。这可以告诉你你的graph所花费的时间是在gpu上还是更多的在内存的传输上。
- 使用 nvcc 选项。 nvcc 支持一些选项来加速某些计算: -ftz=true to flush denormals values to zeros., –prec-div=false 和 –prec-sqrt=false 选项可以通过使用更少的精度来对除法和平方根操作进行加速,。你可以通过 nvcc.flags=–use_fast_math Theano flag 来一次启用它们,或者如子nvcc.flags=-ftz=true –prec-div=false一样分别对它们进行启用。
1.5 GPU 异步功能
从Theano 0.6开始,我们就开始使用gpu的异步功能了。这可以让我们运行的更快,不过可能会让一些错误在它们本应该出现的地方延迟抛出异常。则会导致当分析 theano apply节点的时候有些困难。这里有一个 NVIDIA 驱动特性有助于解决这些问题。如果你将环境变量设置成CUDA_LAUNCH_BLOCKING=1 那么,所有的kernel调用都会自动同步的。这会降低性能,不过却提供很好的profiling和合理的位置错误信息。
该特性会与theano的中间结果的垃圾回收相关联。为了获取该特性的大部分效果,你需要禁用gc来在graph中插入同步点。设置theano flag allow_gc=False 来得到甚至更快的速度!不过这会引起内存使用率上升的问题。
1.6 改变共享变量的值
为了改变共享变量的值,即对进程提供新的数据,可以使用函数shared_variable.set_value(new_value). 更详细的资料,查阅 Understanding Memory Aliasing for Speed and Correctness.
练习:再次拿逻辑回归做例子
import numpy
import theano
import theano.tensor as T
rng = numpy.random
N = 400
feats = 784
D = (rng.randn(N, feats).astype(theano.config.floatX),
rng.randint(size=N,low=0, high=2).astype(theano.config.floatX))
training_steps = 10000
# Declare Theano symbolic variables
x = T.matrix("x")
y = T.vector("y")
w = theano.shared(rng.randn(feats).astype(theano.config.floatX), name="w")
b = theano.shared(numpy.asarray(0., dtype=theano.config.floatX), name="b")
x.tag.test_value = D[0]
y.tag.test_value = D[1]
#print "Initial model:"
#print w.get_value(), b.get_value()
# Construct Theano expression graph
p_1 = 1 / (1 + T.exp(-T.dot(x, w)-b)) # Probability of having a one
prediction = p_1 > 0.5 # The prediction that is done: 0 or 1
xent = -y*T.log(p_1) - (1-y)*T.log(1-p_1) # Cross-entropy
cost = xent.mean() + 0.01*(w**2).sum() # The cost to optimize
gw,gb = T.grad(cost, [w,b])
# Compile expressions to functions
train = theano.function(
inputs=[x,y],
outputs=[prediction, xent],
updates={w:w-0.01*gw, b:b-0.01*gb},
name = "train")
predict = theano.function(inputs=[x], outputs=prediction,
name = "predict")
if any([x.op.__class__.__name__ in ['Gemv', 'CGemv', 'Gemm', 'CGemm'] for x in
train.maker.fgraph.toposort()]):
print 'Used the cpu'
elif any([x.op.__class__.__name__ in ['GpuGemm', 'GpuGemv'] for x in
train.maker.fgraph.toposort()]):
print 'Used the gpu'
else:
print 'ERROR, not able to tell if theano used the cpu or the gpu'
print train.maker.fgraph.toposort()
for i in range(training_steps):
pred, err = train(D[0], D[1])
#print "Final model:"
#print w.get_value(), b.get_value()
print "target values for D"
print D[1]
print "prediction on D"
print predict(D[0])
修改并通过使用floatX= float32来在gpu上执行该例子,并使用time python file.py。来查看执行时间 (帮助资料:Configuration Settings and Compiling Mode)。
从cpu到gpu上有速度的提升吗?
Where does it come from? (Use ProfileMode)
在gpu上如何有更好的速度的提升?
note:
当前只支持32 位 floats (其他待开发)。 有着float32 dtype的Shared 变量默认会放到gpu内存空间上. 当前一个gpu被限制成只允许一个进程。 使用Theano flag device=gpu 来请求使用gpu设备。 当你有多个gpu的时候,使用 device=gpu{0, 1, ...} 来指定具体的那个。 在代码中使用Theano flag floatX=float32 (through theano.config.floatX) 。 在存储到一个shared变量之前记得Cast 输入。 避免本该cast到float32的int32 自动变成float64:- 在代码中手动插入cast或者使用 [u]int{8,16}.
- 在均值操作的周围手动插入cast (这会涉及到length的除法,而这是一个int64类型的).
- 注意:一个新的casting机制在开发中。
答案(Solution)
#!/usr/bin/env python
# Theano tutorial
# Solution to Exercise in section 'Using the GPU'
# 1. Raw results
from __future__ import print_function
import numpy
import theano
import theano.tensor as tt
from theano import sandbox, Out
theano.config.floatX = 'float32'
rng = numpy.random
N = 400
feats = 784
D = (rng.randn(N, feats).astype(theano.config.floatX),
rng.randint(size=N, low=0, high=2).astype(theano.config.floatX))
training_steps = 10000
# Declare Theano symbolic variables
x = theano.shared(D[0], name="x")
y = theano.shared(D[1], name="y")
w = theano.shared(rng.randn(feats).astype(theano.config.floatX), name="w")
b = theano.shared(numpy.asarray(0., dtype=theano.config.floatX), name="b")
x.tag.test_value = D[0]
y.tag.test_value = D[1]
#print "Initial model:"
#print w.get_value(), b.get_value()
# Construct Theano expression graph
p_1 = 1 / (1 + tt.exp(-tt.dot(x, w) - b)) # Probability of having a one
prediction = p_1 > 0.5 # The prediction that is done: 0 or 1
xent = -y * tt.log(p_1) - (1 - y) * tt.log(1 - p_1) # Cross-entropy
cost = tt.cast(xent.mean(), 'float32') + \
0.01 * (w ** 2).sum() # The cost to optimize
gw, gb = tt.grad(cost, [w, b])
"""
# Compile expressions to functions
train = theano.function(
inputs=[x, y],
outputs=[Out(theano.sandbox.cuda.basic_ops.gpu_from_host(tt.cast(prediction, 'float32')),borrow=True), Out(theano.sandbox.cuda.basic_ops.gpu_from_host(tt.cast(xent, 'float32')), borrow=True)],
updates={w: w - 0.01 * gw, b: b - 0.01 * gb},
name="train")
predict = theano.function(inputs=[x], outputs=Out(theano.sandbox.cuda.basic_ops.gpu_from_host(tt.cast(prediction, 'float32')), borrow=True),
name="predict")
"""
# Compile expressions to functions
train = theano.function(
inputs=[],
outputs=[prediction, xent],
updates={w: w - 0.01 * gw, b: b - 0.01 * gb},
name="train")
predict = theano.function(inputs=[], outputs=prediction,
name="predict")
if any([x.op.__class__.__name__ in ['Gemv', 'CGemv', 'Gemm', 'CGemm'] for x in
train.maker.fgraph.toposort()]):
print('Used the cpu')
elif any([x.op.__class__.__name__ in ['GpuGemm', 'GpuGemv'] for x in
train.maker.fgraph.toposort()]):
print('Used the gpu')
else:
print('ERROR, not able to tell if theano used the cpu or the gpu')
print(train.maker.fgraph.toposort())
for i in range(training_steps):
pred, err = train()
#print "Final model:"
#print w.get_value(), b.get_value()
print("target values for D")
print(D[1])
print("prediction on D")
print(predict())
"""
# 2. Profiling
# 2.1 Profiling for CPU computations
# In your terminal, type:
$ THEANO_FLAGS=profile=True,device=cpu python using_gpu_solution_1.py
# You'll see first the output of the script:
Used the cpu
target values for D
prediction on D
# Followed by the output of profiling.. You'll see profiling results for each function
# in the script, followed by a summary for all functions.
# We'll show here only the summary:
Results were produced using an Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz
Function profiling
==================
Message: Sum of all(3) printed profiles at exit excluding Scan op profile.
Time in 10002 calls to Function.__call__: 1.590916e+00s
Time in Function.fn.__call__: 1.492365e+00s (93.805%)
Time in thunks: 1.408159e+00s (88.512%)
Total compile time: 6.309664e+00s
Number of Apply nodes: 25
Theano Optimizer time: 4.848340e-01s
Theano validate time: 5.454302e-03s
Theano Linker time (includes C, CUDA code generation/compiling): 5.691789e+00s
Class
---
<% time>
二、 GpuArray Backend
如果你还没有准备好,你需要安装 libgpuarray 和至少一个计算工具箱。可以看相关的介绍说明 libgpuarray.
如果使用OpenGL,那么所有设备的类型都支持的,对于该章节剩下的部分,不管你使用的计算设备是什么,都表示是gpu。
waring:我们想完全支持 OpenCL, 在2014年5月的时候,该支持仍然是个想法而已。一些有用的ops仍然没有被支持,因为 想要在旧的后端以最小化变化来移植。2.1 Testing Theano with GPU
为了查看是否使用的是GPU,可以将下面代码剪切然后创建个文件运行:
from theano import function, config, shared, tensor, sandbox
import numpy
import time
vlen = 10 * 30 * 768 # 10 x #cores x # threads per core
iters = 1000
rng = numpy.random.RandomState(22)
x = shared(numpy.asarray(rng.rand(vlen), config.floatX))
f = function([], tensor.exp(x))
print f.maker.fgraph.toposort()
t0 = time.time()
for i in xrange(iters):
r = f()
t1 = time.time()
print 'Looping %d times took' % iters, t1 - t0, 'seconds'
print 'Result is', r
if numpy.any([isinstance(x.op, tensor.Elemwise) and
('Gpu' not in type(x.op).__name__)
for x in f.maker.fgraph.toposort()]):
print 'Used the cpu'
else:
print 'Used the gpu'
该程序只计算一群随机数的
exp()
。注意到我们使用
theano.shared()
函数来确保输入x存储在gpu上。
$ THEANO_FLAGS=device=cpu python check1.py
[Elemwise{exp,no_inplace}()]
Looping 1000 times took 2.6071999073 seconds
Result is [ 1.23178032 1.61879341 1.52278065 ..., 2.20771815 2.29967753
1.62323285]
Used the cpu
$ THEANO_FLAGS=device=cuda0 python check1.py
Using device cuda0: GeForce GTX 275
[GpuElemwise{exp,no_inplace}(>), HostFromGpu(gpuarray)(GpuElemwise{exp,no_inplace}.0)]
Looping 1000 times took 2.28562092781 seconds
Result is [ 1.23178032 1.61879341 1.52278065 ..., 2.20771815 2.29967753
1.62323285]
Used the gpu
2.2 返回在设备上分配数据的句柄
在默认情况下,在gpu上执行的函数仍然返回一个标准的numpy ndarray。在得到结果之前会有一个迁移操作,将数据传输会cpu上从而来确保与cpu代码的兼容。这可以让在不改变源代码的情况下只使用flag device来改变代码运行的位置。
如果不建议损失一些灵活性,可以让theano直接返回gpu对象。下面的代码就是这样:
from theano import function, config, shared, tensor, sandbox
import numpy
import time
vlen = 10 * 30 * 768 # 10 x #cores x # threads per core
iters = 1000
rng = numpy.random.RandomState(22)
x = shared(numpy.asarray(rng.rand(vlen), config.floatX))
f = function([], sandbox.gpuarray.basic_ops.gpu_from_host(tensor.exp(x)))
print f.maker.fgraph.toposort()
t0 = time.time()
for i in xrange(iters):
r = f()
t1 = time.time()
print 'Looping %d times took' % iters, t1 - t0, 'seconds'
print 'Result is', numpy.asarray(r)
if numpy.any([isinstance(x.op, tensor.Elemwise) and
('Gpu' not in type(x.op).__name__)
for x in f.maker.fgraph.toposort()]):
print 'Used the cpu'
else:
print 'Used the gpu'
这里的 theano.sandbox.gpuarray.basic.gpu_from_host() 调用的意思是 “将输入复制到 GPU上”。然而在优化的阶段中,因为结果已经在gpu上了,它会被移除掉(即该函数会被忽略)。这里是为了告诉theano我们想要gpu上的结果。
输出为:
$ THEANO_FLAGS=device=cuda0 python check2.py
Using device cuda0: GeForce GTX 275
[GpuElemwise{exp,no_inplace}(>)]
Looping 1000 times took 0.455810785294 seconds
Result is [ 1.23178032 1.61879341 1.52278065 ..., 2.20771815 2.29967753
1.62323285]
Used the gpu
然而每次调用的时间看上去会比之前的两个调用更少 (的确是会更少,因为这里避免了数据传输r)这里这么大的加速是因为gpu上执行的异步过程所导致的,也就是说工作并没有完成,只是“启动”了。
返回的对象是一个从pygou上得到的 GpuArray。它几乎扮演着带有一些异常的 numpy ndarray ,因为它的数据都在gpu上,你可以将它复制到主机上,然后通过使用平常的numpy cast ,例如numpy.asarray()来转换成一个常规的ndarray 。
为了更快的速度,可以使用borrow flag,查阅: Borrowing when Constructing Function Objects.
2.3 什么能够在gpu上加速?
当然在不同设备之间,性能特性还是不太的,同样的,我们会改进我们的实现。
该backend支持所有的常规theano数据类型 (float32, float64, int, ...),然而GPU的支持是变化的,而且一些单元没法处理 double (float64)或者更小的 (小于32 位,比如 int16)数据类型。如果使用了这些单元,那么会在编译的时候或者运行的时候得到一个错误。
复杂的支持还未测试,而且大多数都不行。
通常来说,大的操作,比如矩阵乘法或者有着大量输入的逐元素操作将会明显更快的。
2.4 GPU 异步功能
默认情况下,在gpu上所有的操作都是异步的,这可以通过底层的libgpuarray来使得这些操作都是透明的。
当在设备和主机之间进行内存迁移的时候,可以通过引入同步点。当在gpu上释放活动的(活动的缓冲区就是仍然会被kernel使用的缓冲区)内存缓冲区的时候,可以引入另一个同步点。
可以通过调用它的sync()方法来对一个特定的GpuArray强制同步。这在做基准的时候可以用来得到准确的耗时计算。
强制的同步点会和中间结果的垃圾回收相关联。为了得到最快的速度,你应该通过使用theano flag allow_gc=False来禁用垃圾回收器。不过要注意这会导致内存使用提升的问题。
三、直接对gpu编程的一些软件
撇开theano这种元编程,有:
-
CUDA: GPU 编程API,是NVIDIA 对C的扩展 (CUDA C)
- 特定供应商
- 成熟的数值库 (BLAS, RNG, FFT) 。
-
OpenCL: CUDA的多供应商版本
- 更加的通用和标准。
- 更少的库,传播不广
-
PyCUDA:对CUDA驱动接口的python绑定,允许通过python来访问 Nvidia的 CUDA 并行计算API
-
方便:
使用python来更容易的进行GPU 元编程。
从python中能够抽象的编译更低层的 CUDA 代码 (pycuda.driver.SourceModule).
GPU 内存缓存 (pycuda.gpuarray.GPUArray).
帮助文档.
-
完整性: 绑定了所有的CUDA驱动 API.
-
自动的错误检测:所有的 CUDA 错误都会自动的转到python异常。
-
速度: PyCUDA的底层是用 C++写的。
-
针对GPU对象,具有很好的内存管理:
对象的清理是和对象的生命周期绑定的 (RAII, ‘Resource Acquisition Is Initialization’).
使得更容易编写正确的,无漏洞的和不容易崩溃的代码。
PyCUDA 会知道依赖条件 (例如,它不会在所有分配的内存释放之前对上下文进行分离)。
(查阅PyCUDA的 documentation 和 在PyCUDA上Andreas Kloeckner的 website )
-
-
PyOpenCL: PyCUDA for OpenCL
四、学习用PyCUDA编程
如果你已经精通C了,那么你就可以很容易的通过学习来充分利用你的知识,首先用CUDA C来编写GPU,然后,使用 PyCUDA来访问 CUDA API。
下面的资源有助于你学习的过程:
- CUDA API 和CUDA C: 入门
- NVIDIA’s slides
- Stein’s (NYU) slides
- CUDA API 和 CUDA C: 高级
- MIT IAP2009 CUDA (full coverage: lectures, leading Kirk-Hwu textbook, 例子,额外的资源)
- Course U. of Illinois (full lectures, Kirk-Hwu 教科书)
- NVIDIA’s knowledge base (覆盖范围广,从入门到高级)
- practical issues ( grids, blocks 和 threads之间的关系;并在同一页还有相对应的问题)
- CUDA optimisation
- PyCUDA: 入门
- Kloeckner’s slides
- Kloeckner’ website
- PYCUDA: 高级
- PyCUDA documentation website
下面的例子是用来说明用PyCUDA来对GPU编程的一个预言。一旦你觉得完全足够了,你就可以尝试去做相对应的练习。
Example: PyCUDA
# (from PyCUDA's documentation)
import pycuda.autoinit
import pycuda.driver as drv
import numpy
from pycuda.compiler import SourceModule
mod = SourceModule("""
__global__ void multiply_them(float *dest, float *a, float *b)
{
const int i = threadIdx.x;
dest[i] = a[i] * b[i];
}
""")
multiply_them = mod.get_function("multiply_them")
a = numpy.random.randn(400).astype(numpy.float32)
b = numpy.random.randn(400).astype(numpy.float32)
dest = numpy.zeros_like(a)
multiply_them(
drv.Out(dest), drv.In(a), drv.In(b),
block=(400,1,1), grid=(1,1))
assert numpy.allclose(dest, a*b)
print dest
Exercise
运行之前的例子
修改并执行一个shape(20,10)的矩阵
Example: Theano + PyCUDA
import numpy, theano
import theano.misc.pycuda_init
from pycuda.compiler import SourceModule
import theano.sandbox.cuda as cuda
class PyCUDADoubleOp(theano.Op):
def __eq__(self, other):
return type(self) == type(other)
def __hash__(self):
return hash(type(self))
def __str__(self):
return self.__class__.__name__
def make_node(self, inp):
inp = cuda.basic_ops.gpu_contiguous(
cuda.basic_ops.as_cuda_ndarray_variable(inp))
assert inp.dtype == "float32"
return theano.Apply(self, [inp], [inp.type()])
def make_thunk(self, node, storage_map, _, _2):
mod = SourceModule("""
__global__ void my_fct(float * i0, float * o0, int size) {
int i = blockIdx.x*blockDim.x + threadIdx.x;
if(i
使用这个代码来测试:
>>> x = theano.tensor.fmatrix()
>>> f = theano.function([x], PyCUDADoubleOp()(x))
>>> xv = numpy.ones((4, 5), dtype="float32")
>>> assert numpy.allclose(f(xv), xv*2)
>>> print numpy.asarray(f(xv))
Exercise
运行前面的例子
修改并执行两个矩阵的乘法: x * y.
修改并执行返回两个输出: x + y 和 x - y.
(注意到theano当前的逐元素优化只对涉及到单一输出的计算有用。所以,为了提供基本解决情况下的效率,需要在代码中显式的对这两个操作进行优化)。
修改然后执行来支持跨越行为(stride) (即,避免受限于输入一定是C-连续的)。
五、注意
查阅 Other Implementations 来了解如何在gpu上处理随机数
参考资料:
[1]官网:http://deeplearning.net/software/theano/tutorial/using_gpu.html