3. VaR Monte-Carlo sur GPU
Introduction
0.1 Description de la VaR
La VaR (de l’anglais value at risk, ou « valeur sous le risque ») est une notion utilisée généralement
pour mesurer le risque de marché d’un portefeuille d’instruments financiers. Elle correspond au mon-
tant des pertes qui ne devrait pas être dépassé avec une probabilité fixée sur un horizon temporel donné.
Elle a été importée à la fin des années 1980 sur les marchés financiers aux États-Unis par la banque
Bankers Trust et popularisée par la banque JP Morgan en 1993 et son service (gratuit et public) Risk-
metrics puis adoptée sous une forme embryonnaire par le Comité de Bâle (Bâle II) pour les banques
et Solvabilité II pour les assurances.
De nos jours, son utilisation est fortement demandé et deviendra obligatoire avec les accords de
Bâle III. La VaR d’un portefeuille dépend essentiellement de trois paramètres :
– la distribution des résultats des portefeuilles. Souvent cette distribution est supposée normale,
mais beaucoup d’acteurs financiers utilisent des distributions historiques. La difficulté réside
dans la taille de l’échantillon historique : s’il est trop petit, les probabilités de pertes élevées sont
peu précises, et s’il est trop grand, la cohérence temporelle des résultats est perdue (on compare
des résultats non comparables)
– le niveau de confiance choisi (95 ou 99 % en général)
– l’horizon temporel choisi
D’une manière générale, la VaR donne une estimation des pertes qui ne devrait pas être dépassée
sauf évènement extrême sur un portefeuille pouvant être composé de différentes classes d’actifs.
0.2 Description de la méthode de Monte Carlo
L’appellation "méthode de Monte-Carlo" désigne toute méthode visant à calculer une valeur nu-
mérique en utilisant des procédés aléatoires, c’est-à-dire des techniques probabilistes. Le nom de cette
méthode, vient des jeux de hasard pratiqués à Monte-Carlo. Elle a été inventée en 1947 par Nicholas
Metropolis, et publié pour la première fois en 1949 dans un article co-écrit avec Stanislaw Ulam.
La méthode de simulation de Monte-Carlo permet d’introduire une approche statistique du risque
dans une décision financière. Dans notre cas le calcul de VaR. La VaR-Monte-Carlo permet de simuler
les valeurs historiques de nos actifs. Cependant ces simulations sont couteuses en temps de calcul.
0.3 But du projet
Pour le calcul d’une VaR Monte-Carlo, une majeur partie du temps est consacrée à la généra-
tion des variables aléatoires. Les méthodes de Monte-Carlo demandent beaucoup de simulations par
exemple pour un portefeuille de 100 actifs sans corrélation, sur une durée de 3 mois et 10 millions de
simulations nous devrons générer 100 ∗ 90 ∗ 106 = 9 ∗ 109 variables aléatoires. Ce qui est considérable
Pierre Aït-Tahar Paraita Wohler 2
Master IMAFA - 2012/2013
4. Simulation de la VaR Monte-Carlo sur GPU
tout comme le temps d’exécution.
Pour tenter de diminuer le temps d’exécution nous allons utiliser les cartes graphiques (GPU 1 ),
leur coût d’achat et leur consommation sont inférieurs aux CPU et leur puissance de calcul ( en FLOP
) est très nettement superieure.
Pour programmer sur GPU nous avons besoin d’écrire dans un premier temps un code hôte dans
notre cas en C++, qui lancera a son tour le programme sur le GPU en OpenCL.
L’utilisation de GPU nécessite un temps de lancement, entre la copie du code et le temps de
rapatrier les résultats. Pour compenser ces pertes nous allons toujours calculer un grand nombre de
simulations ( au moins dans l’ordre du million ).
1. Graphical Processing Unit
Pierre Aït-Tahar Paraita Wohler 3
Master IMAFA - 2012/2013
5. VaR Monte-Carlo sur GPU
Partie 1
Var Monte-Carlo
1.1 Simulation d’un actif sur une journée
Nous sommes dans le modèle de Black & Sholes et nous allons utiliser un mouvement brownien
géométrique :
dSt = rSt dt + σSt dWT
S0 > 0
La discrétisation est donnée par :
σ2
)∗(ti+1 −ti )+σ∗dWt
Sti+1 = Sti e(r− 2
On nous a demandé d’utiliser le mouvement brownien géométrique car il permet d’avoir des résul-
tats plus précis.
1.2 Précison de la distribution liée au Simulation de Monte-Carlo
Nous allons simuler pour chaque actif une variation par jour jusqu’à l’horizon avec un Brownien
qui suit une loi N (0; δt) avec δt qui correspond à un jour. La somme de ces estimations nous donne
une estimation de la valeur de portefeuille : P a Cependant nous devons savoir combien de variable
aléatoire nous devons simuler.
Nous savons grâce au théorème de la loi des grands nombres ainsi que le théorème central limite,
que :
√ Pa − µ L
a
Pn = n n −→ N (0; 1)
σ n−→∞
Avec
a
P n = E[P a ]
On obtient l’intervalle de confiance de µ, au niveau de confiance α :
a cα σ a cα σ
µ ∈]P n − √ ; P n + √ [
n n
cα représente le quantile de la loi Normale :
α
cα = Φ−1 (1 − )
2
où Φ est la fonction de répartition de la loi Normale.
Dans la majeur partie des cas, nous voulons un intervalle de confiance de niveau de confiance
α = 0, 95 ou α = 0, 99, donc cα = 1, 92 ou cα = 1, 96.
Pierre Aït-Tahar Paraita Wohler 4
Master IMAFA - 2012/2013
6. Simulation de la VaR Monte-Carlo sur GPU
La variance étant inconnue, on calcule un estimateur sans biais de celle-ci :
n n
2 1 a a 1 a n a
Sn = ((Pn )i − P n )2 = (Pn )2 −
i (P )2
n−1 i=1
n−1 i=1
n−1 n
De plus nous voulons une précision de 0.01% il faut donc que le rapport cαn < 0.01. Le problème
√σ
est que nous calculons la variance pour un nombre de variables fixé par avance, il est fréquent que le
nombre de variables aléatoires soit insuffisant pour la précision voulue. Nous devons donc re-simuler
d’autres variables tant que l’inégalité n’est pas réalisée.
Dans la pratique, avec le nombre très important de variables aléatoires que nous utilisons liés à
utilisation de GPU, ( < 1 000 000 par actifs ) nous avons toujours un intervalle de confiance inferieur
à 0.01%.
1.3 Architecture du code
Sur la figure 1.1 on peut voir l’architecture orientée objet de notre programme.
Même si le framework OpenCL est écrit en C, le projet nécessitait d’utiliser le langage C++. Le
principal avantage est la réutilisabilité de nos classes, en particulier le CLManager qui pourra être
utilisé dans d’autres projets ou domaines. Aussi la compréhension de notre code est plus aisée car
toute la mécanique OpenCL est cachée à l’utilisateur de cette classe.
Pierre Aït-Tahar Paraita Wohler 5
Master IMAFA - 2012/2013
7. Simulation de la VaR Monte-Carlo sur GPU
Figure 1.1 – Diagramme de classes
En fait, OpenCL met à disposition une surcouche C++ vers le framework C mais il est encore à
l’état d’ébauche et n’est pas vraiment utilisable (accès limité aux infos des devices par exemple).
1.3.1 Mécanisme OpenCL
OpenCL est à la fois un langage de programmation, qui sera exécuté sur un périphérique compatible
OpenCL, mais aussi un framework, c’est à dire un ensemble de fonctions utilisées pour envoyer des
commandes OpenCL.
L’idée est de pouvoir faire exécuter du calcul de manière parallèle en profitant du nombre important
de coeurs disponibles sur un GPU. OpenCL pousse l’abstraction plus loin en permettant de ne plus
différencier le périphérique en lui même mais de ne voir que les coeurs (ou Comput Unit en terme
OpenCL). Ainsi il est possible de parler à plusieurs GPU et même des CPU, OpenCL se démocratisant
même aux processeurs ARM.
Lorsqu’on veut exécuter du code OpenCL, il est nécessaire dans un premier temps d’interroger la
machine pour connaître les différents périphériques compatibles. Il faut donc récupérer les platforms 1 ,
1. pilote OpenCL
Pierre Aït-Tahar Paraita Wohler 6
Master IMAFA - 2012/2013
8. Simulation de la VaR Monte-Carlo sur GPU
en général le pilote d’affichage du GPU, mais si on possède plusieurs GPU de marques différentes,
ont aurait alors plusieurs plateformes. Pour chacune des plateformes, il faut récupérer les devices 2 qui
sont composés de plusieurs Comput Units, eux mêmes composés de plusieurs processeurs.
Une fois que l’on sait à qui on va donner du travail, il faut instancier une file de commande ainsi
qu’un contexte, qui feront le lien entre la machine hôte et le GPU.
L’exécution se fait en donnant le nombre de work-items 3 , pour simplifier un work-item = un thread.
On peut grouper un ensemble de work-items (un work-group), ainsi tout les work-items d’un même
work-group peuvent se partager des données, données qui seront stockées localement au Comput
Unit, donc plus rapides. Néanmoins un Comput Unit possède une limite de taille maximale, taille qui
peut être récupérée via une requête au device adéquat. Maximiser la taille des work-groups permet
d’occuper au mieux le GPU, et l’accès aux données se fait plus rapidement. Aussi il faut garder en
tête que tous les work-items ne travaillent pas magiquement tous en même temps mais par paquets
de 32, ce paramètre est apelé la warp chez Nvidia et wavefront chez AMD.
Les données circulant de l’hôte au GPU ont besoin d’être allouées explicitement, car tous les para-
mètres sont passés par pointeurs. De même pour rappatrier un résultat, la mémoire allouée sur l’hôte
accueillera le résultat du calcul effectué sur le GPU.
Une fois le calcul OpenCL effectué et le résultat récupéré, il faut relacher la main sur les ressources
OpenCL, dans l’ordre suivant :
1. vidage de la file de commande
2. fermeture de la file de commande
3. désallocation des kernels utilisés
4. désallocation des kernels compilés (ou cl_program)
5. désallocation des buffers des paramètres des kernels
6. release de la main sur la file de commande
7. release de la main sur le contexte OpenCL
Autant de mécanismes qui peuvent facilement amener à des erreurs, bugs, et autres problèmes de
compréhension du code. En pratique on s’est rendu compte que le nombre de lignes pour le dialogue
de l’hôte au GPU était presque 4 fois supérieur au nombre de ligne d’un kernel. D’ou cette volonté
d’abstraire toute cette mécanique à l’aide de classes.
2. les périphériques pouvant effectuer du calcul OpenCL
3. instanciation du kernel
Pierre Aït-Tahar Paraita Wohler 7
Master IMAFA - 2012/2013
9. Simulation de la VaR Monte-Carlo sur GPU
1.3.2 Langage OpenCL
Le langage OpenCL est dérivé du langage C, et est exécuté sur les devices compatibles. Il faut
savoir qu’une fois un kernel terminé, toute la mémoire utilisée est flushée, donc il n’est plus possible
d’accéder aux mêmes données d’une exécution à l’autre.
Voici un exemple de code OpenCL :
__kernel void addition(__global int *v1,
__global int *v2,
__global int *res)
{
int id = get_global_id(0);
res[id] = v1[id] + v2[id];
}
Ce code fait l’addition de deux vecteurs, le résultat est stocké dans un troisième vecteur.
Les librairies comme la stdlib.h ou time.h par exemple n’existent pas dans OpenCL, d’où la nécessité
de devoir implémenter soi même beaucoup de code, dans notre cas la génération de valeurs aléatoires.
1.3.3 CLManager
Le CLManager, lors de son instanciation, va récupérer auprès du framework toutes les platforms
et leurs devices respectifs.
Une fois instancié, il faut spécifier le device nous allons utiliser avec l’appel à CLManager::init()
(à ce moment on peut même spécifier si on souhaite chronométrer le temps que le calcul mettra sur
le GPU). En fait il est même possible d’utiliser plusieurs devices, mais avec la contrainte de temps
imposée, nous n’avons pas voulu plus approfondir dans ce sens.
Ensuite il faut donner au CLManager le chemin vers le(s) kernel(s) 4 avec l’appel à
CLManager::loadKernels(). Cette manière de charger le code métier OpenCL permet de travailler
sur le code OpenCL sans avoir à recompiler l’ensemble de l’application.
Une fois chargé, on compile ce code avec l’appel CLManager::compileKernel() qui prend en para-
mètre le nom du kernel que l’on veut exécuter (si le fichier comprend plusieurs kernels par exemple).
Il faut donner les paramètres d’appel du kernel, dans l’ordre où ils apparaissent dans la signature
du kernel, avec CLManager::setKernelArg().
Enfin on lance l’exécution du kernel avec l’appel à CLManager::executeKernel() en lui spécifiant
le nombre de work-items ainsi que le nom du kernel à exécuter.
Le résultat de l’exécution se récupère avec l’appel à CLManager::getResultat(), qui va copier le
résultat depuis la mémoire du GPU vers la mémoire RAM de l’ordinateur, dans la variable que l’on
aura instanciée auparavant.
4. c’est le nom qu’on donne à une fonction qui tournera sur GPU
Pierre Aït-Tahar Paraita Wohler 8
Master IMAFA - 2012/2013
10. Simulation de la VaR Monte-Carlo sur GPU
Voici un exemple d’utilisation :
CLManager clm;
clm.init(0,0);
clm.loadKernels("meskernels.cl");
clm.compileKernel("addition");
int *v1 = (int *) calloc(10, sizeof(int));
int *v2 = (int *) calloc(10, sizeof(int));
int *resultat = (int *) calloc(10, sizeof(int));
clm.setKernelArg("addition", 0, 10, sizeof(int), v1, false);
clm.setKernelArg("addition", 1, 10, sizeof(int), v2, false);
clm.setKernelArg("addition", 2, 10, sizeof(int), resultat, true);
clm.executeKernel(10, "addition");
clm.getResultat();
Ce code va donc faire l’addition de 2 vecteurs, comme la taille du vecteur est connue, je spécifie donc
lors de l’appel à clm.executeKernel() que je ne vais utiliser que 10 work-items. Aussi la méthode
setKernelArg() prend en paramètre :
– le nom du kernel ("addition")
– le numéro du paramètre (qui commence à 0)
– le nombre d’élements de mon paramètre (il y a 10 entiers dans mon vecteur)
– la taille d’un élement (la taille d’un entier en mémoire)
– le pointeur vers la donnée qu’on va envoyer au kernel
– false si c’est un paramètre d’entrée, true si c’est un paramètre de sortie
Le résultat sera lisible dans la variable resultat.
Le CLManager nous a permis de réduire considérablement le nombre de lignes dans le code applicatif,
et ainsi de réduire les erreurs de code.
Le constructeur de CLManager va demander les différentes ressources OpenCL disponibles sur la
machine, le destructeur quant à lui va relacher la main sur le périphérique.
1.3.4 Portefeuille
La classe Portefeuille contient les actifs d’un portefeuille, d’ailleurs on l’instancie avec le chemin
d’accès vers un fichier au format csv 5 , avec la structure suivante :
<nom>;<rendement>;<volatilité>;<taux d’intérêts>
Ce qui permet de charger dynamiquement un portefeuille sans avoir à coder le portefeuille en dur
dans le code. De plus la classe Portefeuille permet de récupérer aisément les caractérisques de celui ci,
on peut donc récupérer :
– l’ensemble des rendements sous forme d’array
– l’ensemble des volatilités des actifs
– l’ensemble des taux d’intérêts
– le rendement total du portefeuille
– le nombre d’actifs constituant ce portefeuille
5. Comma Separated Value : format où on sépare des données par un espace, une tabulation, un virgue ou un
point-virgule
Pierre Aït-Tahar Paraita Wohler 9
Master IMAFA - 2012/2013
11. Simulation de la VaR Monte-Carlo sur GPU
1.3.5 Actif
La classe Actif permet de représenter un actif au sens financier avec :
– le nom du sous jacent sur quoi porte l’actif
– le rendement du sous jacent
– la volatilité
– le taux d’intérêts
Dans notre cas d’utilisation, nous nous limitons aux actions simples.
1.4 Simulation des Variables Aléatoires
Comme nous l’avions dit précédemment, c’est la génération des variables aléatoires qui prend le
plus de temps. Dans un premier temps nous avions utilisé l’implémentation de Mersenne Twister
donnée par la librairie Boost 6 , et qui nous a permis de nous concentrer sur le tirage des trajectoires
sur GPU.
Nous nous sommes rendus compte que l’algorithme de Mersenne Twister, même s’il était très rapide
et bénéficiait d’une très grand période (219937 − 1), prenait beaucoup de place en mémoire, sachant que
si chaque work-item devait posséder son propre générateur, il nous faudrait sur le GPU une mémoire
de l’ordre de #(work − items) ∗ 624 ∗ 4 octets, ce qui n’est pas envisageable.
Nous nous sommes donc tournés vers l’algorithme MWC 7 , en particulier une implémentation exis-
tante fonctionnant sur OpenCL, MWC64X 8 . La particularité de cette implémentation est que le
générateur n’occupe que 4 octets, pour une période de 232 . Si on est toujours limités en nombre de
work-items, il est néanmoins possible de calculer la VaR sur un horizon très lointain, car le même
générateur est utilisé jusqu’à l’horizon. Un article de l’auteur 9 de l’implémentation permet de vérifier
la solidité de son générateur, et nous avons nous même vérifié que les valeurs aléatoires générées puis
transformées en gaussiennes étaient cohérentes, voir la figure 1.2. On voit que le générateur est de
bonne qualité, dans la figure on a fait 1966080 tirages.
1.5 Analyse des performances
Pour la figure 1.3 la machine utilisée possède le matériel suivant :
– CPU : iCore 7 avec 4 coeurs logiques
– CPU : 8 Go de RAM
– GPU : Geforce 330M
– GPU : 6 Comput Units
– GPU : 512 Mo de RAM
– GPU : taille max de work-items par workgroup : 256
Dans la première barre, nous avons repris le code du prototype montré lors de la pré-soutenance,
c’est à dire sans optimisation. La génération des valeurs aléatoires est faite côté CPU, le calcul des
trajectoires sur le GPU, et le tri sur le CPU.
6. http://www.boost.org/doc/libs/1_53_0/doc/html/boost_random.html
7. Multiply-With-Carry de Marsaglia
8. http://cas.ee.ic.ac.uk/people/dt10/research/rngs-gpu-mwc64x.html
9. http://cas.ee.ic.ac.uk/people/dt10/research/publications.html
Pierre Aït-Tahar Paraita Wohler 10
Master IMAFA - 2012/2013
12. Simulation de la VaR Monte-Carlo sur GPU
Figure 1.2 – Histogramme de 1966080 tirages gaussiens
Figure 1.3 – Temps cumulé suivant l’optimisation
Pierre Aït-Tahar Paraita Wohler 11
Master IMAFA - 2012/2013
13. Simulation de la VaR Monte-Carlo sur GPU
Dans la deuxième barre, nous avons profité du fait que la mémoire dite globale dans la RAM du
GPU pouvait être mise en cache, l’accès y est donc plus rapide, mais la quantité moins importante.
Plus précisement cela s’est fait aisément sur la signature du kernel.
Avant :
__kernel void calcul_trajectoires(__global const float *RENDEMENTS,
__global const float *VOLS,
__global const float *TI,
__global const float *ALEA,
__global float *rendement,
__global float *TIRAGES,
__global const int *nb_actions,
__global const int *horizon) {
Après :
__kernel void calcul_trajectoires(__global const float *RENDEMENTS,
__global const float *VOLS,
__global const float *TI,
__global const float *ALEA,
__constant float *rendement,
__global float *TIRAGES,
__constant int *nb_actions,
__constant int *horizon) {
Pour la troisième barre, nous avons décidé d’ajuster le nombre de tirages selon l’architecture du
GPU, dans notre cas il fallait que le nombre de tirages soit multiple de :
– 32 car c’est la taille de la warp chez NVidia
– 6 car c’est le nombre de Comput Unit sur le GPU
– 256 car c’est le nombre maximal de work-items dans un workgroup
Pour cela le CLManager demande la taille max de work-items dans un workgroup au pilote OpenCL,
le reste des calculs se fera avec ce paramètre.
Enfin pour la dernière barre nous avons réunit les 2 optimisations précédentes. L’optimisation la
plus remarquable est bien évidemment l’ajustement du nombre de tirages.
Pour le reste des tests, nous avons utilisé le réseau NEF mis en place par l’INRIA et qui met à
disposition plusieurs machines dont certaines équipées de GPU performants. La machine que nous
avons donc utilisé est la suivante :
– CPU : Intel Xeon 24 coeurs
– CPU : 32 Go de RAM
– GPU : NVidia Tesla C2050
– GPU : 2 x 3 Go de RAM
– GPU : 2 x 12 Comput Units
– GPU : taille max de work-items par workgroup : 1024
Nous nous sommes néanmoins limité à l’utilisation d’un seul des GPU sur la Tesla C2050, mais OpenCL
permet l’utilisation de plusieurs GPU en même temps.
Pierre Aït-Tahar Paraita Wohler 12
Master IMAFA - 2012/2013
14. Simulation de la VaR Monte-Carlo sur GPU
Figure 1.4 – Répartition du temps avec le prototype optimisé
1.5.1 Répartition du temps dans l’application
Sur la figure 1.4 on voit la répartition du temps dans l’application lorsqu’on a l’architecture suivante :
– RNG 10 sur CPU
– calcul des trajectoires sur GPU
– tri sur CPU
Qui est en fait l’optimisation de notre prototype.
Sur la figure 1.5 on voit la répartition du temps lorsqu’on bascule la génération des valeurs aléatoires
sur le GPU.
Ce qu’on qualifie de temps autre n’est que le reste du temps où le programme fait l’instanciation
des objets, des variables, l’écriture sur STDOUT, etc...
On voit évidemment après avoir passé la RNG sur le GPU, ce qui nous ralentit encore est le tri qui
lui est resté sur CPU. En passant le tri sur GPU (dans l’état de l’art c’est un problème déjà résolu
et des solutions bien optimisées existent déjà). Malheureusement nous n’avons pas eu le temps d’aller
aussi loin dans l’implémentation.
1.5.2 Passage à l’échelle
Sur un nombre de plus en plus important de tirages, comment se comporte notre application ? Il
faut garder à l’esprit que la taille limitée de la RAM côté GPU impacte grandement le nombre de
tirages, sur la figure 1.6 on voit néanmoins le temps pris par, en bleu le prototype optimisé (RNG sur
CPU), et en rouge la version finale que nous avons codé (RNG sur GPU).
10. Random Number Generation
Pierre Aït-Tahar Paraita Wohler 13
Master IMAFA - 2012/2013
15. Simulation de la VaR Monte-Carlo sur GPU
Figure 1.5 – Répartition du temps avec la RNG sur GPU
Figure 1.6 – Comparatif des 2 versions
Pierre Aït-Tahar Paraita Wohler 14
Master IMAFA - 2012/2013
16. Simulation de la VaR Monte-Carlo sur GPU
La dernière version que nous avons codé passe non seulement sur un plus grand nombre de tirages,
mais nous pouvons aussi calculer la VaR sur un horizon plus lointain (de la taille de la période de
notre générateur). La place utilisée en mémoire n’est pas proportionnelle à l’horizon.
Pierre Aït-Tahar Paraita Wohler 15
Master IMAFA - 2012/2013
17. VaR Monte-Carlo sur GPU
Partie 2
Conclusion
2.1 Travail effectué
Au cours de ce projet nous avons appris sur la difficulté de la programmation gpu,GPU comment
utiliser les différentes mémoires, la répartition des workgroup, l’interaction entre le code GPU et la
structure de la carte.
Nous avons implémenté un CLManager qui permet d’abstraire tous les appels OpenCL, et rendre
ainsi le code plus lisible et plus facile à débugger.
Nous faisons la génération des gaussiennes ainsi que les calculs des trajectoires, seul le tri se fait
coté CPU.
2.2 Évolutions possibles
2.2.1 Gestion plus propre des erreurs
Par manque de temps, pour debugger nous utilisons un mode de compilation dans lequel nous
envoyons le numéro de l’erreur avec une trace qui correspond au nom de la méthode qui l’a lancé.
Pour l’utilisateur final, ça ne présente aucun problème car la gestion des erreurs actuelle est interne à
la classe.
Autrement nous aurions implémenté un système d’Exception, plus propre architecturalement parlant.
2.2.2 La classe Actif
Dans un cadre plus général il serait préférable d’avoir la classe Actif qui serait une interface, que
plusieurs types d’actifs devraient implémenter, par exemple une Action serait un actif particulier. Les
implémentations devraient pouvoir retourner leur rendement respectif.
2.2.3 Spécialisation du CLManager
Une classe CLManagerFi qui hériterait de CLManager permettrait de spécialiser le comportement
de celui ci par exemple en prenant directement le portefeuille en paramètre, et selon la nature de
l’actif, chargerait le kernel adéquat.
2.2.4 Optimisation plus poussée du découpage du travail
Dans l’état actuel, CLManager ne gère qu’un seul device à la fois, il serait intéressant de pouvoir
spécifier un ensemble de devices, et ainsi encore diminuer le temps de calcul. Par exemple sur NEF 1 ,
qui est la plateforme qui nous a été mise à disposition, la machine que nous utilisions bénéficiait de 2
devices, théoriquement nous aurions pu calculer 2 fois plus vite.
1. http://www-sop.inria.fr/dream/Cluster/OverView
Pierre Aït-Tahar Paraita Wohler 16
Master IMAFA - 2012/2013
18. Simulation de la VaR Monte-Carlo sur GPU
2.2.5 Utilisation des variables antithétiques
Suite au cours de M. Tanré nous avons vu l’intéret des variables antithétiques.
Dans notre cas nous savons que :
WT ∼ N (0, T )
σWT ∼ N (0, σ 2 T )
−σWT ∼ N (0, σ 2 T )
On peut en conclure qu’en utilisant cette propriété pour un même nombre de simulation nous
pouvons générer 2 fois moins de variables aléatoires, ce qui représente un grand gain de temps. Une
autre utilisation aurait été si notre générateur de variables aléatoires avait une faible cyclicité, mais
ce n’est pas cas.
2.2.6 Utilisation d’actifs correlés
Dans notre cahier des charges nous avons comme hypothèse que tous nos actifs ne sont pas corrélés.
Dans le cas contraire nous devons faire un changement de repère pour avoir une base où les actifs ne
le sont pas.
La matrice de corrélation est par définition symétrique. Nous pouvons l’exprimer dans une base de
vecteurs propres. La librairie Boost possède des fonctions permettant de faire cette transformation.
2.3 Gestion de projet
2.3.1 Planning de travail
Pour faire ce projet nous avons eu 2 mois où nous avons réparti les tâches de la manière suivante :
Semaine 1 Analyse de la problématique
Semaine 2 Analyse des problèmes liés à la programmation GPU
Semaine 3 Début de la programmation
Semaine 4 Fin d’implémentation Mersenne Twister
Semaine 5 Simulation d’un actif sur une horizon
Semaine 6 Calcul de la Var Monte-Carlo ( un actif )
Semaine 7 Calcul de la Var Monte-Carlo ( plusieurs actifs )
Semaine 8 Améliorations ( précisions de calculs, temps de calcul )
Nous avons réussi à respecter le planning prévisionnel, néanmoins nous regrettons de ne pas avoir
pu bénéficier de plus de temps pour implémenter le tri sur GPU.
2.4 Références
– Options, futures et autres actifs dérivés - John Hull
– Monte Carlo Methods in Financial Engineering - Paul Glasserman
– http ://en.wikipedia.org/wiki/Mersenne_twister
– http ://fr.wikipedia.org/wiki/Méthode_de_Box-Muller
– http ://developer.amd.com/resources/heterogeneous-computing/opencl-zone/
– https ://developer.nvidia.com/opencl
– http ://www.khronos.org/opencl/
– http ://www.giref.ulaval.ca/ãfortin/mat17442/documents/splines.pdf
– http ://en.wikipedia.org/wiki/CUDA#Supported_GPUs
Pierre Aït-Tahar Paraita Wohler 17
Master IMAFA - 2012/2013
19. VaR Monte-Carlo sur GPU
Annexe
Voici les résultats des benchmarks réalisés sur NEF :
Pierre Aït-Tahar Paraita Wohler 18
Master IMAFA - 2012/2013