def get_cnn_grads(cur_img, regions, net, target_layer, step_type='amplify_layer', **kwargs):
  """
  Inputs:
  - cur_img: 3 x H x W
  - regions: Array of (y0, y1, x0, x1); must all have same shape as input to CNN
  - target_layer: String
  
  Returns:
  - grads: N x 3 x h x w array where grads[i] is the image gradient for regions[i] of cur_img
  """
  cur_batch = np.zeros_like(net.blobs['data'].data)
  batch_size = cur_batch.shape[0]
  next_idx = 0
  
  def run_cnn(data):
    net.forward(data=data)
    if step_type == 'amplify_layer':
      l1_weight = kwargs.get('L1_weight', 1.0)
      l2_weight = kwargs.get('L2_weight', 1.0)
      grad_clip = kwargs.get('grad_clip', 5)
      target_data = net.blobs[target_layer].data.copy()
      target_diff = -l1_weight * np.abs(target_data)
      target_diff -= l2_weight * np.clip(target_data, -grad_clip, grad_clip)
      net.blobs[target_layer].diff[...] = target_diff
    elif step_type == 'amplify_neuron':
      if 'target_neuron' not in kwargs:
        raise ValueError('Must specify target_neuron for step_type=amplify_neuron')
      target_idx = kwargs['target_neuron']
      net.blobs[target_layer].diff[...] = 0.0
      net.blobs[target_layer].diff[:, target_idx] = -1.0
    else:
      raise ValueError('Unrecognized step_type "%s"' % step_type)
    net.backward(start=target_layer)
    return net.blobs['data'].diff.copy()
  
  grads = []
  for region in regions:
    y0, y1, x0, x1 = region
    cur_batch[next_idx] = cur_img[0, :, y0:y1, x0:x1]
    next_idx += 1
    if next_idx == batch_size:
      grads.append(run_cnn(cur_batch))
      next_idx = 0
  if next_idx > 0:
    grad = run_cnn(cur_batch)
    grads.append(grad[:next_idx])
  
  vgrads = np.vstack(grads)
  return vgrads

  Inputs:
  - cur_img: 3 x H x W
  - regions: Array of (y0, y1, x0, x1); must all have same shape as input to CNN
  - target_layer: String
  
  Returns:
  - grads: N x 3 x h x w array where grads[i] is the image gradient for regions[i] of cur_img
  
cnn_vis.py