@nocollapse
(
cls: serialization.SerializableConstructor<T>,
config: serialization.ConfigDict,
customObjects = {} as serialization.ConfigDict,
fastWeightInit = false)
| 1195 | */ |
| 1196 | /** @nocollapse */ |
| 1197 | static override fromConfig<T extends serialization.Serializable>( |
| 1198 | cls: serialization.SerializableConstructor<T>, |
| 1199 | config: serialization.ConfigDict, |
| 1200 | customObjects = {} as serialization.ConfigDict, |
| 1201 | fastWeightInit = false): T { |
| 1202 | // Layer instances created during |
| 1203 | // the graph reconstruction process |
| 1204 | const createdLayers: {[layerName: string]: Layer} = {}; |
| 1205 | |
| 1206 | // Dictionary mapping layer instances to |
| 1207 | // node data that specifies a layer call. |
| 1208 | // It acts as a queue that maintains any unprocessed |
| 1209 | // layer call until it becomes possible to process it |
| 1210 | // (i.e. until the input tensors to the call all exist). |
| 1211 | const unprocessedNodes: {[layer: string]: TensorKeyWithArgsArray[][]} = {}; |
| 1212 | function addUnprocessedNode( |
| 1213 | layer: Layer, nodeData: TensorKeyWithArgsArray[]) { |
| 1214 | if (!(layer.name in unprocessedNodes)) { |
| 1215 | unprocessedNodes[layer.name] = [nodeData]; |
| 1216 | } else { |
| 1217 | unprocessedNodes[layer.name].push(nodeData); |
| 1218 | } |
| 1219 | } |
| 1220 | |
| 1221 | function processNode(layer: Layer, nodeData: TensorKeyWithArgsArray[]) { |
| 1222 | const inputTensors: SymbolicTensor[] = []; |
| 1223 | let kwargs; |
| 1224 | for (const inputData of nodeData) { |
| 1225 | const inboundLayerName = inputData[0]; |
| 1226 | const inboundNodeIndex = inputData[1]; |
| 1227 | const inboundTensorIndex = inputData[2]; |
| 1228 | |
| 1229 | kwargs = inputData[3] == null ? |
| 1230 | {} : |
| 1231 | inputData[3] as serialization.ConfigDict; |
| 1232 | if (!(inboundLayerName in createdLayers)) { |
| 1233 | addUnprocessedNode(layer, nodeData); |
| 1234 | return; |
| 1235 | } |
| 1236 | const inboundLayer = createdLayers[inboundLayerName]; |
| 1237 | if (inboundLayer.inboundNodes.length <= inboundNodeIndex) { |
| 1238 | addUnprocessedNode(layer, nodeData); |
| 1239 | return; |
| 1240 | } |
| 1241 | const inboundNode = inboundLayer.inboundNodes[inboundNodeIndex]; |
| 1242 | inputTensors.push(inboundNode.outputTensors[inboundTensorIndex]); |
| 1243 | } |
| 1244 | // Call layer on its inputs, thus creating the node |
| 1245 | // and building the layer if needed. |
| 1246 | // Note: This has Eager vs Graph Implications. |
| 1247 | if (inputTensors.length > 0) { |
| 1248 | layer.apply( |
| 1249 | generic_utils.singletonOrArray(inputTensors), |
| 1250 | kwargs); // was ** kwargs |
| 1251 | } |
| 1252 | } |
| 1253 | |
| 1254 | /** |
nothing calls this directly
no test coverage detected
searching dependent graphs…