You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/guide/gpu.md
+45-68Lines changed: 45 additions & 68 deletions
Original file line number
Diff line number
Diff line change
@@ -232,19 +232,17 @@ More information for conditional use of GPUs in CUDA.jl can be found in its [doc
232
232
233
233
## Using device objects
234
234
235
-
As a more convenient syntax, Flux allows the usage of GPU `device` objects which can be used to easily transfer models to GPUs (and defaulting to using the CPU if no GPU backend is available). This syntax has a few advantages including automatic selection of the GPU backend and type stability of data movement. To do this, the [`Flux.get_device`](@ref) function can be used.
235
+
As a more convenient syntax, Flux allows the usage of GPU `device` objects which can be used to easily transfer models to GPUs (and defaulting to using the CPU if no GPU backend is available). This syntax has a few advantages including automatic selection of the GPU backend and type stability of data movement.
236
+
These features are provided by [MLDataDevices.jl](https://github.com/LuxDL/MLDataDevices.jl) package, that Flux's uses internally and re-exports.
236
237
237
-
`Flux.get_device` first checks for a GPU preference, and if possible returns a device for the preference backend. For instance, consider the following example, where we load the [CUDA.jl](https://github.com/JuliaGPU/CUDA.jl) package to use an NVIDIA GPU (`"CUDA"` is the default preference):
238
+
A `device` object can be created using the [`gpu_device`](@ref MLDataDevices.gpu_device) function.
239
+
`gpu_device` first checks for a GPU preference, and if possible returns a device for the preference backend. For instance, consider the following example, where we load the [CUDA.jl](https://github.com/JuliaGPU/CUDA.jl) package to use an NVIDIA GPU (`"CUDA"` is the default preference):
238
240
239
241
```julia-repl
240
242
julia> using Flux, CUDA;
241
243
242
-
julia> device = Flux.get_device(; verbose=true) # returns handle to an NVIDIA GPU
243
-
[ Info: Using backend set in preferences: CUDA.
244
-
(::Flux.FluxCUDADevice) (generic function with 1 method)
245
-
246
-
julia> device.deviceID # check the id of the GPU
247
-
CuDevice(0): NVIDIA GeForce GTX 1650
244
+
julia> device = gpu_device() # returns handle to an NVIDIA GPU if available
245
+
(::CUDADevice{Nothing}) (generic function with 4 methods)
248
246
249
247
julia> model = Dense(2 => 3);
250
248
@@ -262,77 +260,57 @@ julia> model.weight
262
260
-0.984794 -0.904345
263
261
0.720379 -0.486398
264
262
0.851011 -0.586942
265
-
266
263
```
267
264
268
-
The device preference can also be set via the [`Flux.gpu_backend!`](@ref) function. For instance, below we first set our device preference to `"CPU"`:
265
+
The device preference can also be set via the [`gpu_backend!`](@ref MLDataDevices.gpu_backend!) function. For instance, below we first set our device preference to `"AMDGPU"`:
269
266
270
267
```julia-repl
271
-
julia> using Flux; Flux.gpu_backend!("CPU")
272
-
┌ Info: New GPU backend set: CPU.
273
-
└ Restart your Julia session for this change to take effect!
268
+
julia> gpu_backend!("AMDGPU")
269
+
[ Info: GPU backend has been set to AMDGPU. Restart Julia to use the new backend.
274
270
```
275
-
276
-
Then, after restarting the Julia session, `Flux.get_device` returns a handle to the `"CPU"`:
271
+
If no functional GPU backend is available, the device will default to a CPU device.
272
+
You can also explictly request a CPU device by calling the [`cpu_device`](@ref MLDataDevices.cpu_device) function.
277
273
278
274
```julia-repl
279
-
julia> using Flux, CUDA; # even if CUDA is loaded, we'll still get a CPU device
280
-
281
-
julia> device = Flux.get_device(; verbose=true) # get a CPU device
282
-
[ Info: Using backend set in preferences: CPU.
283
-
(::Flux.FluxCPUDevice) (generic function with 1 method)
275
+
julia> using Flux, MLDataDevices
284
276
285
-
julia> model = Dense(2 => 3);
286
-
287
-
julia> model = model |> device
288
-
Dense(2 => 3) # 9 parameters
277
+
julia> cdev = cpu_device()
278
+
(::CPUDevice{Nothing}) (generic function with 4 methods)
289
279
290
-
julia> model.weight # no change; model still lives on CPU
291
-
3×2 Matrix{Float32}:
292
-
-0.942968 0.856258
293
-
0.440009 0.714106
294
-
-0.419192 -0.471838
295
-
```
296
-
Clearly, this means that the same code will work for any GPU backend and the CPU.
280
+
julia> gdev = gpu_device(force=true) # force GPU device, error if no GPU is available
281
+
(::CUDADevice{Nothing}) (generic function with 4 methods)
297
282
298
-
If the preference backend isn't available or isn't functional, then [`Flux.get_device`](@ref) looks for a CUDA, AMDGPU or Metal backend, and returns a corresponding device (if the backend is available and functional). Otherwise, a CPU device is returned. In the below example, the GPU preference is `"CUDA"`:
283
+
julia> model = Dense(2 => 3); # model in CPU memory
299
284
300
-
```julia-repl
301
-
julia> using Flux; # preference is CUDA, but CUDA.jl not loaded
285
+
julia> gmodel = model |> gdev; # transfer model to GPU
302
286
303
-
julia> device = Flux.get_device(; verbose=true) # this will resort to automatic device selection
304
-
[ Info: Using backend set in preferences: CUDA.
305
-
┌ Warning: Trying to use backend: CUDA but it's trigger package is not loaded.
306
-
│ Please load the package and call this function again to respect the preferences backend.
307
-
└ @ Flux ~/fluxml/Flux.jl/src/functor.jl:637
308
-
[ Info: Using backend: CPU.
309
-
(::Flux.FluxCPUDevice) (generic function with 1 method)
287
+
julia> cmodel = gmodel |> cdev; # transfer model back to CPU
310
288
```
311
-
For detailed information about how the backend is selected, check the documentation for [`Flux.get_device`](@ref).
312
289
313
290
## Data movement across GPU devices
314
291
315
-
Flux also supports getting handles to specific GPU devices, and transferring models from one GPU device to another GPU
316
-
device from the same backend. Let's try it out for NVIDIA GPUs. First, we list all the available devices:
292
+
Flux also supports getting handles to specific GPU devices, and transferring models from one GPU device to another GPU device from the same backend. Let's try it out for NVIDIA GPUs. First, we list all the available devices:
317
293
318
294
```julia-repl
319
295
julia> using Flux, CUDA;
320
296
321
297
julia> CUDA.devices()
322
298
CUDA.DeviceIterator() for 3 devices:
323
-
0. GeForce RTX 2080 Ti
324
-
1. GeForce RTX 2080 Ti
325
-
2. TITAN X (Pascal)
326
-
299
+
0. NVIDIA TITAN RTX
300
+
1. NVIDIA TITAN RTX
301
+
2. NVIDIA TITAN RTX
327
302
```
328
303
329
304
Then, let's select the device with id `0`:
330
305
331
306
```julia-repl
332
-
julia> device0 = Flux.get_device("CUDA", 0) # the currently supported values for backend are "CUDA" and "AMDGPU"
333
-
(::Flux.FluxCUDADevice) (generic function with 1 method)
307
+
julia> device0 = gpu_device(1)
308
+
(::CUDADevice{CuDevice}) (generic function with 4 methods)
334
309
310
+
julia> device0.device
311
+
CuDevice(0): NVIDIA TITAN RTX
335
312
```
313
+
Notice that indexing starts from `0` in the `CUDA.devices()` output, but `gpu_device!` expects the device id starting from `1`.
336
314
337
315
Then, let's move a simple dense layer to the GPU represented by `device0`:
0 commit comments