initialize() {
    this.modelLayersMap.forEach(layer => {
      if (layer.layerClass === 'GlobalAveragePooling2D') {
        this.enabled = true
        this.poolLayer = layer
      }
    })

    if (this.enabled && !this.data) {
      // get feature maps from preceding layer
      this.featureMaps = this.modelLayersMap.get(this.poolLayer.inbound[0]).output

      // traverse until we get feature map weights
      // in Inception-V3, for example, this is the kernel weights of the final fully-connected layer
      // in Squeezenet, for example, this is simply the output of the GlobalAveragePooling2D layer
      let traversingLayer = this.poolLayer
      if (!traversingLayer.outbound.length) {
        this.weights = this.poolLayer.output
      }
      while (traversingLayer.outbound.length) {
        traversingLayer = this.modelLayersMap.get(traversingLayer.outbound[0])
        if (traversingLayer.weights['kernel']) {
          this.weights = traversingLayer.weights['kernel']
        } else {
          this.weights = this.poolLayer.output
        }
      }

      if (this.featureMaps.is2DReshaped) {
        this.inputShape = this.featureMaps.originalShape.slice(0, 2)
      } else {
        this.inputShape = this.featureMaps.tensor.shape.slice(0, 2)
      }
      if (this.weights.tensor.shape.length === 1) {
        this.shape = this.inputShape
      } else {
        const numOutputClasses = this.weights.tensor.shape[1]
        this.shape = [...this.inputShape, numOutputClasses]
      }
      this.data = new Float32Array(this.shape.reduce((a, b) => a * b, 1))
    }
  }
Checks whether CAM can be computed directly (requires GlobalAveragePooling2D layer)
Grad-CAM generalizes this to arbitrary architectures, and may be implemented in the future.