Contents
Waarom signaalverwerking?
Signaalverwerking is overal om ons heen. In het algemeen gedefinieerd als de manipulatie van signalen – of mechanismen voor het verzenden van informatie van de ene plaats naar de andere – maakt het veld van signaalverwerking gebruik van ingebedde informatie om een bepaald doel te bereiken. In het geval van ruisonderdrukking is het doel om de specifieke frequenties die het huilen van de baby bevatten, te onderdrukken of te onderdrukken (via filtering!)
Als je ooit een radio, mobiele telefoon of garagedeuropener hebt gebruikt , GPS-apparaat, of een automatisch afgestemd hiphopnummer hebt gehoord en een spraak-naar-tekst transcriptietool hebt gebruikt, heb je interactie gehad met elementen van een signaalverwerkingsworkflow.
Een wandeling in de tijd
Signaalverwerkingstoepassingen zijn altijd gedreven door realtime vereisten. Die mobiele telefoon-app voor gesproken Spaans naar Engels vertaling zou behoorlijk waardeloos zijn als het dertig seconden zou duren om 5 seconden spraak te verwerken. Evenzo is in een belangrijke subset van het signaalverwerkingsdomein – Software Defined Radio (SDR) – realtime respons van cruciaal belang voor spectrumschatting, geolocatie en andere vormen van snelle respons.
In het verleden maakten deze applicaties gebruik van acceleratorhardware zoals gespecialiseerde ASICS of FPGA's. Hoewel deze apparaten een ultralage latentierespons kunnen bieden, kunnen ze moeilijk te programmeren, duur en inflexibel zijn als het doel van signaalverwerking verandert. Als gevolg daarvan, toen NVIDIA meer dan tien jaar geleden CUDA uitbracht, sprongen veel signaalverwerkingsingenieurs over op GPU's vanwege hun hoge eisen aan lineaire algebra.
NVIDIA biedt een overvloed aan C/CUDA-versnelde bibliotheken die gericht zijn op algemene signaalverwerkingsbewerkingen. cuFFT GPU versnelt de Fast Fourier Transform, terwijl cuBLAS, cuSOLVER en cuSPARSE matrixsolvers en decomposities versnellen die essentieel zijn voor een groot aantal relevante algoritmen.
CUDA kan een uitdaging zijn. Als een ontwikkelaar vertrouwd is met C of C++, kan hij de basisprincipes van de API in een paar dagen leren, maar handmatig geheugenbeheer en decompositie van gewenste algoritmen om parallellisme te benutten kan behoorlijk moeilijk zijn. Om productief te zijn, hebben software-engineers en -ontwikkelaars een extra abstractielaag nodig, waarbij een klein beetje verwerkingssnelheid wordt opgeofferd voor een hogere ontwikkelingssnelheid.
Het door NVIDIA geleide RAPIDS-initiatief krabt deze jeuk. Met cuDF, cuML, cuGraph en cuSpatial — de GPU-gemeenschap voor open source datawetenschap brengt GPU-snelheden naar veelgebruikte Python-API's. CUDA is niet langer de enige manier om prestatieverbeteringen op NVIDIA GPU's te zien.
cuSignal is gebouwd met deze ontwerpfilosofie in gedachten.
Wat is cuSignal?
cuSignal GPU versnelt de populaire SciPy-signaalbibliotheek met CuPy (GPU-versnelde NumPy) en aangepaste Numba CUDA-kernels.
SciPy Signal biedt een functierijke API die zowel MATLAB-programmeurs als Pythonista's een gemakkelijke oprit biedt. Door functionaliteit te bevatten voor veel basissignaalverwerkingstransformaties en technieken zoals convoluties, correlaties, spectrumschattingstechnieken en filtering, maakt SciPy Signal het mogelijk om zowel complexe als snelle applicaties te bouwen vanuit de Python-laag. Hoewel bepaalde SciPy-signaalfuncties, zoals upfirdn (upsample, filter, downsample) en lfilter (lineair filter) bestaan uit Cython-gewikkelde C-code, maakt een groot deel van de codebase gebruik van basis NumPy API-aanroepen.
Figuur 1: Referentie RAPIDS-bibliotheekstack.
cuSignal verschilt van de traditionele filosofie van RAPIDS-softwareontwikkeling. Figuur 1 toont een typische softwarestack, in dit geval voor cuML. In deze bibliotheek vindt GPU-ontwikkeling plaats op CUDA-niveau waar speciale primitieven worden geconstrueerd, gekoppeld aan bestaande CUDA-bibliotheken en vervolgens Python-bindingen krijgen via Cython. Ontwikkeling voor cuSignal, zoals te zien is in figuur 2, vindt volledig plaats in de GPU-versnelde Python-laag.
Figuur 2: cuSignal bibliotheekstack.
cuSignal is sterk afhankelijk van CuPy en een groot deel van het ontwikkelingsproces bestaat simpelweg uit het veranderen van SciPy Signal NumPy-aanroepen naar CuPy. Aangezien CuPy al ondersteuning biedt voor de cuBLAS-, cuDNN-, cuFFT-, cuSPARSE-, cuSOLVER- en cuRAND-bibliotheken, was er geen op rijprestaties gebaseerde behoefte om handmatig afgestemde signaalverwerkingsprimitieven te creëren op het onbewerkte CUDA-niveau in de bibliotheek.
In sommige gevallen maakt cuSignal gebruik van Numba CUDA-kernels wanneer CuPy-vervanging van NumPy geen optie was. In het geval van upfirdn is er bijvoorbeeld een aangepaste op Python gebaseerde CUDA JIT-kernel gemaakt om deze bewerking uit te voeren. Er hadden meer prestaties kunnen worden verkregen met een onbewerkte CUDA-kernel en een door Cython gegenereerde Python-binding, maar nogmaals – cuSignal benadrukt zowel snelle prestaties als go-to-market. Numba's cuda_array_interface-standaard om te specificeren hoe gegevens op GPU zijn gestructureerd, is van cruciaal belang om gegevens door te geven zonder een extra kopie tussen CuPy, Numba, RAPIDS en PyTorch voor diepgaand leren.
De overkoepelende ontwerpfilosofie van cuSignal was:
“Laten we eens kijken hoe ver we kunnen komen door het werk van de gemeenschap aan elkaar te lijmen en gerichte prestatieverbeteringen te bieden wanneer dat nodig is.”
Met dit in gedachten was cuSignal in staat om functies voorop te stellen – waardoor een groot deel van het SciPy-signaal werd versneld API in een snel tijdsbestek. Dit moedigt anderen aan om in de toekomst op dezelfde manier GPU-versnelde bibliotheken te bouwen.
Een volledige lijst met GPU-versnelde functies is te vinden in de cuSignal CHANGELOG, maar omvat over het algemeen spectrale analyse (periodogram, spectrogram, enz.), piekbevinding, windowing, golfvormgeneratie, resampling en convolutie.
Prestaties
Prestaties
Zoals bij alle GPU-applicaties, ziet cuSignal de meeste prestatieverbetering tussen GPU en CPU bij gebruik van grote signaalgroottes. Tabellen 1 en 2 tonen CPU (Intel 2x E5) prestaties versus zowel een NVIDIA P100 als een V100. In beide gevallen werden deze functies uitgevoerd op een echt gewaardeerd FP64-signaal dat 1e8-samples bevat. Extra prestaties kunnen worden bereikt met een verminderde precisie.

Tabel 1: cuSignal-prestaties met behulp van de %time-functie van Python en een NVIDIA P100.

Tabel 2: cuSignal-prestaties met behulp van de %timeit-functie van Python (7 runs) en een NVIDIA V100.
Timeit schakelt de prullenbak van Python uit en bevat geheugen in de cache. Dit kan worden beschouwd als het beste scenario.
De notebooks-sectie van de cuSignal-repository heeft uitgebreide voorbeelden van zowel prestatiebenchmarking als API-gebruik.
Online signaalverwerking — geheugenverwerking en FFT-benchmarking
Hoewel offline signaalverwerking op sterk gesamplede signalen waardevol kan zijn als voorbewerkingsstap in een signaalverwerkingspijplijn, zijn veel toepassingen, met name binnen het SDR-domein, afhankelijk van frequente, relatief kleine kopieën van de radiobuffer naar de CPU of versneller voordat ze verder gaan. verwerking wordt ingeroepen. In het geval van sommige softwaregedefinieerde radio's heeft de buffer de neiging om maximaal 32.768 complexe samples (4 MB) te bereiken.
GPU's zijn een apparaat dat latentie verbergt, dus de naïeve benadering van het overbrengen van 4 MB-bestanden via PCIe van de CPU naar de GPU voor verdere verwerking zou de workflowprestaties verlammen. Als gevolg hiervan maakt cuSignal gebruik van Numba's cuda.mapped_array-functie om een geheugenruimte zonder kopie tot stand te brengen tussen de CPU en GPU. De toegewezen array-aanroep verwijdert een door de gebruiker gespecificeerde hoeveelheid geheugen uit de paginatabel (pint het geheugen vast) en adresseert het vervolgens virtueel zodat zowel CPU- als GPU-aanroepen kunnen worden gedaan met dezelfde geheugenaanwijzer.
cuSignal verbergt de mapped_array aanroepen met
_arraytools.get_shared_mem en _arraytools.get_shared_array waar
get_shared_mem werkt als np.empty en get_shared_array laadt fysiek gegevens in een CPU/GPU gedeelde array.

Figuur 3: FFT-benchmarking met online signaalverwerking.
Afbeelding 3 toont de prestatieverbeteringen die men kan zien door een willekeurig gedeelde GPU/CPU-geheugenruimte te creëren — waarbij het laden van gegevens en FFT-uitvoering plaatsvinden in 0,454 ms, versus CPU/Numpy met 0,734 ms.
Als een speciale opmerking , de eerste CuPy-aanroep naar FFT omvat overhead voor het maken van FFT-plannen en geheugentoewijzing. Deze kosten worden slechts één keer betaald en kunnen 'vooraf betaald' worden voordat een online signaalverwerkingsworkflow wordt gestart. Verder breidt CuPy de ondersteuning uit voor het handmatig maken van FFT-plannen. U kunt meer lezen over CuPy.
cuSignaal naar PyTorch
Een van de meest opwindende functies van cuSignal en het GPU-versnelde Python-ecosysteem is de mogelijkheid om data van de ene bibliotheek/framework naar de andere te kopiëren met Numba's __cuda_array_interface__. De end-to-end-notebook in de cuSignal-repository demonstreert een verzameling om het afleiden van workflow met signaalgegevens. In dit voorbeeld worden 2000 signalen met een lengte van 215 gegenereerd met 1 tot 5 draaggolven op een onderlinge afstand van 10 verschillende middenfrequenties. Gebruik vervolgens cuSignal om het signaalensemble polyphase opnieuw te bemonsteren om het monster met 2 te verhogen en voer vervolgens een periodogram uit met een flattop-filter over elk signaal. Ten slotte wordt deze gegevensstructuur via DLPack aan PyTorch doorgegeven om het aantal dragers in een willekeurig signaal te trainen en te voorspellen.
Vanaf PyTorch 1.2 is de __cuda_array_interface__ samengevoegd in de bibliotheek en zal gegevensverplaatsing niet langer nodig om te verhuizen via DLPack. Meer informatie vindt u bij deze CuPy GitHub-uitgave.
Probeer cuSignal vandaag nog
cuSignal is momenteel alleen beschikbaar via een bronversie in de cuSignal GitHub-repository. Conda-verpakkingen zijn in de maak en deze blog zal worden bijgewerkt wanneer deze beschikbaar is.
cuSignal staat nog in de kinderschoenen en zou baat hebben bij community-gedreven ondersteuning en ontwikkeling. Of u nu geïnteresseerd bent in audiosignaalverwerking, softwaregedefinieerde radio's of ruisonderdrukking, we verwelkomen uw PR's en problemen. Help alstublieft de prestaties van het profiel, optimaliseer code en voeg nieuwe functies toe! Verder, als je geïnteresseerd bent in cuSignal, plaats dan een ster in de repository op GitHub!
Herkenningen
cuSignal is dankbaar voor het kernontwikkelingsteam van SciPy Signal, in het bijzonder Travis Oliphant. Verder bedankt cuSignal alle bètatesters van cuSignal, waaronder onder meer Expedition Technology, Deepwave Digital en Fusion Data Science. Tot slot dank aan NVIDIA-ingenieur Matthew Nicely voor zijn werk aan zero-copy memory en Numba CUDA-optimalisatie.
Adam Thompson
Senior Solutions Architect, NVIDIA


_arraytools.get_shared_mem en _arraytools.get_shared_array waar
get_shared_mem werkt als np.empty en get_shared_array laadt fysiek gegevens in een CPU/GPU gedeelde array.

Senior Solutions Architect, NVIDIA