Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPU support to MRIReco.jl #182

Merged
merged 66 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
72641ee
Update RegLS calls
nHackel Apr 17, 2024
b0af5eb
Add S kwarg to SparseOp
nHackel Apr 17, 2024
ed506cb
Fix NFFTOp call, unsure if trajectory is passed on correctly
nHackel Apr 17, 2024
5557aaa
Add :arrayType to param dict
nHackel Apr 17, 2024
8ecdc66
Init working GPU reconstruction_simple
nHackel Apr 17, 2024
a3a5202
Remove CompositeOp
nHackel Apr 18, 2024
bc1cf80
Fix NFFTOp nodes retrieval from Trajectory
nHackel Apr 18, 2024
7f88b81
Fix SparseOp
nHackel Apr 18, 2024
4cfc217
Fix missing type conversion for default Cartesian3D trajectory
nHackel Apr 18, 2024
fd86c4e
Remove CompOp include
nHackel Apr 18, 2024
ef307cf
Init ExplicitOp for GPU
nHackel Apr 18, 2024
7cc8cd1
ctprod for ExplicitOp on GPU
nHackel Apr 18, 2024
1070052
Add GPU support to SubspaceOp
nHackel Apr 22, 2024
6da90c9
Add S kwarg to MapSliceOp
nHackel Apr 22, 2024
4669dc9
Add GPU support to circulaShutter!
nHackel Apr 22, 2024
4ed271c
Migrate DiagOp to LinearOpCollection, "overwrite" products with @floo…
nHackel Apr 22, 2024
da79555
Add `S` kwarg to EncodingOps
nHackel Apr 22, 2024
a29fd35
Chose `@floop` executor based on arraytype
nHackel Apr 23, 2024
23f9d44
Add GPU support for SensitivityOp
nHackel Apr 23, 2024
c399fe0
Fix missing commas in EncodingOps
nHackel Apr 23, 2024
44a3d08
Adapt to function name change for DiagOp
nHackel Apr 23, 2024
c98b0b3
Add operatore copy function as kwarg
nHackel Apr 24, 2024
8daf6c1
Pass along FFTParams to operators based on array type
nHackel Apr 24, 2024
de51024
Fix GPU FFT params
nHackel Apr 24, 2024
aa4b9a9
Hide copyOpsFn for encoding params
nHackel Apr 24, 2024
4152422
Remove debug for-loop limits for multi_coil reco
nHackel Apr 24, 2024
856f85d
Impore arrayType param handling
nHackel Apr 25, 2024
e362d3d
Remove (broken) default Wavelet sparsityTrafo
nHackel Apr 25, 2024
f934502
Use copyto! for better GPU performance
nHackel Apr 25, 2024
a9e39a3
Remove log message
nHackel May 22, 2024
b5486bb
Init updating FieldmapNFFTOp constructor for GPU
nHackel Jun 5, 2024
a757463
Reduce clutter in ExplicitOp constructor
nHackel Jun 5, 2024
53b4dc4
Init updating MRIOperators tests
nHackel Jun 5, 2024
f214369
Add GPU support for FieldmapNFFTOp (not very optimized)
nHackel Jun 6, 2024
30e0534
Add cuda tests for MRIOperators
nHackel Jun 6, 2024
762bd5a
Update fieldmapop copy
nHackel Jun 6, 2024
b0c13ba
Add arrayTypes to MRIReco tests
nHackel Jun 6, 2024
32e109d
Adapt to RegLS Kwargs renaming
nHackel Jun 6, 2024
2164c8f
Update DirectReco for GPU
nHackel Jun 11, 2024
ffc9499
Fix copy for FieldmapNFFTOp
nHackel Jun 11, 2024
02f0780
Update arrayType parameter handling (lessen restriction to accept fun…
nHackel Jun 11, 2024
7de09ac
Move L_inv and SenseMaps to GPU
nHackel Jun 11, 2024
838773f
Init not-error-ing tests (still some failing)
nHackel Jun 11, 2024
deabe4b
Fix bug in ExplicitOp
nHackel Jun 11, 2024
b9b39cf
Add CUDA buildkite CI
nHackel Jul 3, 2024
55b813b
Add AMD tests (inactive until NFFT runs on AMD)
nHackel Jul 3, 2024
5d54fb1
Update RegLS and LinearOperatorColl. compat
nHackel Jul 4, 2024
01185c0
Readd JLArray tests to MRIOperators
nHackel Jul 4, 2024
e9e2039
Add JLArray test to MRIReco
nHackel Jul 4, 2024
348fcba
Attempt to run buildkite for MRIOperators
nHackel Jul 9, 2024
0499df3
Merge branch 'master' into nh/gpuSupport
nHackel Jul 9, 2024
beea135
prepare project.toml for releases
nHackel Jul 9, 2024
747730f
Fix MRIOperators dep in MRISimulation
nHackel Jul 31, 2024
65c25ab
Try fix CUDA buildkite
nHackel Jul 31, 2024
9c7e769
Try to fix CI by dev'ing all packages in one call
nHackel Jul 31, 2024
d81ded7
Remove CuNFFT from CUDA test
nHackel Jul 31, 2024
a06cad3
Update CUDA and ROCM test files for GPU support
nHackel Jul 31, 2024
32ff016
Merge branch 'master' into nh/gpuSupport
nHackel Jul 31, 2024
c845d6b
Merge branch 'nh/gpuSupport' of github.com:MagneticResonanceImaging/M…
nHackel Jul 31, 2024
6d165d4
Ignore empty plans in FieldMapNFFTOp constructor
nHackel Jul 31, 2024
70bfd37
Use Adapt for MRIOperator constructors
nHackel Jul 31, 2024
fda6fb7
Try fixing MRIOperators buildkite
nHackel Jul 31, 2024
5be9623
Update MRIOperators import in runtests.jl
nHackel Aug 1, 2024
52c8a81
Use MRIOperators test env in buildkite
nHackel Aug 1, 2024
b79c650
Activate AMD MRIOperators buildkite step
nHackel Aug 1, 2024
f0e29bc
Fix whitespace in pipeline.yml
nHackel Aug 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
steps:
- label: "Nvidia GPUs -- MRIReco.jl"
plugins:
- JuliaCI/julia#v1:
version: "1.10"
agents:
queue: "juliagpu"
cuda: "*"
command: |
julia --color=yes --project -e '
using Pkg
Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
, PackageSpec(path=pwd(), subdir="MRIFiles")
, PackageSpec(path=pwd(), subdir="MRISampling")
, PackageSpec(path=pwd(), subdir="MRISimulation")
, PackageSpec(path=pwd(), subdir="MRIOperators")
, PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
Pkg.add("TestEnv")
using TestEnv
TestEnv.activate();
Pkg.add("CUDA")
Pkg.instantiate()
include("test/gpu/cuda.jl")'
timeout_in_minutes: 30

#- label: "AMD GPUs -- MRIReco.jl"
# plugins:
# - JuliaCI/julia#v1:
# version: "1.10"
# agents:
# queue: "juliagpu"
# rocm: "*"
# rocmgpu: "*"
# command: |
# julia --color=yes --project -e '
# using Pkg
# Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
# , PackageSpec(path=pwd(), subdir="MRIFiles")
# , PackageSpec(path=pwd(), subdir="MRISampling")
# , PackageSpec(path=pwd(), subdir="MRISimulation")
# , PackageSpec(path=pwd(), subdir="MRIOperators")
# , PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
# Pkg.add("TestEnv")
# using TestEnv
# TestEnv.activate();
# Pkg.add("AMDGPU")
# Pkg.instantiate()
# include("test/gpu/rocm.jl")'
# timeout_in_minutes: 30

- label: "Nvidia GPUs -- MRIOperators.jl"
plugins:
- JuliaCI/julia#v1:
version: "1.10"
agents:
queue: "juliagpu"
cuda: "*"
command: |
julia --color=yes --project -e '
using Pkg
Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
, PackageSpec(path=pwd(), subdir="MRIFiles")
, PackageSpec(path=pwd(), subdir="MRISampling")
, PackageSpec(path=pwd(), subdir="MRISimulation")
, PackageSpec(path=pwd(), subdir="MRIOperators")
, PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
Pkg.add("TestEnv")
using TestEnv
TestEnv.activate("MRIOperators");
Pkg.add("CUDA")
Pkg.instantiate()
include("MRIOperators/test/gpu/cuda.jl")'
timeout_in_minutes: 30


- label: "AMD GPUs -- MRIOperators.jl"
plugins:
- JuliaCI/julia#v1:
version: "1.10"
agents:
queue: "juliagpu"
rocm: "*"
rocmgpu: "*"
command: |
julia --color=yes --project -e '
using Pkg
Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
, PackageSpec(path=pwd(), subdir="MRIFiles")
, PackageSpec(path=pwd(), subdir="MRISampling")
, PackageSpec(path=pwd(), subdir="MRISimulation")
, PackageSpec(path=pwd(), subdir="MRIOperators")
, PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
Pkg.add("TestEnv")
using TestEnv
TestEnv.activate("MRIOperators");
Pkg.add("AMDGPU")
Pkg.instantiate()
include("MRIOperators/test/gpu/rocm.jl")'
timeout_in_minutes: 30
24 changes: 12 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ jobs:
shell: julia --color=yes --project=. {0}
run: |
using Pkg
Pkg.develop(PackageSpec(path=pwd(), subdir="MRIBase"))
Pkg.develop(PackageSpec(path=pwd(), subdir="MRIFiles"))
Pkg.develop(PackageSpec(path=pwd(), subdir="MRISampling"))
Pkg.develop(PackageSpec(path=pwd(), subdir="MRISimulation"))
Pkg.develop(PackageSpec(path=pwd(), subdir="MRIOperators"))
Pkg.develop(PackageSpec(path=pwd(), subdir="MRICoilSensitivities"))
Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
, PackageSpec(path=pwd(), subdir="MRIFiles")
, PackageSpec(path=pwd(), subdir="MRISampling")
, PackageSpec(path=pwd(), subdir="MRISimulation")
, PackageSpec(path=pwd(), subdir="MRIOperators")
, PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- name: Run subpackage tests
Expand Down Expand Up @@ -78,12 +78,12 @@ jobs:
shell: julia --color=yes --project=. {0}
run: |
using Pkg
Pkg.add(PackageSpec(path=pwd(), subdir="MRIBase"))
Pkg.add(PackageSpec(path=pwd(), subdir="MRIFiles"))
Pkg.add(PackageSpec(path=pwd(), subdir="MRISampling"))
Pkg.add(PackageSpec(path=pwd(), subdir="MRISimulation"))
Pkg.add(PackageSpec(path=pwd(), subdir="MRIOperators"))
Pkg.add(PackageSpec(path=pwd(), subdir="MRICoilSensitivities"))
Pkg.develop([PackageSpec(path=pwd(), subdir="MRIBase")
, PackageSpec(path=pwd(), subdir="MRIFiles")
, PackageSpec(path=pwd(), subdir="MRISampling")
, PackageSpec(path=pwd(), subdir="MRISimulation")
, PackageSpec(path=pwd(), subdir="MRIOperators")
, PackageSpec(path=pwd(), subdir="MRICoilSensitivities")])
- run: |
julia --project=docs -e '
using Pkg
Expand Down
2 changes: 1 addition & 1 deletion MRIBase/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MRIBase"
uuid = "f7771a9a-6e57-4e71-863b-6e4b6a2f17df"
author = ["Tobias Knopp <tobias@knoppweb.de>"]
version = "0.4.3"
version = "0.4.4"

[deps]
AbstractNFFTs = "7f219486-4aa7-41d6-80a7-e08ef20ceed7"
Expand Down
2 changes: 1 addition & 1 deletion MRIBase/src/Trajectories/3D/Cartesian3D.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function CartesianTrajectory3D(::Type{T}, numProfiles, numSamplingPerProfile
, kargs...) where T
nodes = cartesian3dNodes(T, numProfiles, numSamplingPerProfile; numSlices=numSlices)
times = readoutTimes(T, numProfiles, numSamplingPerProfile, numSlices; TE=TE, AQ=AQ)
return Trajectory("Cartesian3D", nodes, times, TE, AQ, numProfiles, numSamplingPerProfile, numSlices, true, false)
return Trajectory("Cartesian3D", nodes, times, T(TE), T(AQ), numProfiles, numSamplingPerProfile, numSlices, true, false)
end

function cartesian3dNodes(::Type{T}, numProfiles, numSamplingPerProfile
Expand Down
19 changes: 12 additions & 7 deletions MRIOperators/Project.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name = "MRIOperators"
uuid = "fb1137e3-90a6-46ce-a672-6e1e53d120f2"
author = ["Tobias Knopp <tobias@knoppweb.de>"]
version = "0.2.1"
version = "0.3.0"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
MRIBase = "f7771a9a-6e57-4e71-863b-6e4b6a2f17df"
Expand All @@ -17,15 +18,20 @@ LinearOperators = "5c8ed15e-5a4c-59e4-a42b-c7e8811fb125"
LinearOperatorCollection = "a4a2c56f-fead-462a-a3ab-85921a5f2575"
Wavelets = "29a6e085-ba6d-5f35-a997-948ac2efa89a"

[weakdeps]
GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7"

[compat]
Adapt = "3, 4"
StatsBase = "0.33, 0.34"
Distributions = "0.25"
GPUArrays = "8, 9, 10"
JLArrays = "0.1"
julia = "1.6"
MRIBase = "0.4"
Reexport = "1"
LinearOperators = "2.3.3"
LinearOperatorCollection = "1.1"
LinearOperatorCollection = "2"
NFFT = "0.13"
FLoops = "0.2"
LowRankApprox = "0.5"
Expand All @@ -34,11 +40,10 @@ Wavelets = "0.9, 0.10"
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
MRISimulation = "8988da37-ea20-4fa6-9af7-8a6f6f9a8970"
JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb"

[targets]
test = ["Test", "MRISimulation"]




test = ["Test", "MRISimulation", "JLArrays"]

[extensions]
MRIOperatorsGPUArraysExt = "GPUArrays"
110 changes: 110 additions & 0 deletions MRIOperators/ext/MRIOperatorsGPUArraysExt/ExplicitOp.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
function MRIOperators.produ!(out::vecTc, x::vecTc, shape::NTuple{2,Int64},
nodes::matT, times::vecT, echoOffset::T,
disturbanceTerm::matTc) where {T, Tc <: Union{T, Complex{T}}, vecTc <: AbstractGPUArray{Tc}, matT <: AbstractGPUArray{T}, vecT <: AbstractGPUArray{T}, matTc <: AbstractGPUArray{Tc}}

factor = Tc(-2 * 1im * pi)
limit = prod(shape)
fill!(out, zero(Tc))
gpu_call(out, reshape(x, shape), shape, nodes, times, echoOffset, disturbanceTerm; elements = size(nodes, 2)) do ctx, out_, x_, shape_, nodes_, times_, echoOffset_, disturbanceTerm_
k = linear_index(ctx)
if !(1 <= k <= limit)
return nothing
end

for nx = 1:shape_[1]
for ny = 1:shape_[2]
phi = (nodes_[1, k] * (nx - shape_[1] / 2 - 1) + nodes_[2, k] * (ny - shape_[2] / 2 - 1))
e = exp(factor * phi - (times_[k] - echoOffset_) * disturbanceTerm_[nx, ny])
out_[k] += x_[nx, ny] * e
end
end
return nothing
end

return out
end

function MRIOperators.produ!(out::vecTc, x::vecTc, shape::NTuple{3,Int64},
nodes::matT, times::vecT, echoOffset::T,
disturbanceTerm::arrTc) where {T, Tc <: Union{T, Complex{T}}, vecTc <: AbstractGPUArray{Tc}, matT <: AbstractGPUArray{T}, vecT <: AbstractGPUArray{T}, arrTc <: AbstractGPUArray{Tc, 3}}

factor = Tc(-2 * 1im * pi)
limit = prod(shape)
fill!(out, zero(Tc))
gpu_call(out, reshape(x, shape), shape, nodes, times, echoOffset, disturbanceTerm; elements = size(nodes, 2)) do ctx, out_, x_, shape_, nodes_, times_, echoOffset_, disturbanceTerm_
k = linear_index(ctx)
if !(1 <= k <= limit)
return nothing
end

for nx = 1:shape_[1]
for ny = 1:shape_[2]
for nz = 1:shape_[3]
phi = (nodes_[1, k] * (nx - shape_[1] / 2 - 1) + nodes_[2, k] * (ny - shape_[2] / 2 - 1) + nodes_[3, k] * (nz - shape_[3] / 2 - 1))
e = exp(factor * phi - (times_[k] - echoOffset_) * disturbanceTerm_[nx, ny, nz])
out_[k] += x_[nx, ny, nz] * e
end
end
end
return nothing
end

return out
end

function MRIOperators.ctprodu!(out::vecTc, x::vecTc, shape::NTuple{2,Int64},
nodes::matT, times::vecT, echoOffset::T,
disturbanceTerm::matTc) where {T, Tc <: Union{T, Complex{T}}, vecTc <: AbstractGPUArray{Tc}, matT <: AbstractGPUArray{T}, vecT <: AbstractGPUArray{T}, matTc <: AbstractGPUArray{Tc}}

factor = Tc(-2 * 1im * pi)
limit = prod(shape)
fill!(out, zero(Tc))
gpu_call(reshape(out, shape), x, shape, nodes, times, echoOffset, disturbanceTerm; elements = limit) do ctx, out_, x_, shape_, nodes_, times_, echoOffset_, disturbanceTerm_
linearIndex = linear_index(ctx)
if !(1 <= linearIndex <= limit)
return nothing
end

cartIndex = CartesianIndices(shape)[linearIndex]

nx = cartIndex[1]
ny = cartIndex[2]
for k = 1:size(nodes_, 2)
phi = (nodes_[1,k]*(nx-shape_[1]/2-1)+nodes_[2,k]*(ny-shape_[2]/2-1))
e = exp(factor * phi - (times_[k]-echoOffset_)*disturbanceTerm_[cartIndex])
out_[cartIndex] += x_[k] * conj(e)
end
return nothing
end

return out
end

function MRIOperators.ctprodu!(out::vecTc, x::vecTc, shape::NTuple{3,Int64},
nodes::matT, times::vecT, echoOffset::T,
disturbanceTerm::arrTc) where {T, Tc <: Union{T, Complex{T}}, vecTc <: AbstractGPUArray{Tc}, matT <: AbstractGPUArray{T}, vecT <: AbstractGPUArray{T}, arrTc <: AbstractGPUArray{Tc, 3}}

factor = Tc(-2 * 1im * pi)
limit = prod(shape)
fill!(out, zero(Tc))
gpu_call(reshape(out, shape), x, shape, nodes, times, echoOffset, disturbanceTerm; elements = limit) do ctx, out_, x_, shape_, nodes_, times_, echoOffset_, disturbanceTerm_
linearIndex = linear_index(ctx)
if !(1 <= linearIndex <= limit)
return nothing
end

cartIndex = CartesianIndices(shape)[linearIndex]

nx = cartIndex[1]
ny = cartIndex[2]
nz = cartIndex[3]
for k = 1:size(nodes_, 2)
phi = (nodes_[1,k]*(nx-shape_[1]/2-1)+nodes_[2,k]*(ny-shape_[2]/2-1)+nodes_[3,k]*(nz-shape_[3]/2-1))
e = exp(factor * phi - (times_[k]-echoOffset_)*disturbanceTerm_[cartIndex])
out_[cartIndex] += x_[k] * conj(e)
end
return nothing
end

return out
end
41 changes: 41 additions & 0 deletions MRIOperators/ext/MRIOperatorsGPUArraysExt/FieldmapNFFTOp.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
function MRIOperators.produ_inner!(K, C::matT, A::matT, shape, d::Vector{vecT}, s::vecT, sp, plan, idx, x_::vecT, p::Vector{arrT}) where {T, vecT <: AbstractGPUVector{T}, matT <: AbstractGPUMatrix{T}, arrT <: AbstractGPUArray{T}}
for κ=1:K
if !isempty(idx[κ])
p[κ][:] .= C[κ,:] .* x_
mul!(d[κ], plan[κ], p[κ])
# Assumption: l is unique per idx[κ]
gpu_call(idx[κ], d[κ], view(A, :, κ), s) do ctx, indices, d_, A_, s_
k = @linearidx(indices)
l = indices[k]
s_[l] += d_[k]*A_[l]
return nothing
end
end
end

return
end


function MRIOperators.ctprodu_inner!(K, C::matT, A::matT, shape, d::Vector{vecT}, y::vecT, sp, plan, idx, x::vecT, p::Vector{arrT}) where {T, vecT <: AbstractGPUVector{T}, matT <: AbstractGPUMatrix{T}, arrT <: AbstractGPUArray{T}}

for κ=1:K
if !isempty(idx[κ])
gpu_call(idx[κ], d[κ], view(A, :, κ), x) do ctx, indices, d_, A_, x_
k = @linearidx(indices)
l = indices[k]
d_[k] = conj(A_[l]) * x_[l]
return nothing
end
mul!(p[κ], adjoint(plan[κ]), d[κ])

gpu_call(p[κ], view(C, κ, :), y) do ctx, p_, C_, y_
k = @linearidx(p_)
y_[k] += conj(C_[k]) * p_[k]
return nothing
end
end
end

return
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module MRIOperatorsGPUArraysExt

using MRIOperators, GPUArrays, MRIOperators.FFTW, MRIOperators.LinearAlgebra

include("ExplicitOp.jl")
include("Shutter.jl")
include("SensitivityOp.jl")
include("FieldmapNFFTOp.jl")

MRIOperators.fftParams(::Type{<:AbstractGPUArray}) = (;)


end # module
Loading
Loading