code: def get_outputs(sym, params, in_shape, in_label):
          
          # remove any input listed in params from sym.list_inputs() and bind them to the input shapes provided
          # by user. Also remove in_label, which is the name of the label symbol that may have been used
          # as the label for loss during training.
          inputs = {n: tuple(s) for n, s in zip([n for n in sym.list_inputs() if n not in params and n != in_label],
                                                in_shape)}
          # Add params and their shape to list of inputs
          inputs.update({n: v.shape for n, v in params.items() if n in sym.list_inputs()})
          # Provide input data as well as input params to infer_shape()
          _, out_shapes, _ = sym.infer_shape(**inputs)
  
          out_names = list()
          for name in sym.list_outputs():
              if name.endswith('_output'):
                  out_names.append(name[:-len('_output')])
              else:
                  logging.info("output '%s' does not end with '_output'", name)
                  out_names.append(name)
  
          assert len(out_shapes) == len(out_names)
          # bind output shapes with output names
          graph_outputs = {n: s for n, s in zip(out_names, out_shapes)}
  
          return graph_outputs
docs: Infer output shapes and return dictionary of output name to shape
  
          :param :class:`~mxnet.symbol.Symbol` sym: symbol to perform infer shape on
          :param dic of (str, nd.NDArray) params:
          :param list of tuple(int, ...) in_shape: list of all input shapes
          :param  in_label: name of label typically used in loss that may be left in graph. This name is
              removed from list of inputs required by symbol
          :return: dictionary of output name to shape
          :rtype: dict of (str, tuple(int, ...))