Parallelization
Version 0.1.15 adds support for parallelization through multi-processing. Currently, the only available backend for parallelization is MPI.jl.
Available functions
Parallelization is only available for certain functions. To check if a function is parallelizable, you can use parallelizable function:
using CounterfactualExplanations.Evaluation: evaluate, benchmark
println(parallelizable(generate_counterfactual))
println(parallelizable(evaluate))
println(parallelizable(predict_label))true
true
falseIn the following, we will generate multiple counterfactuals and evaluate them in parallel:
chosen = rand(findall(predict_label(M, counterfactual_data) .== factual), 1000)
xs = select_factual(counterfactual_data, chosen)Multi-threading
We first instantiate an ThreadParallelizer object:
parallelizer = ThreadsParallelizer()ThreadsParallelizer()To generate counterfactuals in parallel, we use the parallelize function:
ces = @with_parallelizer parallelizer begin
    generate_counterfactual(
        xs,
        target,
        counterfactual_data,
        M,
        generator
    )
endGenerating counterfactuals ...   0%|       |  ETA: 0:01:29 (89.14 ms/it)Generating counterfactuals ... 100%|โโโโโโโ| Time: 0:00:01 ( 1.59 ms/it)
1000-element Vector{AbstractCounterfactualExplanation}:
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 โฎ
 CounterfactualExplanation
Convergence: โ
 after 9 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.To evaluate counterfactuals in parallel, we again use the parallelize function:
@with_parallelizer parallelizer evaluate(ces)Evaluating counterfactuals ...   0%|       |  ETA: 0:07:03 ( 0.42  s/it)Evaluating counterfactuals ... 100%|โโโโโโโ| Time: 0:00:00 ( 0.86 ms/it)
1000-element Vector{Any}:
 Vector[[1.0], Float32[3.2939816], [0.0]]
 Vector[[1.0], Float32[3.019046], [0.0]]
 Vector[[1.0], Float32[3.701171], [0.0]]
 Vector[[1.0], Float32[2.5611918], [0.0]]
 Vector[[1.0], Float32[2.9027307], [0.0]]
 Vector[[1.0], Float32[3.7893882], [0.0]]
 Vector[[1.0], Float32[3.5026522], [0.0]]
 Vector[[1.0], Float32[3.6317568], [0.0]]
 Vector[[1.0], Float32[3.084984], [0.0]]
 Vector[[1.0], Float32[3.2268934], [0.0]]
 Vector[[1.0], Float32[2.834947], [0.0]]
 Vector[[1.0], Float32[3.656587], [0.0]]
 Vector[[1.0], Float32[2.5985842], [0.0]]
 โฎ
 Vector[[1.0], Float32[4.067538], [0.0]]
 Vector[[1.0], Float32[3.02231], [0.0]]
 Vector[[1.0], Float32[2.748292], [0.0]]
 Vector[[1.0], Float32[2.9483426], [0.0]]
 Vector[[1.0], Float32[3.066149], [0.0]]
 Vector[[1.0], Float32[3.6018147], [0.0]]
 Vector[[1.0], Float32[3.0138078], [0.0]]
 Vector[[1.0], Float32[3.5724509], [0.0]]
 Vector[[1.0], Float32[3.117551], [0.0]]
 Vector[[1.0], Float32[2.9670508], [0.0]]
 Vector[[1.0], Float32[3.4107168], [0.0]]
 Vector[[1.0], Float32[3.0252533], [0.0]]Benchmarks can also be run with parallelization by specifying parallelizer argument:
# Models:
bmk = benchmark(counterfactual_data; parallelizer = parallelizer)MPI
To use MPI, you need to have MPI installed on your machine. Running the following code straight from a running Julia session will work if you have MPI installed on your machine, but it will be run on a single process. To execute the code on multiple processes, you need to run it from the command line with mpirun or mpiexec. For example, to run a script on 4 processes, you can run the following command from the command line:
mpiexecjl --project -n 4 julia -e 'include("docs/src/srcipts/mpi.jl")'For more information, see MPI.jl.
We first instantiate an MPIParallelizer object:
import MPI
MPI.Init()
parallelizer = MPIParallelizer(MPI.COMM_WORLD; threaded=true)Precompiling MPIExt
  โ TaijaParallel โ MPIExt
  1 dependency successfully precompiled in 3 seconds. 255 already precompiled.
[ Info: Precompiling MPIExt [48137b38-b316-530b-be8a-261f41e68c23]
โ Warning: Module TaijaParallel with build ID ffffffff-ffff-ffff-0001-2d458926c256 is missing from the cache.
โ This may mean TaijaParallel [bf1c2c22-5e42-4e78-8b6b-92e6c673eeb0] does not support precompilation but is imported by a module that does.
โ @ Base loading.jl:1948
[ Info: Skipping precompilation since __precompile__(false). Importing MPIExt [48137b38-b316-530b-be8a-261f41e68c23].
[ Info: Using `MPI.jl` for multi-processing.
Running on 1 processes.
MPIExt.MPIParallelizer(MPI.Comm(1140850688), 0, 1, nothing, true)To generate counterfactuals in parallel, we use the parallelize function:
ces = @with_parallelizer parallelizer begin
    generate_counterfactual(
        xs,
        target,
        counterfactual_data,
        M,
        generator
    )
endGenerating counterfactuals ...   9%|โ      |  ETA: 0:00:01 ( 1.15 ms/it)Generating counterfactuals ...  19%|โโ     |  ETA: 0:00:01 ( 1.07 ms/it)Generating counterfactuals ...  29%|โโ     |  ETA: 0:00:01 ( 1.10 ms/it)Generating counterfactuals ...  39%|โโโ    |  ETA: 0:00:01 ( 1.08 ms/it)Generating counterfactuals ...  49%|โโโโ   |  ETA: 0:00:01 ( 1.08 ms/it)Generating counterfactuals ...  59%|โโโโโ  |  ETA: 0:00:00 ( 1.08 ms/it)Generating counterfactuals ...  69%|โโโโโ  |  ETA: 0:00:00 ( 1.08 ms/it)Generating counterfactuals ...  79%|โโโโโโ |  ETA: 0:00:00 ( 1.07 ms/it)Generating counterfactuals ...  89%|โโโโโโโ|  ETA: 0:00:00 ( 1.07 ms/it)Generating counterfactuals ...  99%|โโโโโโโ|  ETA: 0:00:00 ( 1.06 ms/it)Generating counterfactuals ... 100%|โโโโโโโ| Time: 0:00:01 ( 1.06 ms/it)
1000-element Vector{AbstractCounterfactualExplanation}:
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 โฎ
 CounterfactualExplanation
Convergence: โ
 after 9 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 6 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 8 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.
 CounterfactualExplanation
Convergence: โ
 after 7 steps.To evaluate counterfactuals in parallel, we again use the parallelize function:
@with_parallelizer parallelizer evaluate(ces)1000-element Vector{Any}:
 Vector[[1.0], Float32[3.0941274], [0.0]]
 Vector[[1.0], Float32[3.0894346], [0.0]]
 Vector[[1.0], Float32[3.5737448], [0.0]]
 Vector[[1.0], Float32[2.6201036], [0.0]]
 Vector[[1.0], Float32[2.8519764], [0.0]]
 Vector[[1.0], Float32[3.7762523], [0.0]]
 Vector[[1.0], Float32[3.4162796], [0.0]]
 Vector[[1.0], Float32[3.6095932], [0.0]]
 Vector[[1.0], Float32[3.1347957], [0.0]]
 Vector[[1.0], Float32[3.0313473], [0.0]]
 Vector[[1.0], Float32[2.7612567], [0.0]]
 Vector[[1.0], Float32[3.6191392], [0.0]]
 Vector[[1.0], Float32[2.610616], [0.0]]
 โฎ
 Vector[[1.0], Float32[4.0844703], [0.0]]
 Vector[[1.0], Float32[3.0119], [0.0]]
 Vector[[1.0], Float32[2.4461186], [0.0]]
 Vector[[1.0], Float32[3.071967], [0.0]]
 Vector[[1.0], Float32[3.132917], [0.0]]
 Vector[[1.0], Float32[3.5403214], [0.0]]
 Vector[[1.0], Float32[3.0588162], [0.0]]
 Vector[[1.0], Float32[3.5600657], [0.0]]
 Vector[[1.0], Float32[3.2205954], [0.0]]
 Vector[[1.0], Float32[2.896302], [0.0]]
 Vector[[1.0], Float32[3.2603998], [0.0]]
 Vector[[1.0], Float32[3.1369917], [0.0]]Note that parallelizable processes can be supplied as input to the macro either as a block or directly as an expression.
Benchmarks can also be run with parallelization by specifying parallelizer argument:
# Models:
bmk = benchmark(counterfactual_data; parallelizer = parallelizer)The following code snippet shows a complete example script that uses MPI for running a benchmark in parallel:
using CounterfactualExplanations
using CounterfactualExplanations.Evaluation: benchmark
using CounterfactualExplanations.Models
import MPI
MPI.Init()
data = TaijaData.load_linearly_separable()
counterfactual_data = DataPreprocessing.CounterfactualData(data...)
M = fit_model(counterfactual_data, :Linear)
factual = 1
target = 2
chosen = rand(findall(predict_label(M, counterfactual_data) .== factual), 100)
xs = select_factual(counterfactual_data, chosen)
generator = GenericGenerator()
parallelizer = MPIParallelizer(MPI.COMM_WORLD)
bmk = benchmark(counterfactual_data; parallelizer=parallelizer)
MPI.Finalize()The file can be executed from the command line as follows:
mpiexecjl --project -n 4 julia -e 'include("docs/src/srcipts/mpi.jl")'