def __init__(self, *,
                 input_shape,
                 action_dim,
                 convs,
                 fc_hidden_sizes,
                 dueling,
                 is_uint8=False):
        """
        is_uint8: scale down uint8 image input from Atari by 255.0
        You can use atari_wrapper.ScaledFloatFrame, but dividing on GPU is more
        computationally and memory efficient
        """
        super().__init__()
        if convs:
            assert len(input_shape) == 3
        self.is_uint8 = is_uint8
        shape = input_shape
        in_channel = input_shape[0]
        self.conv_layers = nn.ModuleList()
        for out_channel, kernel_size, stride in convs:
            # MUST pad to make 'SAME' mode (TF default), otherwise learning much worse
            # pytorch defaults to 'VALID' mode, i.e. pad=0
            conv = nn.Conv2d(in_channel,
                             out_channel,
                             kernel_size,
                             stride=stride,
                             padding=kernel_size // 2)
            U.conv_fc_init(conv)
            in_channel = out_channel
            self.conv_layers.append(conv)
            shape = U.infer_shape_conv2d(shape, out_channel,
                                         kernel_size,
                                         stride=stride,
                                         padding=kernel_size // 2)

        if not U.is_valid_shape(shape):
            raise ValueError('Pre-FC shape has invalid size: {}'.format(shape))

        self.init_dueling(action_dim=action_dim,
                          prelinear_size=int(np.prod(shape)),
                          fc_hidden_sizes=fc_hidden_sizes,
                          dueling=dueling)

        is_uint8: scale down uint8 image input from Atari by 255.0
        You can use atari_wrapper.ScaledFloatFrame, but dividing on GPU is more
        computationally and memory efficient
        
surreal/model/q_net.py