runKernelFunc(kernelParams) {
        let outputs;
        let saved = [];
        const isTapeOn = this.isTapeOn();
        const startingBytecount = this.state.numBytes;
        const startingNumTensors = this.state.numTensors;
        if (this.shouldCheckForMemLeaks()) this.state.numDataMovesStack.push(0);
        let kernelFunc;
        if (this.backendName == null) // backend has not been initialized yet (backend initialization is lazy
        // can be deferred until an op/ kernel is run).
        // The below getter has side effects that will try to initialize the
        // backend and set properties like this.backendName
        // tslint:disable-next-line: no-unused-expression
        this.backend;
        let out;
        const kernelOrScopeName = isRegisteredKernelInvocation(kernelParams) ? kernelParams.kernelName : this.state.activeScope != null ? this.state.activeScope.name : "";
        // Create the kernelFunc from either a registered kernel OR passed in
        // forward/backward functions (used by custom grad). In this context a
        // kernelFunc wraps a kernel implementation with some bookkeeping.
        if (isRegisteredKernelInvocation(kernelParams)) {
            const { kernelName, inputs, attrs } = kernelParams;
            if (this.backendName == null) // backend has not been initialized yet (backend initialization is lazy
            // can be deferred until an op/ kernel is run).
            // The below getter has side effects that will try to initialize the
            // backend and set properties like this.backendName
            // tslint:disable-next-line: no-unused-expression
            this.backend;
            const kernel = (0, _kernelRegistry.getKernel)(kernelName, this.backendName);
            _util.assert(kernel != null, ()=>`Cannot find registered kernel '${kernelName}' for backend '${this.backendName}'`);
            kernelFunc = ()=>{
                const numDataIdsBefore = this.backend.numDataIds();
                out = kernel.kernelFunc({
                    inputs,
                    attrs,
                    backend: this.backend
                });
                const outInfos = Array.isArray(out) ? out : [
                    out
                ];
                if (this.shouldCheckForMemLeaks()) this.checkKernelForMemLeak(kernelName, numDataIdsBefore, outInfos);
                const outTensors = outInfos.map((outInfo)=>{
                    // todo (yassogba) remove this option (Tensor) when node backend
                    // methods have been modularized and they all return tensorInfo.
                    // TensorInfos do not have a rank attribute.
                    if (outInfo.rank != null) return outInfo;
                    return this.makeTensorFromTensorInfo(outInfo);
                });
                // Save any required inputs and outputs.
                // Do not save unless we are recording to the tape. Otherwise it would
                // cause a mem leak since there would be no backprop for these tensors
                // (which would otherwise dispose them).
                if (isTapeOn) {
                    const tensorsToSave = this.getTensorsForGradient(kernelName, inputs, outTensors);
                    saved = this.saveTensorsForBackwardMode(tensorsToSave);
                }
                return outTensors;
            };
        } else {
            const { forwardFunc } = kernelParams;
            // Running a customGrad op.
            const saveFunc = (tensors)=>{
                // Do not save unless we are recording to the tape. Otherwise it would
                // cause a mem leak since we would never run backprop, which disposes
                // the kept tensors.
                if (!isTapeOn) return;
                saved = tensors.map((tensor)=>this.keep(this.clone(tensor)));
            };
            kernelFunc = ()=>{
                const numDataIdsBefore = this.backend.numDataIds();
                out = this.tidy(()=>forwardFunc(this.backend, saveFunc));
                const outs = Array.isArray(out) ? out : [
                    out
                ];
                if (this.shouldCheckForMemLeaks()) // Scope name is used to print a more helpful error message if needed.
                this.checkKernelForMemLeak(kernelOrScopeName, numDataIdsBefore, outs);
                return outs;
            };
        }
        //
        // Run the kernelFunc. Optionally profiling it.
        //
        const { inputs, attrs } = kernelParams;
        const backwardsFunc = isRegisteredKernelInvocation(kernelParams) ? null : kernelParams.backwardsFunc;
        let kernelProfile;
        this.scopedRun(// Stop recording to a tape when running a kernel.
        ()=>this.state.kernelDepth++, ()=>this.state.kernelDepth--, ()=>{
            if (!this.ENV.getBool("DEBUG") && !this.state.profiling) outputs = kernelFunc();
            else {
                kernelProfile = this.profiler.profileKernel(kernelOrScopeName, inputs, ()=>kernelFunc());
                if (this.ENV.getBool("DEBUG")) this.profiler.logKernelProfile(kernelProfile);
                outputs = kernelProfile.outputs;
            }
        });
        if (isTapeOn) this.addTapeNode(kernelOrScopeName, inputs, outputs, backwardsFunc, saved, attrs);
        if (this.state.profiling) this.state.activeProfile.kernels.push({
            name: kernelOrScopeName,
            bytesAdded: this.state.numBytes - startingBytecount,
            totalBytesSnapshot: this.state.numBytes,
            tensorsAdded: this.state.numTensors - startingNumTensors,
            totalTensorsSnapshot: this.state.numTensors,
            inputShapes: Object.keys(inputs).map((key)=>inputs[key] != null ? inputs[key].shape : null),
            outputShapes: outputs.map((item)=>item.shape),
            kernelTimeMs: kernelProfile.timeMs,
            extraInfo: kernelProfile.extraInfo
        });
        return Array.isArray(out) ? outputs : outputs[0];
    }
Internal helper method to execute a kernel Func

Use `runKernel` to execute kernels from outside of engine.