IT wiki

VU MIF STSC

User Tools

Site Tools


hpc:gpu

Skirtumai

Čia matote skirtumus tarp pasirinktos versijos ir esamo dokumento.

Link to this comparison view

Next revision
Previous revision
hpc:gpu [2021/12/16 10:57] – sukurtas eduardashpc:gpu [2022/10/30 13:54] (esamas) linp
Linija 1: Linija 1:
-Info apie GPU skaičiavimus+====== Paketinis užduočių vykdymas su GPU (SLURM) ====== 
 + 
 +Norint pasinaudoti PST skaičiavimo resursais su GPU reikės formuoti užduočių skriptus (.sh): 
 +Labai dažnai GPU mum reiks vykdant mašininio mokymo ir dirbtinio intelekto technologijų modeliams, pažiurėkime kaip pasiruošti PyTorch ir Tensorflow aplinkas ir patikrinti ar bibliotekos gali vykdyti kodą GPU spartinimu. 
 + 
 +====== Skriptų su PyTorch ir GPU paleidimas per SLURM ====== 
 + 
 +Programos vykdymo metu sukuriamas failas gpu.txt su indikatoriumi ir vykdymo laiko momentu: 
 + 
 +<code shell test_gpu.sh> 
 +#!/bin/sh 
 +#SBATCH -p gpu 
 +#SBATCH -n1 
 +#SBATCH --gres gpu 
 + 
 +. gpu_env/bin/activate 
 +python3 test.py 
 +</code> 
 + 
 +Pasinagrinėkime pavyzdį paeilučiui: 
 +<code shell> 
 +$ #SBATCH -p gpu  
 +</code> 
 +nukreipiama į PST su vaizdo plokščių resursais skaičiavimo resursą. 
 + 
 +<code shell> 
 +$ #SBATCH -n1 
 +</code> 
 +nurodome, koks CPU poreikis bus reikalingas 
 + 
 +<code shell> 
 +$ #SBATCH --gres gpu 
 +</code> 
 +nurodome, koks GPU poreikis bus reikalingas (esant N GPU poreikiui būtų nurodoma gpu:N). 
 + 
 + 
 +<code shell> 
 +$ . gpu_env/bin/activate 
 +</code> 
 +pasiruošiame aplinką darbui (pirmą kartą ją reikia sukurti atskirai žr. aplinka.sh) 
 + 
 +<code shell> 
 +$ python3 test.py 
 +</code> 
 +Kviečiame savo kodo skriptą, atlikti užduočiai su Python 
 + 
 + 
 + 
 +Čia iškviečiamo Python kalbos skripto kodas, iškviečiant Pytorch biblioteką ir patikrinat GPU prieigą, kurios dažniausiai reikia kuriant mašininio mokymo modelius. 
 + 
 +<code shell test.py> 
 +import torch 
 +import time 
 + 
 +val = torch.cuda.is_available() 
 + 
 +f = open("gpu.txt", "a"
 +ts = time.time() 
 +f.write("GPU is loaded {} at {}\n".format(val, ts)) 
 +f.close() 
 +</code> 
 + 
 + 
 + 
 +Čia iškviečiamo Python kalbos skripto kodas, iškviečiant Pytorch biblioteką ir patikrinat GPU prieigą, kurios dažniausiai reikia kuriant mašininio mokymo modelius. 
 + 
 +<code shell aplinka.sh> 
 +#!/bin/bash 
 + 
 +python3 -m venv gpu_env 
 + 
 +# pirmą kartą susirašome reikiamas bibliotekas savo projektui pvz: 
 + 
 +pip3 install wheel 
 +pip3 install pillow scikit-image 
 +pip3 install numba  
 +pip3 install torch torchvision torchaudio 
 + 
 +</code> 
 + 
 + 
 +====== Skriptų su Tensorflow/Keras ir GPU paleidimas per SLURM ====== 
 + 
 +Programos vykdymo metu sukuriamas failas gpu.txt su indikatoriumi ir vykdymo laiko momentu: 
 + 
 +<code shell test_gpu_tf.sh> 
 +#!/bin/sh 
 +#SBATCH -p gpu 
 +#SBATCH -n1 
 +#SBATCH --gres gpu 
 + 
 +export PATH=$HOME/miniconda3/bin:$PATH 
 +export CONDA_PREFIX=$HOME/miniconda3/envs/gpu_env 
 +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CONDA_PREFIX/lib/ 
 +. activate base 
 +conda activate gpu_env 
 + 
 + 
 +python3 test_tf.py 
 +</code> 
 + 
 +Pasinagrinėkime pavyzdį paeilučiui: 
 +<code shell> 
 +$ #SBATCH -p gpu  
 +</code> 
 +nukreipiama į PST su vaizdo plokščių resursais skaičiavimo resursą. 
 + 
 +<code shell> 
 +$ #SBATCH -n1 
 +</code> 
 +nurodome, koks CPU poreikis bus reikalingas 
 + 
 +<code shell> 
 +$ #SBATCH --gres gpu 
 +</code> 
 +nurodome, koks GPU poreikis bus reikalingas (esant N GPU poreikiui būtų nurodoma gpu:N). 
 + 
 + 
 +<code shell> 
 +$ export PATH=$HOME/miniconda3/bin:$PATH 
 +$ export CONDA_PREFIX=$HOME/miniconda3/envs/gpu_env 
 +$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CONDA_PREFIX/lib/ 
 +$ . activate base 
 +$ conda activate gpu_env 
 +</code> 
 +pasiruošiame aplinką darbui (pirmą kartą ją reikia sukurti atskirai žr. aplinka_tf.sh) 
 + 
 +<code shell> 
 +$ python3 test_tf.py 
 +</code> 
 +Kviečiame savo kodo skriptą, atlikti užduočiai su Python 
 + 
 + 
 + 
 +Čia iškviečiamo Python kalbos skripto kodas, iškviečiant Tensorflow biblioteką ir patikrinat GPU prieigą, kurios dažniausiai reikia kuriant mašininio mokymo modelius. 
 + 
 +<code shell test_tf.py> 
 +import time 
 +import tensorflow as tf 
 + 
 +val = tf.test.is_gpu_available() 
 + 
 +f = open("gpu.txt", "a"
 +ts = time.time() 
 +f.write("GPU is loaded {} at {}\n".format(val, ts)) 
 +f.close() 
 +</code> 
 + 
 + 
 + 
 +Čia iškviečiamo Python kalbos skripto kodas, iškviečiant Tensorflow biblioteką ir patikrinat GPU prieigą, kurios dažniausiai reikia kuriant mašininio mokymo modelius. 
 + 
 +<code shell aplinka_tf.sh> 
 +#!/bin/bash 
 + 
 +wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh 
 +bash Miniconda3-latest-Linux-x86_64.sh 
 +# yes - on install, no - in init, path default one 
 + 
 +export PATH=~/miniconda3/bin:$PATH 
 +conda create --name gpu_env python=3.9 
 +. activate base 
 +conda activate gpu_env 
 +conda install -c conda-forge cudatoolkit=11.7 cudnn=8.1.0 
 +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CONDA_PREFIX/lib/ 
 + 
 + 
 +# pirmؤ… kartؤ… susiraإ،ome reikiamas bibliotekas 
 +pip3 install wheel 
 +pip3 install pillow scikit-image 
 +pip3 install tensorflow 
 + 
 +</code> 
 + 
 + 
 + 
 + 
 +====== GPU išnaudojimas lygiagretinant kodą su Numba biblioteka ====== 
 + 
 +=== Įvadas į CUDA Python su Numba  === 
 + 
 +CUDA skaičiavimo biblioteka įgalina programų pagreitinimą, vykdant skaičiavimus ant GPU.  
 + 
 +**Numba** yra "vykdymo-realiu-laiku" Python funkcijų kompiliatorius, Python funkcijoms paspartinti. **Numba** dažnai naudojama Python programuotojų norint, norintiems GPU paspartinti savo programas, jų neperašant į C/C++ kodą, ypač jei kodas jau naudoja **NumPy** masyvuos.  
 + 
 + 
 +=== Pavyzdžiai darbas su Numba: Pvz. 1  === 
 + 
 +Pavydžiui, realizuokime Pitagorinę sudėtį: 
 + 
 +https://en.wikipedia.org/wiki/Hypot 
 + 
 +<code shell> 
 +# importuojame jit kompiliatorių 
 +from numba import jit 
 +import numpy as np 
 +import math 
 + 
 +# Sintaksė @jit ekvivalentu užrašui `hypot = jit(hypot)`. 
 +@jit 
 +def hypot(x, y): 
 +    x = abs(x); 
 +    y = abs(y); 
 +    t = min(x, y); 
 +    x = max(x, y); 
 +    t = t / x; 
 +    return x * math.sqrt(1+t*t) 
 + 
 + 
 +# Bandome 
 +hypot(3.0, 4.0) 
 + 
 + 
 +# Nesukompiliuotos su *jit* funkcijos iškvietimas 
 +ypot.py_func(3.0, 4.0) 
 + 
 +</code> 
 + 
 +Gauti metodų vykdymo laikus galėtume atitinkamai pvz: 
 + 
 +<code shell> 
 +timeit hypot.py_func(3.0, 4.0) 
 + 
 +timeit hypot(3.0, 4.0) 
 +</code> 
 + 
 +=== Pavyzdžiai darbas su Numba: Pvz. 2  === 
 + 
 +Parašykime programą pi vertinimui Monte Karlo metodu (žr. https://academo.org/demos/estimating-pi-monte-carlo/
 + 
 +<code shell> 
 +from numba import jit  
 +import random 
 + 
 +@jit  
 +def monte_carlo_pi(nsamples): 
 +    acc = 0 
 +    for i in range(nsamples): 
 +        x = random.random() 
 +        y = random.random() 
 +        if (x**2 + y**2) < 1.0: 
 +            acc += 1 
 +    return 4.0 * acc / nsamples 
 + 
 + 
 + 
 +import matplotlib.pyplot as plt 
 + 
 + 
 +nsamples = 1000000 
 + 
 +n = [2**i for i in range(0, 20)] 
 +pi_values = [monte_carlo_pi(i) for i in n] 
 + 
 +plt.plot(n, pi_values) 
 +plt.axhline(y=np.pi, color='r', linestyle='-'
 +plt.xscale('log'
 +plt.xlabel("Bandymų skaičius n") 
 +plt.ylabel("pi įvertis"
 +</code> 
 + 
 + 
 +Gauti metodų vykdymo laikus galėtume atitinkamai pvz: 
 + 
 +<code shell> 
 +timeit monte_carlo_pi(nsamples) 
 + 
 +timeit monte_carlo_pi.py_func(nsamples) 
 +</code> 
 + 
 + 
 +=== Kaip Numba veikia?  === 
 + 
 +Numba kompiliatorius atsivželgia į duomenų tipus ir optimizuoja tarpinius skaičiavimu (angl. Intermediate representation (IR)) 
 + 
 + 
 +### **Numba** optimizuojant kodą skirtą GPU naudojant **NumPy** universalias funkcijas (ufuncs) 
 +Toliau laikysime GPU programavimo aprėpyje jog dirbsime su NumPy universaliomis funkcijas (arba ufuncs) - t.y. standartinės bibliotekos funkcijos žr. dokumentaciją:   https://docs.scipy.org/doc/numpy-1.15.1/reference/ufuncs.html 
 + 
 +=== Pavyzdžiai darbas su Numba: Pvz. 3  === 
 + 
 +<code shell> 
 + 
 +import numpy as np 
 + 
 +a = np.array([1, 2, 3, 4]) 
 +b = np.array([10, 20, 30, 40]) 
 + 
 +np.add(a, b) 
 + 
 + 
 +# Universalios funkcijos veikia su vektoriais ir skaičiais 
 +np.add(a, 100) 
 + 
 + 
 +# Matriciniu atveju, vektoriai taikomi sąrašo elementams t.y. eilutėms 
 +c = np.arange(4*4).reshape((4,4)) 
 +print('c:', c) 
 + 
 +np.add(b, c) 
 +</code> 
 + 
 + 
 + 
 +=== Universalių funkcijų kūrimas ir optimizavimas  === 
 + 
 + 
 +Svarbu suprasti, jog norint kurti universalias fukcijas, tokias turime ir naudoti. Šiuo atveju, tam mum bus reikalinkas metodas *vectorize*. 
 + 
 +Šiame pačiame pirmame pavyzdyje naudosime *vectorize*, kad sudarytume ir optimizuotume sukurtą universalią funkciją **CPU** 
 + 
 + 
 + 
 +<code shell> 
 +from numba import vectorize 
 + 
 +@vectorize 
 +def add_ten(num): 
 +    return num + 10 
 + 
 +nums = np.arange(10) 
 +nums 
 + 
 +add_ten(nums) 
 + 
 +# Dabar norint išnaudoti **GPU** optimizavimą mum reikia  
 +@vectorize(['int64(int64, int64)'], target='cuda')  
 +def add_ufunc(x, y): 
 +    return x + y 
 + 
 +add_ufunc(a, b) 
 +</code> 
 + 
 + 
 +Gauti metodų vykdymo laikus galėtume atitinkamai pvz: 
 + 
 +<code shell> 
 +timeit np.add(b, c)   # NumPy - CPU 
 + 
 +timeit add_ufunc(b, c) # Numba - GPU 
 +</code> 
 + 
 +# Ant CPU veikia greičiau :)  
 +# 1. duomenys per maži 
 +# 2. operacijos primityvios 
 +# 3. kopijuojame duomenis į GPU 
 +# 4. naudojame didelius duomenis (int64) 
 + 
 + 
 +=== Pavyzdžiai darbas su Numba: Pvz. 4  === 
 + 
 +Panagrinėkime sudėtingesnį atvejį f(x|\mu, \sigma) = \frac{e^{-((x-\mu)/\sigma)^2}}{\sigma \sqrt{2\pi}} 
 + 
 +<code shell> 
 + 
 + 
 +import math  
 + 
 +SQRT_2PI = np.float32((2*math.pi)**0.5)  
 + 
 +@vectorize(['float32(float32, float32, float32)'], target='cuda'
 +def gaussian_pdf(x, mean, sigma): 
 +    return math.exp(-0.5 * ((x - mean) / sigma)**2) / (sigma * SQRT_2PI) 
 + 
 + 
 + 
 +import numpy as np 
 + 
 +x = np.random.uniform(-3, 3, size=1000000).astype(np.float32) 
 +x = np.sort(x) 
 + 
 +mean = np.float32(0.0) 
 +sigma = np.float32(1.0) 
 + 
 + 
 +f = gaussian_pdf(x, 0.0, 1.0) 
 + 
 + 
 + 
 +plt.plot(x, f) 
 +plt.xlabel('x'
 +plt.ylabel('f(x)'
 +</code> 
 + 
 +Gauti metodų vykdymo laikus galėtume atitinkamai pvz: 
 + 
 +<code shell> 
 +timeit gaussian_pdf(x, mean, sigma) 
 + 
 +import scipy.stats  
 +norm_pdf = scipy.stats.norm 
 +timeit norm_pdf.pdf(x, loc=mean, scale=sigma) 
 +</code> 
 + 
 + 
 + 
 + 
 +=== Pavyzdžiai darbas su Numba: Pvz. 5  === 
 + 
 +Tais atvejais, kai norime spartinti vektorinius skaičiavimus, o ne skaičiavimus paelemenčiui -- naudoti *numba.cuda.jit* 
 + 
 + 
 +<code shell> 
 + 
 +from numba import cuda 
 + 
 +@cuda.jit(device=True) 
 +def polar_to_cartesian(rho, theta): 
 +    x = rho * math.cos(theta) 
 +    y = rho * math.sin(theta) 
 +    return x, y 
 + 
 +@vectorize(['float32(float32, float32, float32, float32)'], target='cuda'
 +def polar_distance(rho1, theta1, rho2, theta2): 
 +    x1, y1 = polar_to_cartesian(rho1, theta1)  
 +    x2, y2 = polar_to_cartesian(rho2, theta2) 
 +     
 +    return ((x1 - x2)**2 + (y1 - y2)**2)**0.5 
 + 
 + 
 +n = 1000000 
 +rho1 = np.random.uniform(0.5, 1.5, size=n).astype(np.float32) 
 +theta1 = np.random.uniform(-np.pi, np.pi, size=n).astype(np.float32) 
 +rho2 = np.random.uniform(0.5, 1.5, size=n).astype(np.float32) 
 +theta2 = np.random.uniform(-np.pi, np.pi, size=n).astype(np.float32) 
 + 
 + 
 +polar_distance(rho1, theta1, rho2, theta2) 
 +</code> 
 + 
 + 
 +=== Plačiau apie GPU išnaudojimą  === 
 + 
 + 
 + * [[https://klevas.mif.vu.lt/~linp/hpc/ | Medžiaga ir pavyzdžiai: klevas.mif.vu.lt/~linp/hpc/ ]] 
 + 
 + * [[https://drive.mif.vu.lt/s/9Zpzxzq4XCyMozp|GPU skaičiavimai HPC insfrastruktūroje (video) ]]
hpc/gpu.1639652224.txt.gz · Keista: 2021/12/16 10:57 vartotojo eduardas

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki