class_docstr: A model containing a CNN with N Conv2D layers.
  
  All layers share the same activation function, bias setup (use bias or not),
  and LayerNorm setup (use layer normalization or not).
  
  Note that there is no flattening nor an additional dense layer at the end of the
  stack. The output of the network is a 3D tensor of dimensions
  [width x height x num output filters].
class_docstr_tok: ["A","model","containing","a","CNN","with","N","Conv2D","layers",".","All","layers","share","the","same","activation","function",",","bias","setup","(","use","bias","or","not",")",",","and","LayerNorm","setup","(","use","layer","normalization","or","not",")",".","Note","that","there","is","no","flattening","nor","an","additional","dense","layer","at","the","end","of","the","stack",".","The","output","of","the","network","is","a","3D","tensor","of","dimensions","[","width","x","height","x","num","output","filters","]","."]
code: def forward(self, inputs):
      # Permute b/c data comes in as channels_last ([B, dim, dim, channels]) ->
      # Convert to `channels_first` for torch:
      inputs = inputs.permute(0, 3, 1, 2)
      out = self.cnn(inputs.type(self.expected_input_dtype))
      # Permute back to `channels_last`.
      return out.permute(0, 2, 3, 1)
  
file_path: ray/rllib/core/models/torch/primitives.py
imports: from typing import Callable, Dict, List, Optional, Union, Tuple
  from ray.rllib.core.models.torch.utils import Stride2D
  from ray.rllib.models.torch.misc import same_padding, same_padding_transpose_after_stride, valid_padding
  from ray.rllib.models.utils import get_activation_fn, get_initializer_fn
  from ray.rllib.utils.framework import try_import_torch
label_desc: Use image node_id 2 for calling the TorchCNN obj's underlying member method code with example usage: obj.forward(inputs) and returns: out