bartorch.nlop.GaussNewton#
- class bartorch.nlop.GaussNewton(image_shape, pattern=None, trajectory=None, *, iterations=1, redu=2.0, alpha_min=0.0, batch=1, cg_maxiter=30, cg_tol=0.0, cg_lambda=0.0, kspace_shape=None, coil_shape=None, weights=None, basis=None, mask=None, sobolev=(220.0, 32.0), c=1.0, real=False, sos=False, toeplitz=True)#
One or more Gauss-Newton steps of
nlinv, as an operator that differentiates.Takes
(y, xn, x0, alpha)and returns the iterate:yThe data as the step takes it – coil images, which
prepare()makes from k-space and a sampling pattern.xnThe iterate: the image and the coil coefficients in one flat vector.
start()makes the one BART starts from, anddecompose()reads one back.x0The centre the step regularises towards, which
nlinvleaves at the starting point.alphaThe Tikhonov weight. A number is taken as one; with
iterationsabove one it is the initial weight, divided byreduafter each step and never taken belowalpha_min, which is whatIRGNMdoes.
Every one of those carries a gradient, which is what makes this an unrolled network’s cell rather than a solver’s inside. A denoiser between two of these – or a term in the regularisation centre – is NLINV-Net.
- Parameters:
image_shape (tuple of int) – Coil-image shape,
(coils, *spatial), as the linear encodings take it.pattern (tensor, optional) – Only to give the shape BART should expect; the pattern itself is an argument of
prepare(), because a network is handed one per call. Ones over the image by default.trajectory (tensor, optional) – Off the grid. Its shape is what is kept, for the same reason.
iterations (int) – Steps. One is a step; more is that many, with the weight decaying, wrapped in BART’s own gradient checkpointing.
redu (float) – What the weight is divided by after each step.
alpha_min (float) – What the weight decays towards.
batch (int) – Independent copies of the model, stacked on BART’s batch axis. This is the leading axis of every argument.
cg_maxiter (int, float, float) – The conjugate gradients inside each step:
iter_conjgrad_conf’smaxiter,tolandl2lambda.cg_tol (int, float, float) – The conjugate gradients inside each step:
iter_conjgrad_conf’smaxiter,tolandl2lambda.cg_lambda (int, float, float) – The conjugate gradients inside each step:
iter_conjgrad_conf’smaxiter,tolandl2lambda.weights (tensor, optional) – As
NonlinearSensetakes them. These are held by the model.basis (tensor, optional) – As
NonlinearSensetakes them. These are held by the model.mask (tensor, optional) – As
NonlinearSensetakes them. These are held by the model.sobolev (tuple of float) –
(a, b)of the coil weighting(1 + a |k|^2)^(-b/2).real (bool) – Constrain the image to be real (
nlinv -R).sos (bool) – Normalise the coils by their root sum of squares.
toeplitz (bool) – Off the grid, use a point-spread convolution for the normal operator.
Notes
The step is the library’s, and so is what it costs. Each one runs a conjugate-gradient solve whose backward pass is another, by
norm_inv’s implicit differentiation rather than by unrolling –norm_inv_der_srcandnorm_inv_adj_srcinnlops/norm_inv.c. So the memory of a K-step unroll is K cells and not K times the inner iterations, and BART’snlop_checkpoint_create_Ftakes it down further.The coil weighting is worth knowing about before reading a gradient. BART weights the coil half of the state by
(1 + a |k|^2)^(-b/2), and its defaultb = 32is a sixteenth power: over the state of a small fit the gradient of that half spans tens of decades and its tail runs below float32’s smallest normal number. Below that edge the arithmetic is the platform’s business rather than the library’s – a right-hand side whose norm is no longer a normal number is one BART’scheckepsdeclines to iterate on, and the solve comes back untouched, withWarning: data corruptedin the log and a gradient of zeros. Forward, none of this matters and the default is whatnlinvreconstructs with; a gradient that has to be meaningful in the coil coefficients wants a gentler weighting, which is whatsobolev=(220.0, 8.0)is.- __init__(image_shape, pattern=None, trajectory=None, *, iterations=1, redu=2.0, alpha_min=0.0, batch=1, cg_maxiter=30, cg_tol=0.0, cg_lambda=0.0, kspace_shape=None, coil_shape=None, weights=None, basis=None, mask=None, sobolev=(220.0, 32.0), c=1.0, real=False, sos=False, toeplitz=True)#
Methods
__init__(image_shape[, pattern, trajectory, ...])adjoint(dy)DF(x)^H dyat the last evaluated point, for one input and one output.chain(other, *[, output, input])Output
outputofselfinto inputinputofother.combine(other)selfandotherside by side, sharing nothing.decompose()x->(image, sensitivities), through the model's transforms.del_out([output])Drop an output, and everything computed only for it.
derivative(dx)DF(x) dxat the last evaluated point, for one input and one output.dup([a, b])Make two inputs of the same shape one input, kept at
a.flatten([inputs_only])Every input as one flat vector, and every output as another.
forward(*xs)(y, xn, x0, alpha)-> the iterate.jacobian([output, input])DF/dx_inputof one output, as aLinearOperator.join()(image, coefficients)->x:split()the other way.linearize(*xs)The derivative at
x, as aLinearOperator.link([output, input])Tie an output back into an input; both arguments go away.
permute_inputs(perm)Reorder the inputs: the new input
iis the oldperm[i].permute_outputs(perm)Reorder the outputs: the new output
ois the oldperm[o].pin(input, value)Fix one input to
value; the input goes away.prepare()(kspace, pattern)-> the data a step takes.reshape_input(input, shape)This operator with one input's shape written differently.
reshape_output(output, shape)This operator with one output's shape written differently.
shift_input(new, old)Move one input to another position, the rest closing up behind it.
shift_output(new, old)Move one output to another position, the rest closing up behind it.
split()x->(image, coefficients), with no transform applied.stack_inputs(a, b, axis)Make two inputs one, concatenated along a C-order
axis.stack_outputs(a, b, axis)Make two outputs one, concatenated along a C-order
axis.start([batch, device])The iterate
nlinvstarts from: an image of ones, and no coils.weight(alpha[, device])alphaas the operator takes it.Attributes
data_shapecoil images, batch first.
deviceishapeThe domain, for an operator with one input.
ishapesThe shape of each argument, outputs and inputs kept apart.
oshapeThe codomain, for an operator with one output.
oshapesoutput_shapesThe same for what comes back.
shapesWhat each argument is, without the axes BART leaves empty.
state_shapethe image and the coil coefficients laid end to end, batch first.