* Computes output tensors for new inputs. * * Note: * - Expects `inputs` to be a list (potentially with 1 element). * * @param inputs List of tensors * @param masks List of masks (tensors or null). * @return Three lists: outputTensors, outputMasks, outputShapes
(inputs: Tensor[], masks?: Tensor[])
| 869 | * @return Three lists: outputTensors, outputMasks, outputShapes |
| 870 | */ |
| 871 | protected runInternalGraph(inputs: Tensor[], masks?: Tensor[]): |
| 872 | [Tensor[], Tensor[], Shape[]] { |
| 873 | if (masks == null) { |
| 874 | masks = generic_utils.pyListRepeat(null, inputs.length); |
| 875 | } |
| 876 | |
| 877 | // Dictionary mapping reference tensors to tuples |
| 878 | // (computed tensor, compute mask) |
| 879 | // we assume a 1:1 mapping from tensor to mask |
| 880 | // TODO: raise exception when a `.computeMask()` call |
| 881 | // does not return a list the same size as `call` |
| 882 | const tensorMap: {[tensorID: string]: [Tensor, Tensor]} = {}; |
| 883 | for (let i = 0; i < this.inputs.length; ++i) { |
| 884 | const x = this.inputs[i]; |
| 885 | const y = inputs[i]; |
| 886 | const mask = masks[i]; |
| 887 | tensorMap[x.id] = [y, mask]; |
| 888 | } |
| 889 | |
| 890 | const depthKeys = Object.keys(this.nodesByDepth) |
| 891 | .map(x => parseInt(x, 10)) |
| 892 | .sort(generic_utils.reverseNumberCompare); |
| 893 | for (const depth of depthKeys) { |
| 894 | const nodes = this.nodesByDepth[depth]; |
| 895 | for (const node of nodes) { |
| 896 | // This is always a single layer, never a list. |
| 897 | const layer = node.outboundLayer; |
| 898 | const referenceInputTensors = node.inputTensors; |
| 899 | const referenceOutputTensors = node.outputTensors; |
| 900 | |
| 901 | // If all previous input tensors are available in tensorMap, |
| 902 | // then call node.inboundLayer on them. |
| 903 | // List of tuples [input, mask]: |
| 904 | const computedData = new Array<[Tensor, Tensor]>(); |
| 905 | for (const x of referenceInputTensors) { |
| 906 | if (x.id in tensorMap) { |
| 907 | computedData.push(tensorMap[x.id]); |
| 908 | } |
| 909 | } |
| 910 | if (computedData.length === referenceInputTensors.length) { |
| 911 | // TODO(michaelterry): Add K.name_scope here, if we need it. |
| 912 | let kwargs: Kwargs = {}; |
| 913 | let computedTensors: Tensor[]; |
| 914 | let computedMasks: Tensor[]; |
| 915 | let outputTensors: Tensor[]; |
| 916 | let outputMasks: Tensor[]; |
| 917 | // call layer |
| 918 | if (node.callArgs != null) { |
| 919 | kwargs = node.callArgs; |
| 920 | } |
| 921 | if (computedData.length === 1) { |
| 922 | const [computedTensor, computedMask] = computedData[0]; |
| 923 | if (kwargs['mask'] == null) { |
| 924 | kwargs['mask'] = computedMask; |
| 925 | } |
| 926 | outputTensors = |
| 927 | generic_utils.toList(layer.call(computedTensor, kwargs)); |
| 928 | outputMasks = generic_utils.toList( |
nothing calls this directly
no test coverage detected
searching dependent graphs…