hpc:gpu
Skirtumai
Čia matote skirtumus tarp pasirinktos versijos ir esamo dokumento.
| Kitas pataisymas | Previous revision | ||
| hpc:gpu [2021/12/16 10:57] – sukurtas eduardas | hpc: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/ | ||
| + | python3 test.py | ||
| + | </ | ||
| + | |||
| + | Pasinagrinėkime pavyzdį paeilučiui: | ||
| + | <code shell> | ||
| + | $ #SBATCH -p gpu | ||
| + | </ | ||
| + | nukreipiama į PST su vaizdo plokščių resursais skaičiavimo resursą. | ||
| + | |||
| + | <code shell> | ||
| + | $ #SBATCH -n1 | ||
| + | </ | ||
| + | nurodome, koks CPU poreikis bus reikalingas | ||
| + | |||
| + | <code shell> | ||
| + | $ #SBATCH --gres gpu | ||
| + | </ | ||
| + | nurodome, koks GPU poreikis bus reikalingas (esant N GPU poreikiui būtų nurodoma gpu:N). | ||
| + | |||
| + | |||
| + | <code shell> | ||
| + | $ . gpu_env/ | ||
| + | </ | ||
| + | pasiruošiame aplinką darbui (pirmą kartą ją reikia sukurti atskirai žr. aplinka.sh) | ||
| + | |||
| + | <code shell> | ||
| + | $ python3 test.py | ||
| + | </ | ||
| + | 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(" | ||
| + | ts = time.time() | ||
| + | f.write(" | ||
| + | f.close() | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | Č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> | ||
| + | # | ||
| + | |||
| + | 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 | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ====== Skriptų su Tensorflow/ | ||
| + | |||
| + | 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/ | ||
| + | export CONDA_PREFIX=$HOME/ | ||
| + | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH: | ||
| + | . activate base | ||
| + | conda activate gpu_env | ||
| + | |||
| + | |||
| + | python3 test_tf.py | ||
| + | </ | ||
| + | |||
| + | Pasinagrinėkime pavyzdį paeilučiui: | ||
| + | <code shell> | ||
| + | $ #SBATCH -p gpu | ||
| + | </ | ||
| + | nukreipiama į PST su vaizdo plokščių resursais skaičiavimo resursą. | ||
| + | |||
| + | <code shell> | ||
| + | $ #SBATCH -n1 | ||
| + | </ | ||
| + | nurodome, koks CPU poreikis bus reikalingas | ||
| + | |||
| + | <code shell> | ||
| + | $ #SBATCH --gres gpu | ||
| + | </ | ||
| + | nurodome, koks GPU poreikis bus reikalingas (esant N GPU poreikiui būtų nurodoma gpu:N). | ||
| + | |||
| + | |||
| + | <code shell> | ||
| + | $ export PATH=$HOME/ | ||
| + | $ export CONDA_PREFIX=$HOME/ | ||
| + | $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH: | ||
| + | $ . activate base | ||
| + | $ conda activate gpu_env | ||
| + | </ | ||
| + | pasiruošiame aplinką darbui (pirmą kartą ją reikia sukurti atskirai žr. aplinka_tf.sh) | ||
| + | |||
| + | <code shell> | ||
| + | $ python3 test_tf.py | ||
| + | </ | ||
| + | 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(" | ||
| + | ts = time.time() | ||
| + | f.write(" | ||
| + | f.close() | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | Č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> | ||
| + | # | ||
| + | |||
| + | wget https:// | ||
| + | bash Miniconda3-latest-Linux-x86_64.sh | ||
| + | # yes - on install, no - in init, path default one | ||
| + | |||
| + | export 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: | ||
| + | |||
| + | |||
| + | # pirmؤ… kartؤ… susiraإ،ome reikiamas bibliotekas | ||
| + | pip3 install wheel | ||
| + | pip3 install pillow scikit-image | ||
| + | pip3 install tensorflow | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ====== GPU išnaudojimas lygiagretinant kodą su Numba biblioteka ====== | ||
| + | |||
| + | === Įvadas į CUDA Python su Numba === | ||
| + | |||
| + | CUDA skaičiavimo biblioteka įgalina programų pagreitinimą, | ||
| + | |||
| + | **Numba** yra " | ||
| + | |||
| + | |||
| + | === Pavyzdžiai darbas su Numba: Pvz. 1 === | ||
| + | |||
| + | Pavydžiui, realizuokime Pitagorinę sudėtį: | ||
| + | |||
| + | https:// | ||
| + | |||
| + | <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, | ||
| + | |||
| + | </ | ||
| + | |||
| + | Gauti metodų vykdymo laikus galėtume atitinkamai pvz: | ||
| + | |||
| + | <code shell> | ||
| + | timeit hypot.py_func(3.0, | ||
| + | |||
| + | timeit hypot(3.0, 4.0) | ||
| + | </ | ||
| + | |||
| + | === Pavyzdžiai darbas su Numba: Pvz. 2 === | ||
| + | |||
| + | Parašykime programą pi vertinimui Monte Karlo metodu (žr. https:// | ||
| + | |||
| + | <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, | ||
| + | plt.xscale(' | ||
| + | plt.xlabel(" | ||
| + | plt.ylabel(" | ||
| + | </ | ||
| + | |||
| + | |||
| + | Gauti metodų vykdymo laikus galėtume atitinkamai pvz: | ||
| + | |||
| + | <code shell> | ||
| + | timeit monte_carlo_pi(nsamples) | ||
| + | |||
| + | timeit monte_carlo_pi.py_func(nsamples) | ||
| + | </ | ||
| + | |||
| + | |||
| + | === 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ą: | ||
| + | |||
| + | === Pavyzdžiai darbas su Numba: Pvz. 3 === | ||
| + | |||
| + | <code shell> | ||
| + | |||
| + | import numpy as np | ||
| + | |||
| + | a = np.array([1, | ||
| + | b = np.array([10, | ||
| + | |||
| + | 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, | ||
| + | print(' | ||
| + | |||
| + | np.add(b, c) | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | === 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*, | ||
| + | |||
| + | |||
| + | |||
| + | <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([' | ||
| + | def add_ufunc(x, | ||
| + | return x + y | ||
| + | |||
| + | add_ufunc(a, | ||
| + | </ | ||
| + | |||
| + | |||
| + | Gauti metodų vykdymo laikus galėtume atitinkamai pvz: | ||
| + | |||
| + | <code shell> | ||
| + | timeit np.add(b, c) # NumPy - CPU | ||
| + | |||
| + | timeit add_ufunc(b, | ||
| + | </ | ||
| + | |||
| + | # 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)/ | ||
| + | |||
| + | <code shell> | ||
| + | |||
| + | |||
| + | import math | ||
| + | |||
| + | SQRT_2PI = np.float32((2*math.pi)**0.5) | ||
| + | |||
| + | @vectorize([' | ||
| + | def gaussian_pdf(x, | ||
| + | return math.exp(-0.5 * ((x - mean) / sigma)**2) / (sigma * SQRT_2PI) | ||
| + | |||
| + | |||
| + | |||
| + | import numpy as np | ||
| + | |||
| + | x = np.random.uniform(-3, | ||
| + | x = np.sort(x) | ||
| + | |||
| + | mean = np.float32(0.0) | ||
| + | sigma = np.float32(1.0) | ||
| + | |||
| + | |||
| + | f = gaussian_pdf(x, | ||
| + | |||
| + | |||
| + | |||
| + | plt.plot(x, f) | ||
| + | plt.xlabel(' | ||
| + | plt.ylabel(' | ||
| + | </ | ||
| + | |||
| + | Gauti metodų vykdymo laikus galėtume atitinkamai pvz: | ||
| + | |||
| + | <code shell> | ||
| + | timeit gaussian_pdf(x, | ||
| + | |||
| + | import scipy.stats | ||
| + | norm_pdf = scipy.stats.norm | ||
| + | timeit norm_pdf.pdf(x, | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | === Pavyzdžiai darbas su Numba: Pvz. 5 === | ||
| + | |||
| + | Tais atvejais, kai norime spartinti vektorinius skaičiavimus, | ||
| + | |||
| + | |||
| + | <code shell> | ||
| + | |||
| + | from numba import cuda | ||
| + | |||
| + | @cuda.jit(device=True) | ||
| + | def polar_to_cartesian(rho, | ||
| + | x = rho * math.cos(theta) | ||
| + | y = rho * math.sin(theta) | ||
| + | return x, y | ||
| + | |||
| + | @vectorize([' | ||
| + | def polar_distance(rho1, | ||
| + | x1, y1 = polar_to_cartesian(rho1, | ||
| + | x2, y2 = polar_to_cartesian(rho2, | ||
| + | |||
| + | return ((x1 - x2)**2 + (y1 - y2)**2)**0.5 | ||
| + | |||
| + | |||
| + | n = 1000000 | ||
| + | rho1 = np.random.uniform(0.5, | ||
| + | theta1 = np.random.uniform(-np.pi, | ||
| + | rho2 = np.random.uniform(0.5, | ||
| + | theta2 = np.random.uniform(-np.pi, | ||
| + | |||
| + | |||
| + | polar_distance(rho1, | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Plačiau apie GPU išnaudojimą | ||
| + | |||
| + | |||
| + | * [[https:// | ||
| + | |||
| + | * [[https:// | ||
hpc/gpu.1639652224.txt.gz · Keista: vartotojo eduardas
