1 /** 2 This package contains the framework for constructing and executing operation graphs. 3 4 $(UL 5 $(LI $(D dopt.core.ops) provides functions for constructing nodes in the operation graph.) 6 $(LI $(D dopt.core.grads) provides functions for computing the derivatives of operations.) 7 $(LI $(D dopt.core.cpu) contains a backend that executes operation graphs using the CPU.) 8 $(LI $(D dopt.core.cuda) contains a backend that executes operation graphs using a CUDA enabled GPU.) 9 ) 10 11 Authors: Henry Gouk 12 */ 13 module dopt.core; 14 15 public 16 { 17 import dopt.core.grads; 18 import dopt.core.ops; 19 import dopt.core.types; 20 } 21 22 alias Evaluator = Buffer[] delegate(Operation[] ops, Buffer[Operation] args); 23 alias Compiler = Plan delegate(Operation[] ops); 24 25 private __gshared Evaluator mDefaultEvaluator; 26 private __gshared Compiler mDefaultCompiler; 27 28 Evaluator defaultEvaluator() 29 { 30 return mDefaultEvaluator; 31 } 32 33 void defaultEvaluator(Evaluator de) 34 { 35 mDefaultEvaluator = de; 36 } 37 38 Compiler defaultCompiler() 39 { 40 return mDefaultCompiler; 41 } 42 43 void defaultCompiler(Compiler de) 44 { 45 mDefaultCompiler = de; 46 } 47 48 shared static this() 49 { 50 import std.functional : toDelegate; 51 52 dopt.core.ops.initialize(); 53 dopt.core.grads.initialize(); 54 } 55 56 /** 57 Evaluates a several nodes from the operation graph. 58 59 Params: 60 ops = The nodes of the operation graph that values should be computed for. 61 args = A set of variable assignments. 62 63 Returns: 64 An array of $(D Buffer) objects, each containing the value of the corresponding element in $(D ops). 65 */ 66 Buffer[] evaluate(Operation[] ops, Buffer[Operation] args = null) 67 { 68 return mDefaultEvaluator(ops, args); 69 } 70 71 /** 72 Evaluates an operation graph with a single root node. 73 74 This overload is here for convenience. Internally, the multi-output version of evaluate is called. 75 76 Params: 77 op = The root node of the operation graph. 78 args = A set of variable assignments. 79 80 Returns: 81 A $(D Buffer) containing the result of the computation. 82 */ 83 Buffer evaluate(Operation op, Buffer[Operation] args = null) 84 { 85 return evaluate([op], args)[0]; 86 } 87 88 /** 89 Compile an Operation graph into a reusable execution plan. 90 91 This can be useful in the case where the function might need to be evaluated multiple times, as it will avoid 92 repeating initialisation and optimisation procedures. 93 94 Params: 95 outputs = The output nodes of the Operation graph. 96 97 Returns: 98 A $(D Plan) that can be executed. 99 */ 100 Plan compile(Operation[] outputs) 101 { 102 return mDefaultCompiler(outputs); 103 } 104 105 class Plan 106 { 107 public 108 { 109 this(Operation[] outputs) 110 { 111 import std.array : array; 112 113 mOutputs = outputs.array(); 114 } 115 116 /** 117 Executes the plan. 118 119 Params: 120 args = A set of variable assignments. 121 */ 122 Buffer[] execute(Buffer[Operation] args = null) 123 { 124 auto rets = new Buffer[mOutputs.length]; 125 126 foreach(i, o; mOutputs) 127 { 128 rets[i] = Buffer(new ubyte[o.outputType.volume * o.outputType.elementType.sizeOf()]); 129 } 130 131 execute(args, rets); 132 133 return rets; 134 } 135 136 /// 137 void execute(Buffer[Operation] args, Buffer[] rets) 138 { 139 executeImpl(args, rets); 140 } 141 } 142 143 protected 144 { 145 Operation[] mOutputs; 146 147 abstract void executeImpl(Buffer[Operation] args, Buffer[] rets); 148 } 149 }