code: def convolve(
      _input,
      filter_weights,
      filter_bias,
      strides,
      filters,
      in_channels,
      hidden_nonlinearity,
  ):
      """Helper function for performing convolution.
  
      Args:
          _input (tf.Tensor): Input tf.Tensor to the CNN.
          filter_weights (tuple(tf.Tensor)): The weights of the filters.
          filter_bias (tuple(tf.Tensor)): The bias of the filters.
          strides (tuple[int]): The stride of the sliding window. For example,
              (1, 2) means there are two convolutional layers. The stride of the
              filter for first layer is 1 and that of the second layer is 2.
          filters (Tuple[Tuple[int, Tuple[int, int]], ...]): Number and dimension
              of filters. For example, ((3, (3, 5)), (32, (3, 3))) means there
              are two convolutional layers. The filter for the first layer have 3
              channels and its shape is (3 x 5), while the filter for the second
              layer have 32 channels and its shape is (3 x 3).
          in_channels (tuple[int]): The number of input channels.
          hidden_nonlinearity (callable): Activation function for intermediate
              dense layer(s). It should return a tf.Tensor. Set it to
              None to maintain a linear activation.
  
      Return:
          tf.Tensor: The output of the convolution.
  
      """
      batch_size = _input.shape[0]
      in_width = _input.shape[1]
      in_height = _input.shape[2]
  
      for (
          filter_iter,
          in_shape,
          filter_weight,
          _filter_bias,
          stride,
      ) in zip(
          filters, in_channels, filter_weights, filter_bias, strides
      ):
          filter_width = filter_iter[1][1]
          filter_height = filter_iter[1][0]
          out_width = int((in_width - filter_width) / stride) + 1
          out_height = int((in_height - filter_height) / stride) + 1
          flatten_filter_size = filter_width * filter_height * in_shape
          reshape_filter = filter_weight.reshape(
              flatten_filter_size, -1
          )
          image_vector = np.empty(
              (batch_size, out_width, out_height, flatten_filter_size)
          )
          for batch in range(batch_size):
              for w in range(out_width):
                  for h in range(out_height):
                      image_vector[batch][w][
                          h
                      ] = _construct_image_vector(
                          _input,
                          batch,
                          w,
                          h,
                          filter_width,
                          filter_height,
                          in_shape,
                      )
  
          _input = np.dot(image_vector, reshape_filter) + _filter_bias
          _input = hidden_nonlinearity(_input).eval()
  
          in_width = out_width
          in_height = out_height
  
      return _input
  
file_path: garage/tests/helpers.py
imports: import cloudpickle
  import numpy
  import pytest
  from garage import Environment
  from tests.quirks import KNOWN_GYM_RENDER_NOT_IMPLEMENTED
label_desc: Use image node_id 3 for calling a global function with example usage: convolve(_input, filter_weights, filter_bias, strides, filters, in_channels, hidden_nonlinearity) and returns: _input