Cloud Server GPU: applicazioni nella ricerca

Un algoritmo complesso si può eseguire con prestazioni diverse a seconda della tecnologia utilizzata. Un test pratico, fatto con l'ausilio del software MATLAB, ci mostra le differenze in termini di performance tra Cloud Server GPU e l'approccio tradizionale basato su CPU multi core
Indice dei contenuti

Dopo aver illustrato nei precedenti articoli il servizio Cloud Server GPU basato su scheda grafica NVIDIA QUADRO RTX 6000, vediamo adesso un’applicazione di questa potente infrastruttura di calcolo, utilizzando il software MATLAB.

MATLAB è una piattaforma di programmazione e calcolo numerico utilizzata da milioni di ingegneri e scienziati per l’analisi di dati, lo sviluppo di algoritmi e la creazione di modelli, che consente di utilizzare le GPU NVIDIA per accelerare le attività di intelligenza artificiale, deep learning e altre analisi computazionalmente onerose senza dover essere un programmatore CUDA.

Valutazione delle prestazioni di Cloud Server GPU

Scopo di questo articolo è valutare le prestazioni dell’infrastruttura Cloud Server GPU nell’esecuzione di un algoritmo di test, comparando i risultati con l’approccio tradizionale basato soltanto su CPU multi core.

Predisposizione dell’infrastruttura di calcolo

Il sistema di test che abbiamo utilizzato è un Cloud Server con CPU a 8 core e 32GiB di RAM, con OS Linux Debian 10, dotato di scheda grafica NVIDIA QUADRO RTX 6000 e in cui sono stati installati i driver di supporto NVIDIA. 

La prima osservazione importante che dobbiamo fare è che la grafica non è supportata di default su server Debian e che quindi, se vogliamo utilizzarlo per usare MATLAB in modalità desktop ed eseguire algoritmi di rendering, dobbiamo fornire il supporto del Desktop Environment con tasksel e installare e configurare un VNC server per la connessione remota.

Per semplicità abbiamo comunque preferito utilizzare un docker predefinito realizzato dagli sviluppatori di MATLAB, facendo attenzione al fatto che, per fornire supporto alle GPU NVIDIA, bisogna installare – oltre al pacchetto docker – anche il pacchetto nvidia-docker.

Iniziamo con l’installazione del pacchetto docker:

sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common

curl -s -L https://download.docker.com/linux/debian/gpg | sudo apt-key add –

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

sudo apt update

sudo apt install docker-ce

Procediamo con l’installazione del paccketto nvidia-docker:

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)

curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update
sudo apt-get install -y nvidia-docker2

A questo punto, possiamo procedere con il pull del pacchetto MATLAB con il supporto per il Deep Learning:

sudo docker pull nvcr.io/partners/matlab:r2021a

Per utilizzare questo pacchetto è necessaria una licenza CLOUD MATLAB, che possiamo eventualmente attivare come trial, registrandoci al sito ufficiale.  

Concludiamo il setup dell’ambiente lanciando il docker sul nostro server:

sudo nvidia-docker run -it --rm -p 5901:5901 -p 6080:6080 --shm-size=512M nvcr.io/partners/matlab:r2021a

Per il collegamento al server da un client desktop, possiamo utilizzare il protocollo vnc (porta 5901) o http (porta 6080). Una volta collegati, possiamo eseguire MATLAB, inserendo i dati della nostra licenza.

Simulazione senza il supporto della GPU

Nel nostro test facciamo riferimento alla rappresentazione dei frattali di Mandelbrot descritto nel testo “Experiments with MATLAB” di Cleve Moler’s.

In questo esempio si vuole rappresentare una porzione del set di Mandelbrot, come illustrato in figura.

Di seguito il codice MATLAB che consente di effettuare il rendering, senza utilizzare le funzionalità di accelerazione della GPU.

maxIterations = 500;
gridSize = 1000;
xlim = [-0.748766713922161, -0.748766707771757];
ylim = [ 0.123640844894862,  0.123640851045266];

% Setup
t = tic();
x = linspace( xlim(1), xlim(2), gridSize );
y = linspace( ylim(1), ylim(2), gridSize );
[xGrid,yGrid] = meshgrid( x, y );
z0 = xGrid + 1i*yGrid;
count = ones( size(z0) );

% Calculate
z = z0;
for n = 0:maxIterations
    z = z.*z + z0;
    inside = abs( z )<=2;
    count = count + inside;
end
count = log( count );

% Show
cpuTime = toc( t );
fig = gcf;
fig.Position = [200 200 600 600];
imagesc( x, y, count );
colormap( [jet();flipud( jet() );0 0 0] );
axis off
title( sprintf( '%1.2fsecs (without GPU)', cpuTime ) );

In questo caso, sul nostro server ad 8 core e 32 GB RAM,  il rendering viene effettuato in 2,02 secondi senza utilizzare le funzioni specifiche per il supporto GPU. 

Simulazione con supporto della GPU

Per usufruire del supporto della GPU, è necessario utilizzare la classe gpuArray, che definisce numerose funzioni che possono essere utilizzate per la creazione e l’elaborazione dei data array. Di seguito si riporta il codice precedente modificato in modo da usufruire del supporto della GPU.

maxIterations = 500;
gridSize = 1000;
xlim = [-0.748766713922161, -0.748766707771757];
ylim = [ 0.123640844894862,  0.123640851045266];

% Setup
t = tic();
x = gpuArray.linspace( xlim(1), xlim(2), gridSize );
y = gpuArray.linspace( ylim(1), ylim(2), gridSize );
[xGrid,yGrid] = meshgrid( x, y );
z0 = complex( xGrid, yGrid );
count = ones( size(z0), 'gpuArray' );

% Calculate
z = z0;
for n = 0:maxIterations
    z = z.*z + z0;
    inside = abs( z )<=2;
    count = count + inside;
end
count = log( count );

% Show
count = gather( count ); % Fetch the data back from the GPU
naiveGPUTime = toc( t );
imagesc( x, y, count )
axis off
title( sprintf( '%1.3fsecs (naive GPU) = %1.1fx faster', ...
    naiveGPUTime, cpuTime/naiveGPUTime ) )

In questo caso il rendering viene completato in 0.372 secondi ed è 5.4 più veloce del caso precedente, in cui non veniva richiesto il supporto della GPU.

E’ possibile implementare l’algoritmo in CUDA/C++, convertendo l’algoritmo base in una funzione C-Mex utilizzando il Parallel Computing Toolbox, che consente di richiamare kernel CUDA. Il codice relativo è riportato di seguito.

maxIterations = 500;
gridSize = 1000;
xlim = [-0.748766713922161, -0.748766707771757];
ylim = [ 0.123640844894862,  0.123640851045266];

% Load the kernel
cudaFilename = 'pctdemo_processMandelbrotElement.cu';
ptxFilename = ['pctdemo_processMandelbrotElement.',parallel.gpu.ptxext];
kernel = parallel.gpu.CUDAKernel( ptxFilename, cudaFilename );

% Setup
t = tic();
x = gpuArray.linspace( xlim(1), xlim(2), gridSize );
y = gpuArray.linspace( ylim(1), ylim(2), gridSize );
[xGrid,yGrid] = meshgrid( x, y );

% Make sure we have sufficient blocks to cover all of the locations
numElements = numel( xGrid );
kernel.ThreadBlockSize = [kernel.MaxThreadsPerBlock,1,1];
kernel.GridSize = [ceil(numElements/kernel.MaxThreadsPerBlock),1];

% Call the kernel
count = zeros( size(xGrid), 'gpuArray' );
count = feval( kernel, count, xGrid, yGrid, maxIterations, numElements );

% Show
count = gather( count ); % Fetch the data back from the GPU
gpuCUDAKernelTime = toc( t );
imagesc( x, y, count )
axis off
title( sprintf( '%1.3fsecs (GPU CUDAKernel) = %1.1fx faster', ...
    gpuCUDAKernelTime, cpuTime/gpuCUDAKernelTime ) );

In questo ultimo caso, l’algoritmo viene eseguito in 0.011 secondi, cioè è 154.7 volte più veloce rispetto al primo esempio in cui non veniva richiesto il supporto della GPU.

prestazioni-cloud-server-gpu
Confronto tra le prestazioni che si ottengono a seconda che si utilizzino GPU o CPU multicore. Il massimo delle performance si ottiene scrivendo funzioni CUDA/C++

Conclusioni

Utilizzando il prodotto Cloud Server GPU è possibile migliorare esponenzialmente le performance di MATLAB nell’esecuzione di algoritmi. Le operazioni possono anche essere eseguite su cloud, utilizzando MATLAB Parallel Server, senza modificare il codice. Il massimo delle prestazioni può essere ottenuto scrivendo funzioni CUDA/C++, ma anche con l’utilizzo dei gpuArray si rilevano notevoli miglioramenti, senza la necessità di modificare il codice originale. I risultati ottenuti confermano quindi i vantaggi in termine di velocità di esecuzione che è possibile ottenere, utilizzando le risorse di calcolo dell’infrastruttura SEEWEB fornite dal nuovo servizio Cloud Server GPU, basato su scheda grafica NVIDIA QUADRO RTX 6000.

CONDIVIDI SUI SOCIAL

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

4 + = 14