Perbandingan CPU dan CUDA Pada Gamma Correction
December 31, 2021 ⏱️7 min readIntro
Beberapa waktu yang lalu saya dan tim berhasil menyelesaikan tugas besar komputasi tersebar dan parallel dimana tim/kelompok saya memilih topik perbandingan performa operasi gamma correction menggunakan CPU dan CUDA. Jika ingin meliha full code untuk project ini dapat dilihat di Google Colaboratory pada link berikut : Link Google Colab
CPU vs GPU CUDA
Fungsi GPU (Graphics processing unit) hampir sama dengan CPU, yang membedakan CPU hanya memiliki beberapa core saja, sedangkan untuk GPU memiliki beberapa ribu core. Lebih tepatnya, fungsi utama GPU yaitu mengolah data grafis atau gambar. GPU biasanya didukung oleh adanya panel yang berfungsi sebagai antarmuka antara user dengan perangkat tersebut.
CUDA singkatan dari Compute Unified Device Architecture merupakan arsitektur komputer paralel yang dikembangkan NVIDIA. CUDA memiliki kemampuan melakukan komputasi yang rumit secara bersamaan sehingga prosess komputai bisa berjalan lebih cepat karena mempunyai bandwidth memori yang lebih besar dan GPU menggunakan Parallelization.
Untuk lebih jelas tentang perbedaan CPU dengan GPU simak video berikut :
Gamma Corection??
Menurut wikipedia:
Gamma correction or gamma is a nonlinear operation used to encode and decode luminance or tristimulus values in video or still image systems.
Gamma Correction merupakan salah satu operasi pada Image Processing yang digunakan untuk mengubah nilai Gamma pada gambar.Gamma dapat digambarkan sebagai hubungan antara input dan output yang dihasilkan. Untuk ruang lingkup percobaan ini inputnya adalah nilai intensitas RGB dari suatu gambar.
Gamma correction juga dikenal sebagai Power Law Transform. Pertama, intensitas piksel gambar kita harus diskalakan dari kisaran [0, 255]. Dari sana, kami mendapatkan gambar output gamma correction dengan menerapkan persamaan berikut:
kemudian output diskalakan kembali ke kisaran [0, 255]. Pada percobaan kali ini kami menggunakan library openCV, numpy, numba, matplotlib, Pillow, dan timeit.
Referensi
https://thecryptmag.com/Online/57/imgproc_6.html
Pseudo code pada link referensi
gammaCorrection = 1 / gamma
colour = GetPixelColour(x, y)
newRed = 255 * (Red(colour) / 255) ^ gammaCorrection
newGreen = 255 * (Green(colour) / 255) ^ gammaCorrection
newBlue = 255 * (Blue(colour) / 255) ^ gammaCorrection
PutPixelColour(x, y) = RGB(newRed, newGreen, newBlue)
Implementasi
Gambar diambil dari web https://thispersondoesnotexist.com/ sama seperti nama websitenya, gambar orang yang muncul dalam website tersebut merupakan gambar buatan yang dibuat dengan menggunakan GAN (generative adversarial network). Gambar yang kita gunakan dalam percobaan ini berukuran
256x256 pixel
512x512 pixel
1024x1024 pixel
2048x2048 pixel
4096x4096 pixel
8192x8192 pixel
Import Library
import cv2
import numpy as np
import numba
import matplotlib.pyplot as plt
from PIL import Image
from timeit import default_timer as timer
Download Gambar dengan Menggunakan Perintah Linux Wget
#Download gambar
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_256.jpg
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_512.jpg
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_1024.jpg
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_2048.jpg
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_4096.jpg
!wget https://raw.githubusercontent.com/mrizkitriyanto/Numba-Gamma-Correction/main/Images/thispersondoesntexist_8192.jpg
Load Gambar
Ketikkan kode berikut dan ulangi hingga sampai ukuran 8192 piksel
img_256 = cv2.imread('thispersondoesntexist_256.jpg')
img_256 = cv2.cvtColor(img_256, cv2.COLOR_BGR2RGB)
plt.imshow(img_256)
Pembuatan Dictionary Image
Dictionary digunakan untuk menyimpan nilai data dalam pasangan key:value. Penggunaan dictionary ini bertujuan untuk mempermudah dalam mengeksekusi. Masukkan kode sebagai berikut:
#Pembuatan dictionary supaya mudah dalam melakukan eksekusi secara langsung dengan looping
dictsImages = {} #dictionary kosong yang akan diisi dengan key (angka 0 - 3) dan values (gambar 256 hingga 8192)
keys = range(6)
values = [img_256, img_512, img_1024, img_2048, img_4096, img_8192]
for i in keys:
dictsImages[i] = values[i]
print(dictsImages)
Akan terbentuk dictionary dengan pasangan key dan value. key mulai dari angka 0 hingga 3. Sedangkan value akan berisi array 3 dimensi yang merepresentasikan nilai tiap piksel.
Pembuatan Fungsi Untuk Operasi Gamma Correction Menggunakan CPU
def gamma_correction_seq (image, gamma):
init_image = np.zeros(image.shape, np.uint8) #inisialisasi variabel init_image dengan value setiap index pada matrix = 0 menggunakan numpy.zeros
for i in range(image.shape[0]): # baris
for j in range(image.shape[1]): # kolom
init_image[i][j] = 255.0 * (image[i][j] / 255.0)**(1 / gamma) #mengisi setiap index matrix dengan formula gamma correction yang didapat dari https://thecryptmag.com/Online/57/imgproc_6.html
return init_image # mengembalikan matrix init_image
Pembuatan Fungsi Untuk Operasi Gamma Correction Menggunakan Cuda
Disini kami menggunakan Numba Vectorize Decorator. Apa itu Numba Vectorize Decorator? Vektor Numba memungkinkan fungsi Python mengambil argumen input skalar untuk digunakan sebagai ufuncs NumPy. Menggunakan vectorize()
, Kita dapat menulis fungsi sebagai operasi pada skalar input, bukan array. Numba akan menghasilkan loop (atau kernel) di sekitarnya yang memungkinkan iterasi yang efisien atas input aktual.
@numba.vectorize('uint8(uint8,float64)',target='cuda') #menggunakan numba vectorize decorator dengan target cuda (GPU)
#######
#Arti dari fungsi ini adalah gamma_correction_par yang menggunakan numba vectorize(numba telah membuatkan loop(atau kernel) yang memungkonkan iterasi atas inputan kita)
#kemudian fungsi gamma_correction_par akan mengembalikan nilai setiap index matrix yang valuenya adalah hasil dari formula gamma correction
#######
def gamma_correction_par(image,gamma):
return 255.0 * (image / 255.0)**(1 / gamma)
Menghitung Waktu Runtime CPU
time_seq = {} #dictionary untuk waktu runtime
output_seq = {} #dictionary untuk output matrix
for keys,values in dictsImages.items():
start = timer()
output_seq[keys]=gamma_correction_seq(values, 2)
time_seq[keys] = timer() - start
time_seq #waktu runtime untuk setiap key dan value
Output akan menampilkan waktu runtime untuk setiap key dan value
Menghitung Waktu Runtime CUDA
time_par = {} # dictionary untuk waktu runtime
output_par = {} # dictionary untuk output matrix
for keys,values in dictsImages.items():
start = timer()
output_par[keys]=gamma_correction_par(values, 2)
time_par[keys] = timer() - start
time_par # waktu runtime untuk setiap key dan value
Perbandingan Gambar Hasil Operasi
Gambar Original
Gambar CPU
Gambar CUDA
Grafik Perbandingan
#Grafik Perbandingan Waktu Runtime CPU vs CUDA
def graph(dictionary_sequential,dictionary_parallel,title):
plt.figure(figsize=(20,12))
x = sorted(list(map(int,dictionary_sequential.keys()))) #Mengambil dan mengurutkan Key yang diambil dari dictionary time_seq
y_seq= [dictionary_sequential[i] for i in x] # mengambil waktu eksekusi sequential
y_par= [dictionary_parallel[i] for i in x] # mengambil waktu eksekusi parallel
labels = ["256x256", "512x512", "1024x1024", "2048x2048", "4096x4096", "8192x8192"] # Label untuk sumbu X
plt.plot(x,y_seq,marker='o', c="r") # plot grafix sequential dengan warna merah
plt.plot(x,y_par,marker='o', c="g") # plot grafik parallel dengan warna hijau
plt.ylim(ymin=-1)
plt.xticks(x,labels) # https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.xticks.html?highlight=xtick Mengubah untuk setiap koordinat yang semulanya berisi key dari dictionary [0, 1, 2, 3, 4, 5] menjadi label ["256x256", "512x512", "1024x1024", "2048x2048", "4096x4096", "8192x8192"]
plt.xlabel('Resolusi gambar (px)')
plt.ylabel('Waktu dalam satuan detik (s)')
plt.legend(['Single CPU','CUDA'])
plt.title(title)
plt.show
Jalankan fungsi dengan memanggilnya
graph(time_seq,time_par,"Perbandingan Waktu Runtime Gamma Correction")
Berdasarkan proses Gamma Correction dengan mengguankan pendekatan sekuensial dan paralal dapat disimpulkan bahwa performa waktu terbaik berhasil dicapai oleh proses yang dilakukan dengan menggunakan pendekatan paralelism.
Cara Menjalankan Semua Cell Pada Google Colab
- Ubah runtime type terlebih dahulu menjadi CUDA caranya pilih menu Runtime -> Change Runtime Type -> pilih GPU -> Save.
- Kemudian jalankan cellnya