restauratie in ware tijd van video met behulp van...

109
Jan Parasote Restauratie in ware tijd van video met behulp van CUDA Academiejaar 2010-2011 Faculteit Ingenieurswetenschappen en Architectuur Voorzitter: prof. dr. ir. Herwig Bruneel Vakgroep Telecommunicatie en Informatieverwerking Master in de ingenieurswetenschappen: computerwetenschappen Masterproef ingediend tot het behalen van de academische graad van Begeleiders: dr. Filip Rooms, dr. ir. Bart Goossens Promotoren: prof. dr. ir. Wilfried Philips, prof. dr. ir. Aleksandra Pizurica

Upload: truongkhuong

Post on 23-May-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Jan Parasote

Restauratie in ware tijd van video met behulp van CUDA

Academiejaar 2010-2011Faculteit Ingenieurswetenschappen en ArchitectuurVoorzitter: prof. dr. ir. Herwig BruneelVakgroep Telecommunicatie en Informatieverwerking

Master in de ingenieurswetenschappen: computerwetenschappen Masterproef ingediend tot het behalen van de academische graad van

Begeleiders: dr. Filip Rooms, dr. ir. Bart GoossensPromotoren: prof. dr. ir. Wilfried Philips, prof. dr. ir. Aleksandra Pizurica

Jan Parasote

Restauratie in ware tijd van video met behulp van CUDA

Academiejaar 2010-2011Faculteit Ingenieurswetenschappen en ArchitectuurVoorzitter: prof. dr. ir. Herwig BruneelVakgroep Telecommunicatie en Informatieverwerking

Master in de ingenieurswetenschappen: computerwetenschappen Masterproef ingediend tot het behalen van de academische graad van

Begeleiders: dr. Filip Rooms, dr. ir. Bart GoossensPromotoren: prof. dr. ir. Wilfried Philips, prof. dr. ir. Aleksandra Pizurica

Toelating tot bruikleen

De auteur geeft de toelating deze masterproef voor consultatie beschikbaar te stellen en delenvan de masterproef te kopiëren voor persoonlijk gebruik.Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met be-trekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van resultatenuit deze masterproef.

1 juni 2011Jan Parasote

i

Voorwoord

Via deze weg wil ik enkele mensen bedanken die bijgedragen hebben tot de voltooiing vandeze masterproef.

Allereerst wil ik mijn ouders en familie bedanken voor de kansen die zij mij boden en de steundie zij mij hebben gegeven over de jaren heen.

Verder wil ik graag dr. Filip Rooms en dr. ir. Bart Goossens bedanken. Als begeleidersvan deze masterproef stonden ze mij steeds bij met raad en brachten mij daarmee de nodigeinzichten en ideeën bij voor de uitwerking van deze masterproef. Zonder hen had deze mas-terproef kwalitatief niet hetzelfde niveau behaald.

Ten slotte wil ik de promotoren van deze masterproef bedanken, met name prof. dr. ir.Wilfried Philips en prof. dr. ir. Aleksandra Pižurica, voor de kans die zij mij hebben gegevenom dit onderzoek uit te voeren. Hun supervisie heeft dit werk de juiste richting uitgestuurden meegeholpen om dit eindresultaat te bekomen.

Jan Parasote

ii

Overzicht

Restauratie in ware tijd van video met behulp van CUDAdoor Jan Parasote

Samenvatting

In deze masterproef wordt de GPGPU technologie onder de loep genomen. De nadruk ligthierbij op de mogelijkheden en de beperkingen die gepaard gaan met deze nieuwe technologie.Om hierop een beter zicht te krijgen wordt in deze masterproef een beeldrestauratie algoritmemet deze technologie naar de GPU gebracht. Deze omzetting gebeurt vanuit een algemeenkader. Er wordt bekeken welke factoren er een invloed hebben op de uitvoeringsefficiëntie vaneen GPU algoritme en welke basisalgoritmes voorhanden zijn om een algoritme naar de GPUte brengen. Tijdens de overbrenging zelf wordt dan geanalyseerd waar de pijnpunten liggenvan deze implementatie en worden alternatieven hiervoor voorgesteld. Uit de resultaten volgtuiteindelijk dat deze implementatie op een hedendaagse GPU ware tijd uitvoering toe laat.

Trefwoorden: GPGPU, CUDA, beeldrestauratie, ruisonderdrukking in video

iii

Restauration of video in real time with CUDAJan Parasote

Supervisor(s): prof. dr. ir. Wilfried Philips, prof. dr. ir. Aleksandra Pizurica, dr. Filip Rooms, dr. ir. BartGoossens

Abstract— With the rise of the GPGPU technology, more and more in-terest has come in using the GPU to perform operations and calculationsnormally performed by the CPU. This dissertation seeks to explore the ca-pabilities and limitations of this technology.

Keywords—GPGPU, CUDA, video denoising, real time restauration, mo-tion compensated 3-D wavelet transform with integrated recursive tempo-ral filtering (MC3DWTr)

I. INTRODUCTION

OVER the years, the GPU knew a stronger evolution in com-puting power than the CPU. This evolution was spurred by

the graphics industry, and led to the GPU of today: a processorwith multiple cores, specialised in data-parallel execution. Be-cause of its computing power a lot of interest has recently comein using the GPU not only as a graphics processing device, but asan extra processor next to the CPU. The technology that allowsthe use of the GPU as a general processor is called the General-Purpose computation on the GPU (GPGPU) technology. Thisthesis uses the GPGPU technology of NVIDIA, CUDA. Thegoal is to study the limitations and possibilities introduced bythis technology when converting an algorithm to a GPU im-plementation. To achieve this goal the GPU and the GPGPUtechnology itself is first studied. As a second step existing algo-rithms are sought that typically form a part in larger algorithms.Finally with the aid of these algorithms a video denoising algo-rithm is implemented with the CUDA framework. Next to de-termining the bottlenecks, a secondary goal is to analyse the useof this algorithm for real time processing of a grayscale videostream.

II. FACTORS INFLUENCING PERFORMANCE

In the CUDA C Best Practices Guide [1] a complete set ofguidelines is given which have to be taken into account whenimplementing an algorithm with the CUDA framework. Thekey factors for good performance mentioned are: (1) the degreeof parallellism of the algorithm should be high, (2) the GPUmultiprocessors should be highly occupied during execution, (3)global memory access should be as low as possible and (4) con-ditional execution paths should be limited to avoid serialisationof these paths. When implementing the video denoising algo-rithm these guidelines were kept in mind.

III. GENERIC GPGPU ALGORITHMS

To avoid building the entire algorithm from the ground up,smaller generic (GPGPU) algorithms can be used. Two widelyapplicable algorithms are the reduction and the prefixsum algo-rithms. The reduction algorithm reduces an array to a single

Ghent University (UGent), Gent, Belgium

value. The operation used to perform this reduction can be cho-sen. The most common choices are the sum, the maximum orthe minimum operation. Figure 1 shows the reduction algorithmusing the sum operation.

3 1 2 1 2 5 1 0

4 3 7 1

7 8

15

Fig. 1. The sum reduction algorithm.

The prefixsum algorithm determines the cumulative sum of anarray. In this dissertation two variants of the prefixsum algorithmare also studied. The general prefixsum is a general version ofthe original prefixsum algorithm. It can be described as follows:

y(0) = αx(0)for n = 1→ N doy(n) = βy(n− 1) + αx(n)

end for

The coefficients α and β are parameters of the algorithm. Ifboth equal one, the output array y(n) contains the cumulativesum of the input array x(n). A second variant is the partial pre-fixsum algorithm, which can be described as follows:

y(0) = x(0)for n = 1→ N doy(n) = y(n− 1) + x(n)− x(n−m)

end for

Every output element in the array y(n) is the sum of m el-ements from the input array x(n). Next to the previous algo-rithms other common algorithms of which CUDA implemen-tations exist are: sorting algorithms, algorithms to build his-tograms, Wavelet and Fourier transform algorithms, etc.

IV. VIDEO DENOISING ALGORITHM

The implemented video denoising algorithm is the MC3DWTralgorithm [2]. In figure 2 a scheme of this algorithm is shown.The algorithm uses a framebuffer that contains past denoisedframes and the current noisy frame. Using this setup the framesare recursively filtered and information from past and futureframes is used. A first step in the algorithm is to align the

iv

Temporal decomposition

Spatial decomposition

Wavelet shrinkage

Spatial reconstruction

Temporal reconstruction

Inverse motion compensation

Motion estimation and compensation

Delay

Output

Current frame

Past denoised frames

Fig. 2. The MC3DWTr algorithm.

pixels of the different frames along their motion trajectories.The temporal decomposition performs a 1-D decimated wavelettransform with the Haar wavelet over the motion compensatedframes. This creates a set of low and high-pass frames. Thelow-pass subbands can iteratively be further decomposed untilonly one residual low-pass frame remains. The spatial decom-position step performs a 2-D spatial wavelet decomposition onthe high-pass frames and the residual low-pass frame, creating a3-D decomposition. The wavelet shrinkage step entails: (1) theestimation of the noise level and (2) the use of a 2-D waveletdenoising technique on the seperate 3-D subbands. Finally afterthe reconstruction steps and the inverse motion compensation aframe is chosen as output.

V. CUDA IMPLEMENTATION

A structered approach was used to create the GPGPU imple-mentation of the MC3DWTr algorithm. The algorithm was firstdivided into its subcomponents:

• The motion estimation and compensation• The temporal wavelettransform• The spatial wavelettransform• The noise estimation technique• The 2-D wavelet denoising technique

These components were further divided into a sequence ofsteps. Each of these steps was then implemented using an ex-isting GPGPU algorithm or an own implementation of this step.The complete algorithm was then constructed by linking thesecomponents to each other. To improve the overall performanceof the implementation some of the bottlenecks were replaced bya more performant alternative. The most notable changes were:

• The full-search block matching motion estimation algorithmwas replaced with a hierarchical algorithm.• The spatial wavelettransform was performed with the Haarinstead of the Farras wavelet [3].• The noise estimation has been changed to use a block based

local variance technique [4][5] instead of the robust median es-timator [6].• The BivariateShrinkage 2-D denoising algorithm [7] was re-placed by the BayesShrink algorithm [8].

VI. RESULTS

Table I shows the performance of the CUDA implementationin terms of frames per second. These results were achieved witha NVIDIA 8800GT GPU and an AMD64 3800+ processor.

average # frames per second256x256 512x512 1024x1024

MC3DWTr GPU (2) 348,60 184,79 62,84MC3DWTr GPU (4) 259,24 117,54 36,25MC3DWTr GPU (8) 155,90 64,51 19,98

TABLE IPERFORMANCE OF THE CUDA IMPLEMENTATION

It can be concluded that the implementation allows real timevideo denoising even for high resolutions. The implementationwith a framebuffer of four 1024x1024 frames was also com-pared to a a CPU implementation running on a Intel CORE i7860 2.8Ghz processor and it achieved a speedup of a factor 35.Because of the changes to the algorithm quality loss occuredcompared to the original algorithm, although this was limited to1.5 dB overall when using the PSNR measure.

VII. CONCLUSIONS

By dividing the algorithm and making use of the existingGPGPU algorithms a CUDA implementation of the algorithmcould be relatively easy created. The implementation is capableof real time video denoising and achieved a large speedup com-pared to a CPU implementation. This clearly shows the (future)potential of the GPGPU technology.

ACKNOWLEDGMENTS

The author would like to thank prof. dr. ir. W. Philips andprof. dr. ir. A. Pizurica for the opportunity to perform thisresearch, as well as dr. F. Rooms and dr. ir. B. Goossens fortheir help in reaching these results.

REFERENCES

[1] NVIDIA Corporation, CUDA C Best Practices Guide[2] S. Yu and M. Omair Ahmad and M. N. S. Swamy, Video Denoising Us-

ing Motion Compensated 3-D Wavelet Transform With Integrated RecursiveTemporal Filtering, IEEE Transactions on Circuits and Systems for VideoTechnology, 20:780-791, 2010.

[3] A. F. Abdelnour and I. W. Selesnick, Nearly symmetric orthogonal waveletbases, Proceedings IEEE international conference on acoustics, speech andsignal processing, pages 431-434, May 2001.

[4] J.-S. Lee, Refined filtering of image noise using local statistics, ComputerVision Graphics Image Processing, pages 15:380-389, 1981.

[5] G. Mastin, Adaptive filters for digital noise smoothing, an evaluation, Com-puter Vision Graphics Image Processing, pages 31:103-121, 1985.

[6] D. Donoho and I. Johnstone, Ideal spatial adaption by wavelet shrinkage,Biometrika, pages 8:425-455, 1994.

[7] L. Sendur and I. W. Selesnick, Bivariate Shrinkage with Local VarianceEstimation, IEEE Signal Processing Letters, 9:438-441, 2002.

[8] S. Chang and B. Yu and M. Vetterli, Adaptive wavelet thresholding forimage denoising and compression, IEEE Transactions on Image Processing,pages 9:1532-1546, 2000.

v

Inhoudsopgave

Toelating tot bruikleen i

Voorwoord ii

Overzicht iii

Uitgebreide abstract vi

Inhoudsopgave vii

Lijst met afkortingen viii

1 Inleiding 11.1 Situering en doelstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Overzicht van de hoofdstukken . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 Eigen bijdragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 GPGPU technologie 42.1 Ontstaan van GPGPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 CUDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.2.1 Hardware architectuur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.2.2 Softwaremodel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.3 Factoren voor efficiënte uitvoering op de GPU . . . . . . . . . . . . . . . . . . . . 132.3.1 De mate van parallellisatie van het algoritme . . . . . . . . . . . . . . . . 132.3.2 De GPU architectuur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3 Generieke bouwstenen voor algoritmes op de GPU 183.1 Het concept van een bouwsteen . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.2 Overzicht van GPU bouwstenen . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4 Het berekenen van een algemene prefixsom op de GPU 254.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.2 Een parallel algoritme om de algemene prefixsom te bepalen . . . . . . . . . . . 264.3 Een nieuw algoritme voor de bepaling van de algemene prefixsom . . . . . . . . 27

4.3.1 Algemene beschrijving van het algoritme . . . . . . . . . . . . . . . . . . 274.3.2 Implementatiedetails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4.4 Resultaten en conclusie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

vi

Inhoudsopgave vii

5 Het berekenen van een partiële prefixsom op de GPU 325.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325.2 Algoritmes voor de bepaling van de partiële prefixsom op de GPU . . . . . . . . . 33

5.2.1 Algoritme gebaseerd op een uitbreiding van het prefixsom algoritme . . . 335.2.2 Een directe aanpak algoritme . . . . . . . . . . . . . . . . . . . . . . . . . 345.2.3 Nieuw algoritme om de partiële prefixsom te bepalen . . . . . . . . . . . . 34

5.3 Resultaten en conclusie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

6 De discrete wavelettransformatie op de GPU 376.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376.2 Bepalen van een tweedimensionale wavelettransformatie . . . . . . . . . . . . . 396.3 Gerelateerd Werk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426.4 Nieuwe aanpakken om de 2-D wavelettransformatie uit te voeren op de GPU . . . 43

6.4.1 Blokgebaseerde aanpak . . . . . . . . . . . . . . . . . . . . . . . . . . . 436.4.2 Textuurgeheugen gebaseerde aanpak . . . . . . . . . . . . . . . . . . . . 47

6.5 Resultaten en conclusie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

7 Overbrengen van een algoritme naar de GPU 507.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507.2 Het MC3DWTr algoritme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

7.2.1 De bewegingsgecompenseerde driedimensionale wavelettransformatie . . 527.2.2 Overzicht van het MC3DWTr algoritme . . . . . . . . . . . . . . . . . . . . 547.2.3 Details van het MC3DWTr algoritme . . . . . . . . . . . . . . . . . . . . . 56

7.3 Implementatie op de GPU: algemeen . . . . . . . . . . . . . . . . . . . . . . . . 597.3.1 Algemene aanpak bij de implementatie . . . . . . . . . . . . . . . . . . . 597.3.2 Datastructuren in de implementatie . . . . . . . . . . . . . . . . . . . . . 607.3.3 Het raamwerk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

7.4 Implementatie op de GPU: details . . . . . . . . . . . . . . . . . . . . . . . . . . 637.4.1 Bewegingsestimatie en -compensatie . . . . . . . . . . . . . . . . . . . . 637.4.2 De wavelettransformaties . . . . . . . . . . . . . . . . . . . . . . . . . . . 727.4.3 Ruisschatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747.4.4 Ruisonderdrukking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

7.5 Resultaten en bespreking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837.5.1 Behaalde uitvoeringssnelheid . . . . . . . . . . . . . . . . . . . . . . . . . 837.5.2 Kwaliteit van de ruisonderdrukking . . . . . . . . . . . . . . . . . . . . . . 857.5.3 Vergelijking met een CPU implementatie . . . . . . . . . . . . . . . . . . . 867.5.4 Algemene conclusie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

8 Conclusie en perspectieven 88

A CD 89

Bibliografie 93

Lijst met afkortingen

AMD Advanced Micro Devices

API Application Programming Interface

ATI Array Technologies Inc.

CPU Central Processing Unit

CUDA Compute Unified Device Architecture

FFT Fast Fourier Transform

GPGPU General-Purpose computation on the GPU

GPU Graphics Processing Unit

IBM International Business Machines

IIR Infinite Impulse Response

MAD gemiddelde absolute afwijking

MC3DWT Motion Compensated 3-D Wavelet Transform

MC3DWTr Motion Compensated 3-D Wavelet Transform With Integrated Recursive Tem-poral Filtering

MSE gemiddelde kwadratische fout

OpenCL Open Computing Language

PSNR piek signaal-ruisverhouding

SDK Software Development Kit

viii

Hoofdstuk 1

Inleiding

1.1 Situering en doelstelling

Over de jaren heen kende de Graphics Processing Unit (GPU) een sterkere evolutie qua reken-kracht en geheugenbandbreedte dan de Central Processing Unit (CPU). Als gevolg hiervankwam er meer en meer interesse om de GPU ook voor niet-grafische toepassingen in te zetten.Dit leidde uiteindelijk tot de ontwikkeling van de General-Purpose computation on the GPU(GPGPU) technologie. Deze technologie gaf de ontwikkelaar toegang tot de parallelle krachtvan de GPU en liet hem toe deze te gebruiken om “algemene” problemen op te lossen.

In deze masterproef wordt gekeken naar hoe deze parallelle kracht het best wordt aangespro-ken en welke beperkingen en mogelijkheden deze technologie introduceert bij de implementatievan een algoritme.

Om dit doel te bereiken wordt in eerste instantie gekeken naar de GPU architectuur en debestaande GPGPU technologie. Dit geeft inzicht in wat deze parallelle kracht van de GPUprecies inhoudt en hoe deze het best wordt aangesproken om zo hoog mogelijke prestaties tebekomen.

Verder zal in de literatuur gekeken worden naar reeds bestaande GPU implementaties vanalgoritmes. Hierbij zal aandacht besteed worden aan vaak voorkomende algoritmes. Dit zijnalgoritmes zoals een prefixsom, een reductie etc. Deze vormen typisch een onderdeel van eengroter algoritme en laten het toe bestaande en toekomstige algoritmes eenvoudig en efficiëntover te brengen naar de GPU. Hierdoor zal een meer generieke aanpak mogelijk zijn bij deomzetting van een algoritme naar een GPU implementatie en moet het algoritme niet van degrond af aan opgebouwd worden.

De aanpak om met deze algoritmes grotere algoritmes op te bouwen zal deels geïllustreerdworden via de overzetting van een beeldrestauratie algoritme voor video naar een GPU im-plementatie. Hierbij zal ook de nodige aandacht besteed worden aan de problemen en beper-kingen die de GPGPU technologie met zich teweegbrengt. Een bijkomend aspect hierbij isom te kijken in welke mate dit algoritme ware tijd uitvoering toelaat en welke aanpassingenkunnen doorgevoerd worden om dit te bewerkstelligen.

1

Hoofdstuk 1. Inleiding 2

1.2 Overzicht van de hoofdstukken

Deze masterproef is als volgt ingedeeld:

Het GPGPU concept wordt behandeld in het tweede hoofdstuk. Na een algemene inleidingzal er een kort overzicht gegeven worden van de bestaande GPGPU technolgieën. Vervolgenszal er dieper ingegaan worden op de in dit werk gebruikte technologie: Compute UnifiedDevice Architecture (CUDA). Hierbij zal speciaal aandacht besteed worden aan het CUDAprogrammeermodel. Daarna wordt gekeken naar de factoren die van belang zijn om de GPUten volle te benutten bij de implementatie van een algoritme.

In het derde hoofdstuk zal in eerste instantie de aanpak om een algoritme naar de GPUover te brengen worden toegelicht. Het concept van een bouwblok wordt hierbij geïntrodu-ceerd. Verder wordt in dit hoofdstuk een overzicht gegeven van enkele vaak voorkomendeGPU bouwblokken.

Twee nieuwe bouwblokken worden voorgesteld in hoofdstukken vier en vijf, meer bepaald hetalgemene prefixsom en het partiële prefixsom algoritme.

Het zesde hoofdstuk gaat dieper in op het bepalen van de wavelettransformatie op de GPU.Deze transformatie vormt een belangrijk onderdeel van het beeldrestauratie algoritme. Hierbijworden nieuwe aanpakken voorgesteld die in bepaalde omstandigheden een snellere bepalingzullen toelaten dan de algmene methoden.

Het zevende hoofdstuk behandelt de implementatie van het ruisonderdrukkingsalgoritme voorvideo, meer bepaald het Motion Compensated 3-D Wavelet Transform With Integrated Re-cursive Temporal Filtering (MC3DWTr) algoritme. In eerste instantie wordt het algoritmezelf toegelicht, waarna de gevolgde aanpak voor de overbrenging wordt beschreven. Daarnawordt dan specifiek voor elke component van het algoritme overlopen hoe deze naar de GPUwerd overgebracht. De problemen die optraden en de gemaakte afwegingen worden hierbijbesproken. Er wordt uiteindelijk afgesloten met de behaalde resultaten.

Ten slotte zal in hoofdstuk acht een algemene conclusie volgen en zal er verder nog enkeleperspectieven gegeven worden voor de toekomst.

Hoofdstuk 1. Inleiding 3

1.3 Eigen bijdragen

De eigen inbreng van de auteur in dit werk is:

• In hoofdstukken 4 en 5 worden nieuwe algoritmes voorgesteld om varianten van de pre-fixsom te bepalen. In hoofdstuk 4 komt de algemene prefixsom aan bod en in hoofdstuk5 wordt de partiële prefixsom behandeld.

• Nieuwe aanpakken voor het bepalen van de tweedimensionale wavelettransformatie opde GPU. Dit wordt beschreven in hoofdstuk 6.

• Het beeldrestauratie algoritme uit hoofdstuk 7 is opgebouwd uit een aantal kleinerealgoritmes. Dit zijn bestaande algoritmes waarvan de werking beschreven is in de lite-ratuur. De auteur stond in om de algoritmes over te brengen naar de GPU met hulpvan de CUDA technologie. Verder heeft de auteur afwegingen gemaakt met het oog ophet verbeteren van de uitvoeringssnelheid.

Hoofdstuk 2

GPGPU technologie

Om beter het verdere verloop van deze masterproef te begrijpen, wordt in dit hoofdstuk aan-dacht besteed aan de GPGPU technologie. Na een korte inleiding over het ontstaan van dezetechnologie, zal de in dit werk gebruikte technologie CUDA in meer detail bekeken worden.Hierbij zullen de achterliggende concepten aan bod komen en zal de in deze context gebruikteterminologie toegelicht worden. Daarna worden nog enkele factoren overlopen die van belangzijn voor efficiënte uitvoering van een algoritme op de GPU.

2.1 Ontstaan van GPGPU

De GPU is een computerchip die ontwikkeld is om enerzijds de CPU te ontlasten van grafi-sche taken en anderzijds om deze taken sneller uit te voeren dan de CPU. Over de jaren heenkende de GPU een enorme evolutie qua rekenkracht ten opzichte van de CPU, zoals te zienis in figuur 2.1.

Met de jaren kwam er meer en meer interesse om de rekenkracht van de GPU ook in tezetten voor applicaties die traditioneel op de CPU uitgevoerd worden. In het begin werdenproblemen geformuleerd op een zodanige manier dat de GPU ze kon oplossen via een ren-deringsopdracht. Het formuleren was een tijdrovend proces door een gebrek aan adequatetools. Met de ontwikkeling van de eerste hoger niveau talen BrookGPU1 en sh2 werd de GPUtoegankelijker en groeide de interesse zowel vanuit de academische wereld als de bedrijfswe-reld. Bedrijven zoals RapidMind, Acceleware Corp. en PeakStream waren bij de eerstendie GPGPU technologie ontwikkelden voor commerciële doeleinden. In 2007 sprongen ook dehardware producenten NVIDIA met CUDA en AMD/ATI met Close to Metal3 op de GPGPUkar. In 2008 stelde Apple specificaties voor een nieuwe open standaard voor, genaamd OpenComputing Language (OpenCL)4. Deze standaard maakt het mogelijk om overdraagbare pro-gramma’s te ontwikkelen die op elk platform (CPU en GPU) kunnen uitgevoerd worden. Allegrote producenten ondersteunen ondertussen deze standaard o.a. AMD/ATI, NVIDIA, Intel,IBM... In 2009 ten slotte kwam Microsoft met DirectCompute op de proppen dat onder-

1website: http://graphics.stanford.edu/projects/brookgpu/2website: http://libsh.org/3nu: Stream Computing4Deze standaard wordt onderhouden door de Khronos Group, website: http://www.khronos.org/

4

Hoofdstuk 2. GPGPU technologie 5

Figuur 2.1: Evolutie van het aantal vlottende komma instructies per seconde van de GPU envan de CPU [1].

deel uitmaakt van de DirectX 11 Application Programming Interface (API) en gericht is opGPGPU ontwikkeling voor het Windows besturingssysteem.

Op dit moment wordt de GPGPU technologie in allerhande domeinen gebruikt. Er zijn toe-passingen in de biologie, in de financiële wereld, signaalverwerking...5

De hardware beschikbaar voor dit werk is de NVIDIA 8800GT GPU. Om deze GPU aan testuren zijn er twee GPGPU technologieën beschikbaar: CUDA en OpenCL. Voor dit werkis er gekozen om gebruik te maken van de GPGPU technologie van NVIDIA, CUDA en nietvoor de standaard OpenCL. Hoewel de multiplatform ondersteuning een belangrijke troef isvan de OpenCL standaard, betekent dit echter niet dat één en dezelfde implementatie demaximale prestatie zal halen uit elke mogelijke onderliggende hardware [2]. Door deze alge-mene aanpak zijn ook verschillende kenmerken waarover CUDA wel beschikt niet te benuttenmet OpenCL6. Daarom is om het onderliggende platform maximaal te benutten gekozen omgebruik te maken van de CUDA technologie.

Recentelijk is er onderzoek verricht naar de automatische conversie van CUDA code naarOpenCL code [3]. Dit onderzoek leidde tot de ontwikkeling van een tool genaamd SWAN7.Indien multiplatform ondersteuning toch gewenst zou zijn in de toekomst, kan eventueel met

5Op de site gpgpu.org zjn allerhande voorbeelden te vinden van deze toepassingen.6Met de OpenCL technologie is het bijvoorbeeld niet mogelijk om templates te gebruiken van GPU functies.7http://www.multiscalelab.org/swan

Hoofdstuk 2. GPGPU technologie 6

deze tool getracht worden de conversie naar OpenCL code te maken.

2.2 CUDA

In dit gedeelte wordt het CUDA raamwerk voorgesteld dat data-parallelle uitvoering toelaatop NVIDIA GPUs. Eerst zal de hardware architectuur van de GPU uitgelegd worden, daarnahet CUDA software model. Voor een uitgebreidere uiteenzetting wordt verwezen naar deCUDA C Programming Guide [1].

2.2.1 Hardware architectuur

Een GPU is zoals eerder vermeld gespecialiseerd in grafische taken en renderingsopdrachten.Meer algemeen kunnen deze taken omschreven worden als data-parallelle taken. Dit zijn ta-ken waarbij op elk dataelement van een grote hoeveelheid data een zelfde reeks van instructies(een kernel) wordt uitgevoerd. In het geval van de GPU is een voorbeeld hiervan de pixelsha-der. Dit is een programmaatje dat uitgevoerd wordt op elke pixel van het beeld met als doelde uiteindelijke pixelkleur te bepalen. Een kenmerkende eigenschap van data-parallelle takenis dat ze een hoge aritmetische intensiteit hebben, of nog: de verhouding tussen het aantalaritmetische instructies en het aantal geheugentoegangen is hoog.

Deze specialisatie toont zich ook in de GPU architectuur. Deze is opgebouwd uit een grootaantal rekeneenheden en een klein aantal tussengeheugens (caches). De idee hierbij is dat devertraging tot het geheugen kan opgevangen worden via bewerkingen doordat de taken zo’nhoge aritmetische intensiteit hebben. Dit staat in contrast met de CPU die over grote cachesbeschikt om deze vertraging op te vangen.

Een NVIDIA GPU kent verder een hiërarchische opbouw. Zowel in de rekeneenheden als hetgeheugen kunnen verschillende lagen geïdentificeerd worden. De globale architectuur wordtin figuur 2.2 weergegeven.

De GPU zelf is samengesteld uit meerdere multiprocessoren, die op hun beurt samengesteldzijn uit een aantal processorkernen (ook wel CUDA kernen genoemd). De instructies van eendata-parallelle taak worden op het niveau van een multiprocessor verzonden. Elke kern indeze multiprocessor zal dan deze instructies uitvoeren.

Naast de hiërarchie van processoren, is er ook een hiërarchie van het geheugen. Het grootstegeheugen is het hoofdgeheugen dat toegankelijk is voor alle multiprocessoren. Op elke mul-tiprocessor zelf is een beperkte hoeveelheid zogenaamd gedeeld geheugen aanwezig. Toegangtot dit geheugen is een grootteorde sneller dan toegang tot het hoofdgeheugen. De multipro-cessoren bevatten naast het gedeeld geheugen ook nog caches van het zogenaamde constantgeheugen en textuurgeheugen. Ten slotte beschikt elke processorkern over een aantal regis-ters. In figuur 2.2 is een schematische weergave te zien van de geheugenhiërarchie.

Hoofdstuk 2. GPGPU technologie 7

Figuur 2.2: Schematische weergave van een NVIDIA GPU [4].

2.2.2 Softwaremodel

Het software model van het CUDA raamwerk tracht de parallelle kracht van de GPU eenvou-dig toegankelijk te maken aan de programmeur. Het gebruikt hiervoor de programeertaal Cfor CUDA. Dit is equivalent met de C programeertaal met enkele extensies specifiek voor hetgebruik bij GPGPU toepassingen. In wat volgt wordt verder een overzicht van het software-model gegeven en enkele concepten toegelicht.

Uitvoeringsmodel

Een functie voor uitvoering op de GPU, een kernel genaamd, wordt op dezelfde manier vast-gelegd als een normale CPU functie. In tegenstelling tot een normale functie zal deze echterniet éénmaal, maar meerdere malen worden uitgevoerd. Elke uitvoering zal parallel met deandere plaats vinden. Eén uitvoering zal door één miniproces, genaamd een draad, uitgevoerdworden. Het is aan de programmeur om vast te leggen hoeveel draden er gebruikt moetenworden en dus hoeveel keer de functie zal uitgevoerd worden.

Aangezien elke draad dezelfde functie uitvoert, kan de vraag gesteld worden hoe elke draadkan weten op welke data deze betrekking heeft. Het CUDA raamwerk creëert hiervoor eenhiërarchie in de draden. Deze draadhiërarchie wordt geïllustreerd in figuur 2.3. De totaleverzameling draden wordt in eerste instantie onderverdeeld in blokken van gelijke grootte.Deze blokken kunnen één-, twee- of driedimensionaal zijn. Deze blokken vormen samen dan

Hoofdstuk 2. GPGPU technologie 8

Figuur 2.3: Het uitvoeringsmodel van CUDA: de CPU (host) stuurt asynchroon de GPU(device) aan. Bij het uitvoeren van een kernel worden draden (threads) gegroepeerd in blokken(blocks) en blokken in een grid [4].

een één- of tweedimensionaal grid. Een unieke index voor elke draad kan dan bekomen wordenuit de index van de draad in het blok en van de index van dit blok in het grid. Het CUDAraamwerk voorziet variabelen die deze indexen bevatten en deze kunnen gebruikt worden bijhet programmeren van een kernel. De volgende variabelen kunnen in een kernel gebruiktworden:

• De index van een draad in zijn blok kan verkregen worden via de variabelen threadIdx.x,threadIdx.y en threadIdx.z. Deze geven respectievelijk de index terug in de x-dimensie,y-dimensie en z-dimensie van de draad in het blok.

• De index van een blok in het grid wordt verkregen via de variabelen blockIdx.x enblockIdx.y.

• Er zijn drie variabelen om de dimensie van een blok te verkrijgen in een kernel. De vari-abelen blockDim.x, blockDim.y en blockDim.z geven respectievelijk aan hoeveel dradener in de x-dimensie, y-dimensie en z-dimensie van een blok zijn.

• Ten laatste kan de griddimensie verkregen worden uit de variabelen gridDim.x en grid-Dim.y. Deze variabelen bevatten het aantal blokken in het grid in de x- en y-dimensie.

Hoofdstuk 2. GPGPU technologie 9

Een globale index van de draad in het grid voor elke dimensie kan bekomen worden via:

GlobaleId.x = blockIdx.x× blockDim.x+ threadIdx.x

GlobaleId.y = blockIdx.y × blockDim.y + threadIdx.y

GlobaleId.z = threadIdx.z

(2.1)

De GlobaleId in de z-dimensie is hierbij gelijk aan threadIdx.z omdat het grid slechts één-of tweedimensionaal kan zijn. Het bepalen van de globale index wordt voor de x-dimensienogmaals geïllustreerd in figuur 2.4.

0 1 2 3

0

0 1 2 3

1

0 1 2 3

2

Grid

0 1 2 3 4 5 6 7 8 9 10 11

ThreadIdx.x

BlockIdx.x

BlockDim.x = 4

BlockIdx.x * BlockDim.x + ThreadIdx.x

Figuur 2.4: Illustratie van de bepaling van de globale index van een draad. Deze bepalinggebeurt door de optelling van de draadindex in het blok threadIdx.x met het product van hetblokindex blockIdx.x waartoe deze draad behoort en de blokdimensie blockDim.x.

Via deze variabelen kan dan op een generieke manier in een kernel vastgelegd worden wat doorelke draad moet verwerkt worden. Bij het uitvoeren van een kernel zullen twee parametersmeegegeven moeten worden, enerzijds de blokdimensie en anderzijds de griddimensie. Hierbijmoet nog een belangrijke beperking meegegeven worden. De maximale dimensie van een bloken de maximale dimensie van een grid zijn beperkt. In de CUDA C Programming Guide [1]worden deze limieten voor elk van de verschillende CUDA architecturen besproken.

Om het bovenstaande nog ietwat te verduidelijken, wordt hiervan nog een voorbeeld gegeven.In code fragment 2.1 wordt een kernel (aangegeven met __global__) weergegeven die elkelement van een ingangsrij input zal vermenigvuldigen met een factor twee en wegschrijvennaar de uitgangsrij output. Zowel de ingangs- als uitgangsrij bevinden zich hierbij in hethoofdgeheugen van de GPU. Het aantal draden waarmee deze kernel wordt uitgevoerd wordtmeegegeven bij de uitvoering ervan. Hier zijn er in totaal 8 × 256 = 2048 draden, onder-verdeeld in acht blokken van elk 256 draden. Elke draad zal één element verwerken. Welkelement dit is hangt af van de blockIdx.x en threadIdx.x variabelen.

Hoofdstuk 2. GPGPU technologie 10

__global__ void ProductKernel1D ( f l o a t ∗ input , f l o a t ∗ output ){const unsigned i n t i = blockDim . x ∗ blockIdx . x + threadIdx . x ; //1D abs index

output [ i ] = 2∗ input [ i ] ;}i n t main ( ){

. . .// Ui tvoer ing van de k e rn e l vanuit de CPU code//Deze wordt u i tgevoerd met acht 1D blokken van e l k 256 dradenProductKernel1D <<<8,256>>>(input , output ) ;. . .

}

Code Fragment 2.1: Een voorbeeld van een kernel. Elk element van een ingangsrij wordtvermenigvuldigd met een factor 2.

Bij de uitvoering van een kernel op de GPU worden draden niet individueel toegekend aaneen multiprocessor, maar deze worden per blok van draden toegekend. Elk blok wordt maaraan één multiprocessor toegekend. Een multiprocessor kan meerdere blokken tegelijkertijdverwerken. Deze blokken delen dan de middelen van de multiprocessor. De feitelijke verwer-king van een blok gebeurt met een nog kleinere granulariteit. De draden in het blok wordennamelijk nog onderverdeeld in kleinere blokjes van vaste grootte, genaamd warps. Slechts éénwarp is tegelijk op een multiprocessor in uitvoering. De grootte van een warp is hardwareafhankelijk, maar is voor alle NVIDIA GPUs tot op heden 32 draden.

Figuur 2.3 geeft ook het verband weer tussen de CPU en GPU. Het is de CPU die aan deGPU de opdracht geeft om een kernel uit te voeren. De uitvoering van een kernel door deGPU gebeurt asynchroon ten opzichte van de CPU. Met andere woorden, de CPU moet nietwachten totdat de GPU de kernel heeft uitgevoerd. Aangezien de CPU niet blokkeert, kandeze meerdere kernelinvocaties uitvoeren, deze zullen dan in de juiste volgorde door de GPUverwerkt worden. Bij grotere algoritmes die uit meerdere kernels bestaan, moet daarom ookaandacht besteed worden aan de CPU code, daar deze de GPU op tijd moet voorzien vannieuwe uit te voeren kernels.

Synchronisatie van draden

De uitvoering van blokken en draden gebeurt concurrent op de GPU, met ander woorden devolgorde van uitvoering ligt niet op voorhand vast. Zo kan het voorkomen dat blok b + 1eerder uitgevoerd wordt door de GPU dan blok b en dat draad d eerder uitgevoerd wordt dandraad d+ 1.

Hoewel de uitvoering concurrent gebeurt is het wel mogelijk om te synchroniseren. Synchro-niseren houdt in dat alle draden wachten op elkaar op een bepaald punt tijdens de uitvoering.Als elke draad bij dit punt gekomen is dan gaat de concurrente uitvoering van elke draadverder.

Het CUDA model voorziet enkel functies voor synchronisatie tussen de draden van een blok.Deze synchronisatie wordt ook wel bloksynchronisatie genoemd. Synchronisatie tussen blok-ken onderling is niet mogelijk tijdens de uitvoering van een kernel. De enigste mogelijkheid

Hoofdstuk 2. GPGPU technologie 11

om dit te bekomen is door twee aparte kernels uit te voeren aangezien kernels sequentieelworden uitgevoerd op de GPU.

Het feit dat er geen mogelijkheid is tot synchronisatie tussen de blokken onderling houdt verderook in dat er geen communicatie mogelijk is tussen de draden van twee verschillende blokkentijdens de uitvoering van een kernel. Enkel draden die behoren tot hetzelfde blok kunnen on-derling data uitwisselen. Door dit gebrek aan communicatie kunnen er geen afhankelijkhedenzijn tussen blokken en moeten deze steeds onafhankelijk van elkaar hun bewerkingen kunnenuitvoeren.

Geheugenhiërarchie

De geheugenhiërarchie in het softwaremodel bestaat uit drie niveaus:

• lokaal geheugen

• gedeeld geheugen

• globaal geheugen

Deze drie geheugens verschillen van elkaar door de zichtbaarheid die ze hebben. Zo beschiktelke draad over lokaal geheugen dat enkel door deze draad toegankelijk is. Met andere woor-den enkel deze draad kan lezen en schrijven naar dit geheugen. Elke draad van een blok kanlezen en schrijven naar het gedeeld geheugen van dit blok, draden van andere blokken niet.Het globaal geheugen ten slotte is toegankelijk voor alle draden.

Deze geheugens worden gebruikt in het software model en hebben de volgende equivalentenin de GPU hardware:

• Het lokaal geheugen komt overeen met de registers van de multiprocessoren. Indien eente grote hoeveelheid registers vereist is, dan zal de compiler het hoofdgeheugen van deGPU als lokaal geheugen gebruiken.

• Het gedeeld geheugen komt overeen met het gedeeld geheugen op elke multiprocessor.

• Het globaal geheugen komt dan weer overeen met het hoofdgeheugen van de GPU.

Omdat de toegang tot het globale geheugen een grootteorde trager is dan toegang tot hetgedeeld geheugen, moet er zoveel mogelijk voorkeur gegeven worden aan dit laatste type vangeheugen bij het ontwerp van een kernel.

Over het globale geheugen moet nog een belangrijke opmerking meegegeven worden aan delezer. Indien de draden van een halve warp (een halve warp slaat op de 16 eerste of de 16laatste draden van een warp) toegang tot het globaal geheugen vereisen, dan kunnen dezegeheugentoegangen onder bepaalde voorwaarden samengevoegd worden tot één geheugentoe-gang. Dit zorgt voor een beter gebruik van de bandbreedte tussen de multiprocessoren enhet globale geheugen en heeft een grote invloed op de prestatie van een kernel. Omdat dit inlatere hoofdstukken nog aanbod komt, wordt dit nog iets dieper besproken.

Hoofdstuk 2. GPGPU technologie 12

Halve warp van draden

64 byte gealigneerd segment

Figuur 2.5: Gealigneerde en sequentiële geheugentoegang van een halve warp van draden.Uiteindelijk zal maar één geheugentoegang vereist zijn.

Halve warp van draden

64 byte gealigneerd segment

Figuur 2.6: Niet-gealigneerde geheugentoegang van een halve warp van draden. Voor elkedraad apart zal een geheugentoegang plaats vinden.

Het globaal geheugen kan gezien worden als een set van gealigneerde segmenten van 16 woor-den. Eén woord komt overeen met vier bytes, wat de grootte is van een integer of een float.De totale grootte van een segment is dan 64 bytes. Indien de kde draad van een halve warpeen geheugenoperatie uitvoert op het kde woord in een segment, zoals in figuur 2.5, danzal de geheugenoperaties van alle draden van de halve warp samengevoegd worden naar ééngeheugenoperatie van 64 bytes. Indien echter de geheugentoegangen niet mooi gealigneerdworden, zoals in figuur 2.6, dan zal voor elke draad afzonderlijk een geheugentoegang gebeu-ren8. Met andere woorden 16 aparte geheugentoegangen zullen dan uitgevoerd worden, wateen negatieve impact zal hebben op de prestatie.

Overige geheugens

Naast het globaal geheugen zijn er nog twee speciale alleen-lezen geheugens toegankelijk vooralle draden, namelijk het constant geheugen en het textuurgeheugen. Beiden hebben een spe-cifiek gebruik.

Het gebruik van constant geheugen is aangeraden wanneer een groot aantal draden lezen uit8Dit is zo voor de gebruikte NVIDIA 8800GT. Bij nieuwere generaties van GPUs zijn de voorwaarden voor

een samengevoegde geheugentoegang minder strikt. In de CUDA C Best Practices Guide [5] wordt dit in meerdetail besproken.

Hoofdstuk 2. GPGPU technologie 13

dezelfde geheugenlocatie. De toegang tot deze geheugenlocatie zal parallel kunnen gebeuren,in tegenstelling tot het globaal geheugen en het textuurgeheugen. Dit geheugen beschikt ookover een snel tussengeheugen waar gelezen data tijdelijk zal opgeslagen worden nadat hetis gelezen. Indien andere draden dan dezelfde data lezen kan deze snel worden aangeleverdvanuit het tussengeheugen.

Het CUDA raamwerk biedt toegang tot een deel van de functionaliteit van texturen, hoeweldeze typisch enkel gebruikt worden voor grafische toepassingen. Om gebruik te maken vantextuurgeheugen is het voor de programmeur slechts nodig om een lineair gebied in het glo-baal geheugen te binden aan een textuurreferentie. Via de textuurreferentie kan dit gebieddan als een textuur gebruikt worden in een kernel.

Er is één groot voordeel van het gebruik van textuurgeheugen boven het gewone globaal ge-heugen. Het textuurgeheugen maakt namelijk gebruik van een cache. Hierin wordt tijdelijkopgehaalde data opgeslagen, waardoor draden die deze data vereisen deze uit de cache kun-nen lezen. Dit vermijdt de tragere toegang naar het hoofdgeheugen. Het grote nadeel vantextuurgeheugen is dat het slechts primitieve datatypes toelaat (integers en floats).

Het textuurgeheugen is vooral aangewezen wanneer de te lezen data spatiale lokaliteit ver-toont, maar niet correct gealigneerde geheugentoegangen zou veroorzaken indien globaal ge-heugen in de plaats zou gebruikt worden. Door de cache kunnen al deze extra geheugentoegan-gen zoveel mogelijk vermeden worden. Indien gebruik gemaakt wordt van textuurgeheugenzal bijvoorbeeld het toegangspatroon uit figuur 2.6 niet leiden tot 16 aparte geheugentoegan-gen. Er zullen uiteindelijk maar twee geheugentoegangen plaats vinden, één voor elk segmentvan 64 bytes.

2.3 Factoren voor efficiënte uitvoering op de GPU

In de voorgaande sectie werd de GPU architectuur en het CUDA software model besproken.Wat het voorgaande in de praktijk betekent voor het implementeren van een algoritme op deGPU wordt in deze sectie toegelicht. Meer bepaald wordt besproken hoe de GPU ten vollekan benut worden. Dit is belangrijk om tot een zo performante uitvoering mogelijk te komenvan een algoritme en speelt hierdoor een belangrijke rol bij de overbrenging van een algoritmenaar de GPU. Er zijn twee zaken waar rekening mee moet gehouden worden:

• De mate van parallellisatie van het algoritme

• De GPU architectuur

De volledige set van richtlijnen wordt uitgebreid besproken in de CUDA C Best PracticesGuide [5]. Hieronder worden de belangrijkste verder toegelicht.

2.3.1 De mate van parallellisatie van het algoritme

Waarschijnlijk het meest belangrijke om tot een performante uitvoering te komen op de GPUis de mate van parallellisatie van het algoritme. De GPU is gemaakt voor parallelle uitvoe-

Hoofdstuk 2. GPGPU technologie 14

ring van duizenden draden en zal dan ook slechts enkel bij parallelle algoritmes goed presteren.

Stel bijvoorbeeld dat het volgende sequentiële algoritme moet worden uitgevoerd op de GPU:

for n = 1→ N doo(n) = y(n) + x(n)

end for

Algoritme 1: Een sequentieel sommatie algoritme

Een rechtstreekse overbrenging van dit algoritme op de GPU zou inhouden dat één draad ditalgoritme uitvoert. Dit is echter weinig doordacht en zal weinig performant zijn. Dit typevan algoritme kan echter wel eenvoudig geparallelliseerd worden. Het is namelijk zo dat elkeiteratie van de for lus onafhankelijk is van de voorgaande iteraties. Met andere woorden menkan elke iteratie in parallel uitvoeren:

for all n in parallel doo(n) = y(n) + x(n)

end for

Algoritme 2: Een parallel sommatie algoritme

Dit parallel algoritme zal wel performant kunnen uitgevoerd worden op de GPU, dit in te-genstelling tot het sequentieel algoritme.

Samengevat moet er altijd getracht worden een sequentieel algoritme te vervangen door eenequivalent parallel algoritme. Dit is echter niet altijd even eenvoudig in de praktijk. Sommigealgoritmes zijn op het eerste zicht niet parallelliseerbaar doordat ze bijvoorbeeld recursiebevatten. Een voorbeeld hiervan is het bepalen van de cumulatieve som van een rij:

y(0) = x(0)for n = 1→ N doy(n) = y(n− 1) + x(n)

end for

Algoritme 3: Een sequentieel algoritme voor de bepaling van de cumulatieve som van een rij

Dit sequentieel algoritme is niet in parallel uitvoerbaar, maar er bestaat wel een alternatiefparallel algoritme dat het zelfde resultaat kan bekomen, namelijk het prefixsom algoritme. Inhet volgende hoofdstuk komt dit algoritme aan bod naast nog enkele andere.

2.3.2 De GPU architectuur

Om performant te zijn op de GPU zal een parallel algoritme echter niet alleen voldoende zijn.De GPU architectuur en het bijhorende programeermodel moeten ook in rekening gebracht

Hoofdstuk 2. GPGPU technologie 15

worden. Dit wordt hieronder verder besproken.

De bezettingsgraad van de multiprocessoren

Bij het CUDA softwaremodel werd uitgelegd dat de totale verzameling draden opgedeeldwordt in blokken en dat het deze blokken zijn die in hun geheel op een multiprocessor wordenuitgevoerd. Deze verdeling is echter niet arbitrair en ze is van belang om tot goede prestatieste komen.

Beschouw bijvoorbeeld de kernel die het parallel algoritme 2 uitvoert:

__global__ void SommatieKernel1D ( f l o a t ∗ input1 , f l o a t ∗ input2 , f l o a t ∗ output ){const unsigned i n t i = blockDim . x ∗ blockIdx . x + threadIdx . x ; //1D abs index

output [ i ] = input1 [ i ] + input2 [ i ] ;}

Code Fragment 2.2: De parallelle sommatie kernel

Indien men bijvoorbeeld twee rijen van elk 512 elementen wil sommeren, dan zal deze kerneluitgevoerd moeten worden met 512 draden. De verdeling van het aantal draden per blok envan het totaal aantal blokken wordt door de programmeur vastgelegd bij het uitvoeren vande kernel. Een mogelijke keuze zou zijn om de kernel uit te voeren met één blok van 512draden. Dit zal echter voor onderbenutting van de multiprocessoren leiden. Er zal namelijkmaar één multiprocessor aan het werk zijn.

Het andere extremum 512 blokken van elk één draad zal ook tot onderbenutting leiden. Hierzal elke multiprocessor aan het werk zijn, maar elke processor zal slechts 1

32ste van zijn maxi-male uitvoeringscapaciteit benutten. Dit komt omdat de multiprocessor de draden van eenblok normaal per warp van 32 draden tegelijk verwerkt. Hier is er echter maar één draad inhet blok wat dus niet efficiënt is.

De beste keuze is om het aantal draden T per blok als een veelvoud van de warp groottete nemen, T = 32n. Het aantal blokken B is dan simpelweg gelijk aan B = 512/T . Ermoet hierbij nog vermeld worden dat het aantal draden per blok beperkt is door het CUDAraamwerk. Zo is bijvoorbeeld het maximum aantal draden voor een CUDA 1.1 GPU beperkttot 512 draden. In de CUDA C Programming Guide [1] worden deze limieten voor elk vande verschillende CUDA architecturen besproken.

Naast een correct aantal draden per blok kan ook het aantal blokken dat tegelijk in uitvoeringis op de multiprocessor een invloed hebben op de prestatie. Indien bijvoorbeeld een kernel veeltoegang tot het globaal geheugen vereist, dan kan deze vertraging in het geheel of gedeelte-lijk verborgen worden indien meerdere blokken tegelijk in uitvoering zijn op de multiprocessor.

Het aantal blokken dat tegelijk uitgevoerd kan worden op een multiprocessor is wederombeperkt door het CUDA raamwerk. Dit door beperkingen op het aantal blokken tegelijk inuitvoering per multiprocessor en op het aantal draden dat tegelijkertijd in uitvoering kanzijn per multiprocessor. Bij een GPU van de CUDA 1.1 architectuur bijvoorbeeld zijn deze

Hoofdstuk 2. GPGPU technologie 16

limieten respectievelijk acht blokken en 768 draden. De CUDA C Programming Guide [1]biedt wederom informatie hierover voor de overige architecturen.

Naast de limieten opgelegd door het CUDA raamwerk zijn er nog andere factoren die het aan-tal blokken per multiprocessor kunnen beïnvloeden. Deze zijn gerelateerd aan de beschikbaremiddelen waarover een multiprocessor beschikt. Zo is het gedeeld geheugen van een multi-processor beperkt en moet dit geheugen gedeeld worden tussen de verschillende blokken inuitvoering. Dit betekent dat het totaal aantal blokken dat tegelijk in uitvoering kan zijn medezal bepaald worden door het geheugen dat een blok vereist. Bij oplopende geheugenvereistenzal dit aantal zakken waardoor minder efficiënt vertragingen zullen worden opgevangen.

Toegang tot het globaal geheugen

Een tweede belangrijke invloed op de prestatie wordt bepaald door de manier waarop en hetaantal globaal geheugen toegangen dat de draden moeten uitvoeren.

Zoals vermeld in het vorige deel kunnen geheugentoegangen van de draden samengevoegdworden naar één geheugentoegang. De voorwaarde hiervoor was dat de draden in een halvewarp, zijnde de eerste 16 of de laatste 16, gealigneerde en sequentiële toegang tot het globaalgeheugen vereisen. Is dit niet het geval dan vindt er voor elke draad in de warp apart eengeheugentoegang plaats.

Praktisch houdt dit in dat indien draad i van een warp data inleest uit of wegschrijft naareen rij op positie 16n+ i, met n een natuurlijk getal, dit samengevoegd zal gebeuren met deandere draden van deze warp. In andere gevallen zal dit niet zo zijn.

Als gelezen moet worden volgens een niet-gealigneerd, maar wel sequentieel patroon kan even-tueel gebruikgemaakt worden van het textuurgeheugen. Door de cache moet niet voor elkeleesoperatie uit het hoofdgeheugen gelezen worden.

Naast het correcte toegangspatroon is het verder belangrijk om in het algmeen toegang tothet globaal geheugen zoveel mogelijk te beperken. Dit omdat een geheugentoegang naar hetglobaal geheugen al snel enkele honderden cycli kan duren.

Beschouw bijvoorbeeld het volgende algoritme:

for n = 1→ N dofor m = 1→M doo(n,m) = 1

3 [x(n− 1,m) + x(n,m) + x(n+ 1,m)]end for

end for

Algoritme 4: Een sequentieel algoritme voor de uitmiddeling van elke pixel van een afbeelding

Dit is een algoritme dat van een ingangsbeeld een uitgangsbeeld creëert waarbij elke pixel vanhet ingangsbeeld vervangen wordt door het gemiddelde van deze pixel met de pixel erboven

Hoofdstuk 2. GPGPU technologie 17

en eronder.

Een naïeve aanpak voor een implementatie zou zijn om elke draad drie elementen te lateninlezen, het resultaat te laten berekenen en het weg te laten schrijven. Deze aanpak vraagtdus vier geheugentoegangen per draad.

Een betere aanpak is om gebruik te maken van gedeeld geheugen. Dit is geheugen dat ge-deeld is tussen de draden van een blok. Aangezien het zich op de multiprocessor bevindt,is de geheugentoegang tot dit geheugen typisch een grootteorde sneller dan tot het globaalgeheugen.

Bij deze aanpak wordt het beeld opgedeeld in niet-overlappende blokken. Elk blok van dra-den zal dan één van deze blokken voor zijn rekening nemen. De dimensie van het blok vandraden is hierbij dezelfde als deze van het overeenkomstige blok. In plaats van elke draad zijnvereiste data te laten inlezen, zal de data die het blok van draden vereist ingelezen worden.Dit houdt in dat elk blok van draden een gebied ter grootte van de blokgrootte plus nog tweeextra rijen, namelijk de rij boven en onder het blok zal inlezen in het gedeeld geheugen vanhet blok. Hierbij zullen sommige draden van het blok twee elementen inlezen om de pixelsvan de extra rijen in te lezen. Na het synchroniseren van de draden kan elke draad dan éénuitgangselement bepalen op basis van de pixels in het gedeeld geheugen.

De bovenstaande methode zal al een aanzienlijke snelheidswinst teweegbrengen. Verdere op-timalisaties kunnen zijn om elk blok van draden niet één, maar meerdere blokken te latenverwerken aangezien dit het aantal geheugentoegangen nog verder kan beperken.

Conditionele uitvoeringspaden

Een laatste belangrijke invloedsfactor is het aanwezig zijn van conditionele paden in de uitte voeren code. Een conditioneel pad is een pad dat genomen wordt indien aan een bepaaldeconditie voldaan is. Typisch zijn dit if-then-else of switch constructies, maar ook lussen (do,for en while) vallen hieronder.

Zoals eerder uiteengezet worden de draden van een blok per warp van 32 draden verwerkt dooreen multiprocessor. De verwerking van deze 32 draden gebeurt in parallel indien elke draaddezelfde instructies uitvoert. Bij een conditioneel pad in de code kan het voorkomen dat dedraden van een warp verschillende instructies moeten uitvoeren en dus een verschillend pad inde code volgen. Deze paden zullen sequentieel uitgevoerd worden door de hardware. Wanneerde verschillende paden uitgevoerd zijn, zal de uitvoering van alle draden van de warp opnieuwin parallel verder gezet worden. Het sequentieel verlopen van verschillende uitvoeringspadenis enkel het geval voor draden in dezelfde warp. Indien warp a en warp b verschillende padenvolgen dan heeft dit geen impact op uitvoeringssnelheid, omdat de multiprocessor maar éénwarp tegelijk verwerkt.

Het is duidelijk dat dit een factor is om rekening mee te houden. Indien elke draad vaneen warp een verschillend pad volgt, zal de volledige uitvoering van deze draden sequentieelverlopen, wat zijn impact zal hebben op de uitvoeringssnelheid van een algoritme.

Hoofdstuk 3

Generieke bouwstenen voor algoritmesop de GPU

Een groot en complex algoritme implementeren op de GPU is geen eenvoudige taak. Zekeral niet als de implementatie van de grond af aan moet ontwikkeld worden. Daarom wordtin dit hoofdstuk gekeken hoe dit efficiënter kan verlopen. Hiervoor zal het concept van eenbouwsteen geïntroduceerd worden waardoor het implementeren van een algoritme op de GPUkan vereenvoudigd worden.

Dit hoofdstuk is als volgt georganiseerd: in de eerste sectie wordt het concept van een bouw-steen toegelicht; in de daaropvolgende sectie 3.2 wordt een overzicht gegeven van reeds be-staande vaak voorkomende GPU bouwstenen.

3.1 Het concept van een bouwsteen

Bij het ontwikkelen van software zal men typisch nooit een algoritme in zijn geheel implemen-teren. Men kiest voor een gestructureerde aanpak waarbij het algoritme opgesplitst wordt inkleinere, meer generieke algoritmes. Deze worden dan aaneengeschakeld om de uiteindelijkefunctionaliteit van het algoritme vast te leggen. De subalgoritmes zelf kunnen op hun beurtopnieuw bestaan uit een aaneenschakeling van algoritmes, enzoverder. De opbouw van eenalgoritme kan op deze manier in een piramidestructuur voorgesteld worden zoals in figuur3.1. Op het hoogste niveau staat het volledige algoritme en op de niveaus daaronder staande verschillende subalgoritmes waaruit het algoritme is opgebouwd.

Sommige van deze subalgoritmes zullen ook in andere algoritmes steeds terugkeren, denk hier-bij bijvoorbeeld aan een sorteeroperatie. Deze subalgoritmes kunnen daarom gezien wordenals een soort van generieke bouwstenen, aangezien ze typisch een onderdeel van een groteralgoritme zullen vormen en herbruikbaar zijn bij andere algoritmes. Andere subalgoritmeszullen echter eigen zijn aan het algoritme en zullen nog specifiek geïmplementeerd moetenworden.

Deze aanpak kan ook gevolgd worden om een groot en complex algoritme naar de GPU overte brengen. Het algoritme wordt opgesplitst in kleinere componenten die aaneen worden ge-

18

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 19

Algoritme

Subalgoritme Subalgoritme Subalgoritme

Subalgoritme Subalgoritme Subalgoritme Subalgoritme

Figuur 3.1: De piramidale opbouw van een algoritme.

schakeld. Deze componenten worden dan één na één op de GPU gebracht, ofwel in hun geheelofwel door ze nog verder op te splitsen.

De grote moeilijkheidsgraad hierbij zal zijn om de GPU zo efficiënt mogelijk te gebruiken.Hierdoor zullen sommige algoritmes vervangen moeten worden door equivalente algoritmesdie geschikter zijn voor uitvoering op de GPU. Van een aantal vaak voorkomende opera-ties bestaan er al efficiënte algoritmes voor de uitvoering op GPU. Deze komen aan bod inde volgende sectie. Andere zullen nog door de programmeur moeten geïmplementeerd worden.

Het uiteindelijke GPU algoritme wordt dan gevormd door deze componenten aaneen te schake-len. Dit aaneenschakelen gebeurt in de CPU code. Een GPU implementatie van een algoritmekan hierdoor gezien worden als een sequentiële aaneenschakeling van subalgoritmes, waarbijelk van deze subalgoritmes op de GPU wordt uitgevoerd.

3.2 Overzicht van GPU bouwstenen

In deze sectie wordt een kort overzicht gegeven van reeds bestaande GPGPU realisaties vanenkele vaak voorkomende operaties. Enkele van deze algoritmes en/of de concepten erachterwerden gebruikt bij de implementatie van het beeldrestauratie algoritme.

• Een prefixsom algoritme is een algoritme dat de cumulatieve som bepaalt van een rij.Het sequentieel algoritme voor deze bepaling kan als volgt in pseudocode voorgesteldworden:

y(0) = x(0)for n = 1→ N doy(n) = y(n− 1) + x(n)

end for

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 20

Vanwege de afhankelijkheden tussen de verschillende iteraties, is dit algoritme niet uit-voerbaar in parallel. Het prefixsom algoritme laat de bepaling toe van de cumulatievesom op een manier die efficiënter is voor parallelle architecturen. Het doet dit door detotale prefixsom te bepalen in een sequentie van stappen. Elk van deze stappen is inparallel uitvoerbaar. In pseudocode kan dit algoritme als volgt worden weergegeven:

for d = 1→ log2N dofor all n in parallel do

if n ≥ 2d−1 thenx(n) = x(n− 2d−1) + x(n)

end ifend for

end for

Hierbij stelt x(n) zowel de ingangs- als uitgangsrij voor en N het totaal aantal elementenvan de rij x(n). De indexen n worden in parallel geëvalueerd aan de voorwaarde n ≥2d−1. Indien hieraan voldaan wordt zal in parallel de operatie x(n) = x(n−2d−1)+x(n)uitgevoerd worden. Een visuele voorstelling van dit algoritme voor een rij van acht ele-menten wordt gegeven in figuur 3.2.

X0 X1 X2 X3 X4 X5 X6 X7

∑ Xii=0..0

∑ Xii=0..1

∑ Xii=1..2

∑ Xii=2..3

∑ Xii=3..4

∑ Xii=4..5

∑ Xii=5..6

∑ Xii=6..7

∑ Xii=0..0

∑ Xii=0..1

∑ Xii=0..2

∑ Xii=0..3

∑ Xii=1..4

∑ Xii=2..5

∑ Xii=3..6

∑ Xii=4..7

∑ Xii=0..0

∑ Xii=0..1

∑ Xii=0..2

∑ Xii=0..3

∑ Xii=0..4

∑ Xii=0..5

∑ Xii=0..6

∑ Xii=0..7

d = 1

d = 2

d = 3

d = 4

Figuur 3.2: Berekening van de prefixsom van een rij met acht elementen.

Dit algoritme is niet zondermeer overbrengbaar naar de GPU. Het probleem hierbij isdat het CUDA model geen synchronisatie toelaat tussen draden die niet behoren tothet zelfde blok. Deze synchronisatie is vereist tussen elk niveau van het algoritme. Dusofwel moet dit algoritme maar met één blok uitgevoerd worden, wat niet efficiënt isaangezien er dan maar één multiprocessor aan het werk is, ofwel moet een intelligentereaanpak gevolgd worden. In [6] wordt een implementatie voorgesteld die de rij in eersteinstantie opsplitst in kleinere deelrijen. In een eerste stap zal elk blok van draden dande (sub)prefixsom van een deelrij bepalen. Deze worden dan daarna nog samengesteldtot de prefixsom van de volledige rij in een tweede stap. Dit samenstellingsproces houdtin dat het laatste element van elke subprefixsom van een deelrij verzameld wordt in

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 21

een nieuwe rij. Op deze nieuwe rij wordt dan een prefixsom uitgevoerd. Het elementi van deze prefixsom wordt daarna opgeteld bij subprefixsom i− 1, bij subprefixsom 0wordt niets opgeteld. Dit levert dan de prefixsom op van de volledige rij. Dit proceswordt geïllustreerd in figuur 3.3. Codevoorbeelden van de prefixsom zijn te vinden inde CUDA Software Development Kit (SDK) [7] en de CUDPP bibliotheek [8].

Rij van ingangswaarden

Prefixsom van ingangsrij

SubPrefixsom 0

Prefixsom laatste element van elke subprefixsom

+ + + +

Tel bij elke subprefixsom het overeenkomstig element op

Prefixsom 0 Prefixsom 1 Prefixsom 2 Prefixsom 3 Prefixsom 4

SubPrefixsom 1 SubPrefixsom 2 SubPrefixsom 3 SubPrefixsom 4

Figuur 3.3: Berekening van de totale prefixsom van een rij.

Een mogelijk gebruik van de prefixsom is om een gemiddelde te bepalen van de eerstek elementen van een rij. Hiervoor wordt van de rij een prefixsom genomen, waarna hetkde element gedeeld door k het gemiddelde teruggeeft van de eerste k elementen.

Er bestaan een aantal varianten van het prefixsom algoritme. Een eerste variant is hetgesegmenteerde prefixsom algoritme [6] dat niet de cumulatieve som bepaalt van de vol-ledige rij, maar de cumulatieve som van deelrijen met arbitraire lengte van de originelerij. In de twee volgende hoofdstukken worden nog twee andere varianten besproken,meer bepaald het algemene prefixsom algoritme en het partiële prefixsom algoritme,die respectievelijk in hoofdstukken 4 en 5 worden besproken. De eerste variant is eenalgemenere vorm van het prefixsom algoritme en kan als alternatief hiervoor gebruiktworden. De tweede variant is een nieuwe bouwsteen en vindt onder andere toepassingin het beeldrestauratie algoritme beschreven in hoofdstuk 7.

• Een tweede vaakvoorkomende operatie is de reductie. Deze functie reduceert een rijnaar één element volgens een bepaalde operatie. Bijvoorbeeld een somreductie zal de

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 22

som bepalen van alle elementen van een rij. Een sequentiële bepaling van deze somgebeurt als volgt:

for n = 1→ N doz = z + x(n)

end for

Hierbij is er een afhankelijkheid tussen de verschillende iteraties waardoor dit in paralleluitvoeren niet mogelijk is. Net zoals bij een prefixsom algoritme echter kan deze sombepaald worden door in verschillende niveaus te werken waarbij elk niveau in parallelkan uitgevoerd worden. In figuur 3.4 wordt het reductie algoritme visueel weergegeven.Dit algoritme heeft een boomstructuur, waarbij op elk niveau de resultaten van hetvorige niveau worden samengesteld tot uiteindelijk slechts één waarde meer overblijft.

3 1 2 1 2 5 1 0

4 3 7 1

7 8

15

Figuur 3.4: Het somreductie algoritme.

De operatie die toegepast wordt bij het samenstellen van de elementen van een rij isniet beperkt tot enkel een sommatie. Andere mogelijke operaties zijn onder andere eenminimum-, maximum- en een productoperatie.

Een CUDA implementatie van dit algoritme wordt beschreven in [9]. Deze implementa-tie gebruikt één kernel om één niveau van de reductie uit te voeren. Deze kernel wordtdan meermaals uitgevoerd telkens op het resultaat van de voorgaande kernelinvocatie.Elk blok van draden zal hierbij telkens een deel van de ingangsrij reduceren tot éénelement. Hoe groot deze delen zijn die elk blok reduceert is een parameter van hetalgoritme. De broncode is terug te vinden in de CUDA SDK [7], een alternatief is deCUDPP bibliotheek [8].

• Bij een sorteeroperatie zal een rij gesorteerd worden naar toenemende of afnemendewaarden. Op parallelle architecturen wordt hiervoor een verdeel-en-heers techniek ge-hanteerd om de verschillende multiprocessoren ten volle te benutten. Dit houdt in dathet sorteren van de volledige rij gepartitioneerd wordt. Een veelgebruikt algoritme ishet radix sort algoritme. Dit algoritme sorteert waarden op basis van hun voorstellingin bits. Indien de waarden bestaan uit b bits, dan zal het algoritme in b stappen devolledige verzameling sorteren. Het doet dit door in elke stap de ide bit van de waarden

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 23

met elkaar te vergelijken en op basis hiervan de te sorteren verzameling te partioneren.In de eerste stap wordt de minst significante bit vergeleken, deze zal de verzamelingopdelen in twee partities, namelijk één waarbij deze bit 0 is en een andere waarbij deze1 is. Dit wordt herhaald voor elke volgende bit. Het aantal partities zal bij elke stapverdubbelen en deze kunnen onafhankelijk en dus parallel van elkaar verder verwerktworden. Een CUDA implementatie van dit type van algoritme wordt beschreven in [10]en codevoorbeelden hiervan zijn te vinden in de CUDA SDK [7] en de CUDPP biblio-theek [8]. Naast dit algoritme zijn er nog enkele andere algoritmes in de literatuur tevinden, meer bepaald bitonic sort [11][12] en een merge sort algoritme [13][10].

• Een histogram geeft het aantal keer dat een element optreedt in een rij weer. Een his-togram kan bepaald worden met het volgende sequentieel algoritme:

for n = 0→ N dohistogram[data[i]] + +

end for

Dit lijkt eenvoudig parallelliseerbaar. Men kan bijvoorbeeld elke draad één elementlaten verwerken. Om dit echter correct te laten verlopen zal er gebruikgemaakt moetenworden van een atomaire sommatie instructie. Deze instructie zal ervoor zorgen datmaar één draad tegelijk toegang heeft tot een bepaald histogramelement. Mocht ditniet het geval zijn dan kan het gebeuren dat de sommatie die een draad uitvoerde ver-loren wordt doordat een andere draad tegelijkertijd zijn sommatie uitvoert/wegschrijft.Door deze atomaire sommatie wordt dus een deel van de parallelle uitvoering sequentieel.

Voorgestelde GPGPU implementaties [14, 15, 16, 17] trachten deze seriële uitvoeringte minimaliseren. Hiervoor wordt steeds een verdeel-en-heers strategie toegepast. Deingangsrij wordt opgesplitst in deelrijen waarvan elk afzonderlijk een histogram wordtbepaald. Deze subhistogrammen worden dan verder samengesteld tot het volledigehistogram. Voor details omtrent de implementaties wordt verwezen naar de artikels.Codevoorbeelden zijn te vinden in de CUDA SDK [7] en de NVIDIA PerformancePrimitives bibliotheek [18].

• De convolutie is een operatie die vaak gebruikt wordt bij het toepassen van filters opsignalen. Ze kan symbolisch voorgesteld worden door:

(u⊗ v)(k) =m∑

i=−mu(i)v(k − i) (3.1)

Een CUDA implementatie van de convolutie wordt beschreven in [19]. Hierbij wordtde rij opgesplitst in deelrijen. In de implementatie wordt aan elk van de deelrijen éénblok van draden toegekend met het aantal draden van dit blok gelijk aan het aantalelementen in de deelrij. Elke draad bepaalt dan één uitgangselement k via uitdrukking3.2. Hiervoor wordt de data niet ingelezen per draad, maar per blok van draden ingedeeld geheugen, om globaal geheugen bandbreedte zoveel mogelijk te beperken. Voorverdere details wordt verwezen naar het artikel. De code horend bij deze implementatieis te vinden in de CUDA SDK [7].

Hoofdstuk 3. Generieke bouwstenen voor algoritmes op de GPU 24

• De discrete Fouriertransformatie is een veelgebruikte transformatie in het domein vande signaalanalyse. Het transformeert een rij xn (n = 0 . . . N − 1) in een rij Xk (k =0 . . . N − 1) volgens:

Xk =N−1∑n=0

xn exp−2iπNkn k = 0 . . . N − 1 (3.2)

De complexiteit om dit algoritme uit te voeren is O(n2). Er bestaan echter efficiënterealgoritmes die de Fouriertransformatie kunnen bepalen in O(n logn). Deze worden FastFourier Transform (FFT) algoritmes genoemd. Eén van deze algoritmes is het Cooley-Tukey algoritme [20]. Dit algoritme voert de Fourier transformatie van een rij met lengteN = RM uit door de transformatie uit te drukken als Fourier transformaties van lengteR en M . Deze transformaties kunnen op hun beurt dan verder recursief ontbondenworden. Op deze manier kan de transformatie efficiënter en in parallel verlopen. EenCUDA implementatie gebaseerd op dit algoritme wordt beschreven in [21]. Alternatieveimplementaties worden beschreven in [22]. Een bibliotheek [23] voor de uitvoering van deéén-, twee- en driedimensionale Fourier transformatie is verder voorzien door NVIDIA.

Naast deze operaties zijn er nog enkele bibliotheken beschikbaar die zich richten op specifiekedomeinen. De CUBLAS bibliotheek [24] en de CUSPARSE bibliotheek [25] bevat functies uithet domein van de lineaire algebra. De reeds eerder vermelde NVIDIA Performance Primitivesbibliotheek [18] is ontwikkeld met de bedoeling om beeld- en videoverwerking te versnellen.Deze bevat naast enkele filterfuncties onder andere ook kleurconversiefuncties en statistischefuncties.

Hoofdstuk 4

Het berekenen van een algemeneprefixsom op de GPU

Het originele prefixsom algoritme beschreven in het voorgaande hoofdstuk vormt een belang-rijk onderdeel in verschillende algoritmes. In dit hoofdstuk wordt een algemene versie van hetprefixsom algoritme bestudeerd. Deze variant heeft meer toepassingsmogelijkheden en kanals alternatief gelden voor het originele algoritme.

De organisatie van dit hoofdstuk is als volgt: in sectie 4.1 wordt een beschrijving gegevenvan de meer algemene variant, de algemene prefixsom. In sectie 4.2 wordt dan een parallelalgoritme voorgesteld om de algemene prefixsom te bepalen. In sectie 4.3 wordt een nieuwalgoritme voorgesteld om dit te berekenen op de CUDA architectuur. In sectie 4.4 ten slottevolgen nog de behaalde uitvoeringsresultaten.

4.1 Inleiding

De algemene prefixsom kan als volgt uitgedrukt worden:

y(0) = αx(0)for n = 1→ N doy(n) = βy(n− 1) + αx(n)

end for

Hierbij stelt x(n) de rij met de beginwaarden voor, y(n) de rij met eindwaarden en N delengte van x(n). De coëfficiënten β en α stellen reële waarden voor.

Het verschil met de gewone prefixsom zit hem in de extra termen β en α die toegevoegd zijn.Hierdoor kan een meer algemene prefixsom bepaald worden, vandaar ook de naam ervan.Indien beide termen gelijk zijn aan één dan is de algemene prefixsom gelijk aan de gewoneprefixsom.

De algemene prefixsom operatie kent enkele toepassingen en kan onder andere gebruikt wordenom een Infinite Impulse Response (IIR) filter met één pool te implementeren.

25

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 26

4.2 Een parallel algoritme om de algemene prefixsom te bepalen

Het algemene prefixsom probleem toont veel verwantschap met het originele prefixsom pro-bleem. Het verbaast dan ook niet dat het parallelle oplossingsalgoritme zeer gelijkaardigverloopt:

for d = 1→ log2N dofor all n in parallel do

if n ≥ 2d−1 thenx(n) = β2d−1

x(n− 2d−1) + αx(n)end if

end forend for

Algoritme 5: Het parallelle algemene prefixsom algoritme

Hierbij stelt x(n) zowel de ingangs- als uitgangsrij voor, N het totaal aantal elementen vande rij x(n) en α en β reële waarden. De indexen n worden in parallel geëvalueerd aande voorwaarde n ≥ 2d−1. Indien hieraan voldaan is, zal in parallel de operatie x(n) =β2d−1

x(n− 2d−1) + αx(n) uitgevoerd worden.

In tegenstelling tot het originele algoritme, zal in eerste instantie elk element vermenigvuldigdworden met een term α. Daarnaast zal nog vermenigvuldigd worden met een term β2d−1 bijhet overgaan naar het volgende niveau d. In figuur 4.1 wordt dit algoritme geïllustreerd.

d = 0

d = 1

d = 2

αX0 αX1 αX2 αX3

αX0

αX0

α ∑ β1-i Xii=0..1

α ∑ β2-i Xii=1..2

α ∑ β3-i Xii=2..3

α ∑ β1-i Xii=0..1

α ∑ β2-i Xii=0..2

α ∑ β3-i Xii=0..3

β β β

β2 β2

Figuur 4.1: Berekening van de algemene prefixsom van een rij met vier elementen.

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 27

4.3 Een nieuw algoritme voor de bepaling van de algemene prefix-som

4.3.1 Algemene beschrijving van het algoritme

In de literatuur werd gezocht naar implementaties van dit algoritme op GPU en andere mul-tiprocessorarchitecturen. Dit leverde echter geen resultaat op. Daarom is gekozen om eennieuw algoritme/implementatie uit te werken.

Net zoals bij het prefixsom algoritme, treedt ook hier het probleem op dat geen rechtstreekseimplementatie van het parallelle algoritme mogelijk is. Indien elke draad telkens één elementvan het volgende niveau bepaalt, dan zal het niet mogelijk zijn om een volledige algemeneprefixsom te bepalen. Dit komt doordat er geen communicatie mogelijk is tussen alle draden,maar enkel tussen de draden die behoren tot hetzelfde blok. Deze communicatie is nodigomdat per niveau gesynchroniseerd zou moeten worden tussen alle draden.

Aangezien hetzelfde probleem optrad bij het bepalen van de prefixsom, is voor dit nieuwealgoritme daar inspiratie uit gehaald. Meer bepaald zal ook in het nieuwe algoritme eenverdeel-en-heers aanpak gehanteerd worden. Door de volledige rij op te splitsen in deelrijenen daarvan de algemene prefixsom te bepalen, kan door deze samen te stellen de algemeneprefixsom van de volledige rij bepaald worden.

Het nieuwe algoritme zal in drie niveaus werken om de algemene prefixsom te bepalen. Meerbepaald zal de volledige rij in eerste instantie opgesplitst worden in deelrijen. Deze deelrijenzullen op hun beurt nogmaals opgesplitst worden in kleinere deelrijen. Op dit niveau wordtdan de algemene prefixsom van elke deelrij bepaald. Deze worden dan samengesteld tot deprefixsom van de deelrij op het hogere niveau. Na deze stap kan dan de algemene prefixsomvan de volledige rij bepaald worden.

De drie niveau opsplitsing vindt zijn oorsprong in de draadhiërarchie van de CUDA architec-tuur. De volledige verzameling draden wordt namelijk opgesplitst in blokken en deze wordenbij uitvoering nog verder opgesplitst in warps van 32 draden. In het algoritme zullen dedeelrijen van het laagste niveau overeen komen met de warps en de deelrijen van het hogerniveau met de blokken. Uit de algemene prefixsommen van de warps kan dan de algemeneprefixsom bepaald worden van het omvattende blok. Uit de algemene prefixsommen van deblokken kan de algemene prefixsom bepaald worden van de volledige rij.

De drie niveaus voor het bepalen van een algemene prefixsom worden als volgt benoemd:

• het intrawarp level: bepaling van de algemene prefixsom per warp

• het intrablok level: bepaling van de algemene prefixsom per blok

• het globale level: bepaling van de algemene prefixsom van de volledige rij

Hieronder wordt dit nieuwe algoritme voor de CUDA architectuur verder toegelicht. Hierbijwordt verondersteld dat de twee parameters van het algemene prefixsom algoritme, namelijkα en β gelijk zijn aan respectievelijk αin en βin. Verder moet ook nog opgemerkt wordendat er evenveel draden gebruikt worden als ingangselementen van de rij. Elke draad stemt

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 28

overeen met één element van deze rij.

Op het intrawarp level wordt de algemene prefixsom berekend per warp van 32 draden volgenshet algoritme beschreven in sectie 4.2 met als parameters α = αin en β = βin.

Eens op het intrablok niveau worden de algemene prefixsommen van de verschillende warpsbehorende bij het blok samengesteld tot de algemene prefixsom van dit blok. De sequentievan operaties op dit level zijn:

• Alle warps berekenen hun algemene prefixsom.

• Het laatste element van de algemene prefixsom van elke warp wordt in een tijdelijke rijondergebracht.

• Eén warp voert een algemene prefixsom met α = 1 en β = β32in uit op deze tijdelijke rij.

• Elke draad i (i = 0..31) van warp k (buiten warp 0) sommeert zijn berekende algemeneprefixsom uit stap 1 met het product van βi+1

in en het element op positie k − 1 van dealgemene prefixsom uit stap 3. In pseudocode:

PrefixsomBLOK [i+ 32k] = βi+1in PrefixsomTEMP [k − 1] + PrefixsomWARP [i]

Hierbij bevindt PrefixsomBLOK zich in globaal geheugen en PrefixsomTEMP samen metPrefixsomWARP in gedeeld geheugen. Synchronisatie tussen de draden van het blok zalvereist zijn tussen elke stap.

Op het globale level worden de algemene prefixsommen van elk blok samengebracht. Ditproces bestaat uit de volgende stappen:

• Alle blokken berekenen hun algemene prefixsom.

• Het laatste element van de algemene prefixsom van elk blok wordt in een tijdelijke rijondergebracht.

• Een algemene prefixsom met α = 1 en β = βTin (T = het aantal draden per blok) wordtuitgevoerd op deze tijdelijke rij.

• Elke draad t (t = 0..T-1) van blok b (buiten blok 0) sommeert zijn berekende prefixsomuit stap 1 met het product van βt+1

in en het element op positie b − 1 van de prefixsomuit stap 3. In pseudocode:

PrefixsomGLOBAAL[t+Tb] = βt+1in PrefixsomBLOKTEMP [b−1]+PrefixsomBLOK [t]

Hierbij bevinden zowel PrefixsomGLOBAAL, PrefixsomBLOKTEMP en PrefixsomBLOK

zich in globaal geheugen. Op het globale niveau zullen meerdere aparte kernelinvocatiesvereist zijn. Dit vanwege de noodzaak voor globale synchronisatie tussen de verschillendestappen. Het bepalen van de algemene prefixsom van de tijdelijke rij in stap 3 kan meerdere

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 29

toepassingen van het globale algemene prefixsom algoritme vereisen, indien het aantal blok-ken in stap 1 groter is dan de blokgrootte.

In figuur 4.2 worden de operaties van het intrablok en het globale niveau nogmaals schema-tisch weergegeven.

Rij van ingangswaarden

Algemene prefixsom van ingangsrij

Alg SubPrefixsom 0

++

Alg Prefixsom 0

Alg SubPrefixsom 1

Alg Prefixsom 1 Alg Prefixsom 2 Alg Prefixsom 3 Alg Prefixsom 4

β βT

+

β βT β βT β βT

+

Elke draad t (t=0..T-1) vermenigvuldigt het overeenkomstig element van de temporaire rij met βt+1 en telt dit op bij zijn corresponderend element in de subprefixsom

. . . . . . . . . . . .

Een algemene prefixsom wordt uitgevoerd op de laatste elementen van de subprefixsommen.

Alg SubPrefixsom 2 Alg SubPrefixsom 3 Alg SubPrefixsom 4

Figuur 4.2: Berekening van de totale algemene prefixsom van een blok/rij.

4.3.2 Implementatiedetails

Van het CUDA algoritme hierboven zijn twee verschillende versies ontwikkeld. In een eersteversie zal elke draad de vereiste β machten elk apart berekenen. Dit is echter niet efficiënt enzal de prestatie drukken. Daarom is een tweede versie ontwikkeld.

In deze versie wordt vooraleer de eigenlijke algemene prefixsom bepaald wordt, eerst alle ver-eiste machten van β bepaald. Dit benodige aantal is gelijk aan het aantal draden T per blok,

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 30

meer bepaald β tot βT . Via het prefixproduct algoritme kunnen deze snel bepaald worden:

for d = 1→ log2N dofor all n in parallel do

if n ≥ 2d−1 thenx(n) = x(n− 2d−1)× x(n)

end ifend for

end for

Algoritme 6: Het parallel prefixproduct algoritme

De implementatie van dit prefixproduct algoritme is nagenoeg identiek aan die van het prefix-som algoritme uit het voorgaande hoofdstuk, daarom zal hier niet dieper op ingegaan worden.

Om de vereiste machten te bepalen zal een rij met T elementen, die allemaal aan β gelijk zijn,als ingangswaarde gegeven worden aan het prefixproduct algoritme 6. Het resultaat is dan eenrij β...βT . Via gecachet constant/textuurgeheugen worden deze waarden dan gebruikt doorde draden in de kernels. De meeste geheugentoegangen naar de array van β machten zullenverlopen via de caches waardoor trage globaal geheugen toegangen zoveel mogelijk vermedenkunnen worden.

4.4 Resultaten en conclusie

In tabel 4.1 worden de resultaten weergegeven van de twee CUDA implementaties en wordtvergeleken met een CPU versie van het sequentiële algoritme uit sectie 4. Bij de resultatenvan versie twee is het opstellen van de β machten rij inbegrepen. Met het van en naar de GPUkopiëren van de ingangs- en uitgangsrij is geen rekening gehouden, aangezien de (algemene)prefixsom operatie typisch onderdeel zal vormen van een groter algoritme.

Uit deze tabel kan worden afgeleid dat de tweede CUDA implementatie die gebruik maaktvan vooraf bepaalde β machten superieur is qua prestatie in vergelijking met de eerste versiewaarin elke draad de machten apart bepaalt. Dit verschil is ruwweg een factor 2. Verderblijkt uit deze tabel dat de snelheidswinst ten opzichte van een sequentiële CPU versie heelhoog is, met een maximale snelheidswinst van een factor 9, 73.

Tabel 4.2 toont dan weer een vergelijking tussen de CUDA prefixsom en de CUDA algemeneprefixsom implementaties. Dat deze laatste minder performant is, valt te verwachten vanwegede extra bewerkingen. Het prestatieverlies blijft echter wel beperkt en neemt af met een groteraantal elementen.

Hoofdstuk 4. Het berekenen van een algemene prefixsom op de GPU 31

Uitvoeringstijd (ms)# elementen CPU GPU V1 GPU V2 Versnellingsfactor V2 t.o.v. CPU

65536 0,476 0,115 0,088 5,41262144 1,891 0,425 0,233 8,111048576 7,532 1,587 0,843 8,934194304 31,585 6,333 3,246 9,7316776960 123,739 25,243 12,877 9,61

Tabel 4.1: Uitvoeringstijd (ms) van het algemene prefixsom algoritme voor een verschillendaantal elementen van de twee CUDA implementaties en een sequentiële CPU versie (AMD643800+, C++ code).

Uitvoeringstijd (ms)# elementen Prefixsom Alg prefixsom V2 Versnellingsfactor V2 t.o.v. prefixsom

65536 0,066 0,088 0,75262144 0,206 0,233 0,881048576 0,767 0,843 0,914194304 3,014 3,246 0,9316776960 12,033 12,877 0,93

Tabel 4.2: Vergelijking tussen de prestatie van de CUDA prefixsom met versie twee van hetalgemene prefixsom algoritme.

Hoofdstuk 5

Het berekenen van een partiëleprefixsom op de GPU

Een tweede variant van de prefixsom wordt in dit hoofdstuk toegelicht. Deze variant, departiële prefixsom, kan net zoals het originele prefixsom algoritme een onderdeel vormen vaneen groter algoritme en wordt bijvoorbeeld in het beeldrestauratie algoritme beschreven inhoofdstuk 7 gebruikt.

De opbouw van dit hoofdstuk is als volgt: in sectie 5.1 wordt deze variant geïntroduceerd.Een aantal algoritmes voor de bepaling van deze variant worden daarna in sectie 5.2 voorge-steld. In sectie 5.3 ten slotte worden deze met elkaar vergeleken en wordt de beste van dezealgoritmes bepaald in verschillende omstandigheden.

5.1 Inleiding

De partiële prefixsom kan gezien worden als een beperkte prefixsom. Bij de partiële prefixsomzal elk element namelijk niet gesommeerd worden met alle voorgaande elementen van een rij,maar met slechts een gedeelte van deze rij. Het sequentiële partiële prefixsom algoritme kanals volgt worden voorgesteld:

y(0) = x(0)for n = 1→ N doy(n) = y(n− 1) + x(n)− x(n−m)

end for

Hierbij stelt x(n) de rij met de beginwaarden, y(n) de rij met de partiële som en N de lengtevan de rij x(n) voor. Indien n−m < 0 wordt de term x(n−m) vervangen door nul. De termm geeft het aantal elementen weer waarover moet gesommeerd worden. Bijvoorbeeld voorm = 2 zal y(n) = x(n− 1) + x(n).

De partiële prefixsom heeft enkele toepassingen. Zo vormt deze operatie de basis van de ge-middelde waarde filter, waarbij naast het sommeren, daarna nog zal moeten gedeeld worden

32

Hoofdstuk 5. Het berekenen van een partiële prefixsom op de GPU 33

door het aantal termen m waarover gesommeerd werd.

5.2 Algoritmes voor de bepaling van de partiële prefixsom op deGPU

In deze sectie worden drie algoritmes voorgesteld om de partiële prefixsom te bepalen op deGPU. De eerste twee algoritmes zijn eenvoudige voor de hand liggende algoritmes. Het eerstealgoritme vertrekt vanaf het prefixsom algoritme en bepaalt met een kleine toevoeging hieropde partiële prefixsom. Het tweede algoritme gebruikt een directere methode. Elke draad zaltoegekend worden aan één element. Elke draad kan dan onafhankelijk van elkaar het resultaatbepalen. Het eerste algoritme wordt voorgesteld in sectie 5.2.1 en het tweede algoritme insectie 5.2.2.

Het derde algoritme is een nieuw uitgedacht algoritme. Via prefixsommen van deelrijen vande volledige rij wordt de uiteindelijke partiële prefixsom bepaald. Dit algoritme is beschrevenin sectie 5.2.3.

In sectie 5.3 ten slotte worden deze methoden met elkaar vergeleken en worden deze verderbesproken.

5.2.1 Algoritme gebaseerd op een uitbreiding van het prefixsom algoritme

Een eerste algoritme is een uitbreiding op het originele prefixsom algoritme. In eerste instan-tie zal een normale prefixsom berekend worden van de volledige rij x(n). Van elk elementvan de uitgangsrij y(n) moet dan nog de termen die teveel erbij zijn opgeteld weer wordenafgetrokken. Hiervoor moet enkel het verschil gemaakt worden van het element met een ele-ment op een voorgaande positie van deze rij y(n). Deze laatste operatie kan als volgt wordenvoorgesteld:

for n = 1→ N doo(n) = y(n)− y(n−m)

end for

Hierbij stelt een y(n) de rij van prefixsommen voor van de rij x(n) en o(n) de rij met het uit-eindelijke resultaat. De term m stelt het aantal elementen voor waarover moest gesommeerdworden. Indien (n−m) < 0 dan wordt y(n−m) vervangen door 0.

Deze aanpak heeft twee voordelen. Ze is eenvoudig te implementeren aangezien ze enkel eenverschil operatie extra nodig heeft ten opzichte van het prefixsom algoritme. En verder zal deberekeningstijd enkel afhangen van het aantal elementen in de ingangsrij x(n) en onafhanke-lijk zijn van het aantal termen m waarover gesommeerd moet worden.

Hoofdstuk 5. Het berekenen van een partiële prefixsom op de GPU 34

5.2.2 Een directe aanpak algoritme

Een meer directe aanpak wordt in deze sectie voorgesteld. Hierbij zal elke draad het uitein-delijke element rechtstreeks berekenen. In pseudocode wordt dit:

for all n in parallel doy(n) =

∑m−1i=0 x(n− i)

end for

De rij y(n) bevat de uiteindelijke partiële prefixsom, x(n) de rij met ingangswaarden en mstelt opnieuw het aantal elementen voor waarover gesommeerd wordt. Elke index n zal inparallel geëvalueerd worden, hierbij is er een één op één mapping van een index op een draad.

Om nodeloze geheugentoegangen te vermijden wordt gebruikgemaakt van het gedeeld geheu-gen. Eerst zal elke blok van draden alle benodige data inlezen en opslaan in gedeeld geheugen.De hoeveelheid ingelezen data zal gelijk zijn aan T + m − 1 met T het aantal draden in éénblok. Na bloksynchronisatie kan elke draad dan zijn resultaat berekenen.

De rekentijd van deze methode zal zowel afhangen van de grootte van de rij x(n), als van hetaantal elementen m waarover gesommeerd moet worden.

5.2.3 Nieuw algoritme om de partiële prefixsom te bepalen

Het nieuw algoritme voorgesteld in deze sectie kan gezien worden als een afgeslankt prefixsomalgoritme. In plaats van een volledige prefixsom van een rij te bepalen zal slechts gebruikgemaakt worden van kleine prefixsommen van deelrijen. De grootte van deze deelrijen is inge-geven door de CUDA architectuur en is gelijk aan 32, wat overeenkomt met de warpgrootte.Voor de volledige bepaling van de partiële prefixsom zijn enkel prefixsommen nodig op hetniveau van een warp. Dit is een voordeel ten opzichte van het volledige prefixsom algoritmedat ook nog bewerkingen op het blokniveau en het globale niveau vereiste. Een nadeel vandit algoritme is dat deze methode beperkt is tot het sommeren van maximaal 33 elementen.Dit zal echter in de meeste gevallen geen beperking vormen.

Het algoritme wordt hieronder verder uit de doeken gedaan, hierbij moet nog opgemerkt wor-den dat het algoritme één draad per element van de ingangsrij vereist. Elke draad zal danéén uitgangselement bepalen. Een warp zal 32 uitgangselementen bepalen, meer bepaald zalwarp k de uitgangselementen op positie 32k tot 32k + 31 bepalen.

Zoals aangegeven gebeurt de volledige bepaling op het niveau van de warps. Deze bepalingis in figuur 5.1 weergegeven voor m = 2 en wordt hieronder verder toegelicht:

• In eerste instantie zal een warp k een prefixsom berekenen op de elementen 32k tot32k + 31.

• Daarna zal dezelfde warp een prefixsom berekenen over de 32 voorgaande elementen,hierbij is de volgorde van deze elementen geïnverteerd.

Hoofdstuk 5. Het berekenen van een partiële prefixsom op de GPU 35

• In een derde fase zal elk element van de prefixsom uit stap 1 waar er teveel elementenbij opgeteld zijn, verminderd worden met het element op m posities ervoren.

• In een laatste fase zal elk element van de prefixsom uit stap 1 waar er nog te weinigelementen bij opgeteld zijn, vermeerderd worden met het element op positie (m− 2)− ivan de prefixsom uit stap 2. i stelt hierbij de index van de draad voor in de warp.

intrawarp prefixsom

X31 X30 X29 … X2 X1 X0 X32 X33 X34 … X61 X62 X63

…∑ Xi

i=32..32

∑ Xi

i=32..33

∑ Xi

i=32..34

∑ Xi

i=32..61

∑ Xi

i=32..62

∑ Xi

i=32..63…∑ Xi

i=31..31

∑ Xi

i=31..30

∑ Xi

i=31..29

∑ Xi

i=32..2

∑ Xi

i=32..1

∑ Xi

i=31..0

…∑ Xi

i=32..32

∑ Xi

i=32..33

∑ Xi

i=33..34

∑ Xi

i=60..61

∑ Xi

i=61..62

∑ Xi

i=62..63

-

…∑ Xi

i=31..32

∑ Xi

i=32..33

∑ Xi

i=33..34

∑ Xi

i=60..61

∑ Xi

i=61..62

∑ Xi

i=62..63

---

+

Figuur 5.1: Berekening van de partiële prefixsom in een warp met m = 2.

In de kernel zal in eerste instantie opnieuw alle vereiste data per blok ingelezen worden. Con-creet zal T + 32 (T = het aantal draden per blok) waarden uit het globale geheugen gelezenworden naar gedeeld geheugen. Hierna kunnen de verschillende warps dan elk afzonderlijkhun prefixsommen en het uiteindelijke resultaat berekenen.

5.3 Resultaten en conclusie

Tabel 5.1 geeft de resultaten weer van de drie besproken CUDA implementaties voor eenverschillend aantal elementen m waarover werd gesommeerd.

De voornaamste conclusie die uit de tabel volgt is dat voor kleine m het direct algoritmeaanzienlijk beter presteert dan de versie gebaseerd op de uitgebreide prefixsom. Aangeziendeze laatste een constante uitvoeringstijd kent, zal echter bij grotere waarden van m dezehet direct algoritme overtreffen. Het nieuwe algoritme presteert beter dan het uitgebreideprefixsom algoritme, maar kan niet tippen aan de directe implementatie. In de praktijk zal

Hoofdstuk 5. Het berekenen van een partiële prefixsom op de GPU 36

Uitvoeringstijd (ms)m Uitgebreide prefixsom Direct algoritme Nieuw algoritme16 14,82 4,95 13,2232 14,82 5,63 13,0164 14,82 8,94 x128 14,82 15,59 x256 14,82 29,13 x

Tabel 5.1: Uitvoeringstijd (ms) van de drie CUDA partiële prefixsom algoritmes voor16776960 elementen. Hierbij werd gesommeerd over m elementen.

het dan ook beter zijn om bij kleine m (tot 128) te kiezen voor het directe algoritme en bijnog grotere m de uitgebreide prefixsom versie.

In tabel 5.2 wordt de vergelijking gemaakt tussen het direct algoritme en een sequentiële CPUimplementatie van het recursieve algoritme uit sectie 5. Met het van en naar de GPU kopiërenvan de ingangs- en uitgangsrij is geen rekening gehouden.

De CPU implementatie is aanzienlijk trager dan het direct algoritme, tot een factor 26, 35.Daarnaast kan opgemerkt worden dat de versnellingsfactor nog hoger wordt met een groteraantal elementen. Ook hier biedt dus de GPU implementatie een snelheidswinst ten opzichtevan de CPU implementatie.

Uitvoeringstijd (ms)#elementen CPU Direct algoritme Versnellingsfactor

65536 0,57 0,03 19,01262144 2,47 0,10 23,741048576 9,34 0,37 25,124194304 36,90 1,41 26,1016776960 148,26 5,63 26,35

Tabel 5.2: Vergelijking tussen het directe algoritme en een sequentiële recursieve CPU im-plementatie (AMD64 3800+, C++ code) voor een verschillend aantal elementen. Het aantalelementen m waarover gesommeerd werd is 32.

Hoofdstuk 6

De discrete wavelettransformatie op deGPU

In dit hoofdstuk wordt het bepalen van de tweedimensionale discrete wavelettransformatie opde GPU toegelicht. Deze transformatie vormt een belangrijk onderdeel van het geïmplemen-teerde beeldrestauratie algoritme uit hoofdstuk 7.

Dit hoofdstuk is als volgt georganiseerd: in sectie 6.1 wordt in eerste instantie een inleidinggegeven over de wavelettransformatie. Daarna volgt in sectie 6.3 hoe deze bepaald kan wor-den. In sectie 6.3 wordt het gerelateerde werk besproken, waarna in sectie 6.4 de nieuweaanpakken worden besproken. Ten slotte volgen nog resultaten en een conclusie in sectie 6.5.

6.1 Inleiding

In de signaal- en beeldverwerking wordt veel gebruik gemaakt van transformaties. Een trans-formatie stelt een ingangssignaal op een andere manier voor. Meer bepaald zal een trans-formatie het ingangssignaal beschrijven ten opzichte van een nieuwe verzameling basiseenhe-den. De reden waarom men een signaal transformeert, is bijvoorbeeld omdat een alternatievevoorstellingswijze het eenvoudiger maakt om een bepaalde bewerking uit te voeren op hetingangssignaal.

Eén zo’n bekende transformatie is de Fouriertransformatie. Deze transformatie beschrijft hetingangssignaal ten opzichte van een reeks sinusoïdale basisfuncties met verschillende frequen-tie. Anders verwoord geeft de Fouriertransformatie informatie over de frequentie-inhoud vanhet ingangssignaal. In een beeld zullen homogene gebieden voornamelijk met lage frequentieskunnen beschreven worden, terwijl randen en hoeken beschreven worden met hoge frequenties.

Hoewel de Fouriertransformatie informatie geeft omtrent de frequentie-inhoud, geeft ze geeninformatie over wat in het beeld aan de basis ligt van de bekomen frequenties. De oorzaakhiervan ligt in de sinusoïdale basisfuncties die zich oneindig uitstrekken. Informatie omtrentde kenmerken die aan de basis liggen van bepaalde frequenties zou echter zeer interessant zijn,aangezien dit meer informatie oplevert met het oog op verdere analyse/verwerking.

37

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 38

Om dit te bekomen wordt de Korte-Termijn-Fourier-Transformatie gebruikt, die het ingangs-signaal eerst vermenigvuldigt met een vensterfunctie vooraleer de Fouriertransformatie wordttoegepast. Deze vensterfunctie is verschillend van nul in een beperkt gebied, waardoor hetsignaal enkel in dit gebied waarden zal aannemen. Door het venster te verschuiven en telkensde Fouriertransformatie toe te passen wordt dan de lokale frequentie-inhoud van het signaalbepaald. Hierdoor laat deze transformatie dus een lokale frequentie-analyse van het signaaltoe. De Korte-Termijn-Fourier-Transformatie heeft een belangrijk nadeel. Omdat de breedtevan het venster vast is, moet er een keuze gemaakt worden tussen een goede frequentiere-solutie of een goede tijdsresolutie. Een goede frequentieresolutie laat toe om frequenties diedicht bij elkaar liggen te onderscheiden. Een goede tijdsresolutie laat toe om de tijden waaropfrequenties veranderen beter te onderscheiden. Een klein venster zal een goede tijdsresolutietoelaten, terwijl een groot venster een goede frequentieresolutie zal toelaten.

Zowel een goede tijdsresolutie als een goede frequentieresolutie is niet tegelijkertijd mogelijk.De oorzaak hiervan is gerelateerd aan het onzekerheidsprincipe van Heisenberg. Dit principevindt zijn oorsprong in de quantummechanica en stelt dat de impuls van een deeltje en depositie niet tegelijkertijd met oneindige precisie kan geweten zijn. In deze context houdt ditin dat het onmogelijk is om te weten welke frequentiecomponenten voorkomen op een bepaaldtijdstip. Het is echter wel mogelijk om de frequentiecomponenten in een bepaald tijdsintervalte onderzoeken, maar hierbij moet dan wel een afweging gemaakt worden tussen de tijds- enfrequentieresolutie.

In een beeld zullen zoals eerder aangehaald homogene gebieden vooral beschreven worden intermen van lage frequenties. Hier zou het interessanter zijn om een hoge frequentieresolutiete hanteren, omdat deze homogene gebieden zich ruimtelijk uitstrekken. De exacte locatiewaar de frequenties veranderen is vanwege deze ruimtelijke uitstrekking minder belangrijk.Bij randen en dergelijke in een beeld zal een hoge spatiale resolutie interessanter zijn, omdatkennis over waar deze optreden belangrijker is dan de exacte frequenties.

Aangezien de Korte-Termijn-Fourier-Transformatie een vaste resolutie heeft, moet er gekozenworden voor ofwel een goede tijdsresolutie of een goede frequentieresolutie. Maar zoals in hetvoorgaande werd aangehaald, is de meest interessante resolutie afhankelijk van het beeldken-merk.

De wavelettransformatie laat een variabele resolutie toe en zal voor de hoogfrequente inhoudvan een signaal een goeie spatiale resolutie hanteren, terwijl voor de laagfrequente inhoudeen goeie frequentieresolutie zal gebruikt worden. Dit kan nog anders geformuleerd/geïnter-preteerd worden. De wavelettransformatie zal het ruimte-frequentie diagram opsplitsen inblokken van variabele grootte afhankelijk van de frequentie- en ruimtelokalisatie, zoals weer-gegeven in figuur 6.1. Bij de Korte-Termijn-Fourier-Transformatie echter wordt het ruimte-frequentie diagram verdeeld in gelijke blokken.

Wat de wavelettransformatie nu specifiek interessant maakt in het domein van de beeldver-werking is dat ze een multiresolutievoorstelling van een beeld creëert. Dit houdt in dat detransformatie een voorstelling van de beeldkenmerken geeft op verschillende resolutiescha-len. Een mogelijke toepassing hiervan is om bijvoorbeeld ruis in een beeld te onderdrukken.Door beeldkenmerken te volgen over de verschillende schalen heen kan een beter onderscheid

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 39

f

x

Figuur 6.1: Het ruimte-frequentie diagram bij de wavelettransformatie.

gemaakt worden tussen wat ruis is en wat een hoort bij het originele beeld. De wavelettrans-formatie kent nog andere toepassingen onder andere in het domein van de datacompressie1.

6.2 Bepalen van een tweedimensionale wavelettransformatie

Om een beeld te transformeren naar het waveletdomein wordt gebruikgemaakt van de twee-dimensionale discrete wavelettransformatie. Om deze wavelettransformatie uit te voeren zijner twee gangbare methoden, nl. het filterbank-schema [26] en het lifting-schema [27]. In[28] wordt het verschil tussen de twee aanpakken op de GPU architectuur onderzocht. Deconclusie in het artikel is dat het filterbank-schema in de meeste gevallen beter presteert danhet lifting-schema. De verbetering bevindt zich tussen de 10% en 140% afhankelijk van deprobleemgrootte, het type en de lengte van de waveletfilter. Daarom is in deze masterproefgekozen om gebruik te maken van een filterbankgebaseerde techniek in plaats van een lifting-schema gebaseerde techniek. De techniek gebaseerd op de filterbank wordt hieronder verdertoegelicht.

In figuur 6.2 wordt een één-niveau voorwaartse (analyse) filterbank weergegeven. Deze vormtde basiscomponent van de filterbankgebaseerde voorwaartse tweedimensionale wavelettrans-formatie. Zoals op de figuur weergegeven zal tweedimensionale data als ingang gegeven wordenaan de filterbank. De rijen van deze data zullen dan zowel door een laag- als een hoogdoorlaat-filter passeren, waardoor het spectrum van de data in beide gevallen gehalveerd wordt. Hetresultaat hiervan zijn twee subbanden elk met evenveel coëfficiënten als het oorspronkelijkebeeld. Een deel van deze coëfficiënten is echter redundant en kan verwijderd worden. Meerbepaald kan de helft van de coëfficiënten in elk van de subbanden verwijderd worden. Het ver-wijderen van deze coëfficiënten wordt onderbemonsteren genoemd. Deze onderbemonsteringhoudt in dat alle oneven kolommen van de data verwijderd worden. Op de resultaten van dezestap wordt dan nogmaals een laag- en een hoogdoorlaatfilter toegepast, maar deze keer op de

1bijvoorbeeld JPEG2000

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 40

Laag

Hoog

Laag

Hoog

2

2

2

2

Laag

Hoog

2

2

Rijen Kolommen

2D data

LL

LH

HL

HH

Figuur 6.2: Eén-niveau voorwaartse (analyse) tweedimensionale filterbank.

kolommen. Hierna kan dan opnieuw onderbemonsterd worden door de oneven rijen ditmaalte verwijderen. Als resultaat hiervan worden vier banden bekomen: de LL-, LH-, HL- en deHH-band. Om een meerdere-niveauontbinding te verkrijgen wordt de één-niveau filterbankverder aan elkaar verbonden zoals weergegeven in figuur 6.3. Hierbij zal een volgende niveaude LL-band van het vorige niveau als ingang krijgen. Per niveau zal door deze methode despatiale resolutie halveren en de frequentieresolutie verdubbelen. In figuur 6.4 wordt het re-sultaat van een tweedimensionale decompositie weergegeven voor de lena afbeelding.

2D data

LL1

LH1

HL1

HH1

Eén niveau

Filterbank

LL2

LH2

HL2

HH2

LL3

LH3

HL3

HH3

Analyse

Eén niveau

Filterbank

Analyse

Eén niveau

Filterbank

Analyse

Figuur 6.3: Voorwaartse filterbank met meerdere niveaus.

De één-niveau inverse (synthese) filterbank wordt in figuur 6.5 weergegeven. Deze zal elkestap van de voorwaartse filterbank ongedaan maken. De verschillende banden (LL, LH, HL enHH) worden als ingang gegeven. Deze worden in eerste instantie overbemonsterd door tussenelke rij een rij met nullen te plaatsen. Daarna wordt een laagdoorlaatfilter toegepast op dekolommen van de LL- en HL-band en een hoogdoorlaatfilter op kolommen van de LH- en HH-band. Hierna worden de LL- en LH-band net zoals de HL- en HH-band samengebracht viaoptelling. Daarna wordt opnieuw overbemonsterd, ditmaal door nullen tussen de kolommenin te brengen. Na deze stap moet dan nog een laagdoorlaatfilter en een hoogdoorlaatfilterinwerken en het resultaat hiervan samengebracht worden om terug de oorspronkelijke twee-dimensionale data te bekomen. Om een meerdere-niveau reconstructie te bekomen zal de

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 41

HL2

HH2LH2

LL2

LH1 HH1

HL1

Figuur 6.4: De tweedimensionale gedecimeerde wavelettransformatie van de lena afbeelding.

één-niveau filterbank meermaals toegepast worden zoals weergegeven in figuur 6.6. Elk ni-veau zal hierbij het resultaat van het voorgaande niveau als ingang krijgen.

De voorgaande wavelettransformatie staat bekend als de gedecimeerde wavelettransformatie.Deze transformatie is echter niet translatie-invariant. Anders verwoord: indien een beeld eneen verschoven beeld beiden deze wavelettransformatie ondergaan, dan zullen de twee resul-taten geen verschoven versie van elkaar zijn. Om dit te voorkomen wordt gebruikgemaaktvan de niet-gedecimeerde wavelettransformatie, die wel translatie-invariant is. Het verschilmet de gedecimeerde transformatie is dat er niet onderbemonsterd wordt, er worden dus geenrijen en kolommen verwijderd na het toepassen van de laag- en hoogdoorlaatfilters. Hierdoorhebben de verschillende uitgangsbanden dezelfde dimensie als het ingangsbeeld. Tussen elkniveau worden de laag- en hoogdoorlaatfilters wel verhoogd in resolutie door nullen tussenelke filtercoëfficiënt in te voegen. Dit algoritme staat ook bekend als het à trous algoritme [29].

Er zal verder gebruikgemaakt worden van de Daubechies wavelets. Dit is een verzameling vanorthogonale wavelets en deze worden typisch aangeduid met de lettercombinatie DX waarbijX het aantal filtercoëfficiënten voorstelt. Bijvoorbeeld D2 (ook wel de Haar wavelet genoemd)telt twee coëfficiënten, namelijk [1, 1] of indien ze genormeerd worden 1√

2 [1, 1]. Dit zijn decoëfficiënten van de laagdoorlaatfilter. De coëfficiënten van de hoogdoorlaatfilter h[n] wordengevormd uit deze van de laagdoorlaatfilter l[n] via de formule: h[n] = (−1)nl[1− n].

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 42

Laag

Hoog

Kolommen

LL

LH

HL

HH 2

2

2

2 Laag

Hoog

Laag

Hoog

2

2

Rijen

2D data

Figuur 6.5: Eén-niveau inverse (synthese) tweedimensionale filterbank.

LL3

LH3

HL3

HH3

Eén niveau

Filterbank

SyntheseLH2

HL2

HH2

Eén niveau

Filterbank

SyntheseLH1

HL1

HH1

Eén niveau

Filterbank

Synthese 2D data

Figuur 6.6: Inverse filterbank met meerdere niveaus.

6.3 Gerelateerd Werk

Het aantal GPU en GPGPU implementaties is tot op heden relatief beperkt. Alle bestaandeimplementaties [30, 31, 32, 33] volgen een gescheiden aanpak. In deze aanpak zal eerst deééndimensionale wavelettransformatie uitgevoerd worden over de rijen. Daarna wordt detransformatie uitgevoerd over de kolommen van het resultaat van de rijen.

Vanwege het beperkte bronmateriaal van GPU implementaties werd verder nog gekeken naarimplementaties op FPGA. Deze kunnen onderverdeeld worden in drie technieken:

• De eerste methode is dezelfde als deze gevolgd door de GPU implementaties, namelijkeen gescheiden rij-kolom methode. Voor FPGA komt deze aan bod in [34].

• Een tweede methode is de rijgebaseerde methode [35, 36, 34]. Hierbij wordt in eersteinstantie ook eerst op de rijen een wavelettransformatie toegepast. In tegenstelling totde rij-kolomgebaseerde methode wordt echter niet gewacht totdat alle rijen getransfor-meerd zijn vooraleer gestart wordt met de transformatie op de kolommen.

• Een derde en laatste methode is de blokgebaseerde methode [34, 37] om een gedeci-meerde wavelettransformatie uit te voeren. Hierbij wordt het beeld opgesplitst in blok-

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 43

ken. De blokgrootte wordt zo gekozen dat een blok net één coëfficiënt uit het hoogsteniveau kan bepalen. De volledige transformatie van het beeld wordt dan bepaald doorblok per blok te transformeren. Hierbij wordt gebruikgemaakt van overlapgeheugen omcoëfficiënten tijdelijk op te slaan voor gebruik bij het volgende blok.

6.4 Nieuwe aanpakken om de 2-D wavelettransformatie uit te voe-ren op de GPU

In dit gedeelte worden twee nieuwe aanpakken voorgesteld om de voorwaartse wavelettrans-formatie uit te voeren op de GPU. Deze methoden zijn ingegeven door de GPU architectuuren het CUDA programmeermodel.

6.4.1 Blokgebaseerde aanpak

De niet-gedecimeerde wavelettransformatie

Deze methode volgt een blokgebaseerde aanpak om een niveau van de transformatie te be-palen. Het verschil met de reeds bestaande methoden is dat hier niet eerst volledige rijenworden bepaald zoals bij de rij-kolom en de rijgebaseerde methoden. Het verschil met deblokgebaseerde methode van [34, 37] is dat de blokken niet sequentieel worden bepaald, maarin parallel en er geen waveletcoëfficiënten worden doorgegeven tussen de blokken.

Concreet zal in deze methode één niveau van de wavelettransformatie bepaald worden met éénkernel. Om een meerdere-niveauontbinding te bekomen zal deze kernel meermaals uitgevoerdmoeten worden, telkens met de LL subband van het vorige niveau als ingang.

De kernel zelf zal in parallel alle waveletcoëfficiënten bepalen van de vier waveletbanden LLi,LHi, HLi en HHi. Hiervoor worden deze vier waveletbanden in niet overlappende blokkenonderverdeeld. De kernel is zo vastgelegd dat elk blok van draden een blok van waveletcoëf-ficiënten zal bepalen van elk van de vier waveletbanden. Hierbij is de dimensie van het blokvan draden gelijk aan de dimensie van het blok van waveletcoëfficiënten. Zo zal bijvoorbeeldeen 16x16 blok van draden een gebied ter grootte van 16 bij 16 bepalen in elk van de vierwaveletbanden. Elke draad van een blok zal hierbij één uitgangscoëfficiënt van elk van devier banden bepalen. Indien blockDim.x en blockDim.y respectievelijk de x- en y-dimensievoorstellen van een blok van draden en Dim.x en Dim.y respectievelijk de x- en y-dimensievoorstellen van de ingangsafbeelding, dan wordt de kernel uitgevoerd met een grid met alsx-dimensie Dim.x

blockDim.x en als y-dimensie Dim.yblockDim.y . De dimensies van het grid moeten geheel

zijn, hierdoor kan het voorkomen dat de ingangsafbeelding uitgebreid moet worden. Als bij-voorbeeld de blokdimensie blockDim.x = 16 dan moet de breedte van de ingangsafbeeldingeen veelvoud zijn van 16 of uitgebreid worden totdat dit het geval is.

In de kernel kunnen verder drie fases geïdentificeerd worden. In een eerste fase zal elk blokvan draden zijn vereiste data inlezen in het gedeeld geheugen. Deze data is afkomstig vande ingangsafbeelding of de LL subband van het vorige niveau en bevindt zich in het glo-baal geheugen. Bij het inlezen van de data wordt gebruikgemaakt van het gedeeld geheugen

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 44

Extra pixels niveau 1

Extra pixels niveau 2

Kern pixels

Extra pixels niveau 3

Figuur 6.7: Vereiste pixels voor een 8x8 blok bij de berekening van de niet-gedecimeerdetweedimensionale discrete wavelettransformatie met de Haar wavelet.

om slechts éénmaal de data in te lezen die elke draad zal vereisen voor zijn berekeningen.Aangezien het toepassen van de laag- en hoogdoorlaatfilters met de convolutie operator zalgebeuren, zullen meer pixels ingelezen moeten worden dan er draden in het blok zijn. Ombijvoorbeeld met een 16x16 blok van draden een 16x16 gebied te bepalen zal indien gebruik-gemaakt wordt van de Haar wavelet een 17x17 gebied moeten ingelezen worden op het eersteniveau. Met constante blokgrootte zal op hogere niveaus de hoeveelheid extra ingelezen pixelsverder verhogen. Per niveau k (k startend vanaf 1) moet elk blok van draden een blok inlezenvan blockDim.y + (2k−1 × (F − 1)) bij blockDim.x+ (2k−1 × (F − 1)) met F het aantal fil-tercoëfficiënten van de gebruikte wavelet. Dit wordt weergegeven in figuur 6.7 voor een blokvan 8 bij 8 met de Haar wavelet.

Na synchronisatie van de draden in het blok kan in de tweede fase dan elke draad van hetblok één uitgangselement bepalen van elk van de vier subbanden. Hiervoor zal elke draad devereiste elementen van de rijtransformatie bepalen om dan hierover de kolomtransformatieuit te voeren. Dit gebeurt met een dubbele for-lus:

shift = 2k−1

for m = 0→ F − 1 doLtemp = 0Htemp = 0for l = 0→ F − 1 doLtemp+ = lowwavfilter[l]× imageblock[idy +m× shift][idx+ l × shift]Htemp+ = highwavfilter[l]× imageblock[idy +m× shift][idx+ l × shift]

end forLLfinal+ = lowwavfilter[m]× LtempHLfinal+ = lowwavfilter[m]×HtempLHfinal+ = highwavfilter[m]× LtempHHfinal+ = highwavfilter[m]×Htemp

end for

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 45

Hierbij stelt k (startend vanaf 1) het niveau voor. Deze parameter moet meegegeven wordenbij de uitvoering van de kernel. Verder stelt F het aantal filtercoëfficiënten, imageblock deingelezen data in het gedeeld geheugen van het blok en XXfinal de finale waarde van decoëfficiënt van waveletband XX voor. De termen idy en idx zijn respectievelijk gelijk aanthreadIdx.y en threadIdx.x en stellen dus de y- en x-index van een draad voor in het blokvan draden. Zoals uit de pseudocode blijkt worden de filtercoëfficiënten niet aangepast af-hankelijk van het niveau, maar worden in de plaats daarvan de pixels waarop ze inwerkenopgeschoven volgens 2k−1. Op deze manier blijft het aantal vermenigvuldigingen constantongeacht het niveau.

In een laatste fase ten slotte zal elke draad zijn vier bepaalde waveletcoëfficiënten dan weg-schrijven naar het globaal geheugen.

Een probleem dat optreedt bij deze methode is dat het aantal ontbindingsniveaus beperkt is.Er is namelijk een beperking op de hoeveelheid fysiek gedeeld geheugen per multiprocessor.Aangezien de hoeveelheid data per blok steeds verhoogd per niveau, zal het hierdoor op ter-mijn niet meer mogelijk zijn nog verdere ontbindingen uit te voeren.

Dit zal vooral een probleem vormen bij grotere filtermaskers zoals de D8. Bijvoorbeeld zal meteen blokgrootte van 16x16 de wavelettransformatie met D8 op niveau drie al (16+4×7)2×4 =7744 bytes vereisen per blok. Op een NVIDIA 8800GT2 laat dit nog maar twee blokken toeper multiprocessor. Een vierde niveau kan zelfs niet berekend worden. Recentere GPUs be-schikken over grotere hoeveelheden gedeeld geheugen, dus hier zal het probleem zich mindersnel stellen. Desalniettemin zal ook hier het aantal decomposities beperkt zijn. Indien dit eenprobleem vormt kan een alternatief algoritme gebruikt worden zoals de rij-kolom methodevan [33].

De gedecimeerde wavelettransformatie

De gedecimeerde wavelettransformatie kan op een analoge manier bepaald worden als de niet-gedecimeerde wavelettransformatie. Een naïeve aanpak zou zijn om telkens de filters van heteerste niveau te hergebruiken en na elk niveau dan de oneven rijen en kolommen te verwij-deren. Een efficiëntere aanpak is om al op voorhand rekening te houden met het feit dat deoneven rijen en kolommen zullen verwijderd worden door deze in de eerste plaats al niet teberekenen. Hierdoor moet er maar een vierde van de berekeningen plaats vinden ten opzichtevan het naïeve geval, wat logischerwijs de prestatie ten goede zal komen.

Net zoals in het niet-gedecimeerde geval zal een kernel in parallel alle waveletcoëfficiëntenbepalen van de vier waveletbanden LLi, LHi, HLi en HHi. Ook hier is het zo dat elk blokvan draden een blok van waveletcoëfficiënten zal bepalen van elk van de vier waveletbandenen dat elke draad in het blok hierbij één uitgangscoëfficiënt van elk van de vier banden zal be-palen. Hierbij is het ook zo dat de dimensie van het blok van draden gelijk is aan de dimensievan het blok van waveletcoëfficiënten. Indien blockDim.x en blockDim.y respectievelijk de x-en y-dimensie voorstellen van een blok van draden en Dim.x en Dim.y respectievelijk de x-

2Een multiprocessor beschikt bij dit model over 16kB.

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 46

en y-dimensie voorstellen van de ingangsafbeelding (of de LL subband), dan wordt de kerneluitgevoerd met een grid met als x-dimensie Dim.x

2×blockDim.x en als y-dimensie Dim.y2×blockDim.y .

Elk blok van draden zal in eerste instantie de vereiste data ingelezen worden in het gedeeldgeheugen. Uit de ingangsafbeelding of de LL band van het vorige niveau zal een blok van((2×blockDim.y)+(F−2)) bij ((2×blockDim.x)+(F−2)) ingelezen worden. Hierbij is F hetaantal filtercoëfficiënten van de gebruikte wavelet. In het geval van een wavelettransformatiemet de Haar wavelet (F = 2) bijvoorbeeld, zal een 16x16 blok van draden een 32 bij 32 blokinlezen om een 16x16 blok in elk van de waveletbanden te bepalen.

De bewerking die elke draad van een blok uitvoert is analoog aan het niet-gedecimeerde geval:

for m = 0→ F − 1 doLtemp = 0Htemp = 0for l = 0→ F − 1 doLtemp+ = lowwavfilter[l]× imageblock[2× idy +m][2× idx+ l]Htemp+ = highwavfilter[l]× imageblock[2× idy +m][2× idx+ l]

end forLLfinal+ = lowwavfilter[m]× LtempHLfinal+ = lowwavfilter[m]×HtempLHfinal+ = highwavfilter[m]× LtempHHfinal+ = highwavfilter[m]×Htemp

end for

Hierbij stelt F het aantal filtercoëfficiënten, imageblock de ingelezen data in het gedeeld ge-heugen van het blok en XXfinal de finale waarde voor van de coëfficiënt van waveletbandXX. idy en idx zijn respectievelijk gelijk aan threadIdx.y en threadIdx.x en stellen dus dey- en x-index van een draad voor in het blok van draden. De termen 2× idx en 2× idy zorgenervoor dat elke draad op de correcte positie zijn berekeningen start. Deze startposities volgeneen schaakbord patroon zoals weergegeven in figuur 6.8 voor een 4x4 blok met de Haar wavelet.

+

Ingelezen pixels

Draad startpositie

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

Figuur 6.8: Startpositie van de draden voor een 4x4 blok (Haar wavelet).

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 47

Na de berekeningen kan elke draad dan zijn vier berekende coëfficiënten wegschrijven.

In dit geval treedt het probleem met het oplopende gedeeld geheugen niet op, omdat over deniveaus heen de hoeveelheid gedeeld geheugen dat elk blok van draden vereist constant blijft.

6.4.2 Textuurgeheugen gebaseerde aanpak

De tweede methode is nagenoeg identiek aan de voorgaande blokgebaseerde aanpak. Maar integenstelling tot de voorgaande methode zal in deze aanpak elke blok van draden niet eerstzijn vereiste data inlezen in gedeeld geheugen. Elke draad in een blok zal bij uitvoering zijnvereiste data inlezen vanuit het textuurgeheugen.

Concreet zal in deze aanpak in eerste instantie het ingangsbeeld of de LL subband van hetvorige niveau aan een textuur gebonden worden. In de kernel zal elke draad dan zijn vereistedata om zijn bewerkingen uit te voeren inlezen tijdens de verwerkingsfase. Bijvoorbeeld voorhet niet-gedecimeerde geval zal elke draad de volgende bewerking uitvoeren tijdens de ver-werkingsfase:

shift = 2k−1

for m = 0→ F − 1 doLtemp = 0Htemp = 0for l = 0→ F − 1 doLtemp+ = lowwavfilter[l]× tex(absx+ l × shift, absy +m× shift)Htemp+ = highwavfilter[l]× tex(absx+ l × shift, absy +m× shift)

end forLLfinal+ = lowwavfilter[m]× LtempHLfinal+ = lowwavfilter[m]×HtempLHfinal+ = highwavfilter[m]× LtempHHfinal+ = highwavfilter[m]×Htemp

end for

Hierbij stelt k (startend vanaf 1) wederom het niveau, F het aantal filtercoëfficiënten enXXfinal de finale waarde van de coëfficiënt van waveletband XX voor. De functie tex(x, y)leest de pixel op positie (x, y) uit het textuurgeheugen. De termen absy en absx stellen hierbijde absolute index van elke draad voor in het grid en zijn bepaald via de uitdrukkingen:

absx = blockID.x× blockDim.x+ threadID.x

absy = blockID.y × blockDim.y + threadID.y(6.1)

Omdat het textuurgeheugen gecachet is, kunnen de niet-gealigneerde geheugentoegangen vande draden in een warp grotendeels via de cache opgevangen worden. Elke warp wordt ech-ter onafhankelijk van de andere warps uitgevoerd in een niet op voorhand bepaalde volgorde.Hierdoor is het onwaarschijnlijk dat de opgehaalde en gecachte data van een warp hergebruiktzal kunnen worden door een andere warp van het blok. Dit leidt ertoe dat dezelfde geheu-gentoegangen typisch meerdere malen zullen uitgevoerd worden door verschillende warps. De

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 48

prestatie zal hierdoor aanzienlijk afnemen met steeds groter wordende waveletlengtes, waar-door ook deze methode uitsluitend geschikt zal zijn voor wavelets met kleine lengte.

6.5 Resultaten en conclusie

In tabel 6.1 zijn de resultaten te zien van drie implementaties voor de niet-gedecimeerdetweedimensionale wavelettransformatie: de twee nieuwe aanpakken, namelijk de blokgeba-seerde aanpak en de aanpak die gebruikmaakt van textuurgeheugen. Deze worden vergelekenmet een gescheiden rij-kolom aanpak.

Uitvoeringstijd (ms)Wavelet Blokgebaseerd Textuur Rij-kolom

Niveau 1D2 (Haar) 2,71 1,89 4,18

D4 3,58 4,81 4,43D6 5,16 8,13 4,71D8 7,17 12,74 5,21

Niveau 2D2 (Haar) 2,93 2,26 4,27

D4 4,03 4,89 4,57D6 5,72 8,21 4,89D8 7,84 13,50 5,25

Tabel 6.1: Uitvoeringstijden (ms) van drie implementaties van de voorwaartse niet-gedecimeerde wavelettransformatie uitgevoerd op een 2048x2048 beeld voor verschillende wa-velets. Het aantal ontbindingsniveaus was twee, de duurtijd van het eerste niveau wordt inhet bovenste gedeelte van de tabel weergegeven, de duurtijd van het tweede niveau in hetonderste gedeelte.

De twee nieuwe aanpakken zijn vooral geschikt voor de niet-gedecimeerde transformatie metwavelets met kleine lengte. Zo presteren beide aanpakken beter dan de rij-kolom methode bijde transformatie met de Haar wavelet. Bij de D4 wavelet presteert enkel de blokgebaseerdemethode nog beter dan de rij-kolom methode. Bij nog grotere waveletfilters (D6 en hoger)komt de rij-kolom steeds als beste uit de bus. De verklaring hiervoor is dat de nieuwe aan-pakken een hoger aantal bewerkingen vergen dan de rij-kolom methode. Deze laatste bepaaltnamelijk zowel het resultaat van de transformatie van de rijen als deze van de kolommenslechts éénmaal. Bij de nieuwe aanpakken wordt enkel het resultaat van de kolomtransforma-tie éénmaal bepaald, de tussenliggende resultaten van de rijtransformatie worden meermaalsbepaald door elke draad afzonderlijk.

De resultaten van de gedecimeerde transformatie in tabel 6.2 leiden tot dezelfde conclusie alsdeze van de niet-gedecimeerde transformatie. Wederom presteren de nieuwe aanpakken betervoor de wavelets met kleine lengte. Bij grotere wavelets wordt de invloed op de prestatie vande extra bewerkingen groter en wordt het dan ook beter om de rij-kolom methode te verkiezen.

Hoofdstuk 6. De discrete wavelettransformatie op de GPU 49

Uitvoeringstijd (ms)Wavelet Blokgebaseerd Textuur Rij-kolom

D2 (Haar) 0,89 0,73 1,41D4 1,44 1,77 1,55D6 2,14 3,28 1,72D8 3,13 5,13 1,92

Tabel 6.2: Uitvoeringstijden (ms) van drie implementaties van de voorwaartse gedecimeerdewavelettransformatie uitgevoerd op een 2048x2048 beeld voor verschillende wavelets. Deweergegeven uitvoeringstijden zijn deze om één niveau van de transformatie uit te voeren.

Een mogelijke verbetering van de twee nieuwe technieken zou zijn om het aantal bewerkingendat de draden dubbel uitvoeren te verminderen. Dit zou mogelijk zijn door de verwerkingsfasevan een blok van draden op te splitsen in een fase waarbij eerst éénmaal het resultaat van derijtransformatie van dit blok wordt bepaald en daarna pas de resultaten van de kolomtrans-formatie. Dit is echter niet verder onderzocht/geïmplementeerd.

Ter vergelijking werd ook nog een CPU implementatie van de voorwaartse wavelettransforma-tie met de Haar wavelet ontwikkeld. Deze had voor de niet-gedecimeerde en de gedecimeerdetransformatie van een 2048x2048 respectievelijk 34, 115ms en 8.43ms nodig om één-niveauontbinding uit te voeren met een AMD64 3800+ processor. Dit is respectievelijk een factor18 en 11 trager dan de GPU implementatie. De GPU kan dus voor dit type van algoritmeeen aanzienlijke snelheidswinst verkrijgen ten opzichte van een CPU implementatie.

Hoofdstuk 7

Overbrengen van een algoritme naarde GPU

In dit hoofdstuk wordt de overbrenging van een beeldrestauratie algoritme naar de GPU methulp van het CUDA raamwerk overlopen. Hierbij worden naast de implementatiedetails ookde opgetreden moeilijkheden besproken. Verder worden de factoren die de uitvoeringseffici-ëntie beïnvloeden toegelicht en worden alternatieven hiervoor voorgesteld.

Dit hoofdstuk is als volgt georganiseerd. In sectie 7.1 wordt een inleiding gegeven over hetprobleem dat ruis vormt voor een videosequentie en welke aanpakken er zijn om deze te on-derdrukken. Het geïmplementeerde ruisonderdrukkingsalgoritme, het MC3DWTr algoritmewordt daarna in sectie 7.2 toegelicht. In sectie 7.3 wordt de algemene aanpak voor de omzet-ting overlopen, daarna worden de datastructuren en het CPU raamwerk verder besproken. Deimplementatiedetails van het algoritme worden in sectie 7.4 toegelicht. Van elke componentwordt de implementatie afzonderlijk besproken. Uiteindelijk worden in sectie 7.5 de behaalderesultaten van deze GPU implementatie voorgesteld en besproken.

7.1 Inleiding

Bij het vastleggen van videobeelden of het verzenden van beelden over een analoog kanaal kanhet voorkomen dat de beeldsequentie beschadigd raakt door ruis. Naast een storend visueeleffect, kan deze ruis ook de efficiëntie van verdere verwerkingsstappen of codering beïnvloeden.

Hoewel er verschillende types/modellen van ruis zijn, wordt er typisch in deze context gebruikgemaakt van zogenaamd additieve witte Gaussiaanse ruis. Dit model zal kwaliteitsverlies mo-delleren door witte ruis op te tellen bij het originele beeld. Concreet houdt dit in dat bij elkepixel van het beeld een waarde zal opgeteld worden. Deze waarde volgt een Gaussiaansedistributie met gemiddelde nul en standaardafwijking σn.

Vervuiling met ruis n(z, t) van een beeld I(z, t) kan als volgt worden voorgesteld:

In(z, t) = I(z, t) + n(z, t) (7.1)

50

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 51

Hierbij staat z = (x, y) voor de spatiale locatie, t voor de index in de videosequentie en In(z, t)voor het met ruis vervuilde beeld.

Ruisonderdrukking houdt in dat getracht wordt het originele beeld te reconstrueren vertrek-kende vanuit het met ruis vervuilde beeld. Perfecte reconstructie van een beeld zal over hetalgemeen echter niet mogelijk zijn.

Het effect van ruis op een afbeelding wordt weergeven in figuur 7.1. Links wordt het ruisvrijebeeld weergegeven, in het midden het met ruis vervuilde beeld en rechts het beeld na ruison-derdrukking met een ruisonderdrukkingsalgoritme.

Figuur 7.1: Weergave van lena voor en na ruisonderdrukking. Links de originele lena afbeel-ding, in het midden lena met ruisniveau σn = 20 en rechts de lena afbeelding na ruisonder-drukking.

Vele ruisonderdrukkingstechnieken die gebruikt worden voor ruisonderdrukking in losse af-beeldingen zouden ook toegepast kunnen worden op videobeelden. Elk beeld kan namelijk alseen los beeld gezien worden en individueel en onafhankelijk van elkaar verwerkt worden. Dezetechnieken zullen echter weinig visueel aantrekkelijk zijn. Doordat ruisonderdrukking geenperfecte reconstructie toelaat zullen er in elk beeld artefacten optreden ten gevolge van deruisonderdrukking. Bij een videosequentie zullen deze snel fluctueren tussen de verschillendebeelden en net deze fluctuaties zorgen voor een storend visueel effect. Om dit effect tegen tegaan zal rekening moeten gehouden worden met de evolutie van de frames.

Verder kan informatie uit meerdere opeenvolgende frames gebruikt worden om tot een betereruisonderdrukking te komen. Omdat er veelal een zekere correlatie is tussen opeenvolgendeframes. Een videosequentie zal namelijk typisch bestaan uit een statische achtergrond metdaarop bewegende objecten. Indien de achtergrond tussen opeenvolgende frames niet of wei-nig verandert, dan kan bijvoorbeeld via uitmiddeling in de tijd over deze statische pixelsde ruis onderdrukt worden. Om ruis te onderdrukken van de bewegende objecten, moetendeze objecten gevolgd worden over de verschillende frames heen en moet dan uitgemiddeldworden over de bewegende pixels van deze objecten. Hiervoor wordt gebruikgemaakt van be-wegingsestimatie. Dit houdt in dat de beweging tussen opeenvolgende frames wordt geschatom zo te bepalen welke pixels in het ene frame uitgemiddeld moeten worden met de pixelsvan het volgende frame.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 52

In de bovenstaande beschreven techniek wordt video beschouwd als een sequentie van beelden.Andere technieken zullen video beschouwen als één driedimensionale afbeelding. De correlatietussen opeenvolgende frames en tussen de pixels onderling van een frame wordt dan samenuitgebuit om de ruisonderdrukking uit te voeren.

Het geïmplementeerde ruisonderdrukkingssalgoritme voor video, het Motion Compensated 3-D Wavelet Transform With Integrated Recursive Temporal Filtering (MC3DWTr) algoritme[38] behoort tot deze laatste klasse. Deze techniek zal echter niet de volledige video als eendriedimensionale afbeelding beschouwen. De oorzaak hiervan is dat niet altijd op voorhandgeweten is uit hoeveel frames de video bestaat. Bijvoorbeeld een bewakingscamera kan eencontinue (eindeloze) stroom aan beelden genereren. Verder stijgen naarmate het aantal fra-mes toeneemt ook de vereisten omtrent geheugenopslag en rekenkracht. Daarom wordt in hetalgoritme gebruikgemaakt van een glijdend venster. Het huidig frame samen met een vastaantal voorgaande frames wordt in een framebuffer geplaatst. Het ruisonderdrukkingsprocesvindt dan plaats op basis van de frames in de buffer. Telkens een nieuwe frame toekomt wordtdeze in de buffer gebracht, een oud frame wordt hierbij verwijderd.

Hieronder volgt een gedetailleerde uiteenzetting van dit algoritme.

7.2 Het MC3DWTr algoritme

Het MC3DWTr algoritme [38] is een recent1 algoritme voor het onderdrukken van ruis uit eenvideosequentie. Het is zoals eerder aangehaald een techniek gebaseerd op de voorstelling vande video als een driedimensionale afbeelding en gebruikt hierbij een beperkte framebuffer. Hetalgoritme zelf voert op deze verzameling frames een zogenaamde bewegingsgecompenseerdedriedimensionale wavelettransformatie (MC3DWT) uit om daarna dan de ruisonderdrukkinguit te voeren. De toelichting van deze transformatie gebeurt in sectie 7.2.1. Een overzichtvan het eigenlijke algoritme wordt daarna gegeven in sectie 7.2.2. Verder volgen hierna nogenkele details van het algoritme in sectie 7.2.3.

7.2.1 De bewegingsgecompenseerde driedimensionale wavelettransformatie

De tweedimensionale wavelettransformatie zoals die gebruikt wordt voor losse beelden kanuitgebreid worden naar een driedimensionale wavelettransformatie voor een verzameling vanvideoframes. Een (gescheiden) driedimensionale wavelettransformatie van een verzamelingframes kan op twee manieren bekomen worden: een temporele gevolgd door een spatiale wa-velettransformatie (t + 2-D) of een spatiale gevolgd door een temporele wavelettransformatie(2-D + t).

In het geval van een t + 2-D wavelettransformatie wordt de verzameling van frames eerstgetransformeerd in een verzameling van temporele laag- en hoogfrequente waveletsubbanden.Dit gebeurt door een ééndimensionale temporele wavelettransformatie uit te voeren over deverschillende frames heen. De laagfrequente waveletsubbanden kunnen nog verder ontbonden

12010

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 53

worden op dezelfde wijze totdat er slechts één laagfrequente waveletsubband overblijft.

De eenvoudigste temporele wavelettransformatie is deze met de Haar wavelet. Met de notatieLki en Hk

i worden respectievelijk de laag- en de hoogfrequente waveletsubbanden aangegevenvan niveau i en op temporele locatie k. De temporele decompositie kan dan uitgedrukt wordenals volgt:

Lk/2i+1(z) = 1√

2[Lki (z) + Lk−1

i (z)] (7.2)

en

Hk/2i+1(z) = 1√

2[Lki (z)− Lk−1

i (z)] (7.3)

Hierbij stelt z de spatiale locatie (x, y) voor. Voor de decompositie naar niveau 1 wordtLk0 = xk gesteld met xk de ingangsframe op temporele locatie k. Iteratief gebruik van de for-mules 7.2 en 7.3 zal een boom genereren. Dit wordt weergegeven in figuur 7.2 voor vier framesuit de Foreman sequentie. Bij de eerste decompositie zullen twee laagfrequente (L0

1 en L11) en

twee hoogfrequente waveletsubbanden (H01 en H1

1 ) gecreëerd worden. De twee laagfrequentewaveletsubbanden worden dan nog verder ontbonden in de laagfrequente waveletsubband L0

2en de hoogfrequente waveletsubband H0

2 .

H1(1)H1

(0)

H2(0)L2

(0)

Figuur 7.2: De temporele decompositie van vier frames uit de Foreman sequentie.

Na de temporele wavelettransformatie wordt dan nog een spatiale wavelettransformatie uit-gevoerd op alle hoogfrequente waveletsubbanden Hk

i en de overblijvende laagfrequente wave-letsubband (L0

2 in de figuur). Dit geeft dan een driedimensionale wavelettransformatie. Dit

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 54

wordt symbolisch voorgesteld in figuur 7.3.

H1(0)

H1(1)

H2(0)

L2(0)

Niveau 1

Niveau 2

Ingangsframes

Figuur 7.3: De driedimensionale wavelettransformatie van vier frames. De temporele één-dimensionale transformatie is uitgevoerd via de gedecimeerde wavelettransformatie met deHaar wavelet.

De inverse driedimensionale wavelettransformatie zal de originele frames terug reconstrueren.Hiervoor zal in eerste instantie de inverse tweedimensionale wavelettransformatie de temporelewaveletsubbanden reconstrueren. Daarna kan dan de inverse temporele wavelettransformatiede originele frames reconstrueren.

Om beter de temporele correlatie uit te buiten zullen de frames zo goed mogelijk met elkaargealigneerd worden vooraleer de driedimensionale wavelettransformatie uitgevoerd wordt. Inde praktijk komt dit neer op de uitvoering van een bewegingsestimatie en -compensatie stapvan alle frames ten opzichte van een ankerframe. Hierdoor zal dan de temporele decompositieplaats vinden langs de bewegingspaden. Het uitbuiten van de temporele correlatie gebeurtbijvoorbeeld bij toepassingen in het videocoderingsdomein en het videoruisonderdrukkings-domein. De combinatie van de bewegingsestimatie en -compensatie met de driedimensionalewavelettransformatie wordt ook wel de bewegingsgecompenseerde driedimensionale wavelet-transformatie (MC3DWT) genoemd.

7.2.2 Overzicht van het MC3DWTr algoritme

De MC3DWT werd oorspronkelijk gebruikt in de videocodering. In dat domein behaalde hetgoede resultaten. Het MC3DWTr algoritme is ontstaan uit het idee dat deze techniek ookmet succes zou kunnen toegepast worden voor ruisonderdrukking van video omdat deze tech-niek toelaat de temporele correlatie tussen de frames uit te buiten. Met andere woorden nietenkel de informatie uit één frame zal aan de basis liggen van de ruisonderdrukking, maar de

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 55

Temporele decompositie

Spatiale decompositie

Drempelwaarde toepassen

Spatiale reconstructie

Temporele reconstructie

Inverse bewegingscompensatie

Bewegingsestimatie en -compensatie

Vertraging

Uitgangsframe

Huidige frame

Vorige ruisverwijderde frames

Figuur 7.4: Diagram van het MC3DWTr ruisonderdrukkingsalgoritme met een framebuffervan vier frames.

informatie uit verschillende frames wordt gecombineerd om tot een beter resultaat te komen.

In figuur 7.4 wordt het blokdiagram van het MC3DWTr algoritme weergegeven dat gebruikmaakt van een twee-niveau temporele decompositie (vier ingangsframes). De voorwaartseMC3DWT komt overeen met de eerste drie stappen. De inverse MC3DWT met de laatstedrie stappen. De ingangsframes van de transformatie bestaan uit voorgaande ruisonderdrukteframes en het huidige met ruis vervuild frame. Het idee achter dit recursief schema is omnog beter de temporele correlatie uit te buiten tussen de frames aangezien er zo meer frameseen rechtstreekse of onrechtstreekse bijdrage leveren in het ruisonderdrukkingsproces van elkeframe. Na het uitvoeren van de voorwaartse MC3DWT volgt de ruisonderdrukkingsstap.Hierbij wordt er een drempelwaarde toegepast op elk van de driedimensionale waveletsubban-den. Daarna volgt de inverse MC3DWT om de frames opnieuw te reconstrueren.

Eén frame wordt als uitgangsframe gekozen. In [38] werd vastgesteld dat de middelste fra-mes de hoogste kwaliteit vertonen, omdat deze frames meerdere keren gefilterd worden. Hetzou daarom logisch zijn één van deze te kiezen als uitgangsframe. Dit zorgt echter wel voor

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 56

een zekere vertraging tussen het moment waarop een met ruis vervuild frame het algoritmebinnenkomt en het moment waarop dit frame het algoritme opnieuw verlaat. De keuze vanuitgangsframe zal dus afhangen van het tijdskritische karakter van de toepassing of de noodaan kwaliteit.

Een deel van de gereconstrueerde frames kan verder nog (optioneel) verwijderd worden en decorresponderende nog gebufferde frames kunnen dan in een volgende iteratie hergebruikt wor-den. Dit vermindert de uitvoeringstijd zonder de ruisonderdrukkingsprestatie te verminderen.

In de volgende sectie worden nog enkele details van het algoritme overlopen.

7.2.3 Details van het MC3DWTr algoritme

Bewegingsestimatie en -compensatie

Een eerste stap in het algoritme is de bewegingsestimatie en -compensatie stap. Het doelvan deze stap is om de pixels van de voorgaande ruisonderdrukte frames zo goed mogelijk tealigneren met die van het nieuwe vervuild frame. Dit is zoals eerder vermeld nodig om zogoed mogelijk de temporele correlatie uit te buiten tussen de frames, wat belangrijk is omeen goede ruisonderdrukkingsprestatie te bekomen en om artefacten te vermijden.

Om te kunnen aligneren moet er aan bewegingsestimatie worden gedaan tussen het nieuwmet ruis vervuild frame en alle voorgaande frames. Bewegingsestimatie houdt het bepalenvan bewegingsvectoren in. Dit zijn vectoren die de beweging tussen de pixels van twee framesaangeeft.

Er worden twee methoden gehanteerd om de bewegingsvectoren te bepalen tussen het nieuwmet ruis vervuild frame en de voorgaande frames. Tussen twee opeenvolgende frames wordteen bewegingsestimatie algoritme gebruikt om de bewegingsvectoren te bepalen. Tussen tweeniet opeenvolgende frames wordt gebruikgemaakt van de opeenvolgende bewegingsvectorenvan de tussenliggende frames. Concreet houdt dit in dat de bewegingsvectoren van opeenvol-gende frames geaccumuleerd worden om zo de bewegingsvectoren tussen de niet opeenvolgendeframes te bepalen:

vk−1(z) = uk−1(z) (7.4)

en

vk−d−1(z) = vk−d(z) + uk−d−1(z + vk−d(z))d = 1, ...,K − 2

(7.5)

Hierbij is z de spatiale locatie, vk−d(z) de bewegingsvector tussen het (k-d)de frame en hetnieuw met ruis vervuild frame k, uk−d−1(z) de bewegingsvector tussen het (k-d-1)de frameen het (k-d)de frame en K de lengte van de frame buffer.

Na het vinden van de bewegingsvectoren kunnen deze gebruikt worden om de bewegingsge-compenseerde voorgaande frames te bekomen:

xk−d(z) = xk−d(z + vk−d(z))d = 1, ...,K − 1

(7.6)

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 57

Hierbij stelt xk−d(z) het bewegingsgecompenseerde (k-d)de frame en x(k−d)(z) het (k-d)deframe uit de buffer voor. Deze bewegingsgecompenseerde frames en het huidig met ruis ver-vuild frame worden dan verder gebruikt in de volgende stap van het algoritme. Uiteindelijkna het ruisonderdrukkingsproces wordt op de bewegingsgecompenseerde frames de inversebewegingscompensatie toegepast:

xk−d(z + vk−d(z)) = xk−d(z)d = 1, ...,K − 1

(7.7)

Hierna wordt dan één frame het uitgangsframe en wordt de framebuffer bijgewerkt met hetnieuw ruisonderdrukt frame en de geüpdatete voorgaande frames.

Temporele decompositie en reconstructie

Er wordt voor de ééndimensionale temporele wavelettransformatie gebruikgemaakt van degedecimeerde wavelettransformatie met de Haar wavelet. Naast snelheid is de voornaamstereden hiervoor dat er geen periodische uitbreiding nodig is om de wavelettransformatie uit tevoeren. Bij wavelets met een grotere filterlengte zal een deel van de transformatie plaats vin-den over de laatste en de eerste frames, net door de periodische uitbreiding. Dit is natuurlijkniet gewenst aangezien de correlatie tussen deze frames beperkt zoniet onbestaande zal zijn.

Spatiale decompositie en reconstructie

De spatiale decompositie en reconstructie vindt plaats aan de hand van een wavelettransfor-matie. Er zijn verschillende varianten van deze transformatie maar hier zal gebruikgemaaktworden van een orthogonale wavelettransformatie zoals beschreven in hoofdstuk 6. Er kanzowel een gedecimeerde als een niet-gedecimeerde wavelettransformatie gebruikt worden ende lengte van de waveletfilter kan vrij gekozen worden.

Drempelwaarde toepassen

Het ruisonderdrukkingsproces vindt plaats in het driedimensionale waveletdomein. In [38]wordt aangegeven dat technieken voor tweedimensionale waveletdomeinruisonderdrukkingook kunnen toegepast worden in het driedimensionale waveletdomein omdat de driedimensi-onale waveletcoëfficiënten dezelfde clusterings- en persistentiekenmerken vertonen als tweedi-mensionale waveletcoëfficiënten. In beide gevallen kunnen deze beschreven worden door eenveralgemeende Gaussiaanse distributie en bestaan er correlaties binnen een subband en tussende verschillende subbanden.

Bij een tweedimensionale wavelettransformatie van een afbeelding zullen de hoogfrequente wa-veletsubbanden, namelijk de HH, HL en de LH subbanden waveletcoëfficiënten bevatten metgrote absolute waarde. Deze waveletcoëfficiënten worden veroorzaakt door grote verschillentussen naburige pixels in de originele afbeelding, bijvoorbeeld randen en hoeken van objectenin de afbeelding en bepaalde patronen, zoals bijvoorbeeld een lijnpatroon in een kledingstuk.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 58

Naast deze grote waveletcoëfficiënten zullen er ook waveletcoëfficiënten zijn met kleine abso-lute waarde. Deze treden op bij kleine verschillen tussen pixelwaarden, wat bijvoorbeeld bijhomogene gebieden zal voorkomen. De waveletcoëfficiënten zijn verder niet onafhankelijk vanelkaar. Er is een sterke correlatie tussen naburige coëfficiënten van een waveletsubband enook tussen de verschillende waveletsubbanden.

Indien Gaussiaanse ruis wordt toegevoegd aan de originele afbeelding dan leidt dit tot dezelfdeGaussiaanse ruis in de waveletsubbanden bij het gebruik van een orthogonale wavelettrans-formatie. Ondanks de ruis kan gesteld worden dat waveletcoëfficiënten die groot waren bijde originele decompositie ook nog groot zullen zijn bij de decompositie van de met ruis ver-vuilde afbeelding. In figuur 7.5 wordt dit geïllustreerd voor de lena afbeelding waar ruis metstandaardafwijking σn = 10 is aan toegevoegd.

HL2

HH2LH2

LL2

LH1 HH1

HL1

Figuur 7.5: Tweedimensionale wavelettransformatie van de met ruis vervuilde lena afbeelding(σn = 10).

Dit levert een methode op om ruis in een afbeelding te onderdrukken. Door na de decomposi-tie een drempelwaarde toe te passen op de waveletsubbanden kan de ruis onderdrukt worden.Alle waveletcoëfficiënten kleiner dan een bepaalde drempelwaarde worden hierbij op nul ge-plaatst. De waveletcoëfficiënten groter dan de drempelwaarde kunnen behouden blijven ofeventueel ook aangepast worden. Het toepassen van de drempelwaarde zal tot verminderingvan de ruis leiden, terwijl de beeldkenmerken van de afbeelding zo goed mogelijk bewaardblijven.

Andere technieken gaan nog een stap verder en zullen rekening houden met de correlaties tus-sen de waveletoëfficiënten van een waveletsubband en/of correlaties tussen de verschillende

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 59

waveletsubbanden. Deze kennis gebruikt men dan om te bepalen in welke mate de waveleto-ëfficiënten moeten aangepast worden.

In het MC3DWTr algoritme wordt de tweedimensionale ruisonderdrukkingstechniek toege-past op alle subbanden van de driedimensionale waveletpiramide waarbij er een invloed wasvan het huidige frame. In figuur 7.3 zijn dit de temporele subbanden H1

1 , H02 en L0

2. Door hettoepassen van de ruisonderdrukkingstechniek zullen de (kleine) verschillen tussen de framesverwijderd worden. Deze verschillen vinden voor een groot deel hun oorsprong in de witteadditieve ruis.

De meeste tweedimensionale ruisonderdrukkingstechnieken maken gebruik van zogenaamderuisschatting. Via deze ruisschatting wordt de hoeveelheid ruis in het beeld geschat. Dezestap is belangrijk om te bepalen welke drempelwaarde moet toegepast worden en dus hoeveelhet ruisonderdrukkingsalgoritme zal moeten filteren. Met het additief Gaussiaans model vande ruis houdt ruisschatting in dat de standaardafwijking σn van de Gaussiaanse distributiegeschat wordt. Eénmaal de ruis geschat is, kan deze schatting door de ruisonderdrukkings-techniek gebruikt worden. De exacte gebruikte schatting hangt af van het temporeel niveau.Meer bepaald wordt de originele schatting geschaald met een factor 1√

2 voor elke hoger tem-poreel niveau.

7.3 Implementatie op de GPU: algemeen

In eerste instantie wordt in dit gedeelte de gevolgde aanpak om het algoritme naar de GPUover te brengen besproken. Dit gebeurt in sectie 7.3.1.

Daarna wordt in de daarop volgende gedeeltes aandacht besteed aan het CPU raamwerk.Hierbij wordt in sectie 7.3.2 eerst de datastructuren voorgesteld die werden gebruikt in deGPU implementatie. Daarna volgt in sectie 7.3.3 een overzicht van het CPU raamwerk.

De eigenlijke creatie van de functionaliteit op de GPU wordt besproken in gedeelte 7.4.

7.3.1 Algemene aanpak bij de implementatie

De algemeen gevolgde aanpak voor de implementatie van dit algoritme is om het in eersteinstantie op te splitsen in zijn deelcomponenten, meer bepaald:

• De bewegingsestimatie en -compensatie

• De temporele wavelettransformatie

• De spatiale wavelettransformatie

• De ruisschatting

• De ruisonderdrukking

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 60

Deze componenten worden los van elkaar naar de GPU gebracht. Om dit te doen wordenze nog verder onderverdeeld in een sequentie van stappen. Deze stappen worden dan inge-vuld door reeds bestaande GPU bouwstenen of door eigen implementaties van deze stappen.Hierbij werd telkens zo goed mogelijk rekening gehouden met de GPU architectuur en hetbovenliggende CUDA programmeermodel.

Deze verschillende stappen worden dan aaneengeschakeld via de CPU code om de functional-teit van elke component vast te leggen en om uiteindelijk de functionaliteit van het volledigealgoritme vast te leggen.

Hieronder wordt verder het CPU raamwerk toegelicht, in sectie 7.4 komen de implementatie-details van elke component aan bod.

7.3.2 Datastructuren in de implementatie

Een eerste aspect dat besproken wordt is het ontwerp van de datastructuren voor gebruik inhet raamwerk. Het idee bij dit ontwerp was voornamelijk om zo goed mogelijk het verschiltussen data op de GPU en data op de CPU te verbergen.

Dit ontwerp zal uitgelegd worden aan de hand van een voorbeeld, namelijk het datagrid. Hetdatagrid stelt tweedimensionale data voor, bijvoorbeeld een afbeelding. Een datagrid kanvastgelegd worden in het geheugen met de structuur in code fragment 7.1.

s t r u c t DataGrid{i n t breedte ;i n t hoogte ;f l o a t ∗ g r id ;

} ;

Code Fragment 7.1: DataGrid structuur bestaande uit een breedte, hoogte en een wijzer naarhet grid

De wijzer grid wijst hierbij naar een bepaalde geheugenlocatie waar de data zich bevindt.Deze geheugenlocatie kan zowel in het RAM geheugen (op het moederbord) of in het hoofd-geheugen op de GPU liggen. Dit hangt af van waar de data gealloceerd werd.

Deze DataGrid structuur wordt daarna geaggregeerd in twee klassen, namelijk DataGrid-CPU en DataGridGPU. In de constructor van deze klassen zal de data van de onderliggendeDataGrid structuur gealloceerd worden, in de destructor terug vrijgegeven. Bij de DataGrid-CPU zal de data gealloceerd worden in het RAM geheugen, terwijl bij de DataGridGPU dedata zal gealloceerd worden in het hoofdgeheugen van de GPU. Anders verwoord, bij eenobject van de DataGridCPU klasse zal de grid wijzer naar een locatie in het RAM geheugenwijzen, terwijl bij een object van de DataGridGPU klasse deze naar een locatie in het hoofd-geheugen van de GPU zal wijzen. Dit wordt in figuur 7.6 weergegeven.

Samengevat kan gesteld worden dat DataGridCPU een datagrid voorstelt voor gebruik metCPU functies, terwijl DataGridGPU een datagrid voorstelt voor gebruik bij GPU kernels.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 61

Float * grid;

DataGrid

int width;

int height;

DataGridCPU

Float * grid;

DataGrid

int width;

int height;

DataGridGPU

RAM geheugen (moederbord)

GPU geheugen

Figuur 7.6: Het verband tussen een DataGridCPU en een DataGridGPU object. Bij hetDataGridCPU object zal de grid wijzer steeds wijzen naar een locatie in het RAM geheugen,terwijl bij de DataGridGPU de grid wijzer steeds zal wijzen naar een locatie in het GPUgeheugen. Conversie tussen beide DataGrids is mogelijk.

Aan een GPU kernel kan geen object van een klasse meegegeven worden, maar de structDataGrid en de wijzer grid kunnen wel meegegeven worden als argument. Hiervoor zijn toe-gangsfuncties in de klasse voorzien.

Op deze manier wordt al de (de)allocatie van data op de GPU verborgen. Om ook het ko-piëren van en naar de GPU eenvoudiger te maken werden in beide klassen conversiefunctiesvoorzien. Deze converteren een object van de ene klasse naar een object van de andere klasse.Dit wordt ook in figuur 7.6 geïllustreerd.

Het grote voordeel van deze aanpak is de abstractie die ze creëert. De programmeur weet inwelk geheugen de data zich bevindt via het gebruik van de klassen. Hierdoor hoeft hij zichniets meer aan te trekken van de GPU specifieke code voor databeheer.

Een tweede voordeel van deze aanpak is dat de metadata (de breedte en de hoogte) van hetdatagrid in beide klasses beschikbaar blijft voor het controleverloop in de CPU code.

In het uiteindelijk raamwerk werden nog drie andere datastructuren op deze wijze geïmple-menteerd:

• Een datastructuur voor een bewegingsveld MotionVectorField

• Een datastructuur voor één niveau van een tweedimensionale waveletpiramide SubBand

• Een datastructuur voor de geschatte ruisstandaardafwijking Float

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 62

Verder werden nog containers gebruikt om deze datastructuren te groeperen:

• Een PyramidGPU verzamelt objecten van het type SubBandGPU. Deze container wordtgebruikt om een volledige tweedimensionale waveletpiramide voor te stellen.

• De Pyramid3dGPU container verzamelt objecten van het type PyramidGPU. Dezewordt gebruikt om een volledige driedimensionale waveletpiramide voor te stellen.

• De containter GOP verzamelt objecten van het type DataGridGPU. Een verzamelingvan frames wordt hiermee voorgesteld.

Deze containers bevinden zich allemaal in het RAM geheugen en niet op de GPU.

7.3.3 Het raamwerk

Het raamwerk van de GPU implementatie kan op dezelfde manier opgebouwd worden alseen raamwerk voor een CPU implementatie. Er is gekozen om van een componentsgewijzeopbouw gebruik te maken. Dit laat toe om eenvoudig componenten te wisselen voor eenalternatieve component. Hiervoor werden abstracte klassen voor de volgende componentenvastgelegd:

• De bewegingsestimatie

• De ruisschatting

• De ruisonderdrukkingstechniek

Deze klassen leggen de manier van aanroepen vast van de component. Bijvoorbeeld de ab-stracte klasse voor de ruisschatting ziet er als volgt uit:

c l a s s WavNoiseEstimationGPU {pub l i c :

/∗\ b r i e f Schat de r u i s s tandaarda fw i jk ing in een a f b e e l d i n g\param input de subband d i e gebru ik t wordt om het r u i s n i v e a u te schatten\param output de ge s cha t t e r u i s s tandaarda fw i jk ing∗/v i r t u a l void parse (DataGridGPU<f l o a t > ∗ input , FloatGPU ∗ output ) = 0 ;

} ;

Code Fragment 7.2: De abstracte ruisschatting klasse. De klasse legt de manier van aanroepenvast.

In klassen die overerven van deze abstracte klassen wordt dan de eigenlijke functionaliteitvastgelegd van de component. Deze functionaliteit wordt gevormd uit een aaneenschakelingvan de GPU bouwblokken (zoals die uit hoofdstuk 3) en GPU kernels. In de volgende sectiewordt per component van het algoritme in meer detail ingegaan op de invulling van dezefunctionaliteit.

Voor de overige twee componenten, de bewegingscompensatie en de driedimensionale wavelet-transformatie zijn geen abstracte klassen voorzien, aangezien deze een vaste invulling hebben.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 63

Het volledige algoritme wordt dan uiteindelijk gevormd uit de correcte aaneenschakeling vandeze componenten. Bij deze aaneenschakeling is er verder voor gezorgd dat de CPU codezo efficiënt mogelijk is. Het is namelijk zo dat de GPU kernels worden opgeroepen vanuitde CPU code en indien de CPU er niet op tijd in slaagt om de GPU te voorzien van eenvolgende opdracht, dan zal een deel van de beschikbare rekentijd verloren worden. Dit moetdus vermeden worden zeker met het oog op ware tijd uitvoering.

7.4 Implementatie op de GPU: details

In deze sectie wordt component per component overlopen hoe deze werd geïmplementeerdop de GPU. Hierbij komt de implementatie van elke component aan bod en de gemaakteafwegingen om het algoritme meer geschikt te maken voor ware tijd uitvoering.

7.4.1 Bewegingsestimatie en -compensatie

Voor het bepalen van de bewegingsvectoren waren er twee algoritmes die in het MC3DWTralgoritme werden gebruikt:

• Een bewegingsestimatie algoritme om de beweging te schatten tussen het huidige metruis vervuild frame en het hier net aan voorafgaande frame.

• Een recursief algoritme om de onderlinge bewegingsvectoren samen te stellen tot debewegingsvectoren tussen het met ruis vervuild frame en de overige voorgaande frames.

Na het bepalen van deze bewegingsvectoren kon dan de bewegingscompensatie stap uitge-voerd worden.

In eerste instantie werd voor het bewegingsestimatie algoritme een blokgebaseerd Volledig-Zoek algoritme (Eng: Full Search) geïmplementeerd. Dit is een veelgebruikt algoritme omde bewegingsestimatie uit te voeren en wordt ook in het originele algoritme gebruikt. Ditalgoritme wordt hieronder verder toegelicht.

Het blokgebaseerd Volledig-Zoek algoritme

Bij het blokgebaseerd Volledig-Zoek algoritme wordt het huidige frame in eerste instantieopgedeeld in niet overlappende blokken. Dan wordt er per blok in het voorgaande frame eenblok gezocht dat zo goed mogelijk hiermee overeenstemt. Dit zoeken gebeurt niet over hetvolledige voorgaande frame, maar is typisch beperkt tot een venster. Dit venster in het voor-gaande frame is gecentreerd rond de positie van het blok in het huidig frame. Dit zoekproceswordt weergegeven in figuur 7.7. Hier wordt gezocht in een venster rond de positie van hetblok (x, y) over een zoekafstand z. Elke bewegingsvector in het venster [x ± z ,y ± z] zalworden getoetst. De beste van deze bewegingsvectoren wordt dan gekozen.

Om de overeenkomst tussen de blokken te kwantificeren wordt gebruikgemaakt van een cri-terium. Een veelgebruikt criterium is het gemiddelde absolute afwijking (MAD) criterium.Bij dit criterium wordt in eerste instantie bij elke bewegingsvector een gemiddeld absoluutverschil berekend tussen de twee blokken. Meer bepaald zal een gemiddeld absoluut verschil

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 64

Zoekvenster

Voorgaande frame Huidige frame

z n

nz

Beste overeenkomst

(x,y) (x,y)

Figuur 7.7: Zoeken van het best overeenkomende blok in het voorgaande frame. Er wordtgezocht in een venster rond de positie van het blok (x, y) over een zoekafstand z. Elkebewegingsvector in het venster [x± z ,y ± z] zal worden getoetst.

bepaald worden tussen het bij deze bewegingsvector horende blok P in het voorgaande frameen het blok C in het huidige frame:

MAD = 1n2

n∑i=1

n∑j=1|P (i, j)− C(i, j)| (7.8)

Voor elke bewegingsvector zal er één gemiddeld absoluut verschil bepaald worden. De bestebewegingsvector is dan deze met het kleinste gemiddelde verschil. Bij deze bewegingsvectoris de afwijking tussen het blok in het voorgaande frame en het huidige frame het kleinst.

Het volledige algoritme zal elk blok b van het huidig frame overlopen. Hiervoor wordt elkemogelijke bewegingsvector v overlopen in het zoekvenster horend bij het blok en wordt debeste bewegingsvector bepaald. In pseudocode kan dit als volgt worden voorgesteld:

for blok b = 1→ B dofor bewegingsvector v = 1→ V do

if MAD(v) < MAD(beste(b)) thenbeste(b) = v

end ifend for

end for

Dit algoritme efficiënt naar de GPU overbrengen is niet eenvoudig. De buitenste lus is nogeenvoudig parallelliseerbaar en een logische aanpak is om elk blok van het huidig frame telaten overeenkomen met één blok van draden. Anders verwoord, elk blok van draden zalde beste bewegingsvector bepalen van één blok in het huidig frame. De draden in een blok

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 65

moeten dan instaan om de MAD waarden horende bij de bewegingsvectoren te bepalen enuiteindelijk te bepalen welk van deze de beste is. De binnenste lus in parallel uitvoeren isechter niet mogelijk. Het probleem hierbij is dat het in parallel controleren van de MADwaarden een raceconditie zal introduceren. Stel bijvoorbeeld dat twee draden a en b eenbewegingsvector controleren en beiden een MAD waarde bekomen die lager is dan de reedsbest gevonden waarde en dat de waarde van draad a nog lager is dan de waarde van draadb. Aangezien er geen garantie is omtrent de uitvoeringsvolgorde kan de volgende reeks vanoperaties voorkomen:

1. Draad b controleert of zijn bepaalde MAD waarde lager is dan de beste reeds gevondenwaarde.

2. Draad a controleert of zijn bepaalde MAD waarde lager is dan de beste reeds gevondenwaarde.

3. Draad a overschrijft de best gevonden MAD waarde met zijn MAD waarde en vernieuwtook de best gevonden bewegingsvector.

4. Draad b overschrijft de best gevonden MAD waarde met zijn MAD waarde en vernieuwtook de best gevonden bewegingsvector.

Met andere woorden de bewegingsvector van draad b wordt verder gebruikt in plaats vandeze van draad a, hoewel deze niet beter is. De enige oplossing voor dit probleem is om decontrole en het vernieuwen van de beste bewegingsvector sequentieel te laten verlopen. Ditkan bijvoorbeeld door één draad de controle en het vernieuwen te laten uitvoeren. In eenconcrete implementatie zal elke draad van het blok dan één MAD waarde berekenen. Nasynchronisatie van de draden in het blok zal dan één enkele draad de beste MAD waarde enbijhorende bewegingsvector bepalen.

Het feit dat slechts één draad de beste MAD waarde bepaalt is echter weinig efficiënt en zaleen impact hebben op de prestatie bij grotere zoekvensters. Dit kan echter wel nog verbeterdworden. De beste bewegingsvector kan bepaald worden via een parallelle minreductie. Hierbijwordt de verzameling van MAD waarden gereduceerd tot één waarde, zijnde het minimumvan de lijst. Simultaan met deze reductie wordt ook de lijst met bewegingsvectoren geredu-ceerd tot de bewegingsvector die hoort bij het minimum uit de lijst.

De uiteindelijke CUDA implementatie volgt de voorgaande procedure, specifiek zal elk blokvan draden de volgende operaties uitvoeren:

• Eerst worden de pixels van het blok uit het huidig frame en deze van het venster inhet voorgaande frame ingelezen in het gedeeld geheugen. Voor dit inleesproces wordtgebruik gemaakt van het textuurgeheugen, om onsamengevoegde geheugentoegangen tevermijden. Deze onsamengevoegde geheugentoegangen zouden optreden ten gevolge vanniet gealigneerde geheugentoegangen bij het inlezen van de pixels van het zoekvenster.

• Na synchronisatie zal elke draad in het blok dan de MAD waarde horende bij éénbewegingsvector bepalen.

• Hierna wordt dan opnieuw gesynchroniseerd en de parallelle minreductie uitgevoerd omde beste bewegingsvector te bepalen.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 66

• Eén draad schrijft de beste bewegingsvector weg naar het globaal geheugen.

Hierboven staat de eerste geïmplementeerde versie beschreven. Deze heeft echter het pro-bleem dat de zoekafstand beperkt wordt doordat er een beperking is op het aantal draden ineen blok2. Deze beperking kan echter verholpen worden door elke draad van een blok nietéén maar meerdere bewegingsvectoren te laten testen.

Bij steeds groter wordende zoekvensters zal hier verder ook het probleem optreden dat hetgedeeld geheugen dat elk blok vereist steeds hoger en hoger wordt. Dit zal uiteindelijk ookde zoekafstand beperken aangezien het gedeeld geheugen beperkt is. De enigste oplossinghiervoor is om geen gebruik te maken van gedeeld geheugen, maar dit zal aanzienlijk presta-tieverlies teweegbrengen. Daarom is gekozen om het zoekvenster beperkt te houden.

In de uiteindelijke implementatie wordt gebruikgemaakt van drie vaste zoekafstanden, na-melijk 3, 7 en 15. Dit geeft genoeg diversiteit en levert geen problemen op met het beperktgedeeld geheugen. De blokgroottes, zijnde de blokken waarin de originele afbeelding wordtopgesplitst kunnen 4x4, 8x8 of 16x16 zijn.

De uitvoeringsresultaten van dit algoritme komen aan bod in sectie 7.4.1. Uit de resultatenblijkt dat bij grotere zoekvensters het Volledig-Zoek algoritme een hoge uitvoeringstijd heeft.Daarom is nog gezocht naar een alternatief van dit algoritme dat gelijkaardige prestatieskan bieden in minder tijd. Het gevonden alternatief is het hiërarchisch algoritme en wordthieronder verder toegelicht.

Het hiërarchisch algoritme

In [39] worden een tiental bewegingsestimatie algoritmes voorgesteld en met elkaar vergele-ken. Uit deze vergelijkende studie werd bepaald dat het beste zoekalgoritme qua kwaliteit hetVolledig-Zoek algoritme is, maar dat de kwaliteit van een zogenaamd hiërarchisch zoekalgo-ritme hier dicht bij ligt. Naast de goede kwaliteit vraagt dit algoritme ook minder rekentijddan het Volledig-Zoek algoritme.

Zoals de naam doet vermoeden maakt het hiërarchisch zoekalgoritme gebruik van een hië-rarchie om de bewegingsvectoren tussen twee frames te bepalen. Van de twee frames wordtelk een piramide p geconstrueerd via onderbemonstering. In eerste instantie werd hiervoorgewoon alle oneven rijen en kolommen verwijderd. Dit leverde echter een weinig kwalitatiefresultaat op, vooral door de invloed van de ruis in de frames. Er werd dan gekozen om eerstuit te middelen per blok van vier pixels en dan pas te onderbemonsteren. Meer bepaald wordthet niveau L gegenereerd uit het voorgaande niveau L− 1 op de volgende wijze:

pL(m,n) = 14(

1∑u=0

1∑v=0

pL−1(2m+ u, 2n+ v)) (7.9)

Dit kan beschouwd worden als een laagdoorlaatfilter. Door uit te middelen in plaats vangewoon rijen en kolommen te verwijderen wordt beter de invloed van ruis op gevangen, wat

2Bij een 8800GT is het maximaal aantal draden per blok gelijk aan 512. Dit laat een maximale zoekafstandtoe van 10

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 67

met het oog op toepassing in het algoritme van belang is.

Elk niveau van deze piramides is qua grootte een vierde van het vorige (fijnere) niveau. Hetbepalen van de uiteindelijke bewegingsvectoren gebeurt via propagatie van de bewegings-vectoren van de ruwste schaal naar de fijnste schaal. Tijdens deze propagatie worden debewegingsvectoren verder verfijnd. Deze verfijning houdt in dat de bewegingsvectoren vaneen bepaald niveau gebruikt worden als startpunt van het zoekalgoritme op het vorige fijnereniveau. Om als startpunt te dienen van een hoger niveau moet de bewegingsvector geschaaldworden met een factor twee.

Het grote voordeel qua rekentijd van deze methode is dat de zoekvensters op elke schaal be-perkt kunnen zijn aangezien de bewegingsvectoren van de vorige schaal als startpunt dienen.Enkel op de ruwste schaal is er geen informatie van het voorgaande niveau, hier gaat dantypisch ook een groter zoekvenster gebruikt worden. De zoektijd op de ruwste schaal zalechter wel beperkt blijven aangezien de frames onderbemonsterd zijn.

Een nadeel van deze methode is dan weer dat een verkeerde bewegingsvector kan propagerenvan de ruwere schaal naar de fijnere schaal. Een oplossing hiervoor is om meerdere bewe-gingsvectoren te propageren naar de fijnere schalen, maar al deze bewegingsvectoren moetendan nog verder verfijnd worden. Een minder rekenintensieve oplossing is om maar één ruweschaal te hanteren.

Voor de CUDA implementatie werd naast het Volledig-Zoek algoritme ook zo een hiërarchischalgoritme geïmplementeerd. Hierbij wordt gebruikgemaakt van één ruwe schaal. Op deze ruw-ste schaal bepaalt een Volledig-Zoek algoritme met blokgrootte van 8x8 en zoekafstand 7 deruwe bewegingsvectoren. Op het fijnste niveau worden de uiteindelijke bewegingsvectorenmet een Volledig-Zoek algoritme met blokgrootte 16x16 en zoekafstand 3 bepaald. Via dezeconfiguratie kan men een vergelijkbare prestatie bekomen als met het Volledig-Zoek algoritmemet zoekafstand 15.

De eigenlijke implementatie maakt gebruik van twee kernels:

• De onderbemonsteringskernel om een frame te onderbemonsteren via uitmiddeling.Deze kernel wordt uitgevoerd met een aantal draden gelijk aan 1

4 van het totaal aantalpixels in de afbeelding. Elke draad bepaalt dan via uitdrukking 7.9 het gemiddelde vanéén blok van vier pixels en schrijft dan zijn resultaat weg.

• De originele Volledig-Zoek kernel.

Na het tweemaal uitvoeren van de onderbemonsteringskernel, éénmaal op het huidige frameen éénmaal op het voorgaande frame, worden deze onderbemonsterde frames gebruikt alsingangsframes voor de Volledig-Zoek kernel. De bewegingsvectoren die hieruit voortkomenworden dan samen met de originele frames aan de Volledig-Zoek kernel meegegeven om dande uiteindelijke bewegingsvectoren te bepalen.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 68

Het recursieve algoritme

Het recursieve algoritme wordt gebruikt om de bewegingsvectoren te bepalen tussen het huidigen de overige voorgaande frames. Dit algoritme wordt nogmaals opgefrist:

vk−1(z) = uk−1(z) (7.10)

en

vk−d−1(z) = vk−d(z) + uk−d−1(z + vk−d(z))d = 1, ...,K − 2

(7.11)

Hierbij is z de spatiale locatie, vk−d(z) de bewegingsvector tussen het (k-d)de frame en hetnieuw met ruis vervuild frame k, uk−d−1(z) de bewegingsvector tussen het (k-d-1)de frameen het (k-d)de frame en K de lengte van de framebuffer.

Het algoritme overbrengen naar een CUDA implementatie is eenvoudig omdat elke spatialelocatie z in parallel kan verwerkt worden. Eén kernel wordt gebruikt om de recursieve bewe-gingsvectoren te bepalen tussen het huidig frame en één van de voorgaande frames. In dezekernel zal elke draad één recursieve bewegingsvector bepalen via uitdrukking 7.11.

Deze kernel wordt meermaals uitgevoerd om de bewegingsvectoren te bepalen tussen alleframes. Met bijvoorbeeld vier ingangsframes i = 0..3 zal deze kernel tweemaal uitgevoerdworden, éénmaal om de bewegingsvectoren tussen frame 0 en frame 2 te bepalen. Deze be-wegingsvectoren worden dan samen met de bewegingsvectoren tussen frame 2 en frame 3nogmaals als ingang gegeven om de bewegingsvectoren tussen frame 0 en frame 3 te bepalen.

Een probleem kan optreden bij deze kernel waardoor de performantie aanzienlijk kan verlaagdworden. De oorzaak hiervan ligt in de term uk−d−1(z + vk−d(z)). Het gedeelte z + vk−d(z),zijnde de positie waar uit gelezen moet worden om de bewegingsvector op te halen, kan be-perkte correlatie vertonen met naburige posities. De reden hiervoor is dat de bewegingstra-jecten per pixel van een blok kunnen verschillen, zoals in figuur 7.8 wordt geïllustreerd. Eendeel van de pixels uit het blauwe blok zullen een traject via het rode blok volgen, andere viahet groene blok. De posities waaruit gelezen zal worden kunnen hierdoor dus verschillen vandraad tot draad. In figuur 7.9 wordt dit nogmaals voorgesteld voor een 4 bij 4 blok.

Figuur 7.8: De pixels van een blok kunnen elk een verschillend pad volgen.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 69

(0,0) (0,1)

(1,0) (1,1)

(2,1) (0,0)

(1,4) (2,0)

(2,1) (0,1)

(2,4) (3,1)=+

z v(z) z + v(z)

Figuur 7.9: Het mogelijk probleem bij de recursieve bepaling van de bewegingsvector. Er kanweinig correlatie zijn tussen naburige bewegingsvectoren, hierdoor gaan de geheugentoegangenvan de draden onsamengevoegd verlopen.

Het eigenlijke probleem dat hiermee gepaard gaat is dat de geheugentoegangen van de dradenin een warp niet correct gealigneerd of niet sequentieel kunnen verlopen. Hierdoor zullen degeheugentoegangen van deze draden niet samengevoegd kunnen worden, waardoor er extrageheugentoegangen vereist zullen zijn. Het gebruik van het textuurgeheugen zal dit slechtsgedeeltelijk kunnen opvangen, daar dit vooral geschikt is voor geheugentoegangen met eensequentieel toegangspatroon. In het extreme geval kan het voorkomen dat voor elke geheu-gentoegang een aparte geheugentransfer plaats moet vinden. Hiermee moet dus rekeninggehouden worden met het oog op ware tijd uitvoering van het algoritme aangezien dit kanleiden tot schommelingen in de verwerkingstijden van de frames. De precieze impact hiervanwordt besproken in de resultaten in sectie 7.4.1.

Bewegingscompensatie

Bij de bewegingscompensatie gaan de bepaalde bewegingsvectorvelden toegepast worden opde beelden in de buffer. De voorwaartse bewegingscompensatie kan als volgt worden voorge-steld in pseudocode:

for z = 1→ Z doxk−d(z) = xk−d(z + vk−d(z))

end for

Hierbij stelt xk−d(z) het bewegingsgecompenseerde (k-d)de frame voor en x(k−d)(z) het (k-d)de frame uit de buffer.

En de inverse bewegingscompensatie om een frame te reconstrueren kan als volgt wordenvoorgesteld in pseudocode:

for z = 1→ Z doxk−d(z + vk−d(z)) = xk−d(z)

end for

Hierbij stelt x(k−d)(z) het gereconstrueerde frame en xk−d(z) het bewegingsgecompenseerde(k-d)de frame voor.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 70

In beide gevallen kan elke pixel onafhankelijk en in parallel van elkaar verwerkt worden. Voorzowel de voorwaartse als de inverse compensatie is een kernel vastgelegd. In deze kernels zalelke draad dan één spatiale locatie z voor zijn rekening nemen. Merk op dat ook hier hetzelfdeprobleem optreedt als bij het recursieve algoritme. Er moet namelijk gelezen worden van delocatie z+vk−d(z) in het voorwaartse geval en er naar geschreven worden in het inverse geval.Ook hier kunnen dus schommelingen in de uitvoeringstijd van de kernels optreden.

Resultaten en conclusie

In tabel 7.1 worden de uitvoeringssnelheden weergeven van de twee bewegingsestimatie algo-ritmes, namelijk het Volledig-Zoek algoritme en het hiërarchisch algoritme voor verschillenderesoluties.

Uitvoeringstijd (ms)Zoekalgoritme 512x512 1024x1024 2048x2048 3072x3072

Volledig-Zoek (3) 0,58 2,27 9,05 20,40Volledig-Zoek (7) 1,88 7,52 29,80 66,96Volledig-Zoek (15) 7,66 30,55 121,86 273,97

Hiërarchisch 1,29 5,08 20,36 45,95

Tabel 7.1: Uitvoeringstijden (ms) van de twee bewegingsestimatie algoritmes. De bewe-gingsestimatie werd telkens uitgevoerd tussen paren van frames voor de resoluties 512x512,1024x1024, 2048x2048 en 3072x3072. Het Volledig-Zoek algoritme werd uitgevoerd met driezoekafstanden, namelijk 3, 7 en 15. De blokgrootte bij het Volledig-Zoek algoritme was 16bij 16.

De geschiktheid van het Volledig-Zoek algoritme voor ware tijd uitvoering van het ruison-derdrukkingsalgoritme hangt af van een aantal factoren. De resolutie van de ingangsvideospeelt een rol samen met het beoogde aantal frames dat per seconde verwerkt moet worden.Indien het beoogde aantal frames per seconde 30 (33ms per frame) is, dan kan dit algoritmegebruikt worden voor ware tijd uitvoering. Hoe groot de zoekafstand kan zijn, hangt af van deresolutie van de ingangsvideo. Bij grotere zoekafstanden moeten meer bewegingsvectoren ge-controleerd worden, wat zowel zorgt voor een verhoging in de rekentijd als voor een verhogingin de geheugentransfers. Dit leidt ertoe dat grote zoekvensters slechts geschikt zullen zijn voorlage resoluties. Een groot zoekvenster is echter wel interessant om correcte bewegingsvectorente bekomen bij snelle beweging. Het hiërarchisch algoritme biedt hier een oplossing voor. Intabel 7.2 wordt de kwaliteit van de ruisonderdrukking bekomen met deze twee algoritmes ver-geleken. Om de kwaliteit tussen de twee algoritmes te kwantificeren wordt gebruikgemaaktvan de objectieve piek signaal-ruisverhouding (PSNR). Deze is als volgt gedefinieerd:

PSNR = 10 log10(MAX2

MSE ) (7.12)

Hierbij isMAX de maximale waarde die een pixel in de afbeelding kan aannemen. Aangezienhier uitsluitend gewerkt wordt met grijswaarde videosequenties is MAX = 255. De gemid-

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 71

delde kwadratische fout (MSE) tussen het originele beeld I en het ruisonderdrukte beeld I isgedefinieerd als volgt:

MSE = 1mn

m−1∑i=0

m−1∑j=0

(I(i, j)− I(i, j))2 (7.13)

Uit de tabel kan geconcludeerd worden dat het hiërarchisch algoritme een gelijkaardige kwa-liteit biedt als het Volledig-Zoek algoritme met zoekafstand 15. Het maximale verschil inPSNR loopt slechts op tot 0,17 dB. Het hiërarchisch algoritme is echter ongeveer een factor 6sneller in de uitvoering, zoals blijkt uit tabel 7.1. Dit maakt het een interessant alternatief enlaat ware tijd toepassing toe voor hogere resoluties. Indien zeer hoge resoluties (2048x2048en hoger) het doel zijn, dan kan een hiërarchisch algoritme gebruikt worden met meerdereniveaus of kan nog gezocht worden naar een ander alternatief.

σn 10 15 20techniek Salesman

Volledig-Zoek (15) 36,20 33,67 31,70Hiërarchisch 36,19 33,66 31,71

TennisVolledig-Zoek (15) 34,32 31,96 30,36

Hiërarchisch 34,15 31,82 30,20Flower Garden

Volledig-Zoek (15) 31,87 29,38 27,64Hiërarchisch 31,81 29,32 27,59

Tabel 7.2: PSNR (dB) waarden behaald met het Volledig-Zoek algoritme en het Hiërarchischalgoritme voor variërende ruisniveaus.

De impact van de ongecorreleerde geheugentoegangen wordt in tabel 7.3 weergegeven voor hetrecursief algoritme en in tabel 7.4 voor de bewegingscompensatie. In het beste geval, indienalle geheugentoegangen samengevoegd kunnen verlopen, dan zal de uitvoeringssnelheid vande kernels een factor 3 hoger liggen dan in het slechtste geval waarbij alle geheugentoegangenonsamengevoegd verlopen. In de praktijk zal de waarde tussen deze twee uitersten liggen.Zoals eerder aangehaald kan dit schommelingen in de verwerkingstijden van de frames teweegbrengen. Vooral bij hogere resoluties zal dit duidelijk merkbaar zijn. Het zal daarom belang-rijk zijn om hier rekening mee te houden en genoeg marge te voorzien om deze schommelingenop te vangen.

Uitvoeringstijd (ms)Geval 512x512 1024x1024 2048x2048 3072x3072

Beste geval 0,17 0,65 2,63 5,93Slechtste geval 0,49 1,90 7,78 17,66

Tabel 7.3: Uitvoeringstijden (ms) van de kernel voor het bepalen van de recursieve bewegings-vectoren voor verschillende resoluties. Het slechtste en het beste geval wordt weergegeven.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 72

Uitvoeringstijd (ms)Geval 512x512 1024x1024 2048x2048 3072x3072

Beste geval 0,10 0,36 1,43 3,21Slechtste geval 0,27 1,06 4,14 9,33

Tabel 7.4: Uitvoeringstijden (ms) van de kernel voor het uitvoeren van de voorwaartse/inversebewegingscompensatie voor verschillende resoluties. Het slechtste en het beste geval wordtweergegeven.

7.4.2 De wavelettransformaties

De temporele wavelettransformatie

Bij de implementatie van de temporele wavelettransformatie werden twee kernels vastgelegd.Eén voor de voorwaartse temporele ontbinding van twee frames en één voor de inverse tem-porele reconstructie van twee frames.

In de voorwaartse kernel zal elke draad één uitgangselement bepalen in de laag- en hoogfre-quente subband. Hiervoor zal elke draad één pixel inlezen van elk van de twee ingangsframes.Via de formules 7.2 en 7.3 kan dan elke draad dan één waveletcoëfficiënt uit de hoogfrequenteen laagfrequente subband bepalen en wegschrijven naar het globale geheugen.

De inverse kernel is nagenoeg identiek en zal een laag- en hoogfrequente subband terug sa-menstellen naar twee laagfrequente subbanden of twee ingangsframes.

Om de volledige temporele transformatie uit te voeren zullen deze kernels dan meermaalsmoeten uitgevoerd worden. De uitvoeringstijden van de temporele transformatie voor ver-schillende framebuffergroottes worden weergegeven in tabel 7.5.

Uitvoeringstijd (ms)# frames 512x512 1024x1024 2048x20482 frames 0,18 0,70 2,804 frames 0,55 2,12 8,388 frames 1,27 5,01 19,54

Tabel 7.5: Uitvoeringstijden (ms) van de temporele transformatie (voorwaarts en invers) voorverschillende framebuffergroottes en resoluties.

Een piste die hier niet onderzocht is, is om de volledige transformatie (dus alle niveaus) uit tevoeren met één kernel. Om alle coëfficiënten van de temporele waveletdecompositie te bepalenop een bepaalde spatiale locatie z, is slechts kennis vereist van de pixels op spatiale locatiez in de ingangsframes. Dus door een draad alle pixels op locatie z te laten inlezen kan dezealle coëfficiënten op locatie z bepalen. Het voordeel hierbij zou dan zijn dat de intermediairecoëfficiënten van de laagfrequente Li banden niet telkens weggeschreven moeten worden naarhet hoofdgeheugen. Deze aanpak had hierdoor een zekere snelheidswinst kunnen betekenen,

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 73

vooral bij grotere framebuffergroottes (acht en meer).

De spatiale wavelettransformatie

De spatiale wavelettransformatie wordt uitgevoerd met een orthogonale wavelettransformatie.In het originele algoritme is dit met de Farras [40] wavelet, die een filterlengte heeft van tien.Omdat de transformatie meermaals uitgevoerd moet worden per iteratie van het algoritme isgekozen om voor het GPU algoritme gebruik te maken van de meest eenvoudige en snelstetransformatie namelijk deze met de Haar wavelet, die een filterlengte heeft van slechts twee.Vanwege de kortere lengte van de Haar wavelet kan de transformatie aanzienlijk sneller be-paald worden dan met de Farras wavelet, wat met het oog op ware tijd uitvoering van belangis. De gebruikte implementatie is deze die gebruikmaakt van textuurgeheugen beschreven inhoofdstuk 6.

De gebruikte transformatie kan verder zowel een gedecimeerde als een niet-gedecimeerdetransformatie zijn. De niet-gedecimeerde transformatie zal een hogere kwaliteit bekomen dande gedecimeerde transformatie. Dit blijkt uit tabel 7.13 waar de behaalde PSNR waardenworden weergegeven voor drie videosequenties: Salesman, Foreman en Flower Garden. Uitde tabel kan worden afgeleid dat de niet-gedecimeerde wavelettransformatie hogere PSNRwaarden haalt, typisch tussen de 0,3-1,7 dB.

σn 10 15 20techniek Salesman

MC3DWTr GPU TIDWT 36,19 33,66 31,71MC3DWTr GPU DWT 34,76 32,04 30,05

ForemanMC3DWTr GPU TIDWT 35,91 33,63 31,98MC3DWTr GPU DWT 34,81 32,42 30,69

Flower GardenMC3DWTr GPU TIDWT 31,81 29,32 27,59MC3DWTr GPU DWT 31,49 28,81 26,95

Tabel 7.6: PSNR (dB) waarden behaald met de niet-gedecimeerde (TIDWT) en de gedeci-meerde (DWT) transformatie voor variërende ruisniveaus en videosequenties.

Het gebruik van de gedecimeerde transformatie heeft echter wel voordelen. Zo kan deze aan-zienlijk sneller bepaald worden, zal de ruisonderdrukkingstechniek sneller uitgevoerd kunnenworden doordat er minder waveletcoëfficiënten verwerkt moeten worden en is de vereiste ge-heugenopslag lager. De keuze voor de transformatie hangt dus af of een meer kwaliteitsvollereconstructie het doel is of hogere resoluties/verwerkingssnelheden het doel zijn. Hier is ge-kozen om net zoals in de configuratie van het originele algoritme verder te werken met degedecimeerde wavelettransformatie.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 74

7.4.3 Ruisschatting

De ruisschattingsstap is onderdeel van het ruisonderdrukkingsproces. Zoals eerder aangehaaldwordt de ruis verondersteld een Gaussiaanse distributie te volgen. De ruisschatting zelf houdtin dat de standaardafwijking σn van deze Gaussiaanse distributie geschat wordt.

In het orginele MC3DWTr algoritme gebeurt deze schatting op de H1HH1 subband. Dit is dehoogste frequentiesubbandHH1 van de spatiale decompositie van de hoogfrequente temporelesubband H1. Deze subband H1 wordt bepaald uit de temporele transformatie over het huidigmet ruis vervuild frame en het voorgaande frame. Hierbij kan gebruikgemaakt worden vaneen techniek voor de ruisschatting in het tweedimensionale waveletdomein. In het algoritmeis dit de veelgebruikte robuuste mediaan schatter [41].

De robuuste mediaan schatter

De robuuste mediaan schatter [41] schat de standaardafwijking van het ruis in de HH1 sub-band door de mediaan te nemen van de absolute waarde van de waveletcoëfficiënten en ditdaarna te delen door 0, 6754. Symbolisch wordt dit:

σn = mediaan(|w(m,n)|)0, 6745 , w(m,n) ∈ subbandHH1 (7.14)

De implementatie op de GPU van deze schatter kan eenvoudig door gebruik te maken van desorteer bouwblok. De precieze bepaling gebeurt via de volgende sequentie van stappen:

• Eerst zal een kernel de elementsgewijze absolute waarde nemen van elke waveletcoëffici-ënt w(m,n) in de subbandHH1. Elke draad zal hierbij één waveletcoëfficiënt verwerken.

• Daarna wordt de sorteeroperatie gebruikt om deze waarden te sorteren.

• Hierna volgt dan nog een kernel uitgevoerd met één draad die de middelste waarde uitdeze gesorteerde rij neemt en deze deelt door 0,6745.

Het gebruikte algoritme om de sorteeroperatie uit te voeren is het radix sort algoritme uit deCUDPP bibliotheek [8]. Het is dit algoritme dat de prestatie van de schatter volledig bepaalt.Zoals uit de resultaten in sectie 7.4.3 kan geconcludeerd worden loopt de uitvoeringstijd snelop met hoger wordende resoluties. Dit is te verklaren door de complexiteit van dit algoritme,dit is namelijk O(kn) met k het aantal bits van de te sorteren elementen (hier 32 bit). Hetaantal vergelijkingen dat hierdoor uitgevoerd moet worden loopt hierdoor steeds verder op.Bijvoorbeeld om een miljoen elementen te sorteren moeten 32 miljoen vergelijkingen uitge-voerd worden.

De robuuste mediaan schatter is vanwege de sorteeroperatie daarom minder geschikt voorware tijd uitvoering bij hogere resoluties. De prestatie zou bijvoorbeeld wel verbeterd kunnenworden door de waveletband eerst éénmaal of tweemaal te onderbemonsteren. Hierdoor is hetaantal elementen dat gesorteerd moet worden een factor vier of 16 kleiner. De uitvoeringstijdblijft echter dan nog aan de hoge kant. Daarom is gekeken naar alternatieven voor dezeschatter. Een eerste onderzocht alternatief is de variantie schatter.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 75

De variantie schatter

De variantie schatter is een eenvoudige techniek om een schatting te bekomen van de ruis. Hetachterliggende idee bij deze schatter is dat de coëfficiënten van de HH1 subband observatieszijn van de Gaussiaanse ruis. De meest aannemelijke schatter voor de variantie σ2

n wordt dangegeven door:

σ2n = 1

mn

∑m,n

w(m,n)2, w(m,n) ∈ subbandHH1 (7.15)

De CUDA implementatie hiervan maakt gebruik van de reductie operatie, waarmee op eenefficiënte manier de volledige som kan bepaald worden. Om deze operatie te gebruiken wordtde term 1

mn binnen de sommatie gebracht. De concrete bepaling gaat als volgt:• Een kernel zal eerst elke waveletcoëfficiënt w(m,n) elementsgewijs kwadrateren en delen

door het aantal coëfficiënten. Het resultaat hiervan w(m,n)2

mn wordt naar het globaalgeheugen weggeschreven.

• Daarna zal via de reductie operatie de volledige som van het voorgaande resultaat endus de schatting σ2

n van de ruis bepaald worden.De resultaten in sectie 7.4.3 geven het snelheidsvoordeel aan van dit algoritme ten opzichtevan de robuuste mediaan schatter. Bij een resolutie van 2048x2048 loopt dit voordeel op toteen factor van 100, wat zijn oorzaak vindt in de efficiëntie waarmee een reductie operatie kanuitgevoerd worden. Als gekeken wordt naar de kwaliteit van de schatting, weergegeven intabel 7.7 dan is die echter over heel de lijn slechter dan die van de robuuste mediaan schatter.Dit komt omdat de inhoud van het beeld een grotere invloed heeft op de schatting. Indienhet beeld veel hoogfrequente inhoud heeft, zoals randen, hoeken en texturen dan zullen diein de subband gereflecteerd worden door grote waveletcoëfficiënten. Hierdoor zal de variantievan de subband ook een hogere waarde aannemen, wat leidt tot een onnauwkeurige schattingvan de ruis.

Er is daarom nog gezocht naar een alternatief dat een betere balans biedt tussen kwaliteit enuitvoeringssnelheid. De passende moment schatter leek een goed alternatief te zijn.

De passende moment schatter

In de passende moment methode [42] wordt verondersteld dat het ruisvrije beeld I een Lap-laciaanse distributie kent. In combinatie met het Gaussiaanse ruismodel wordt dan het 2deen 4de moment van het met ruis vervuild beeld In gegeven door:

m2 = σ2I + σ2

n

m4 = 6σ4I + 3σ4

n + 6σ2Iσ

2n

(7.16)

Deze momenten worden geschat als volgt:

mk = 1mn

∑m,n

w(m,n)k, w(m,n) ∈ subbandHH1 (7.17)

Hierbij is wederom verondersteld dat het gemiddelde nul is. Indien 7.16 opgelost wordt naarde onbekende ruisvariantie en de geschatte momenten worden ingevuld dan krijgt men:

σ2n = m2

(1−

√13m4m2

2− 1

)(7.18)

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 76

In het geval dat m4 < 3m22 dan wordt σ2

n = m2. In het geval dat m4 > 6m22 dan wordt σ2

n = 0gesteld. Deze gevallen komen voor indien de afbeelding geen Laplaciaanse distributie kent.

Het bepalen van deze ruisschatting op de GPU is analoog aan deze van de variantie schatter:

• De schatting van het 2de moment wordt bepaald door een kernel eerst elementsgewijs dewaveletcoëfficiënten te laten kwadrateren en delen door het aantal coëfficiënten. Daarnawordt dan via een reductie operatie het uiteindelijke 2de moment bepaald.

• De schatting van het 4de moment is analoog aan het 2de moment, maar met dat verschildat er elementsgewijs de 4de macht genomen wordt in plaats van te kwadrateren.

• Uiteindelijk wordt dan nog een kernel met één draad uitgevoerd die via 7.18 de uitein-delijke ruisschatting bepaalt.

Qua snelheid heeft dit algoritme ongeveer een dubbel zo hoge uitvoeringstijd als de variantieschatter. Dit is te verwachten aangezien er twee parallelle reductie operaties in plaats vanéén plaats vinden. De kwaliteit is echter op het eerste zicht aanzienlijk beter dan zowel devariantie als de robuuste mediaan schatter. Tabel 7.7 geeft echter een vertekend beeld. Deschatter veronderstelt een Laplaciaanse distributie van het beeld. Dit is echter maar een modelen hier wordt niet altijd aan voldoen. Bijvoorbeeld bij de videosequentie Flower Garden werdbij het ruisniveau σn = 5 voor het overgrote deel van de frames telkens m4 > 6m2

2. Dit leverdedan een schatting op van σ2

n = 0. Dit heeft tot gevolg dat er geen ruisonderdrukking plaatsvindt aangezien er volgens de schatter geen aanwezig is. Dit is natuurlijk niet gewenst. Delokale variantie schatter hieronder kent dit probleem niet en is ook performant genoeg voorware tijd uitvoering.

De lokale variantie schatter

De lokale variantie [43, 44] schatter is gerelateerd aan de variantie schatter. Deze schatterdeelt de waveletband op in niet overlappende blokken en gaat het ruisniveau schatten via hetgemiddelde van de kleinste varianties van deze blokken. Op deze manier wordt de invloedvan afbeeldingskenmerken zoals randen en hoeken beperkt. Het aantal blokken waarover uit-gemiddeld wordt is een vast percentage p van het totaal aantal blokken T .

Het bepalen van de lokale varianties van elk blok kan in parallel gebeuren. Aan elk blokwordt één blok van draden toegekend. Er is gekozen voor blokken van 8x8 omdat dit eengoed compromis levert tussen kwaliteit en uitvoeringssnelheid. Elk blok van draden zal ineerste instantie de waveletcoëfficiënten van het toegekende blok in gedeeld geheugen inlezen.De draden van het blok zullen dan een parallelle reductie uitvoeren van de kwadraten vandeze ingelezen waarden. Dit levert de som op van deze kwadraten. Na synchronisatie zal danéén draad de uiteindelijke variantie van het blok bepalen en wegschrijven.

Aangezien het gemiddelde moet genomen worden van de kleinste van de lokale varianties moe-ten deze eerst gesorteerd worden. Dit kan via de sorteeroperatie. Door een blokgrootte van8x8 is het aantal elementen dat gesorteerd moet worden 1

64 van de grootte van de waveletband.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 77

Na het verkrijgen van de gesorteerde rij moet hiervan nog het gemiddelde genomen wordenvan de eerste k = pT elementen. Dit kan efficiënt uitgevoerd worden via de prefixsom opera-tie. Deze bepaalt de cumulatieve som van de elementen in de rij. Het is dan nog een kwestievan het element k − 1 uit de berekende prefixsom te halen en deze te delen door het aantalblokken k.

Zoals blijkt uit de resultaten uit sectie 7.4.3 is de kwaliteit van deze schatter gemiddeld ge-nomen de beste. Qua uitvoeringssnelheid is deze aanzienlijk sneller dan de robuuste mediaanschatter, maar wel trager dan de variantie en de passende moment schatter. Deze schatter isgeschikt voor ware tijd uitvoering en kan dus in de implementatie gebruikt kunnen worden.

De volledige resultaten worden hieronder verder besproken.

Resultaten

σn Mediaan Variantie Moment Lokale variantieE σE E σE E σE E σE

5 1,56 1,03 2,38 1,98 2,18 0,54 1,35 1,7110 1,41 1,10 1,75 1,50 0,99 0,57 0,95 1,0215 1,23 1,01 1,48 1,30 0,80 0,44 0,91 0,7820 1,09 0,91 1,23 1,15 0,84 0,46 0,90 0,5825 0,90 0,90 1,05 1,08 0,92 0,55 0,85 0,4730 0,84 0,79 0,97 0,97 1,09 0,72 0,97 0,39

Gemiddelde 1,17 0,95 1,48 1,33 1,13 0,54 0,99 0,83

Tabel 7.7: Het gemiddelde absolute verschil E en de standaardafwijking σE van de vier ruis-schatters: de robuuste mediaan schatter, de variantie schatter, de passende moment schatteren de lokale variantie schatter. Er zijn vier videosequenties gebruikt: Salesman, Foreman,Flower Garden en Tennis.

Tabel 7.7 toont de resultaten qua ruisschattingsprestatie van de vier ruisschatters in termenvan het gemiddelde absolute verschil E:

E =∑Ni=1EiN

(7.19)

Hierbij staat N voor het aantal metingen en is Ei het absolute verschil tussen σn(i) en σe(i),respectievelijk de geschatte standaardafwijking van de ruis en de werkelijke standaardafwij-king van de ruis. Ei werd bepaald via:

Ei = |σn(i)− σe(i)| (7.20)

De standaardafwijking σE is bepaald volgens:

σE =

√√√√ 1N

N∑i=1

(Ei − E)2 (7.21)

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 78

Uit de tabel kan afgeleid worden dat over het algemeen de lokale variantie schatter het bestepresteert, gevolgd door de passende moment schatter. De overige twee schatters: de robuustemediaan en de variantie schatters zijn respectievelijk derdes en vierdes gerangschikt qua ge-middelde ruisschattingsprestatie. De variantie schatter presteert daarenboven over heel delijn slechter dan de overige drie.

Als gekeken wordt naar de individuele ruisniveaus, dan behaalt de lokale variantie schattergemiddeld genomen de beste schattingen voor de ruisniveaus σn = 5, 10 en 25. De schattingenvoor de ruisniveaus σn = 15 en 20 zijn het meest accuraat met de passende moment schatter.De robuuste mediaan schatter ten slotte is gemiddeld genomen het beste voor het ruisniveauσn = 30.

Uitvoeringstijd (ms)Ruisschatter 512x512 1024x1024 2048x2048Mediaan 4,85 17,98 106,73Variantie 0,08 0,27 1,05

Passende moment 0,16 0,54 2,11Lokale variantie 0,51 0,96 3,05

Tabel 7.8: Uitvoeringstijden (ms) van de vier ruisschatters: de robuuste mediaan schatter, devariantie schatter, de lokale variantie schatter en de passende moment schatter. De uitvoeringgebeurde op de GPU voor verschillende resoluties.

In tabel 7.8 worden de uitvoeringstijden (ms) op de GPU weergegeven van de vier ruisschat-ters. Het eerste dat hierbij meteen in het oog springt is de hoge uitvoeringstijd van de robuustemediaan schatter ten opzichte van de overige drie. De oorzaak hiervan is te vinden in de sor-teeroperatie die moet uitgevoerd worden over alle waveletcoëfficiënten van de subband om demediaan te bepalen. Om de uitvoeringstijd te verlagen zou men eerst de waveletband één-of tweemaal kunnen onderbemonsteren vooraleer de mediaan te bepalen, maar de uitvoe-ringstijden zullen dan nog steeds hoger zijn dan bij de overige schatters. De andere schatterdie gebruik maakt van een sorteeroperatie, de lokale variantie schatter heeft een aanzienlijklagere uitvoeringstijd dan de robuuste mediaan schatter. Het aantal elementen dat gesorteerdmoet worden is slechts 1

64 van het totaal aantal elementen in de waveletsubband en de impactop de prestatie hiervan is daardoor beperkt. De variantie schatter die een reductie operatieuitvoert, heeft de laagste uitvoeringstijd, vanwege de efficiëntie waarmee een reductie opera-tie kan worden uitgevoerd. Aangezien de passende moment schatter gebruikmaakt van tweereducties is het te verwachten dat deze tweemaal zo traag is.

Als de balans wordt gemaakt qua kwaliteit tegenover uitvoeringstijd, dan kan gesteld wordendat de lokale variantie schatter de beste keuze is. Deze levert gemiddeld genomen de besteruisschattingen op en is snel genoeg om in ware tijd uit te voeren.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 79

7.4.4 Ruisonderdrukking

De ruisonderdrukkingsstap houdt in dat een algoritme voor ruisonderdrukking uit het twee-dimensionale waveletdomein wordt toegepast op de driedimensionale waveletsubbanden. Inhet originele algoritme is dit het BivariateShrinkage algoritme [45].

Het BivariateShrinkage algoritme

Het BivariateShrinkage algoritme is een algoritme dat gebruikmaakt van de informatie uittwee subbanden om de aanpassing van een waveletcoëfficiënt te bepalen. Hierbij speelt deomgeving van de waveletcoëfficiënt in de waveletband een rol en de ouder van deze waveletco-ëfficiënt. De ouder van een waveletcoëfficiënt k bevindt zich op dezelfde positie maar op eenhoger niveau. Indien w2k de ouder voorstelt van w1k, dan kan samen met de veronderstellingvan witte Gaussiaanse ruis geschreven worden dat y1k = w1k+n1k en y2k = w2k+n2k. Hierbijis yik de met ruis vervuilde waveletcoëfficiënt en nik de ruis component. Het algoritme schatw1 (de k werd weggelaten voor betere leesbaarheid) via de maximum a posteriori (MAP)schatter w1:

w1 =(√y2

1 + y22 −

√3σ2n

σ )+√y2

1 + y22

y1 (7.22)

Hierbij is (x)+ equivalent met max(x, 0) en is σ de marginale standaardafwijking van dewaveletcoëfficiënt y1. Deze kan geschat worden via de uitdrukking:

σ =√

(σ2y − σ2

n)+ (7.23)

Met σ2n de geschatte ruis variantie en σ2

y de marginale variantie van y1 en y2. Deze laatstekan geschat worden uit de lokale variantie van y1:

σ2y = 1

M

∑yiεN(k)

y2i (7.24)

Hierbij is M de grootte van een (rechthoekige) omgeving N(k) rond y1.Om het voorgaande samen te vatten, is de te volgen sequentie van stappen als volgt:

1. Eerst moet een schatting gemaakt worden met een ruisschatter om σ2n te bekomen.

2. Daarna wordt voor elke waveletcoëfficiënt k (k=1..aantal waveletcoëfficiënten) de vol-gende stappen uitgevoerd:

(a) σ2y wordt berekend via uitdrukking 7.24.

(b) Daarna wordt σ berekend via uitdrukking 7.23.(c) Uiteindelijk wordt in uitdrukking 7.22 σ en σ2

y ingevuld, waarna de originele wa-veletcoëfficiënt w1 geschat kan worden.

In het originele MC3DWTr algoritme wordt gebruikgemaakt van een spatiale wavelettransfor-matie met drie niveaus. Dit algoritme past enkel de waveletcoëfficiënten aan van de HL, LHen HH subbanden van de twee eerste niveaus. Het derde niveau blijft onveranderd aangeziendeze geen ouder in een hoger niveau heeft. Qua grootte van de omgeving N(k) wordt een 5x5

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 80

gebied gekozen. Volgens [45] biedt dit een gelijkaardige kwaliteit aan als een 7x7 gebied.

Voor de overbrenging van dit algoritme naar de GPU kan gebruikgemaakt worden van departiële prefixsom. De lokale varianties σ2

y uit uitdrukking 7.24 kunnen namelijk als volgtbepaald worden:

• Een kernel zal eerst elementsgewijs de waveletcoëfficiënten kwadrateren en delen doorM .

• Een partiële prefixsom wordt uitgevoerd over de rijen van dit resultaat. De parameterm, het aantal elementen waarover gesommeerd moet worden, is gelijk aan de breedtevan het rechthoekige gebied.

• Daarna wordt opnieuw een partiële prefixsom uitgevoerd, maar deze keer over de ko-lommen van het voorgaande resultaat. De parameter m is hier gelijk aan de hoogte vanhet rechthoekige gebied.

Dit geeft voor elke waveletcoëfficiënt de lokale variantie σ2y .

Hierna is het dan nog slechts een kwestie van via uitdrukkingen 7.23 en 7.22 de uiteindelijkewaarde van elke waveletcoëfficiënt te bepalen. Dit kan in parallel gebeuren voor elke wavelet-coëfficiënt. De volledige ruisonderdrukking gebeurt door het bovenstaande proces te herhalenvoor elke subband.

Omdat dit algoritme meerdere malen moet uitgevoerd worden per iteratie is nog gezocht naareen alternatief dat performanter is en niet veel aan kwaliteit moet inboeten. Een mogelijkalgoritme dat hier aan voldoet is het BayesShrink algoritme.

Het BayesShrink algoritme

Het BayesShrink algoritme [46] bepaalt per subband een drempelwaarde die moet toegepastworden op elke van de waveletcoëfficiënten van deze subband. Het algoritme verondersteltdat de originele waveletcoëfficiënten een algemene Gaussiaanse distributie volgen. Onderdeze veronderstelling en met de veronderstelling van Gaussiaanse ruis legt het algoritme eenoptimale drempelwaarde T vast voor elke subband w:

Tw = σ2n

σx(7.25)

Hierbij is σ2n de geschatte standaardafwijking van het Gaussiaanse ruis en σx de geschatte

standaardafwijking van de originele subband zonder ruis. Deze laatste schatting kan bepaaldworden uit de relatie:

σ2y = σ2

x + σ2n (7.26)

Hierbij stelt σ2y de variantie van de met ruis vervuilde subband voor, σ2

x de variantie van deoriginele ruisvrije subband en σ2

n de variantie van de Gaussiaanse ruis. Deze relatie geldt inhet geval van additieve witte Gaussiaanse ruis, zoals hier het geval is. De variantie van demet ruis vervuilde subband kan empirisch bepaald worden via de relatie:

σ2y = 1

mn

∑m,n

w(m,n)2 (7.27)

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 81

Door de geschatte variantie σ2y en de geschatte ruisvariantie σ2

n in te vullen in 7.26 kan degeschatte variantie σ2

x bekomen worden van de subband. In het geval dat σ2x negatief of nul

zou zijn dan worden de waveletcoëfficiënten van de subband op nul geplaatst. Indien dit niethet geval is wordt de uiteindelijke drempelwaarde toegepast op de volgende manier:

w(m,n) = max(w(m,n)− T, 0) indien w(m,n) ≥ 0w(m,n) = min(w(m,n) + T, 0) indien w(m,n) < 0

(7.28)

Dit algoritme wordt uitgevoerd op elk van de HL, LH en HH subbanden van elk niveau vande waveletdecompositie. In tegenstelling tot het BivariateShrinkage algoritme wordt ook hethoogste niveau dus aangepast. Er is daarom gekozen om dit algoritme toe te passen op eentwee-niveau ontbinding in tegenstelling tot de gebruikte drie-niveau ontbinding voor het Bi-variateShrinkage algoritme.

Het BayesShrink algoritme naar de GPU brengen is relatief eenvoudig. De variantie van elkewaveletband kan opnieuw efficiënt bepaald worden via de reductie operatie.

Er is verder gekozen om een kernel te ontwikkelen die de drempelwaarde bepaalt en toepastper waveletsubband. Elke draad zal hierbij afzonderlijk de drempelwaarde 7.25 berekenenen toepassen op een waveletcoëfficiënt. Aangezien de drempelwaarde dezelfde is voor elkewaveletcoëfficiënt zou een alternatief geweest zijn om dit éénmaal te berekenen. Deze aan-pak is ook getest door per blok van draden de drempelwaarde éénmaal te berekenen. Eéndraad bepaalde hierbij deze drempelwaarde. Na synchronisatie konden de overige draden dandeze drempelwaarde toepassen op de hun toegekende waveletcoëfficiënt. De synchronisatie-vertraging maakte echter dat het verschil qua uitvoeringstijd tussen de twee alternatievenverwaarloosbaar was.

Bij het toepassen van de drempelwaarde via uitdrukking 7.28 werd in eerste instantie eenconditioneel pad gebruikt afhankelijk van het teken van de waveletcoëfficiënt. Dit vermin-derde echter de prestatie aangezien de twee uitvoeringspaden sequentieel worden uitgevoerd.Een verbeterde prestatie werd bekomen door de uitdrukking 7.28 te herformuleren naar éénuitdrukking:

w(m,n) = copysign(max(|w(m,n)| − T, 0), w(m,n)) (7.29)

Hierbij is de copysign(x,y) functie een functie die het teken van y kopieert naar x. Via dezeherformulering is geen conditioneel pad meer nodig en zullen alle draden in parallel uitgevoerdworden.

De resultaten van dit algoritme worden hieronder verder besproken.

Resultaten

In tabel 7.9 worden de resultaten weergegeven van het algoritme uitgerust met de twee ruis-onderdrukkingsalgoritmes in termen van PSNR waarden. Uit de tabel kan geconcludeerdworden dat de kwaliteit van de ruisonderdrukking bij beide algoritmes gelijkaardig is. Hetverschil in PSNR waarden blijft beperkt tot maximum 0,5 dB. Het BayesShrink algoritme is

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 82

σn 10 15 20techniek Salesman

BivariateShrinkage 34,76 32,04 30,05BayesShrink 34,68 32,22 30,33

ForemanBivariateShrinkage 34,81 32,42 30,69

BayesShrink 34,31 32,08 30,56Flower Garden

BivariateShrinkage 31,49 28,81 26,95BayesShrink 31,04 28,40 26,62

Tabel 7.9: PSNR (dB) waarden behaald met het algoritme uitgerust met het BivariateShrin-kage en het BayesShrink algoritme voor variërende ruisniveaus en videosequenties. Bij hetBivariateShrinkage algoritme werden drie decompositieniveaus gebruikt voor de spatiale wave-lettransformatie (gedecimeerde wavelettransformatie) en bij het BayesShrink algoritme warendit er slechts twee.

hierdoor een goed alternatief voor het BivariateShrinkage algoritme.

Tabel 7.10 toont de uitvoeringssnelheden van de twee algoritmes voor verschillende resolu-ties. Hierbij is te zien dat het BayesShrink algoritme over alle resoluties heen 45% sneller kanuitgevoerd worden dan het BivariateShrinkage algoritme. Dit laatste algoritme wordt vooralvertraagd door het berekenen van de lokale varianties: dit bedraagt 70% van de totale uitvoe-ringstijd. Bij nog grotere vensters om de lokale variantie te schatten loopt dit nog verder op:bij een 7x7 venster bedraagt dit al 79%. Dit is voornamelijk te wijten aan de extra vereistebewerkingen.

Uitvoeringssnelheid (ms)techniek 512x512 1024x1024 2048x2048

BivariateShrinkage 0,72 2,55 10,12BayesShrink 0,40 1,48 5,70

Tabel 7.10: Uitvoeringssnelheid (ms) van het BivariateShrinkage en het BayesShrink algo-ritme voor één schaal met verschillende resoluties. De lokale variantie in het BivariateShrin-kage algoritme is geschat met een 5x5 venster.

Omdat het ruisonderdrukkingsalgoritme meerdere malen moet uitgevoerd worden per iteratievan het algoritme is uiteindelijk gekozen voor het BayesShrink algoritme dat een snelheids-winst heeft van 45% ten opzichte van het BivariateShrinkage algoritme. Verder kan hierdoorde spatiale decompositie beperkt worden tot twee niveaus wat opnieuw snelheidswinst ople-vert.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 83

7.5 Resultaten en bespreking

In deze sectie worden de behaalde resultaten besproken van het GPGPU algoritme. Eerstwordt de volledige configuratie van het algoritme nog eens herhaald:

Voor de bewegingsestimatie tussen twee opeenvolgende frames wordt het hiërarchisch algo-ritme (7.4.1) gebruikt. Voor het bepalen van de bewegingsvectoren tussen twee niet opeen-volgende frames wordt het recursieve algoritme (7.4.1) toegepast. De temporele decompositiegebeurt met de gedecimeerde Haar wavelettransformatie (7.4.2). De spatiale wavelettrans-formatie is een twee-niveau gedecimeerde Haar wavelettransformatie (7.4.2). De gebruikteruisonderdrukkingstechniek is BayesShrink (7.4.4) dat voor de ruisschatting gebruik maaktvan de lokale variantie schatter (7.4.3).

7.5.1 Behaalde uitvoeringssnelheid

In tabel 7.11 wordt weergegeven hoeveel frames het algoritme kan verwerken per seconde.Hierbij wordt een onderscheid gemaakt tussen de minimale en de maximale hoeveelheid fra-mes dat per seconde verwerkt kan worden. Het verschil tussen deze twee vindt zijn oorzaakin het recursieve algoritme en de bewegingscompensatie. Deze twee kunnen zoals eerder aan-gegeven schommelingen veroorzaken in de uitvoeringstijden van het algoritme. De waardenin de tabel zijn de uiterste waarden die aangenomen kunnen worden. In de praktijk zal hetaantal frames dat per seconde verwerkt wordt hier tussen liggen.

gemiddeld # frames per seconde (fps)256x256 512x512 1024x1024

Min Max Min Max Min MaxMC3DWTr GPU (2) 348,60 361,19 184,79 197,18 62,84 68,90MC3DWTr GPU (4) 259,24 294,34 117,54 146,03 36,25 47,87MC3DWTr GPU (8) 155,90 191,05 64,51 89,27 19,98 30,53

Tabel 7.11: Het behaalde aantal frames per seconde van de GPU implementatie voor vari-ërende framebuffergroottes en resoluties. Het van en naar de GPU kopiëren van frames isinbegrepen in de resultaten. De framebuffergrootte is aangeven tussen de ronde haakjes. Deingangsframes waren grijswaarde frames. De gebruikte CPU is de AMD64 3800+ processoren de gebruikte GPU is de NVIDIA 8800GT.

Het uiteindelijke algoritme laat ware tijd (minimum 30 frames per seconde) verwerking toevoor hoge resoluties tot 1024x1024. In het beste geval kan gekozen worden voor elk van dedrie framebuffergroottes. Indien echter gekeken wordt naar de minimaal mogelijke frames perseconde, dan kan slechts ware tijd uitvoering bekomen worden voor een video van 1024x1024mits het gebruik van een framebuffergrootte van vier frames of lager.

Bij deze resultaten moet wel de bedenking gemaakt worden dat deze bekomen zijn met deietwat verouderde NVIDIA 8800GT. Recentere GPUs beschikken over een groter aantal mul-tiprocessoren en grotere en snellere geheugens waardoor een verbeterde prestatie zal bekomenworden. Deze extra prestatie zou het toelaten om hogere resoluties in ware tijd te verwerken.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 84

Verder zou bijvoorbeeld ook de overstap kunnen gemaakt worden naar kleurenvideo.

Een tweede opmerking die hier van belang is, is dat het algoritme niet beperkt is tot video-resoluties waarbij de breedte en de hoogte gelijk moeten zijn. Het is voldoende dat zowelde breedte als de hoogte een veelvoud zijn van 64. Het gebruik van de twee-niveau gedeci-meerde wavelettransformatie is hiervan de oorzaak. De kernel beschreven in sectie 6.4.2 omeen niveau van de transformatie te bepalen wordt uitgevoerd met blokken van draden vanvaste grootte. Deze blokken zijn 16x16 en bepalen een 16x16 gebied van elke waveletsubband.Hiervoor is uit het ingangsframe of de LL-subband een gebied nodig van 32 bij 32. Doordateen twee-niveau ontbinding wordt gebruikt leidt dit tot de vereiste dat zowel de breedte als dehoogte van de ingangsframes een veelvoud moeten zijn van 64. Als de resolutie van de videohier niet aan voldoet, zullen de frames uitgebreid moeten worden totdat dit wel het geval is.

Verdere mogelijke optimalisatie

In dit gedeelte wordt bekeken wat de impact is van elke component in het algoritme op deuitvoeringssnelheid. Op deze manier kunnen dan die factoren geïdentificeerd worden die hetmeeste uitvoeringstijd vergen. In tabel 7.12 worden deze uitvoeringstijden weergegeven voorelk van de componenten uit het algoritme. De weergegeven tijden zijn de hoogst mogelijkeuitvoeringstijden van elke component.

Component tijd (ms) % duurtijdBewegingsestimatie 9,18 42%

Bewegingscompensatie 3,17 14%Temporele decompositie 1,06 5%Spatiale decompositie 1,03 5%

Ruisschatting 0,51 2%Ruisonderdrukking 1,79 8%

Spatiale reconstructie 0,96 4%Temporele reconstructie 1,06 5%Inv bewegingscompensatie 3,18 15%

Totaal 21,94 100%

Tabel 7.12: Uitvoeringstijden (ms) van elke component van het algoritme. De ingangsbufferis vier frames groot en de resolutie van de ingangsframes is 1024x1024.

Uit de tabel blijkt dat de uitvoeringstijd voor het grootste deel bepaald wordt door de bewe-gingsestimatie (42%) en de bewegingscompensatie (14%+15% = 29%) componenten, samengoed voor 71% van de totale uitvoeringstijd. De uitvoeringstijden van de spatiale wavelet-transformatie (5%+4%=9%), de temporele wavelettransformatie (5%+5%=10%) en de ruis-onderdrukking (8%) zijn gelijkaardig en hebben een beperkte bijdrage. De ruisschatting tenslotte neemt slechts 2% van de totale uitvoeringstijd in beslag.

De uitvoeringstijd van het GPU algoritme zou verlaagd kunnen worden door het bewe-gingsestimatie algoritme aan te passen. Een mogelijkheid zou zijn om nog meer niveauste hanteren bij het hiërarchisch algoritme. Een alternatief algoritme voor het Volledige-Zoek

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 85

algoritme zou ook overwogen kunnen worden.

De bewegingscompensatie verbeteren qua uitvoeringstijd lijkt niet mogelijk aangezien er geendirect alternatief voorhanden is dat hetzelfde kan bekomen. Hierbij moet wel nogmaals be-nadrukt worden dat de weergegeven uitvoeringstijden de hoogst mogelijke zijn en dat inpraktische toepassingen (zoals videobewaking) deze voor de bewegingscompensatie niet zohoog zullen oplopen.

7.5.2 Kwaliteit van de ruisonderdrukking

Het MC3DWTr GPU algoritme wordt vergeleken met een configuratie van het origineleMC3DWTr algoritme [38] en met het SEQWT [47] algoritme in tabel 7.13. Hierbij wor-den de gemiddelde PSNR waarden weergegeven over drie sequenties: Salesman, Foremanen Flower Garden. De getabeleerde waarden van het originele MC3DWTr algoritme en hetSEQWT algoritme komen uit [38]. De PSNR waarden van het GPU algoritme zijn bekomenmet de eerder besproken configuratie en met een framebuffergrootte van vier frames.

De configuratie van het originele MC3DWTr algoritme zoals beschreven in [38] is als volgt:de bewegingsestimatie tussen twee frames wordt uitgevoerd met een Volledig-Zoek algoritme.De zoekafstand wordt niet vermeld in het artikel. De bewegingsvectoren tussen niet opeen-volgende frames worden bepaald met het recursieve algoritme. De bewegingsvectoren wordenuiteindelijk nog per pixel verfijnd via een zoekafstand van één pixel. De temporele wavelet-transformatie gebeurt met de gedecimeerde Haar wavelettransformatie. De spatiale (gedeci-meerde) waveletdecompositie is een drie-niveau decompositie met de Farras [40] wavelet. Hetruisonderdrukkingsalgoritme is het BivariateShrinkage algoritme dat de lokale standaardaf-wijking σ van elke waveletcoëfficiënten schat met een 7x7 gebied. De ruisschatting vindtplaats met de robuuste mediaan schatter.

Het SEQWT algoritme [47] is een spatio-temporele techniek. Het algoritme zal eerst het metruis vervuilde frame filteren met het BivariateShrinkage algoritme. Daarna wordt temporeelgefilterd via een recursief uitmiddelingsschema. Hierbij wordt enkel uitgemiddeld over diepixels waarbij geen beweging is gedetecteerd. Een parameter van deze bewegingsdetectie, debewegingsdrempelwaarde, wordt op T = σn geplaatst in de plaats van T = 23.

De PSNR waarden in tabel 7.13 geven aan dat het GPU algoritme een minder kwaliteitsvollereconstructie toelaat dan het originele algoritme voor de sequenties salesman en foreman.Hier zijn een aantal oorzaken voor. Zo werd het originele algoritme uitgevoerd met eenframebuffer van acht voor de salesman sequentie. In [38] wordt aangegeven dat dit voor desalesman sequentie leidt tot een verlies van om en bij de 1,1 dB. Het overige verschil (≈ 1, 5dB) bij de salesman en foreman sequenties is te wijten aan de verschillende vereenvoudigingen.Zo wordt in het GPU algoritme het hiërarchisch algoritme in plaats van het Volledig-Zoekalgoritme gebruikt. De verfijningsstap van de bewegingsvectoren wordt ook niet uitgevoerd.Verder wordt de spatiale wavelettransformatie uitgevoerd met de Haar wavelet van lengtetwee in plaats van de Farras wavelet van lengte tien. Ook het ruisonderdrukkingsalgoritmeten slotte is vereenvoudigd via het gebruik van het BayesShrink algoritme. De betere prestatievan het GPU algoritme bij de flower garden sequentie is te wijten aan het gebruik van eengrotere framebuffer dan het originele algoritme. Bij deze sequentie is het verschil tussen

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 86

σn 10 15 20techniek SalesmanMC3DWTr Origineel (8) 36,99 35,02 33,47MC3DWTr GPU 35,18 32,82 30,89SEQWT 32,58 30,34 28,82

ForemanMC3DWTr Origineel (4) 35,87 33,86 32,46MC3DWTr GPU 34,63 32,34 30,80SEQWT 33,51 31,36 29,87

Flower GardenMC3DWTr Origineel (2) 30,81 28,18 26,36MC3DWTr GPU 31,03 28,40 26,63SEQWT 28,88 26,30 24,54

Tabel 7.13: PSNR (dB) waarden van verschillende ruisonderdrukkingstechnieken voor vari-ërende ruisniveaus en videosequenties. De framebuffergrootte van het originele algoritme isaangeven tussen de ronde haakjes. Het GPU algoritme is uitgevoerd met een vaste framebuffervan grootte vier frames.

twee en vier frames als framebuffer ongeveer 0,7 dB. Zoals verder uit tabel 7.13 blijkt haalthet GPU algoritme systematisch hogere PSNR waarden dan het spatio-temporele SEQWTalgoritme, tussen de 0,93 en 2,6 dB. Dit is niet geheel onverwacht aangezien het MC3DWTralgoritme beter in staat is om de temporele correlatie tussen de frames uit te buiten.

7.5.3 Vergelijking met een CPU implementatie

De prestatie van het GPU algoritme wordt in deze sectie vergeleken met een CPU implemen-tatie. Hiervoor werd van de individuele componenten een CPU implementatie gecreëerd. Dezeimplementaties zijn geschreven in C++ en maken gebruik van OpenMP om parallellisatie uitte kunnen buiten. De code is verder gecompileerd met de vlag /O2 om de uitvoeringssnel-heid te maximaliseren en ook met de /arch : SSE2 vlag om de geavanceerde instructieset tegebruiken. De implementaties zijn uitgevoerd op een windows 7 64-bit systeem uitgerust meteen CORE i7 860 2,8Ghz processor en 4GB ram geheugen. De resultaten worden weergevenin tabel 7.14.

Het GPU algoritme kent een totale versnelling ten opzichte van de CPU implementatie vaneen factor 35, 07. De grootste bijdrage van deze versnelling komt van de bewegingsestimatiecomponent, deze is een factor 74, 92 sneller. De bewegingscompensatie kent een kleinere ver-snelling van slechts 10%. Dit is vooral te wijten aan de vertraging door de onsamengevoegdegeheugentoegangen. De overige compenenten behalen een versnelling tussen een factor 4 en15 ten opzichte van de CPU implementatie. Als conclusie kan hier gesteld worden dat hetgebruik van de GPU in plaats van de CPU een aanzienlijk snelheidsvoordeel oplevert.

Hoofdstuk 7. Overbrengen van een algoritme naar de GPU 87

Component CPU GPU VersnellingsfactorBewegingsestimatie 687,73 9,18 74,92

Bewegingscompensatie 3,50 3,17 1,10Temporele decompositie 10,94 1,06 10,32Spatiale decompositie 14,89 1,03 14,46

Ruisschatting 2,21 0,51 4,33Ruisonderdrukking 20,81 1,79 11,62

Spatiale reconstructie 14,87 0,96 15,49Temporele reconstructie 10,96 1,06 10,34Inv bewegingscompensatie 3,51 3,18 1,10

Totaal 769,40 21,94 35,07

Tabel 7.14: Vergelijking tussen de uitvoeringstijden (ms) van de componenten van het GPUalgoritme en een CPU implementatie. De ingangsbuffer is vier frames groot en de resolutievan de ingangsframes 1024x1024.

7.5.4 Algemene conclusie

Het opzet van dit hoofdstuk was om te illustreren hoe een algoritme naar de GPU kan gebrachtworden en welke moeilijkheden hierbij kunnen optreden. Het gekozen algoritme hiervoor waseen beeldrestauratie algoritme. Bij deze overzetting kon structureel dezelfde aanpak gevolgdworden als van een CPU implementatie van dit algoritme. Het omzetten van het algoritmekon hierdoor componentsgewijs gebeuren.

De moeilijkheid bij het overbrengen van deze componenten was laag. De oorzaak hiervan lagonder andere in het gebruik van de GPU bouwstenen zoals bijvoorbeeld de reductie operatie.Deze vormden een alternatief voor een anders sequentieel algoritme en lieten een efficiëntereuitvoering toe op de GPU. Een aantal beperkingen die eigen zijn aan de GPU architectuuren het CUDA raamwerk kwamen ook aan bod. Zo zorgde bijvoorbeeld het beperkte gedeeldegeheugen voor een beperking op de zoekafstand in het Volledig-Zoek bewegingsestimatie al-goritme.

De uiteindelijke implementatie was capabel om ware tijd uitvoering toe te laten tot resolutiesvan 1024x1024. Hierbij werd rekening gehouden met de schommelingen in uitvoeringstijd dieoptraden door het recursieve algoritme en de bewegingscompensatie. Verbetering van de uit-voeringstijd zou nog verder mogelijk geweest zijn door bijvoorbeeld de bewegingsestimatie tevereenvoudigen. Het algoritme kent door de vereenvoudigingen een minder kwaliteitsvolle res-tauratie dan het originele algoritme, maar dit blijft beperkt tot een verlies van om en bij de 1,5dB. Verder is ook aangetoond dat een GPU algoritme een enorme versnelling kan betekenenten opzichte van een CPU implementatie, hier kwam dit neer op een versnelling met factor 35.

Hoofdstuk 8

Conclusie en perspectieven

In deze masterproef werd gekeken naar de mogelijkheden en beperkingen die verbonden zijnaan de GPGPU technologie. Hiervoor werd in eerste instantie gekeken naar de factoren dievan belang zijn om een efficiënte uitvoering van een algoritme op de GPU toe te laten.

Daarna werd onderzocht naar hoe een groot algoritme overgebracht kon worden naar de GPU.Hiervoor werd een gestructeerde aanpak voorgesteld, waarbij het algoritme wordt opgesplitstin kleinere componenten. Deze componenten worden dan zo efficiënt mogelijk naar de GPUgebracht. Om deze overdracht eenvoudiger te maken werd het concept van een bouwsteengeïntroduceerd. Dit zijn algoritmes die vaak terugkeren in bestaande algoritmes en dus ookvaak terug zullen keren in toekomstige algoritmes.

Via deze aanpak werd een implementatie gecreëerd van een beeldrestauratie algoritme. Tij-dens de implementatie werd dan gekeken naar eventuele moeilijkheden of problemen die optra-den. Een tweede aspect hierbij was om te kijken in welke mate ware tijd uitvoering mogelijkwas en welke aanpassingen de prestatie van het algoritme konden verbeteren. Het uiteinde-lijke uitgewerkte algoritme was in staat om in ware tijd aan videoruisonderdrukking te doen.Hierbij werd een zekere balans gezocht tussen de uitvoeringssnelheid en de kwaliteit van derestauratie. Verdere optimalisatie van het algoritme zou echter nog mogelijk geweest zijn.

De GPGPU technologie is op dit moment nog volop in groei. Wel is duidelijk dat deze tech-nologie meer en meer aan belang zal winnen door de snelheidswinsten die ze toelaat. Hetaantal vrij beschikbare codebibliotheken en al geïmplementeerde algoritmes is nu nog aan delage kant. In de toekomst zullen er ongetwijfeld echter meer en meer van deze uitgebrachtworden, waardoor grote en complexe algoritmes eenvoudiger en efficiënter naar de GPU zullenkunnen gebracht worden.

88

Bijlage A

CD

89

Bibliografie

[1] NVIDIA Corporation. CUDA C Programming Guide. http://developer.download.nvidia.com/compute/cuda/3_2/toolkit/docs/CUDA_C_Programming_Guide.pdf,2011.

[2] John Stone. An introduction to OpenCL. http://www.ks.uiuc.edu/Research/gpu/files/openclintrowebinar.pdf, 2009.

[3] M.J. Harvey and G. De Fabritiis. Swan: A tool for porting CUDA programs to OpenCL.Computer Physics Communications, 182(4):1093 – 1099, 2010.

[4] NVIDIA Corporation. CUDA C Programming Guide. http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/NVIDIA_CUDA_Programming_Guide_2.3.pdf, 2009.

[5] NVIDIA Corporation. CUDA C Best Practices Guide. http://developer.download.nvidia.com/compute/cuda/3_2/toolkit/docs/CUDA_C_Best_Practices_Guide.pdf,2011.

[6] Shubhabrata Sengupta, Mark Harris, and Michael Garland. Efficient parallel scan algo-rithms for GPUs. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.163.847&rep=rep1&type=pdf, 2008.

[7] NVIDIA Corporation. NVIDIA CUDA Software Development Kit. http://developer.nvidia.com/cuda-downloads, 2010.

[8] CUDPP Group. CUDA Data Parallel Primitives library. http://code.google.com/p/cudpp/, 2010.

[9] Mark Harris. Optimizing parallel reduction in CUDA. http://developer.download.nvidia.com/compute/cuda/1_1/Website/projects/reduction/doc/reduction.pdf,2009.

[10] Nadathur Satish, Mark Harris, and Michael Garland. Designing efficient sorting algo-rithms for manycore GPUs. In Proceedings of the 2009 IEEE International Symposiumon Parallel&Distributed Processing, pages 1–10, 2009.

[11] H. Peters, O. Schulz-Hildebrandt, and N. Luttenberger. Fast in-place, comparison-basedsorting with CUDA: a study with bitonic sort. Concurrency and Computation: Practiceand Experience, 23(10):681 – 693, 2011.

90

Bibliografie 91

[12] Ranieri Baraglia, Gabriele Capannini, Franco Maria Nardini, and Fabrizio Silvestri. Sor-ting using bitonic network with CUDA. http://lsdsir09.isti.cnr.it/lsdsir09-4.pdf, 2009.

[13] Erik Sintorn and Ulf Assarson. Fast parallel GPU-sorting using a hybrid algorithm.Journal of Parallel and Distributed Computing, 68(10):1381 – 1388, 2008.

[14] Victor Podlozhnyuk. Histogram calculation in CUDA. http://developer.download.nvidia.com/compute/cuda/1_1/Website/projects/histogram256/doc/histogram.pdf, 2007.

[15] Sisir Koppaka, Dheevatsa Mudigere, Srihari Narasimhan, and Babu Narayanan. Fast his-tograms using adaptive CUDA streams. http://www.hipc.org/hipc2010/HIPCSS10/m1569364359-koppaka.pdf, 2010.

[16] Ramtin Shams and R.A. Kennedy. Efficient histogram algorithms for NVIDIA CUDAcompatible devices. http://csce.uark.edu/~jgauch/library/papers/Shams.2007.pdf, 2007.

[17] Cedric Nugteren, Gert-Jan van den Braak, Henk Corporaal, and Bart Mesman. Highperformance predictable histogramming on GPUs: exploring and evaluating algorithmtrade-offs. In Proceedings of the Fourth Workshop on General Purpose Processing onGraphics Processing Units, GPGPU-4, pages 1:1–1:8, 2011.

[18] NVIDIA Corporation. NVIDIA CUDA Performance Primitives library. http://developer.stage.nvidia.com/npp, 2010.

[19] Victor Podlozhnyuk. Image convolution with CUDA. http://developer.download.nvidia.com/compute/cuda/1.1-Beta/x86_64_website/projects/convolutionSeparable/doc/convolutionSeparable.pdf, 2007.

[20] J.W. Cooley and J.W. Turkey. An algorithm for the machine calculation of complexFourier series. Mathematics of Computation, 19:297–301, 1965.

[21] V. Volkov and B. Kazian. Fitting FFT onto the G80 architecture. http://www.cs.berkeley.edu/~kubitron/courses/cs258-S08/projects/reports/project6_report.pdf, 2008.

[22] Naga K. Govindaraju, Brandon Lloyd, Yuri Dotsenko, Burton Smith, and John Manfer-delli. High performance discrete Fourier transforms on graphics processors. In Proceedingsof the 2008 ACM/IEEE conference on Supercomputing, SC ’08, pages 2:1–2:12, 2008.

[23] NVIDIA Corporation. NVIDIA CUDA Fast Fourier Transform library. http://developer.nvidia.com/cufft, 2010.

[24] NVIDIA Corporation. NVIDIA CUDA Basic Linear Algebra Subprograms library. http://developer.nvidia.com/cublas, 2010.

[25] NVIDIA Corporation. NVIDIA CUDA SPARSE library. http://developer.stage.nvidia.com/cusp, 2010.

Bibliografie 92

[26] S. G. Mallat. A theory for multiresolution signal decomposition: The wavelet represen-tation. IEEE Transactions on Pattern Analysis and Machine Intelligence, 11:674–693,July 1989.

[27] Wim Sweldens. The lifting scheme: a construction of second generation wavelets. SIAMJournal on Mathematical Analysis, 29:511–546, March 1998.

[28] Christian Tenllado, Javier Setoain, Manuel Prieto, Luis Piñuel, and Francisco Tirado.Parallel implementation of the 2D discrete wavelet transform on graphics processingunits: Filter bank versus lifting. IEEE Transactions on Parallel and Distributed Systems,19:299–310, March 2008.

[29] Stephane Mallat and Sifen Zhong. Characterization of signals from multiscale edges.IEEE Transactions on Pattern Analysis and Machine Intelligence, 14:710–732, July 1992.

[30] Dietmar Wippig and Bernd Klauer. Translation-invariant two-dimensional discrete wa-velet transform on graphics processing units. In Proceedings of the European confe-rence of systems, and European conference of circuits technology and devices, and Eu-ropean conference of communications, and European conference on Computer science,ECS’10/ECCTD’10/ECCOM’10/ECCS’10, pages 105–110, 2010.

[31] Christian Tenllado, Roberto Lario, Manuel Prieto, and Francisco Tirado. The 2D dis-crete wavelet transform on programmable graphics hardware. http://zengine3d.com/papers/DWTonGPU_VIIP2004.pdf.

[32] Joaquín Franco, Gregorio Bernabé, Juan Fernández, and Manuel E. Acacio. The GPUon the 2D wavelet transform. survey and contributions. http://vefir.hi.is/para10/extab/para10-paper-26.pdf.

[33] Joaquín Franco, Gregorio Bernabé, Juan Fernández, and Manuel E. Acacio. A parallelimplementation of the 2D wavelet transform using CUDA. In Proceedings of the 200917th Euromicro International Conference on Parallel, Distributed and Network-basedProcessing, pages 111–118, 2009.

[34] Inge Doms. Ontwerp van wavelettransformaties op FPGA. http://lib.ugent.be/fulltxt/RUG01/000/820/283/RUG01-000820283_2010_0001_AC.pdf, 2004.

[35] Mihajlo Katona, Aleksandra Pižurica, Nikola Teslić, Vladimir Kovačević, and WilfriedPhilips. A real-time wavelet-domain video denoising implementation in FPGA. EURA-SIP Journal on Embedded Systems, 2006:6–6, January 2006.

[36] Xiaodong Xu and Yiqi Zhou. Efficient FPGA implementation of 2-D DWT for 9/7float wavelet filter. International Conference on Information Engineering and ComputerScience, 2009. ICIECS 2009., pages 1–4, December 2009.

[37] Y. Andreopoulos, P. Schelkens, and J. Cornelis. Analysis of wavelet transform imple-mentations for image and texture coding applications in programmable platforms. InProceedings of the 2001 IEEE signal processing systems, pages 273–284, 2001.

[38] S. Yu, M. Omair Ahmad, and M. N. S. Swamy. Video denoising using motion compen-sated 3-D wavelet transform with integrated recursive temporal filtering. IEEE Trans-actions on Circuits and Systems for Video Technology, 20:780–791, 2010.

Bibliografie 93

[39] Deepak Turaga and Mohamed Alkanhal. Search algorithms for block-matching in motionestimation. http://www.ece.cmu.edu/~ee899/project/deepak_mid.htm, 1998.

[40] A. F. Abdelnour and I. W. Selesnick. Nearly symmetric orthogonal wavelet bases. InProceedings IEEE international conference on acoustics, speech and signal processing,pages 431–434, May 2001.

[41] D. Donoho and I. Johnstone. Ideal spatial adaption by wavelet shrinkage. Biometrika,8:425–455, 1994.

[42] A. De Stefano, P. White, andW. Collis. Training methods for image noise level estimationon wavelet components. Journal on Applied Signal Processing, Special Issue on non-linearsignal and image processing-part 2, 2004:2400–2407, January 2004.

[43] J.-S. Lee. Refined filtering of image noise using local statistics. Computer Vision GraphicsImage Processing, 15:380–389, 1981.

[44] G. Mastin. Adaptive filters for digital noise smoothing, an evaluation. Computer VisionGraphics Image Processing, 31:103–121, 1985.

[45] Levent Sendur and Ivan W. Selesnick. Bivariate shrinkage with local variance estimation.IEEE Signal Processing Letters, 9:438–441, 2002.

[46] S. Chang, B. Yu, and M. Vetterli. Adaptive wavelet thresholding for image denoisingand compression. IEEE Transactions on Image Processing, 9:1532–1546, 2000.

[47] Aleksandra Pižurica, Vladimir Zlokolica, and Wilfried Philips. Noise reduction in videosequences using wavelet-domain and temporal filtering. In Proceedings SPIE ConferenceWavelet Applications in Industrial Processing, pages 48–59, 2003.

Lijst van figuren

2.1 Evolutie van het aantal vlottende komma instructies per seconde van de GPU envan de CPU [1]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.2 Schematische weergave van een NVIDIA GPU [4]. . . . . . . . . . . . . . . . . . 72.3 Het uitvoeringsmodel van CUDA: de CPU (host) stuurt asynchroon de GPU (de-

vice) aan. Bij het uitvoeren van een kernel worden draden (threads) gegroepeerdin blokken (blocks) en blokken in een grid [4]. . . . . . . . . . . . . . . . . . . . . 8

2.4 Illustratie van de bepaling van de globale index van een draad. Deze bepalinggebeurt door de optelling van de draadindex in het blok threadIdx.x met het pro-duct van het blokindex blockIdx.x waartoe deze draad behoort en de blokdimensieblockDim.x. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.5 Gealigneerde en sequentiële geheugentoegang van een halve warp van draden.Uiteindelijk zal maar één geheugentoegang vereist zijn. . . . . . . . . . . . . . . 12

2.6 Niet-gealigneerde geheugentoegang van een halve warp van draden. Voor elkedraad apart zal een geheugentoegang plaats vinden. . . . . . . . . . . . . . . . . 12

3.1 De piramidale opbouw van een algoritme. . . . . . . . . . . . . . . . . . . . . . . 193.2 Berekening van de prefixsom van een rij met acht elementen. . . . . . . . . . . . 203.3 Berekening van de totale prefixsom van een rij. . . . . . . . . . . . . . . . . . . . 213.4 Het somreductie algoritme. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.1 Berekening van de algemene prefixsom van een rij met vier elementen. . . . . . . 264.2 Berekening van de totale algemene prefixsom van een blok/rij. . . . . . . . . . . . 29

5.1 Berekening van de partiële prefixsom in een warp met m = 2. . . . . . . . . . . . 35

6.1 Het ruimte-frequentie diagram bij de wavelettransformatie. . . . . . . . . . . . . . 396.2 Eén-niveau voorwaartse (analyse) tweedimensionale filterbank. . . . . . . . . . . 406.3 Voorwaartse filterbank met meerdere niveaus. . . . . . . . . . . . . . . . . . . . 406.4 De tweedimensionale gedecimeerde wavelettransformatie van de lena afbeelding. 416.5 Eén-niveau inverse (synthese) tweedimensionale filterbank. . . . . . . . . . . . . 426.6 Inverse filterbank met meerdere niveaus. . . . . . . . . . . . . . . . . . . . . . . 426.7 Vereiste pixels voor een 8x8 blok bij de berekening van de niet-gedecimeerde twee-

dimensionale discrete wavelettransformatie met de Haar wavelet. . . . . . . . . . 446.8 Startpositie van de draden voor een 4x4 blok (Haar wavelet). . . . . . . . . . . . 46

94

Lijst van figuren 95

7.1 Weergave van lena voor en na ruisonderdrukking. Links de originele lena afbeel-ding, in het midden lena met ruisniveau σn = 20 en rechts de lena afbeelding naruisonderdrukking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

7.2 De temporele decompositie van vier frames uit de Foreman sequentie. . . . . . . 537.3 De driedimensionale wavelettransformatie van vier frames. De temporele ééndi-

mensionale transformatie is uitgevoerd via de gedecimeerde wavelettransformatiemet de Haar wavelet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

7.4 Diagram van het MC3DWTr ruisonderdrukkingsalgoritme met een framebuffer vanvier frames. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

7.5 Tweedimensionale wavelettransformatie van de met ruis vervuilde lena afbeelding(σn = 10). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

7.6 Het verband tussen een DataGridCPU en een DataGridGPU object. Bij het Data-GridCPU object zal de grid wijzer steeds wijzen naar een locatie in het RAM geheu-gen, terwijl bij de DataGridGPU de grid wijzer steeds zal wijzen naar een locatie inhet GPU geheugen. Conversie tussen beide DataGrids is mogelijk. . . . . . . . . 61

7.7 Zoeken van het best overeenkomende blok in het voorgaande frame. Er wordtgezocht in een venster rond de positie van het blok (x, y) over een zoekafstand z.Elke bewegingsvector in het venster [x± z ,y ± z] zal worden getoetst. . . . . . . 64

7.8 De pixels van een blok kunnen elk een verschillend pad volgen. . . . . . . . . . . 687.9 Het mogelijk probleem bij de recursieve bepaling van de bewegingsvector. Er kan

weinig correlatie zijn tussen naburige bewegingsvectoren, hierdoor gaan de ge-heugentoegangen van de draden onsamengevoegd verlopen. . . . . . . . . . . . 69

Lijst van tabellen

4.1 Uitvoeringstijd (ms) van het algemene prefixsom algoritme voor een verschillendaantal elementen van de twee CUDA implementaties en een sequentiële CPU ver-sie (AMD64 3800+, C++ code). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4.2 Vergelijking tussen de prestatie van de CUDA prefixsom met versie twee van hetalgemene prefixsom algoritme. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

5.1 Uitvoeringstijd (ms) van de drie CUDA partiële prefixsom algoritmes voor 16776960elementen. Hierbij werd gesommeerd over m elementen. . . . . . . . . . . . . . 36

5.2 Vergelijking tussen het directe algoritme en een sequentiële recursieve CPU imple-mentatie (AMD64 3800+, C++ code) voor een verschillend aantal elementen. Hetaantal elementen m waarover gesommeerd werd is 32. . . . . . . . . . . . . . . 36

6.1 Uitvoeringstijden (ms) van drie implementaties van de voorwaartse niet-gedecimeerdewavelettransformatie uitgevoerd op een 2048x2048 beeld voor verschillende wa-velets. Het aantal ontbindingsniveaus was twee, de duurtijd van het eerste niveauwordt in het bovenste gedeelte van de tabel weergegeven, de duurtijd van hettweede niveau in het onderste gedeelte. . . . . . . . . . . . . . . . . . . . . . . . 48

6.2 Uitvoeringstijden (ms) van drie implementaties van de voorwaartse gedecimeerdewavelettransformatie uitgevoerd op een 2048x2048 beeld voor verschillende wa-velets. De weergegeven uitvoeringstijden zijn deze om één niveau van de transfor-matie uit te voeren. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

7.1 Uitvoeringstijden (ms) van de twee bewegingsestimatie algoritmes. De bewegingsesti-matie werd telkens uitgevoerd tussen paren van frames voor de resoluties 512x512,1024x1024, 2048x2048 en 3072x3072. Het Volledig-Zoek algoritme werd uitge-voerd met drie zoekafstanden, namelijk 3, 7 en 15. De blokgrootte bij het Volledig-Zoek algoritme was 16 bij 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

7.2 PSNR (dB) waarden behaald met het Volledig-Zoek algoritme en het Hiërarchischalgoritme voor variërende ruisniveaus. . . . . . . . . . . . . . . . . . . . . . . . . 71

7.3 Uitvoeringstijden (ms) van de kernel voor het bepalen van de recursieve bewe-gingsvectoren voor verschillende resoluties. Het slechtste en het beste geval wordtweergegeven. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

7.4 Uitvoeringstijden (ms) van de kernel voor het uitvoeren van de voorwaartse/inversebewegingscompensatie voor verschillende resoluties. Het slechtste en het bestegeval wordt weergegeven. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

7.5 Uitvoeringstijden (ms) van de temporele transformatie (voorwaarts en invers) voorverschillende framebuffergroottes en resoluties. . . . . . . . . . . . . . . . . . . . 72

96

Lijst van tabellen 97

7.6 PSNR (dB) waarden behaald met de niet-gedecimeerde (TIDWT) en de gedeci-meerde (DWT) transformatie voor variërende ruisniveaus en videosequenties. . . 73

7.7 Het gemiddelde absolute verschil E en de standaardafwijking σE van de vier ruis-schatters: de robuuste mediaan schatter, de variantie schatter, de passende mo-ment schatter en de lokale variantie schatter. Er zijn vier videosequenties gebruikt:Salesman, Foreman, Flower Garden en Tennis. . . . . . . . . . . . . . . . . . . . 77

7.8 Uitvoeringstijden (ms) van de vier ruisschatters: de robuuste mediaan schatter, devariantie schatter, de lokale variantie schatter en de passende moment schatter.De uitvoering gebeurde op de GPU voor verschillende resoluties. . . . . . . . . . 78

7.9 PSNR (dB) waarden behaald met het algoritme uitgerust met het BivariateShrin-kage en het BayesShrink algoritme voor variërende ruisniveaus en videosequen-ties. Bij het BivariateShrinkage algoritme werden drie decompositieniveaus ge-bruikt voor de spatiale wavelettransformatie (gedecimeerde wavelettransformatie)en bij het BayesShrink algoritme waren dit er slechts twee. . . . . . . . . . . . . . 82

7.10 Uitvoeringssnelheid (ms) van het BivariateShrinkage en het BayesShrink algoritmevoor één schaal met verschillende resoluties. De lokale variantie in het Bivaria-teShrinkage algoritme is geschat met een 5x5 venster. . . . . . . . . . . . . . . . 82

7.11 Het behaalde aantal frames per seconde van de GPU implementatie voor varië-rende framebuffergroottes en resoluties. Het van en naar de GPU kopiëren vanframes is inbegrepen in de resultaten. De framebuffergrootte is aangeven tussende ronde haakjes. De ingangsframes waren grijswaarde frames. De gebruikteCPU is de AMD64 3800+ processor en de gebruikte GPU is de NVIDIA 8800GT. . 83

7.12 Uitvoeringstijden (ms) van elke component van het algoritme. De ingangsbuffer isvier frames groot en de resolutie van de ingangsframes is 1024x1024. . . . . . . 84

7.13 PSNR (dB) waarden van verschillende ruisonderdrukkingstechnieken voor varië-rende ruisniveaus en videosequenties. De framebuffergrootte van het originelealgoritme is aangeven tussen de ronde haakjes. Het GPU algoritme is uitgevoerdmet een vaste framebuffer van grootte vier frames. . . . . . . . . . . . . . . . . . 86

7.14 Vergelijking tussen de uitvoeringstijden (ms) van de componenten van het GPUalgoritme en een CPU implementatie. De ingangsbuffer is vier frames groot en deresolutie van de ingangsframes 1024x1024. . . . . . . . . . . . . . . . . . . . . . 87