First, we need to import the main Nipype tools: Node
and Workflow
In [ ]:
from nipype import Node, Workflow
Now, we can import the interfaces that we want to use for the preprocessing.
In [ ]:
from nipype.interfaces.fsl import SliceTimer, MCFLIRT, Smooth
Next, we will put the three interfaces into a node and define the specific input parameters.
In [ ]:
# Initiate a node to correct for slice wise acquisition
slicetimer = Node(SliceTimer(index_dir=False,
interleaved=True,
time_repetition=2.5),
name="slicetimer")
In [ ]:
# Initiate a node to correct for motion
mcflirt = Node(MCFLIRT(mean_vol=True,
save_plots=True),
name="mcflirt")
In [ ]:
# Initiate a node to smooth functional images
smooth = Node(Smooth(fwhm=4), name="smooth")
After creating the nodes, we can now create the preprocessing workflow.
In [ ]:
preproc01 = Workflow(name='preproc01', base_dir='.')
Now, we can put all the nodes into this preprocessing workflow. We specify the data flow / execution flow of the workflow by connecting the corresponding nodes to each other.
In [ ]:
preproc01.connect([(slicetimer, mcflirt, [('slice_time_corrected_file', 'in_file')]),
(mcflirt, smooth, [('out_file', 'in_file')])])
To better understand what we did we can write out the workflow graph and visualize it directly in this notebook.
In [ ]:
preproc01.write_graph(graph2use='orig')
In [ ]:
# Visualize graph
from IPython.display import Image
Image(filename="preproc01/graph_detailed.png")
In [ ]:
slicetimer.inputs.in_file = '/data/ds000114/sub-01/ses-test/func/sub-01_ses-test_task-fingerfootlips_bold.nii.gz'
To show off Nipype's parallelization power, let's run the workflow in parallel, on 5 processors and let's show the execution time:
In [ ]:
%time preproc01.run('MultiProc', plugin_args={'n_procs': 5})
In [ ]:
!tree preproc01 -I '*js|*json|*pklz|_report|*.dot|*html'
Now, for fun. Let's run the workflow again, but let's change the fwhm
value of the Gaussian smoothing kernel to 2
.
In [ ]:
smooth.inputs.fwhm = 2
And let's run the workflow again.
In [ ]:
%time preproc01.run('MultiProc', plugin_args={'n_procs': 5})
Interesting, now it only took ~15s to execute the whole workflow again. What happened?
As you can see from the log above, Nipype didn't execute the two nodes slicetimer
and mclfirt
again. This, because their input values didn't change from the last execution. The preproc01
workflow therefore only had to rerun the node smooth
.
Ok, ok... Rerunning a workflow again is faster. That's nice and all, but I want more. You spoke of parallel execution!
We saw that the preproc01
workflow takes about ~2min to execute completely. So, if we would run the workflow on five functional images, it should take about ~10min total. This, of course, assuming the execution will be done sequentially. Now, let's see how long it takes if we run it in parallel.
In [ ]:
# First, let's copy/clone 'preproc01'
preproc02 = preproc01.clone('preproc02')
preproc03 = preproc01.clone('preproc03')
preproc04 = preproc01.clone('preproc04')
preproc05 = preproc01.clone('preproc05')
We now have five different preprocessing workflows. If we want to run them in parallel, we can put them all in another workflow.
In [ ]:
metaflow = Workflow(name='metaflow', base_dir='.')
In [ ]:
# Now we can add the five preproc workflows to the bigger metaflow
metaflow.add_nodes([preproc01, preproc02, preproc03,
preproc04, preproc05])
Note: We now have a workflow (metaflow
), that contains five other workflows (preproc0?
), each of them containing three nodes.
To better understand this, let's visualize this metaflow
.
In [ ]:
# As before, let's write the graph of the workflow
metaflow.write_graph(graph2use='flat')
In [ ]:
# And visualize the graph
from IPython.display import Image
Image(filename="metaflow/graph_detailed.png")
Ah... so now we can see that the metaflow
has potential for parallelization. So let's put it to test
In [ ]:
%time metaflow.run('MultiProc', plugin_args={'n_procs': 5})
This time we can see that Nipype uses all available processors.
And if all went well, the total execution time should still be around ~2min.
That's why Nipype is so amazing. The days of opening multiple SPMs, FSLs, AFNIs etc. are past!
In [ ]:
!tree metaflow -I '*js|*json|*pklz|_report|*.dot|*html'