Mentions légales du service

Skip to content
Snippets Groups Projects
Commit b35f847e authored by hhakim's avatar hhakim
Browse files

Add a notebook to introduce GPU pyfaust API and integrate it in the doxygen...

Add a notebook to introduce GPU pyfaust API and integrate it in the doxygen doc and notebook zip archive.
parent b65bff62
No related branches found
No related tags found
No related merge requests found
Pipeline #833783 skipped
......@@ -134,6 +134,8 @@ if(BUILD_DOCUMENTATION)
configure_file(${FAUST_DOC_SRC_DIR}/Use_of_Faust_objects_in_algorithms.html ${PROJECT_BINARY_DIR}/doc/html/Use_of_Faust_objects_in_algorithms.html COPYONLY)
configure_file(${FAUST_DOC_SRC_DIR}/faust_projectors.ipynb ${PROJECT_BINARY_DIR}/doc/html/faust_projectors.ipynb COPYONLY)
configure_file(${FAUST_DOC_SRC_DIR}/faust_projectors.html ${PROJECT_BINARY_DIR}/doc/html/faust_projectors.html COPYONLY)
configure_file(${FAUST_DOC_SRC_DIR}/using_gpu_pyfaust.ipynb ${PROJECT_BINARY_DIR}/doc/html/using_gpu_pyfaust.ipynb COPYONLY)
configure_file(${FAUST_DOC_SRC_DIR}/using_gpu_pyfaust.html ${PROJECT_BINARY_DIR}/doc/html/using_gpu_pyfaust.html COPYONLY)
# matfaust matlab livescripts (mlx and html)
configure_file(${FAUST_DOC_SRC_DIR}/Faust_creation.mlx ${PROJECT_BINARY_DIR}/doc/html/Faust_creation.mlx COPYONLY)
configure_file(${FAUST_DOC_SRC_DIR}/Faust_creation.mlx.html ${PROJECT_BINARY_DIR}/doc/html/Faust_creation.mlx.html COPYONLY)
......
......@@ -9,6 +9,7 @@ You might also be interested in this introduction to pyfaust through Jupyter Not
- [How to Manipulate a Faust](./Faust_manipulation.html)
- [Using the FAµST API in Algorithms](./Use_of_Faust_objects_in_algorithms.html)
- [Using The FAµST Projectors API](./faust_projectors.html)
- [Using GPU with pyfaust](./using_gpu_pyfaust.html)
Download all the notebooks (.ipynb) [here](./pyfaust_notebooks.zip).
......
This diff is collapsed.
%% Cell type:markdown id: tags:
# Using The GPU FAµST API
In this notebook we'll see quickly how to leverage the GPU computing power with pyfaust.
Since pyfaust 2.9.0 the API has been modified to make the GPU available directly from the python wrapper.
Indeed, a GPU plug-in (aka ``gpu_mod``) has been developed in that purpose.
The first question you might ask is: does it work on my computer? Here is the answer: the loading of this plug-in is quite transparent, if a NVIDIA GPU is available and CUDA properly installed on your system, you have normally nothing to do except installing pyfaust to get the GPU implementations at your fingertips. We'll see in the end of this notebook how to load manually the plug-in and how to get further information in case of error.
It is worthy to note two drawbacks about the pyfaust GPU support:
- Mac OS X is not supported because NVIDIA has stopped to support this OS.
- On Windows and Linux, the pyfaust GPU support is currently limited to CUDA 9.2 version.
In addition to these drawbacks, please notice that the GPU pyfaust support is still considered in beta status as the code is relatively young and still evolving. However the API shouldn't move that much in a near future.
%% Cell type:markdown id: tags:
### Creating a GPU Faust object
Let's start with some basic Faust creation on the GPU. Almost all the ways of creating a Faust object in CPU memory are also available to create a GPU Faust.
First of all, creating a Faust using the constructor works seamlessly on GPU, the only need is to specify the ``dev`` keyword argument, as follows:
%% Cell type:code id: tags:
``` python
from pyfaust import Faust
from numpy.random import rand
M, N = rand(10,10), rand(10,15)
gpuF = Faust([M, N], dev='gpu')
gpuF
```
%% Cell type:markdown id: tags:
It's clearly indicated in the output that the Faust object is instantiated in GPU memory (the N and M numpy arrays are copied from the CPU to the GPU memory). However it's also possible to check this programmatically:
%% Cell type:code id: tags:
``` python
gpuF.device
```
%% Cell type:markdown id: tags:
In ``gpuF`` the factors are dense matrices but it's totally possible to instantiate sparse matrices on the GPU as you can do on CPU side.
%% Cell type:code id: tags:
``` python
from pyfaust import Faust
from scipy.sparse import random, csr_matrix
S, T = csr_matrix(random(10, 15, density=0.25)), csr_matrix(random(15, 10, density=0.05))
sparse_gpuF = Faust([S, T], dev='gpu')
sparse_gpuF
```
%% Cell type:markdown id: tags:
You can also create a GPU Faust by explicitly copying a CPU Faust to the GPU memory. Actually, at anytime you can copy a CPU Faust to GPU and conversely. The ``clone()`` member function is here in that purpose. Below we copy ``gpuF`` to CPU and back again to GPU in the new Faust ``gpuF2``.
%% Cell type:code id: tags:
``` python
cpuF = gpuF.clone('cpu')
gpuF2 = cpuF.clone('gpu')
gpuF2
```
%% Cell type:markdown id: tags:
## Generating a GPU Faust
Many of the functions for generating a Faust object on CPU are available on GPU too. It is always the same, you precise the ``dev`` argument by assigning the ``'gpu'`` value and you'll get a GPU Faust instead of a CPU Faust.
For example, the code below will successively create a random GPU Faust, a Hadamard transform GPU Faust and finally an identity GPU Faust.
Note that the [dft](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust.html#aa29a92f23ffb210ad9bdcdc4c740c2b2) function is not yet available as the complex GPU support is not yet linked into the pyfaust wrapper (even if the C++ core is already complex-compatible).
%% Cell type:code id: tags:
``` python
from pyfaust import rand as frand, eye as feye, wht
print("Random GPU Faust:", frand(10,10, num_factors=11, dev='gpu'))
print("Hadamard GPU Faust:", wht(32, dev='gpu'))
print("Identity GPU Faust:", feye(16, dev='gpu'))
```
%% Cell type:markdown id: tags:
### Manipulating GPU Fausts and CPU interoperability
Once you've created GPU Faust objects, you can perform operations on them staying in GPU world (that is, with no array transfer to CPU memory). That's of course not always possible.
For example, let's consider Faust-scalar multiplication and Faust-matrix product. In the first case the scalar is copied to the GPU memory and likewise in the second case the matrix is copied from CPU to GPU in order to proceed to the computation. However in both cases the Faust factors stay into GPU memory and don't move during the computation.
%% Cell type:code id: tags:
``` python
# Faust-scalar multiplication
2*gpuF
```
%% Cell type:code id: tags:
``` python
# Faust-matrix product (the matrix is copied to GPU then the multiplication is performed on GPU)
gpuF@rand(gpuF.shape[1],15)
```
%% Cell type:markdown id: tags:
On the contrary, and that matters for optimization, there is no CPU-GPU transfer at all when you create another GPU Faust named for example ``gpuF2`` on the GPU and decide to multiply the two of them like this:
%% Cell type:code id: tags:
``` python
from pyfaust import rand as frand
gpuF2 = frand(gpuF.shape[1],18, dev='gpu')
gpuF3 = gpuF@gpuF2
gpuF3
```
%% Cell type:markdown id: tags:
Besides, it's important to note that ``gpuF3`` factors are not duplicated in memory because they already exist for ``gpuF`` and ``gpuF2``, that's an extra optimization: ``gpuF3`` is just a memory view of ``gpuF`` and ``gpuF2`` factors (the same GPU arrays are shared between ``Faust`` objects). That works pretty well the same for CPU ``Faust`` objects.
Finally, please notice that CPU Faust objects are not directly interoperable with GPU Fausts objects. You can try, it'll end up on an error.
%% Cell type:code id: tags:
``` python
cpuF = frand(5,5,5, dev='cpu')
gpuF = frand(5,5,6, dev='gpu')
try:
cpuF@gpuF
except:
print("it doesn't work, you must either convert cpuF to GPU Faust or gpuF to CPU Faust before.")
cpuF.clone('gpu')@gpuF # this is what you should do
```
%% Cell type:markdown id: tags:
### Benchmarking your GPU with pyfaust!
Of course when we run some code on GPU rather than on CPU, it is clearly to enhance the performances. So let's try your GPU and find out if it is worth it or not compared to your CPU.
First, measure how much time it takes on CPU to compute a Faust norm and its product:
%% Cell type:code id: tags:
``` python
from pyfaust import rand as frand
cpuF = frand(1024, 1024, num_factors=10, fac_type='dense')
%timeit cpuF.norm(2)
%timeit cpuF.toarray()
```
%% Cell type:markdown id: tags:
Now let's make some GPU heat with norms and matrix products!
%% Cell type:code id: tags:
``` python
gpuF = cpuF.clone(dev='gpu')
%timeit gpuF.norm(2)
%timeit gpuF.toarray()
```
%% Cell type:markdown id: tags:
### Running some FAµST algorithms on GPU
Some of the FAµST algorithms implemented in the C++ core are now also available in pure GPU mode.
For example, let's compare the factorization times taken by the hierarchical factorization when launched on CPU and GPU.
When running on GPU, the matrix to factorize is copied in GPU memory and almost all operations executed during the algorithm don't imply the CPU in any manner (the only exception at this stage of development is the proximal operators that only run on CPU).
**Warning**: the computation can last thirty minutes or so on CPU.
%% Cell type:code id: tags:
``` python
def factorize_MEG(dev='cpu'):
from pyfaust.fact import hierarchical
from scipy.io import loadmat
from pyfaust.demo import get_data_dirpath
from time import time
from numpy.linalg import norm
d = loadmat(get_data_dirpath()+'/matrix_MEG.mat')
MEG = d['matrix'].T
num_facts = 9
k = 10
s = 8
t_start = time()
MEG16 = hierarchical(MEG, ['rectmat', num_facts, k, s], backend=2020, on_gpu=dev=='gpu', full_gpu=dev=='gpu')
total_time = time()-t_start
err = norm(MEG16.toarray()-MEG)/norm(MEG)
return MEG16, total_time, err
```
%% Cell type:code id: tags:
``` python
gpuMEG16, gpu_time, gpu_err = factorize_MEG(dev='gpu')
print("GPU time, error:", gpu_time, gpu_err)
```
%% Cell type:code id: tags:
``` python
cpuMEG16, cpu_time, cpu_err = factorize_MEG(dev='cpu')
print("CPU time, error:", cpu_time, cpu_err)
```
%% Cell type:markdown id: tags:
Depending on you GPU card and CPU the results may vary, so below are showed some results obtained on specific hardware.
<table align="left">
<tr align="center">
<th>Implementation</th>
<th> Hardware </th>
<th> Time </th>
<th>Error Faust vs MEG matrix </th>
</tr>
<tr>
<td>CPU</td>
<td>Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz</td>
<td>2230.77</td>
<td>.129</td>
</tr>
<tr>
<td>GPU</td>
<td>NVIDIA GTX980</td>
<td>465.42</td>
<td>.129</td>
</tr>
<tr>
<td>GPU</td>
<td>NVIDIA Tesla V100</td>
<td>321.50</td>
<td>.129</td>
</tr>
</table>
%% Cell type:markdown id: tags:
### Manually loading the pyfaust GPU plug-in
If something goes wrong when trying to use the GPU pyfaust extension, here is how to manually load the plug-in and obtain more information.
The key is the function [enable_gpu_mod](https://faustgrp.gitlabpages.inria.fr/faust/last-doc/html/namespacepyfaust.html#aea03fff2525fc834f2a56e63fd30a54f). This function allows to give another try to ``gpu_mod`` loading with the verbose mode enabled.
%% Cell type:code id: tags:
``` python
import pyfaust
pyfaust.enable_gpu_mod(silent=False, fatal=True)
```
%% Cell type:markdown id: tags:
Afterward you can call ``pyfaust.is_gpu_mod_enabled()`` to verify it works in your script.
<hr style="width:50%;text-align:left;margin-left:0">
%% Cell type:markdown id: tags:
**Note**: this notebook was executed using the following pyfaust version:
%% Cell type:code id: tags:
``` python
import pyfaust
pyfaust.version()
```
%% Cell type:markdown id: tags:
Thanks for reading this notebook! Many other are available at [faust.inria.fr](https://faust.inria.fr).
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment