If you're looking to leverage the insane power of modern GPUs for data science and machine learning, you might think you'll need to use some low-level programming language, such as C++.
But the folks over at NVIDIA have been hard at work building Python SDKs, which provide near-native level of performance when doing Pythonic GPU programming.
Bryce Adelstein-Lelbach is here to tell us about programming your GPU in pure Python.
This is Talk Python To Me, episode 509, recorded May 13th, 2025.
Are
you ready for your host, please?
You're listening to Michael Kennedy on Talk Python To Me.
Live from Portland, Oregon, and this segment was made with Python.
Welcome to Talk Python To Me, a weekly podcast on Python.
This is your host, Michael Kennedy.
Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython, both accounts over at Fostadon.org and keep up with the show and listen to over nine years of episodes at talkpython.fm.
If you want to be part of our live episodes, you can find the live streams over on YouTube.
Subscribe to our YouTube channel over at talkpython.fm/youtube and get notified about upcoming shows.
This episode is sponsored by Posit Connect from the makers of Shiny.
Publish, share, and deploy all of your data projects that you're creating using Python.
Streamlit, Dash, Shiny, Bokeh, FastAPI, Flask, Quarto, Reports, Dashboards, and APIs.
Posit Connect supports all of them.
Try Posit Connect for free by going to talkpython.fm/posit, P-O-S-I-T.
And it's brought to you by Agency.
Discover agentic AI with Agency.
Their layer lets agents find, connect, and work together, any stack, anywhere.
Start building the internet of agents at talkpython.fm/agency spelled A-G-N-T-C-Y.
I want to share an awesome new resource with you all before we talk GPUs with Bryce.
You may have seen the episode deep dives on the episode pages at talkpython.fm.
These are roughly 1,250 word write-ups about the episode.
It's not just a summary or list of topics.
These cover additional study materials you might focus on to get the most out of the episode as well as related tools and topics to explore.
The reason we're talking about these now is that I just finished the very last deep dive write-up for the entire back catalog.
That's 510 episodes resulting in 600,000 words of extra detailed information for our podcasts.
These are only available online on the website and not in the podcast player feeds because podcast players are already complaining that our RSS feed is too big for them as if it's 1993 or something.
adding the deep dives would surely cause more trouble.
So be sure to visit the episode page for each episode to check out the deep dive.
I did a write-up on how these were created, why, and more at the Talk Python blog over at talkpython.fm/blog, creative I know.
I'll put the link to the blog post in the show notes.
These deep dives were a big effort, but I really think they add a lot of value to the show.
Thanks as always. Let's talk GPUs.
Bryce, welcome to Talk Python To Me. Awesome to have you here.
Thrilled to be here. It's my first appearance on a podcast, actually.
Okay, very cool, very cool. Well, we're going to talk a lot about GPUs and not that much about graphics, which is ironic, but, you know, that's the world we live in these days, right? It's amazing.
It's funny, I've worked at NVIDIA for eight years now. I know next to nothing about graphics.
That's pretty funny. I do on my gaming PC have a 2070 RTX, but I don't do any programming. I probably should. It's just so loud when that thing is turned on. It's like it's going to take off.
But they
sure are powerful. They sure are powerful, these GPUs. So it's going to be exciting to talk about it, what you can do with them.
That's true. I remember when we launched the 27 day.
I'm
trying to think what my first GPU was, but because when I used to play video games when I was a kid, I didn't play video games. I played text-based games, MUDs. So I never really needed a graphics card because it was all just command my interface.
The modem is the limiting factor or whatever for your MUD, right? I'm presuming it's on the internet. I used to play a MUD called Shadow's Edge. I don't know if people heard of this one out there in the world, but
I don't think I've heard of that one. This
is early 90s, early 90s.
That was a little before my time.
I used to play like a lot of Star Wars MUDs and I played a pretty popular one that was called Avatar.
That was one of the big ones.
And that's actually how I got started programming.
Yeah, I actually know a friend who got started that way as well.
All right, just acronym police here.
What is a MUD?
So it stands for Multi-User Dungeon.
And it's like a very weird little corner of the gaming world because MUDs are largely not run for profit.
It's like somebody creates it, and for the most part, they host it, and then they build a little community around it.
And so they're little multiplayer games.
Some of them are like a role-playing theme to them, and it's usually coded by volunteers, run by volunteers.
And I always found it a very pure form of gaming.
I really like them as well.
Just take your time, you build a little community of friends, and a little world, and you just go live in it.
It's been a long time since I played it, and I recently played Something Like a Mud, but it wasn't multiplayer with my daughter, and she thought it was the coolest thing.
So there's hope for the new generation to carry on the torch.
I've played some text-based games powered by large language models where you're basically just interacting with a large language model recently, and it kind of reminded me of the MUDs from back in the day because it's all just textual interaction.
I think as the LLMs get better and the tools for building these things get better, there'll probably be some really interesting stories that are powered by them.
Really interesting stories.
interesting games. Yeah, it's an exciting future ahead of us.
Yeah, I'm kind of looking forward to it. And that brings us kind of to our topic a little bit. Like, how do those LLMs get trained?
Well, probably on NVIDIA things. Before we jump into that, though, give us a quick introduction.
Who are you? I got
my start at programming, teaching myself how to program a MUD. And that was when I was about 19. And from there, I got involved in open source working on the Boost C++ plus libraries. And I was a college dropout at that point and was looking for a job. And so I just asked somebody who I knew through the open source communities, through the Boost community, like, hey, I need a job. And this guy said, you should come down to Louisiana, come work for me at my supercomputing research center. And I was like, sure, like I'm a college dropout, why not?
My parents didn't think this was such a good idea, but I managed to convince them. So I went down there. And I worked there for about four years working on HPX, which is a distributed C++ runtime for HPC or high performance computing. And I sort of learned under this professor, Hartman Kaiser, who was my first mentor. And he kind of tricked me into going back to college. And so I completed my degree when I was there. And we started and ran. What was your
degree
in? It was applied mathematics. I figured if I tried to get a degree in computer science, I knew that I was an arrogant teenager and I figured I'd clash with my professors. So I was like, I got to get my major in a field where I don't know anything so that I'll respect the professors and I won't get in trouble in school. So that's the math
degree. It's easy to feel like you don't know too much doing math. I've been there. When
I was there, we started this research group. We developed this the HPX runtime together. And then after that, I went to work at Lawrence Berkeley National Lab in California, which is a part of the US Department of Energy research apparatus.
And I was there for about two years, also doing high performance computing stuff and C++ stuff.
And around that time, I got involved in the C++ Standards Committee. And then I went to NVIDIA.
And I've been at NVIDIA for, I think, eight years now, 2017.
And at NVIDIA, what I primarily do is I work on programming language evolution.
So that means thinking about how should languages like C++, Python, and Rust evolve.
And in particular, because it's NVIDIA, my focus is thinking about concurrency, parallelism, and GPU acceleration.
So how do we make it easier and more accessible to write parallel and GPU accelerated code in these programming languages?
And it's not just programming languages.
I also work a lot on library design, interface design.
I started the CUDA C++ core libraries team here at NVIDIA.
But I spent maybe the first six or seven years of my career at NVIDIA almost exclusively doing C++ stuff.
And then the last one, two years, I've been getting ramped up on Python things, learning more about Python.
And now I'm involved in a lot of NVIDIA's Python efforts, although I am by no means a Python expert, I would say.
Interesting. That's quite the background.
A couple of things I want to ask you about.
I guess start from the beginning.
I'm less likely to forget them.
So you were doing high performance computing and grid computing type stuff in the early days.
I mean, these are like SETI at home and protein folding days and all that kind of stuff.
I know that's not exactly the same computers, but what were some of the cool things you were working on?
Did you come across some neat projects or have some neat stories to share from there?
I came in, you can sort of break up the HPC era into the like what scale of compute we were at.
And so I came in after TeraScale, TeraFlops, right at the advent of the Petaflop era.
And there was sort of this big question of how do we go from petaflop to exaflop.
And at the time, we thought it was going to be really, really hard because this was before accelerators were a thing.
And so the plan for going from petaflops to exaflops was just to scale it up with CPUs.
And to scale from petaflops to exaflops and CPUs, to be able to do an exaflop of compute with CPUs, you would need millions of processors and cores. And the mean time to failure for hardware components was very low. Like if you're running something on a million CPUs, a million nodes, a hard drive is going to fail every two to three minutes on average.
Yeah, something's breaking all the time, right?
And
the computing modalities that we had at the time, we didn't think that they were going to be resilient at that scale. And so there was this big challenge of how do we come up with new computing modalities. The main modality at the time was what's called MPI message passing interface plus X, where X is your on-node solution for parallelism, you know, how you're going to use the threads on your system. And so what I worked on was HPX, which was this sort of one of a variety of different competing research runtimes that were exploring new parallel computing models.
And HPX was this fine-grained tasking model, so you could launch tasks that were very, very lightweight.
And it also had what we'd call an active address space.
So it could dynamically load balance work, and this would give you both load balancing but also resiliency, because if a node went down, you could move the work to another node.
And I mostly worked on the thread scheduling system and the migration and global address space system.
But what ended up happening in this push to the exascale era is that GPUs came onto the scene, accelerators came onto the scene. And it turned out that we could get to an exaflop of compute with 10,000 nodes that had GPUs in them or 20,000 nodes that had GPUs in them. And so we were able to scale up a different way.
And so it ended up that the existing modalities, the existing ways that we did parallel computing, they were basically good enough.
Like the way that we did the distributed computing was more or less good enough.
We just had to add the GPU programming aspect.
Right. Get a whole lot more parallels than per node, right?
Yep, exactly.
Today, obviously, there's huge clusters of very powerful GPUs like H100, H200 sort of processors that you all are making, right?
And our new, the Blackwell processors, which somebody can get their hands on. I don't know who. It's hard for me to get my hands on them, but they're out there somewhere.
What are your thoughts on ARM in the data center or supercomputers?
I
think that ARM is ultimately going to take over everything for the very simple reason that the software world loves simplicity and consistency.
And if we can support one type of CPU instead of two types of CPUs, that's so great.
It's like a 10x win.
That's what I often like to say with programming languages.
For a new programming language to be successful, to gain inertia, it needs to be 10x better in some way.
And for hardware, it's probably more like 20X or maybe 100X better.
And so like what is the 10X or 100X advantage that ARM has?
There's lots of like actual advantages.
We could talk about the merits of the hardware itself.
But at the end of the day, the only thing that matters is that ARM is the architecture that's in your phones and in your tablets.
And so naturally, but like x86 doesn't really scale down to the phone and the tablets.
People have tried, not really a good option.
not a good architecture for going at the low end of computing for a variety of reasons.
And so because x86 can't survive at the low scale of computing, then even if it's a better processor at the high end of computing, naturally ARM is going to push it out of the high end of computing.
And so I think that ARM is the inevitable future for CPU architectures.
Eventually something will come around to disrupt, but we tend to like uniformity.
And so I think that ARM will be dominant for a while.
Yeah, very interesting.
I also think ARM has a massive energy benefit or advantage, right?
And data centers are almost limited by energy these days more than a lot.
Energy and cooling.
In video, we also make CPUs.
We make ARM processors for both data center and mobile.
And our ARM processors are, yes, very energy efficient.
And that's one of the big advantages for us in picking that architecture.
Yeah, when you hear headlines like, Microsoft is starting up Three Mile Island again for a data center, you realize, oh, that's a lot of energy they need.
It is becoming the limiting factor
on compute.
This portion of Talk Python To Me is brought to you by the folks at Posit.
Posit has made a huge investment in the Python community lately.
Known originally for RStudio, they've been building out a suite of tools and services for Team Python.
Over the past few years, we've all learned some pretty scary terms.
hypersquatting, supply chain attack, obfuscated code, and more. These all orbit around the idea that when you install Python packages, you're effectively running arbitrary code off the internet on your dev machine, and usually even on your servers. But thought alone makes me shudder, and this doesn't even touch the reproducibility issues surrounding external packages.
But there are tools to help. Posit Package Manager can solve both problems for you.
Think of Posit Package Manager as your personal package concierge.
Use it to build your own package repositories within your firewall that keep your project safe.
You can upload your own internal packages to share or import packages directly from PyPI.
Your team members can install from these repos in normal ways using tools like pip, Poetry, and uv.
Posit Package Manager can help you manage updates, ensuring you're using the latest, most secure versions of your packages.
but it also takes point-in-time snapshots of your repos, which you can use to rerun your code reproducibly in the future.
Posit Package Manager reports on packages with known CVEs and other vulnerabilities so you can keep ahead of threats.
And if you need the highest level of security, you can even run Posit Package Manager in air-gapped environments.
If you work on a data science team where security matters, you owe it to you and your org to check out Posit Package Manager.
Visit talkpython.fm/ppm today and get a three-month free trial to see if it's a good fit.
That's talkpython.fm/ppm.
The link is in your podcast player's show notes.
Thank you to Posit for supporting the show.
The other thing I want to talk to you about is, before we get into the topic exactly, is with all of your background in C++, working with the standards, give people a sense of how has C++ evolved.
When you're talking to me, you're talking to a guy who did some professional C++, but stopped at the year 2000.
You know what I mean?
Like there's one view of C++ and there's probably something different now.
C++ is, the evolution of C++ is managed by an international standards organization, ISO.
And ISO has a very interesting stakeholder model where the stakeholders in ISO are national delegations or national bodies as we call them.
So each different country that participates in ISO can choose to send a national delegation.
And each different country has different roles for how their national delegations work.
In the U.S., membership in the national delegation is by company.
And there's no real requirement other than that you have to pay a fee.
It's like 2.5K a year.
And you can join the C++ committee if you're a U.S.-based organization.
In other countries, like in the U.K., it's a panel of experts.
And you're invited by the panel of experts to join the panel of experts.
And there's different, like some other countries have different models.
In some countries, the standards body is actually run by the government.
And so you have all these experts, these national delegates that come together, and then they all work on C++.
And there's a lot of bureaucracy and procedure, and it's sort of like a model UN, but for a programming language.
But yeah, for angle brackets and
semicolons,
got it.
A
lot of people on the committee love to talk about all the details of how the committee works.
I don't really think that it's particularly important.
I think that the key thing to understand is that it's sort of got an odd stakeholder model.
It's not a stakeholder model where it's like, oh, let's get the major implementations together or let's get the major users together.
For the most part, it's like anybody who can figure out how to join a national body can participate.
And if you happen to live from some small country where you're the only delegate, then you get the same vote as the entire United States national body because at the end of the day, votes on the C++ standard are by national body.
And so there's some people that have an outsized influence in the C++ committee.
The C++ committee itself is organized into a number of subgroups.
There's one for language evolution.
There's one for library evolution, which I chaired for about three years.
And then there are core groups for both language and library.
And so the evolution groups, they work on the design of new features and proposals.
And then the core groups sort of vet those designs and make sure that they're really solid.
And then there's a bunch of study groups that there's one for concurrency.
There's one for particular features like ranges or reflection.
And those groups develop those particular features or represent a particular interest area, like game developers, for example.
And proposals flow from those study groups to those evolution groups and then through the core groups.
And then eventually they go into the standard and then the national bodies vote on the standard.
Sounds pretty involved.
I guess the main thing I was wondering about is like, how different is C++ today versus 20, 30 years ago?
I
think it's a radically different language.
C++ 11 completely changed the language in many ways and really revitalized it after a very long period.
after the first standard, which was C++98.
And then after C++11, C++ began shipping new versions every three years.
Whatever features were ready would ship.
So we adopted a consistent ship cycle.
And the next big revision after C++11 was C++20.
Not as transformative, I think, as C++11, but pretty close.
And then we're just about to finish C++26, which will also be a pretty substantial release.
And probably by the time that this goes out to your podcast audience, we'll be right around when we finalize the feature set for C++ 26.
Interesting.
So if I want to do more C++, I probably need to start over and learn it again.
If
you learned it before C++ 11, yeah, you'd have to relearn some patterns.
Yeah.
We
like to talk about modern C++ versus old C++.
C++ 11 is sort of like a Python 2 to Python 3 sort of jump,
except...
Yeah, I was thinking maybe.
without as much breaking behavior.
There was very little breaking behavior.
But the best practices changed drastically from the pre-C++11 era to the modern era.
Yeah, super interesting.
I honestly could talk to you for a long time about this.
But this is not a C++ show, so let's move on to Python.
But I've been focused a little bit on C++ because traditionally that's been one of the really important ways to program GPUs and work with CUDA and things like that, right?
And now one of the things that you all have announced, released, or are working on is CUDA-Python, right?
How long has this been out here for?
Five months?
Something like that?
Not terribly long.
I
don't know how long the repo's been out, but the CUDA-Python effort's been around for about a year or two.
And you're absolutely right that for a long time, C++ was the primary interface to not just our compute platform, but to most compute platforms.
And so what changed?
Well, the two big things is that data science and machine learning happened.
Both fields that tend to have a lot of domain experts, computational scientists, who are not necessarily interested in writing low-level code in C++ and learning the best practices of software engineering in a systems language like C++.
They just want to be able to do their domain expertise, to do their data science, or to build their machine learning models.
So naturally they gravitated towards a more accessible and user-friendly language, Python.
And it became apparent a couple of years ago within NVIDIA that we needed to make our platform language agnostic.
And that's really what we've been focusing on the last year or two.
And CUDA Python is not just us saying, let's add another language.
Let's, okay, now we're going to do Python and C++.
It really reflects our overall goal of making the platform more language agnostic.
And you'll see that in our focus more and more on exposing things at the compiler level, exposing ways for other languages, other compilers, other DSLs to target our platform via things like MLIR dialects, which we've announced a bunch of recently.
But CUDA Python obviously was the place where we needed to start.
So the goal of CUDA Python is to provide the same experience with more or less the same performance that you would get in C++.
And when I say more or less, I mean that there are some higher level parts of CUDA Python that don't necessarily map directly to C++ things.
But the parts of CUDA Python that have direct counterparts in CUDA C++, we expect that you will get the same performance.
And we think that's really important because we don't want users to have to sacrifice performance to be able to do things natively within Python.
That's pretty impressive, honestly.
I think a lot of times when people think about doing stuff with Python, they're shown or they discover some kind of benchmark that is 100% Python or 100% the other language.
Like, oh, here's the three-body problem implemented in Python, and here it is implemented in Rust.
And look, it's 100 times slower or something.
But much of this work, much of the data science work especially, but even in the web, a lot of times what you're doing is you take a few pieces together in Python and you hand it off to something else, right?
In this case, you're handing it off to the GPU through the CUDA bindings, the C bindings.
And once it's in there, it's off to the races internally, right?
And yeah, and when I think of like the web, you very likely are taking a little bit of data, a little bit of string stuff, doing some dictionary things, handing it to a database or handing it to a third-party API.
And again, it doesn't matter what you're doing.
Like it's off into this, whatever that's written in C or whatever for the database.
Tell me a bit about like the work you had to do to sort of juggle that.
Sometimes people think of Python as being
a slow language.
I actually will make the claim that Python is a great language for doing high performance work.
And the reason for that is because Python, it's very easy.
Python's a very flexible language where it's very easy to do two things.
One, to
make,
to optimize the fast path to either through JIT or through Cython extensions.
It's very amenable to that.
And two, the language semantics are flexible enough that it's in the AST and the parsing is accessible enough that it's super, super easy to build a DSL in Python.
And because the language semantics are flexible, it's very easy to build a DSL where it's like, okay, well, our DSL, you write the syntax of Python, and there's some caveats here where some of the things that you know about Python are maybe a little bit different in this DSL.
But with those relaxations, we can give you super fast code.
And that's how things like Numba and things like Numbacuda and things like CoupyX and things like Triton, LANG, that's how those things all work, is they build the DSL where they take Python-like syntax, they follow most of the rules of Python with a couple relaxations, restrictions, et cetera.
And then they give you super fast code that has native performance.
And if you look at other languages that have tried to deliver on this, that have tried to have a managed runtime, tried to give you portability and high level ease of use and also performance, a lot of the other ones have failed.
I remember seeing a talk a couple of years ago from one of the lead engineers on, I forget which JVM, but of a particular JVM implementation.
And he was talking about everything that goes into making a native call from Java, like the protocol for Java to call a C function.
And he was showing us an assembly, like the call convention, and like you have to do all this stuff and save and restore all this stuff.
And he was like, and we have to do all this work to be able to make this fast.
And because Java doesn't have as flexible
semantics,
you have to do all that.
But in Python, it's so much easier.
And this is, I think, one of the reasons why Python has succeeded as a language because it's so easy when you need to put something in production, if it is slow, it's so easy to make that slow thing fast.
It's a really interesting take.
I hadn't really thought of that because it's a more malleable language that can be shaped to adapt to something underlying that's faster.
Exactly.
How much does Numba or Cython or things like that factor into what's happening here?
I see it's 16% Cython according to GitHub, but I don't know, Yeah, those stats are sometimes crazy.
We use Cython in a lot of places on fast paths.
Now, with CUDA, there's a couple different types of things that you do with CUDA.
The first with CUDA is when you're writing code that runs on your CPU, that is managing and orchestrating GPU actions.
That could be allocating GPU memory.
That could be launching and waiting on CUDA kernels.
It could be that sort of thing.
making work, making memory, transferring work in memory, waiting on things, setting up dependencies, et cetera. For the most part, a lot of those tasks are not going to be performance critical.
And the reason for that is because the limiting factor for performance is typically around like synchronization costs. If your major cost is like acquiring a lock or allocating memory, that whether you call Cuda Malic from C++ or Python, it
doesn't really
matter what language you're calling it from.
Cuda Malic is going to take a little while because it's got to go and get storage.
Now, one of the exceptions to this is when you're launching a kernel.
That's a thing that we want to be very, very fast.
So some of our frameworks have their kernel launch paths sithonized.
Numba we use pretty extensively.
So we use Numba for the other piece.
So I just talked about the orchestration and management of GPU work and memory.
But how do you actually write your own algorithms that run on the GPU?
So you don't have to do this frequently because we provide a whole huge library of existing algorithms.
And generally, we advise you should try to use the existing algorithms.
We got a lot of top people, spend a lot of time making sure that those algorithms are fast.
So you should try really hard to use the algorithms that we provide.
But sometimes you've got to write your own algorithm.
If you want to do that natively in Python, you need some sort of JIT compiler that's going to know how to compile some DSL that's going to JIT compile it down to native code that can run on the device.
We use Numba for that.
There's a Numba backend called CUDA that allows you to write CUDA kernels in Python with the same speed and performance that you'd get out of writing those kernels in CUDA C++.
And then we have a number of libraries for the device-side programming that you can use in Numba CUDA.
That sounds pretty useful, like a pretty good library to start with instead of trying to just straight talk to it, the GPUs directly.
This portion of Talk Python To Me is brought to you by Agency.
Agency, spelled A-G-N-T-C-Y, is an open-source collective building the internet of agents.
We're all very familiar with AI and LLMs these days But if you have not yet experienced the massive leap that agentic AI brings, herein for a treat Agentic AIs take LLMs from the world's smartest search engine to truly collaborative software That's where agency comes in Agency is a collaboration layer where AI agents can discover, connect, and work across frameworks For developers, this means standardized agent discovery tools, seamless protocols for interagent communication, and modular components to compose and scale multi-agent workflows.
Agency allows AI agents to discover each other and work together regardless of how they were built, who built them, or where they run.
Agency just announced several key updates as well, including interoperability for Anthropics Model Contacts Protocols, MCP, across several of their key components.
a new observability data schema enriched with concepts specific to multi-agent systems, as well as new extensions to the Open Agentic Schema Framework, OASF.
Are you ready to build the future of multi-agent software?
Get started with Agency and join Crew AI, LangChain, Llama Index, BrowserBase, Cisco, and dozens more.
Build with other engineers who care about high-quality multi-agent software.
Visit talkpython.fm/agency to get started today.
That's talkpython.fm/agency.
The link is in your podcast players, show notes, and on the episode page.
Thank you to agency for supporting Talk Python To Me.
So how much do people need to understand GPUs, GPU architecture and compute, especially Python people, to work with it?
I see a bunch of things like you talked about kernels.
warps, memory hierarchies, threads?
Give us a sense of some of these definitions and then which ones we need to pay attention to.
Most people need to know very little of this.
When we teach CUDA programming, when we teach it in C++ even these days, we start off by teaching you how to use the CUDA algorithms, how to use CUDA accelerated libraries, how to use kernels or GPU code that people have already written where you just plug in operators in the data that you want and how to use that.
And then we teach you about the notion of different kinds of memory, memory that the CPU can access and that the GPU can access.
And then like we teach you about like how to optimize using those algorithms and that memory.
And it's like only after like hour three or four of the education do we introduce to you the idea of writing a kernel because we don't want you to have to write your own kernels and because it's not the highest productivity thing and oftentimes it's not going to be the highest performance thing.
Writing GPU kernels has gotten more and more complex as GPUs have matured because the way that we get more and more perf out of our hardware today because we can no longer just get more as well scaling is that we have to expose more and more of the complexity of the hardware to the programmer.
And so writing a good GPU kernel today is in some ways easier but in some ways more challenging than it was 5 to 10 years ago.
Because five to 10 years ago, there were a lot less tools to help you out in writing a GPU algorithm.
But the hardware was a bit simpler.
Most people, I would say 90 to 95% of people, do not need to write their own kernels.
And if you don't need to write your own kernels, you don't have to understand the CUDA thread hierarchy.
And the CUDA thread hierarchy is what warps and blocks are.
So on the GPU, you've got a bunch of different threads.
And those threads are grouped into subsets that are called blocks.
And the blocks all run at the same time.
So all the threads in the block run at the same time, rather.
And all the threads within the block have fast ways of communicating to each other.
And they have fast memory that they can use to communicate to each other.
This scratchpad memory that we call shared memory.
And blocks are further divided into warps, which are smaller subsets of threads that are executed as one.
Like they do the same operations on the same particular physical piece of hardware at a time.
They do each have an individual state, so they can be at different positions.
They essentially each have their own thread, but they're executed in lockstep.
But you don't need to know most of that if you're looking to use CUDA.
What you need to understand is some of the basics of parallel programming and how to use algorithms.
And there are, I would say, three main generic algorithms that matter.
And the first is just like four, it's just a for loop.
And the for loop that we most often think about is the one that we call transform, where you've got an input of an array of some shape and an output of an array of some shape. And you just apply a function to every element of the input, and then that produces the output for you.
The second algorithm
Sounds a little like pandas or something like that, right? The vectorized math and so on.
That's exactly right. Or in Numba, it's like the notion of a generalized universal function or like a ufunk from NumPy or something like that. Just an element-wise function. The next algorithm is reduction. So this is like doing a sum. It's just a generalized version of doing a sum over something. And a reduction is a basis operation that you can use to implement all sorts of things like counting, any form of counting, any form of searching. If you're looking for the maximum of something, you can do that with a reduction. And the last algorithm is a scan, which is also known in some circles as a partial sum. So a scan works somewhat similar to a reduction, but it gives you the intermediate sums. So if you're scanning an array of length n, the output of that scan is the sum of the first element and the second element, the first element, the second element, and the third element, the first element, the second element, the third element, and the fourth element, et cetera, through to the end. And scans are very useful for anything that has position-aware logic.
Like if you want to do something where you want to reason about adjacent values, or if you want to do something like a copy if, or like a filter, something like that, that's what you'd use a scan for. And those three, I think, are the basis of programming with parallel algorithms. And you would be surprised at how often a parallel programming problem will break down into calling some combination of those three
algorithms. With this version of Python 3.13, we kind of have no more gil. Right. How much does that matter? It sounds like it might not actually really make much difference for this project. This
is a question I get asked a lot internally. I do think it matters.
One of the reasons it matters is that these days you don't normally have just one GPU in like a high-end system.
You tend to have multiple GPUs.
Multiple being two or four or 20?
Two,
four, or like eight. Eight is what you typically see.
You typically see like two CPUs and eight GPUs in like your default like high-end compute
notes.
Yeah, but even if you just serialize one of those, that's only 16% of the GPU processing, right?
Like one eighth.
Oftentimes
to feed all the GPUs, you need to have parallelism on the CPU.
It's oftentimes not sufficient to just have one thread in the CPU, launch everything.
And there's also like, GPUs are not the answer for everything.
Like people often have ideas of what they think a GPU is, But I'll tell you my definition of what a GPU is.
A GPU is just a bandwidth optimized processor.
It's a general purpose processor, just like a CPU.
But a CPU is optimized for latency.
It's optimized for the single threaded case.
It's optimized for getting you an answer for every operation as quickly as possible.
A GPU is optimized for bandwidth.
If you ask a GPU to load from memory, it's going to take a while.
If you ask a GPU to add something, it's going to take a while.
but it will have a higher bandwidth of doing those things.
And so for some tasks, a lot of like data loading, storing and ingestion tasks, the CPU might be the better fit.
And also the CPU is generally the better thing to talk to disk and to talk to network directly.
And so for a lot of applications, the CPU has got to do work to get data ready and then to communicate that data to the GPU.
And oftentimes the highest performance architectures are going to be ones where that data prep and loading and command and control work is being done in parallel.
And a gill-less Python will enable us to be able to express those efficient command and control architectures directly in Python and to be able to have Python efficiently communicate with the GPU.
Yeah, maybe make a thread per GPU or something like that and send them all off the...
Or even multiple threads per GPU
you may need in some cases.
Probably depends on how many threads your CPU has also.
Yes, definitely.
That all sounds super interesting.
I want to dive into the different building blocks.
There's all these, like CUDA Python is at least in its current and ongoing, maybe future form, what's called a meta package in the sense that it is not itself a thing that has a bunch of functionality, but it sort of claims dependency on a bunch of things and does an import of them and centralizes that to like sort of bundle a bunch of pieces, right?
So I want to talk about all of those.
But before we do, give people out there who maybe have Python, I guess, mostly data science problems, maybe AI, email problems.
Or it'd be interesting if there was something that didn't fit either of those that is good to solve with CUDA and GPU programming.
Like, maybe give us some examples of what people build with this.
The more important question is usually what order of magnitude of data do you have to work with?
If you don't have a large enough problem size, you're not going to get a benefit out of using a GPU.
Okay, define large.
That means different things for different people, right?
Measured
in gigabytes of memory footprint.
Okay.
You typically will need to have, well, it's a little more nuanced than that.
If the compute that you're doing is linear in your problem size, that is, if you're doing like ON operations, like you're doing some linear number of operations, like per element your data size, then you need gigabytes.
If you're doing more than that per element, if you've got something that's like n squared or exponential or n log in, something like sorting, where it's not going to scale linearly with the number of elements, where it's going to be worse than that, then you might have a smaller problem size that will make sense to run on the GPU.
But the majority of people who have a compute task have things that fall into the ON regime.
It's like, oh, I've got a set of in things and I want to apply this function to each one of them.
And in that case, you normally need gigabytes.
If you're sorting things, if you're sorting 100 megabytes of ints, you'll probably see a speedup on a GPU.
If you're just adding a million ints to a million ints, that's probably about the cutoff point for seeing a benefit from using the GPU.
The types of workloads, I think generally, It's sort of hard to say because it's so broad in what you can do.
You need to have something that has some amount of parallelism.
So there needs to be some data parallel aspect to your problem.
If you can't parallelize it, you're not going to benefit from the GPS.
Right. Maybe I have questions about all the, I don't know, sales or some sort of prediction per state for all 50 states in the U.S.
or all countries in the world.
You could just break it up by country or state and let it rip.
Yeah. And those are definitely the easiest, the easiest.
When it's completely embarrassingly parallel, that's usually a good sign that it's something that will fit well in GPU.
But also if you have something like, I want to add up, I want to take the sum of every integer in this huge data set or something like that, that's also a task that GPUs can be good for, even though it's not embarrassingly parallel, even though there are data dependencies.
Where's a good place to run it?
Something I've been fascinated with is this thing you guys announced but have not yet shipped, the home AI computer, This little golden box.
So
the DGX Spark, great entry-level platform, but there is no reason to have to buy something if you want to play around with CUDA.
One of the best places to play around with CUDA Python, I think, is Google CoLab.
Google CoLab, it's a Jupyter notebook environment, and they have three GPU instances with T4 GPUs.
It's not there by default, but if you go in, If you go to runtime, you can change to use a GPU environment.
And then you can play around with Python in the Colab environment.
There is also Compiler Explorer, which is an online platform.
It's godbolt.org is the link.
It's an online compiler sandbox, and it has GPU environments.
And it does also have Python support, although I think they're still working on getting Python packaging to be available here.
But for something like CUDA C++, you can use this to write code and then see what the assembly is that you'd get, make sure that your code compiles, and then also run that code, and you can even run the code on a GPU.
So I think if you want to get started, there's a lot of different places where you can do GPU development without having to have your own GPU.
Another couple possibilities, it's not too bad.
It's not that cheap, but if you don't leave it on all the time, it's not too bad to get a cloud Linux machine that's got some GPU component.
But if you leave it on all the time, they do get expensive.
So
set
yourself a reminder to turn it off.
Another one that's interesting, which I was just thinking about with my Mac Mini here.
I don't know that you've said it yet, but I'm pretty sure it's still true, that CUDA requires NVIDIA GPUs, not just a GPU, right?
That is true, yes.
So it's not going to work super well on my Apple Silicon.
That is true.
For that reason, amongst possibly others, but certainly that's one of them.
But I have like a gaming PC, or you might have a workstation with a really good GPU.
You could set up things like change your Docker host on your computer, and anything you run on Docker will run over there on that machine or build on that machine and so on.
So that's a pretty interesting way to say, well, everybody in the lab, we're changing your Docker host to like the one big machine that's got the NVIDIA GPU.
I think there's a lot of flexibility.
You
don't even need to have the highest-end GPU to get started with CUDA programming.
And there are a lot of people who have use cases that would benefit from GPU acceleration where an everyday commodity gaming GPU would be fine.
Not going to be true for every application.
And of course, if you scale up, what usually happens when people start with GPU acceleration is first they take their existing thing and then they add the GPU acceleration.
and now it runs a lot faster.
And then they start thinking, aha, now that it runs faster, I can increase my problem size.
I no longer have these constraints.
And then they end up needing a bigger GPU.
But for that initial speed up, you're usually fine to start prototyping and developing on your everyday monody GPU.
Not usually going to be the thing that makes sense to take to production.
And one of the biggest downsides to the GPU that's in your gaming box is that you're going to have greater latency between the CPU and the GPU.
And you're not going to have as much memory compared to what you get in a server GPU.
It's a step on the staircase maybe of getting started.
Yes.
Prototyping and so on.
Okay.
We don't have too much time left, but maybe let's dive into each of these pieces here that make up CudaPython.
There's some that are listed here.
Let me give people the overview of what parts of CudaPython you've created started with.
The first one isn't even listed here, and that is Coupy.
Okay.
So it's not listed here because it's not part of that CudaPython meta package.
So QPY is a NumPy and SciPy-like library that is GPU accelerated.
So it's the interface that you know from NumPy and SciPy.
When you invoke the operations, they run on your GPU.
So this is by far where everybody should start.
Could I get away with even saying import QPY as NP?
Is it that compatible?
You
could get away with that, but there are certainly going to be cases where the semantics may not 100% line up.
I think for the most part, you would be fine doing that, but there is no way to make a 100% fully compatible drop and replacement.
And so it's important to read the docs and make sure you understand where there may be little subtle differences.
But yeah, definitely think of it as drop and replace.
Yeah, the reason I was asking is maybe that's a super simple way to experiment, right?
I've got something written in Pandas, NumPy, and so on.
Could I just change the import statement what happens without like completely rewriting it. That's kind of what's getting at. Yeah,
you can definitely do that. I mean, it's, I think the docs even say right there that, yeah, it's meant to be a drop and replacement. So yeah, that's definitely how you could get started.
The one thing to keep in mind is that if you're running in a single thread on the CPU, the problem size that you're running with may not be large enough to see an impact. So you may have to think about you running with a larger problem size than, than it makes sense with NumPy.
It might even be slower, right? Because of the overhead
of CPU
and stuff.
If you do like a sum of like
three elements.
Although I would hope and assume that that path we maybe don't dispatch to GPU translation, but I suspect we still do.
Kupi
is sort of the foundational thing that I'd say everybody should get started with.
Okay, let me ask you a follow-up question.
So this is like NumPy.
NumPy is the foundation mostly, starting to change a little bit.
But for pandas, is there a way to kind of pandify my GPU programming?
Yes, there is.
We have QDF, libqdf, which is a part of Rapids.
And libqdf has a, it's a data frame library and it has a panda mode.
I think the module is just like qdf.pandas that aims to be a drop and replacement.
And then it also has its own like data frame interface that's, I think, a little bit different than pandas in some ways.
It allows it to be more efficient for GPU in parallel.
And there's a whole bunch of other libraries that are a part of the Rapids frameworks for doing accelerated data science.
Yeah, I'm going to probably be doing an episode on Rapids later as well.
So diving more into that.
But OK, it's good to know that that kind of is the parallel there.
That was actually the next piece I was going to mention was going to be Rapids and Kudia.
Now, the next two most frequent things that you might need is the like a Pythonic interface to the CUDA run plan.
So the CUDA runtime is the thing that you use to do that command and control, that orchestration of NVIDIA GPUs.
Things like managing configurations and settings in the GPUs, loading programs, compiling and linking programs, doing things like launching work on the GPU, allocating memory, creating queues of work, creating dependencies, etc.
Cuda.core is a Pythonic API to all of those things.
And that's what almost everybody should be using for doing those sorts of management tasks.
It pretty much one-to-one maps to things, to ideas, concepts from the CUDA C++ runtime.
And then the final piece would be Numba CUDA, which is the thing that you would use to write your own CUDA kernels.
And when you're writing those CUDA kernels, there are some libraries that can help you with that.
And one of them is CUDA Cooperative, which is going to be the thing I'll probably talk about the most in my Python talk.
And so CUDA Cooperative provides you with these algorithmic building blocks for writing CUDA kernels.
And we also have a package called NVMath Python, which provides you with more, CUDA Cooperative is generic algorithmic building blocks for things like loading and storing or doing a sum or a scan.
NVMath Python provides you with building blocks for things like a matrix multiply or random numbers or a Fourier transform, etc.
And NVMath Python also has host side APIs, so you can use it.
For the most part, you can access those with Kupi's SciPy packages, but you can also go directly through NVMath Python if you want to get to the slightly lower level APIs that give you a little bit more control.
I've heard the docs talk about host side operations versus not.
What does that mean?
Host side operations means things that you call from the CPU so that your Python program calls just as a regular Python program would, and then it runs some work on the GPU, and then when it's done, it reports back to the CPU.
And typically, in a lot of cases, like Kupi, these operations are synchronous.
So like you call like Kupi sum, it launches the work on the GPU, the work on the GPU finishes.
And this whole time, the Kupi sum has been waiting for that work by default.
And so it gives you this sequential.
So real simple distributed programming model, right?
It looks like you're just calling local functions, but it's kind of distributed computing.
Distributed in the sense of it's distributed from the host to the device.
Device side operations are things that you're calling from within a CUDA kernel.
And a CUDA kernel is a function that gets run by every thread on the GPU or every thread within the collection that you tell it to run on.
For simplicity, let's just assume every thread on the GPU.
And so those operations are what we call cooperative operations in that a cooperative sum is a sum where every thread is expected to call the sum function at the same time.
and they all cooperate together, communicate amongst themselves to compute the sum across all the threads.
We're just about out of time.
You mentioned it in passing, but you're going to have a talk coming up at PyCon.
Yes.
Which, if people are watching the YouTube live stream, starts in just a couple days.
If they're listening to the podcast, maybe you can catch the video now.
It's about time enough.
But it's called GPU Programming in Pure Python.
You want to give a quick shout out to your talk?
In this talk, we're going to look at how you write CUDA kernels or how you can write CUDA kernels in Python without having to go to CUDA C++ and how you have access to all the tools that you have in CUDA C++ and you can get the same performance that you would have in CUDA C++.
Sounds like a good hands-on, not exactly hands-on, but at least concrete code version of a lot of the stuff we talked about here.
Yeah.
Yeah, great.
And now people are excited, they're interested in this.
What do you tell them?
How do they get started?
What do they do?
I
would say they should go to the Accelerated Computing Hub, which is another GitHub repo that we have.
And on the Accelerated Computing Hub, we have open source learning materials and courses, self-guided courses.
And one of them is a GPU Python tutorial.
So you just go to Accelerated Computing Hub.
It's on GitHub.
Click on GPU Python tutorial.
And it takes you to a page with a whole bunch of Jupyter Notebooks.
And you start with the first one.
It opens up in CoLab.
It uses those Colab GPU instances, and you can start learning there.
There's other resources available on Accelerated Computing Hub, and that is that we're always working on new stuff.
So that is a good place to look.
There's also, I think, a PyTorch tutorial there, and we have Accelerated Python User Guide, which has some other useful learning material.
Thanks for being here, Bryce.
I love you.
Good luck with your talk.
And yeah, thanks for giving us this look at GPU programming in Python.
Thank
you.
It was great being here.
Oh, I should also, I should plug my podcast, ADSP, the podcast, Algorithms Plus Data Structures Equals Programming.
We talk about parallel programming.
We talk about those three algorithms that I mentioned, transform, reduce, and scan, and how you can use them to write the world's fastest GPU-excited code.
And we talk a lot about array programming languages and all sorts of fun stuff.
So check it out.
Excellent.
Yeah, I'll link to it in the show notes for people.
Thanks.
Thanks for being here.
See you later.
This has been another episode of Talk Python To Me.
Thank you to our sponsors.
Be sure to check out what they're offering.
It really helps support the show.
This episode is sponsored by Posit Connect from the makers of Shiny.
Publish, share, and deploy all of your data projects that you're creating using Python.
Streamlit, Dash, Shiny, Bokeh, FastAPI, Flask, Quarto, Reports, Dashboards, and APIs.
Posit Connect supports all of them.
Try Posit Connect for free by going to talkpython.fm/posit, B-O-S-I-T.
And it's brought to you by Agency.
Discover agentic AI with Agency.
Their layer lets agents find, connect, and work together, any stack, anywhere.
Start building the internet of agents at talkpython.fm/agency, spelled A-G-N-T-C-Y.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show, open your favorite podcast app, and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.