async function writeInternalActivationAndGetOutput(
    model, layerNames, inputImage, numFilters, outputDir) {
  const layerName2FilePaths = {};
  const layerName2ImageDims = {};
  const layerOutputs =
      layerNames.map(layerName => model.getLayer(layerName).output);

  // Construct a model that returns all the desired internal activations,
  // in addition to the final output of the original model.
  const compositeModel = tf.model(
      {inputs: model.input, outputs: layerOutputs.concat(model.outputs[0])});

  // `outputs` is an array of `tf.Tensor`s consisting of the internal-activation
  // values and the final output value.
  const outputs = compositeModel.predict(inputImage);

  for (let i = 0; i < outputs.length - 1; ++i) {
    const layerName = layerNames[i];
    // Split the activation of the convolutional layer by filter.
    const activationTensors =
        tf.split(outputs[i], outputs[i].shape[outputs[i].shape.length - 1], -1);
    const actualNumFilters = numFilters <= activationTensors.length ?
        numFilters :
        activationTensors.length;
    const filePaths = [];
    let imageTensorShape;
    for (let j = 0; j < actualNumFilters; ++j) {
      // Format activation tensors and write them to disk.
      const imageTensor = tf.tidy(
          () => deprocessImage(tf.tile(activationTensors[j], [1, 1, 1, 3])));
      const outputFilePath = path.join(outputDir, `${layerName}_${j + 1}.png`);
      filePaths.push(outputFilePath);
      await utils.writeImageTensorToFile(imageTensor, outputFilePath);
      imageTensorShape = imageTensor.shape;
    }
    layerName2FilePaths[layerName] = filePaths;
    layerName2ImageDims[layerName] = imageTensorShape.slice(1, 3);
    tf.dispose(activationTensors);
  }
  tf.dispose(outputs.slice(0, outputs.length - 1));
  return {
    modelOutput: outputs[outputs.length - 1],
    layerName2FilePaths,
    layerName2ImageDims
  };
}
Write internal activation of conv layers to file; Get model output.

@param {tf.Model} model The model of interest.
@param {string[]} layerNames Names of layers of interest.
@param {tf.Tensor4d} inputImage The input image represented as a 4D tensor
  of shape [1, height, width, 3].
@param {number} numFilters Number of filters to run for each convolutional
  layer. If it exceeds the number of filters of a convolutional layer, it
  will be cut off.
@param {string} outputDir Path to the directory to which the image files
  representing the activation will be saved.
@return modelOutput: final output of the model as a tf.Tensor.
        layerName2FilePaths: an object mapping layer name to the paths to the
          image files saved for the layer's activation.
        layerName2FilePaths: an object mapping layer name to the height
          and width of the layer's filter outputs.