title: TensorFlow: How does tf.set_shape change the channel information of grayscale images?
body: <p>If I have a grayscale image that undergoes a preprocessing that has its shape shaped as <code>[None, None, 3]</code>, where does the additional channel information come from? Does the channel information actually replicate? I am referring to the following preprocessing that could turn a grayscale image into an image with 3 channels:</p>
  
  <pre><code>def preprocess_for_train(image, height, width, bbox,
                           fast_mode=True,
                           scope=None):
    """Distort one image for training a network.
  
    Distorting images provides a useful technique for augmenting the data
    set during training in order to make the network invariant to aspects
    of the image that do not effect the label.
  
    Additionally it would create image_summaries to display the different
    transformations applied to the image.
  
    Args:
      image: 3-D Tensor of image. If dtype is tf.float32 then the range should be
        [0, 1], otherwise it would converted to tf.float32 assuming that the range
        is [0, MAX], where MAX is largest positive representable number for
        int(8/16/32) data type (see `tf.image.convert_image_dtype` for details).
      height: integer
      width: integer
      bbox: 3-D float Tensor of bounding boxes arranged [1, num_boxes, coords]
        where each coordinate is [0, 1) and the coordinates are arranged
        as [ymin, xmin, ymax, xmax].
      fast_mode: Optional boolean, if True avoids slower transformations (i.e.
        bi-cubic resizing, random_hue or random_contrast).
      scope: Optional scope for name_scope.
    Returns:
      3-D float Tensor of distorted image used for training with range [-1, 1].
    """
    with tf.name_scope(scope, 'distort_image', [image, height, width, bbox]):
      if bbox is None:
        bbox = tf.constant([0.0, 0.0, 1.0, 1.0],
                           dtype=tf.float32,
                           shape=[1, 1, 4])
      if image.dtype != tf.float32:
        image = tf.image.convert_image_dtype(image, dtype=tf.float32)
      # Each bounding box has shape [1, num_boxes, box coords] and
      # the coordinates are ordered [ymin, xmin, ymax, xmax].
      image_with_box = tf.image.draw_bounding_boxes(tf.expand_dims(image, 0),
                                                    bbox)
      # tf.summary.image('image_with_bounding_boxes', image_with_box)
  
      distorted_image, distorted_bbox = distorted_bounding_box_crop(image, bbox)
      # Restore the shape since the dynamic slice based upon the bbox_size loses
      # the third dimension.
      distorted_image.set_shape([None, None, 3])
      image_with_distorted_box = tf.image.draw_bounding_boxes(
          tf.expand_dims(image, 0), distorted_bbox)
      # tf.summary.image('images_with_distorted_bounding_box',
      #                  image_with_distorted_box)
  
      # This resizing operation may distort the images because the aspect
      # ratio is not respected. We select a resize method in a round robin
      # fashion based on the thread number.
      # Note that ResizeMethod contains 4 enumerated resizing methods.
  
      # We select only 1 case for fast_mode bilinear.
      num_resize_cases = 1 if fast_mode else 4
      distorted_image = apply_with_random_selector(
          distorted_image,
          lambda x, method: tf.image.resize_images(x, [height, width], method=method),
          num_cases=num_resize_cases)
  
      # tf.summary.image('cropped_resized_image',
      #                  tf.expand_dims(distorted_image, 0))
  
      # Randomly flip the image horizontally.
      distorted_image = tf.image.random_flip_left_right(distorted_image)
  
      # # Randomly distort the colors. There are 4 ways to do it. #No need to edit color as there's only graycsale images.
      # distorted_image = apply_with_random_selector(
      #     distorted_image,
      #     lambda x, ordering: distort_color(x, ordering, fast_mode),
      #     num_cases=4)
  
      # tf.summary.image('final_distorted_image',
      #                  tf.expand_dims(distorted_image, 0))
      distorted_image = tf.sub(distorted_image, 0.5)
      distorted_image = tf.mul(distorted_image, 2.0)
      return distorted_image
  </code></pre>
  
  <p>if you look at the code line <code>distorted_image.set_shape([None, None, 3])</code>, this is what that changed my grayscale image into 3 channels. Where does the additional information come from, and if I were to fine-tune a pre-trained model on grayscale images, should I let this happen? Because if the image is 3 channels, I can reuse the variables from the input layer scope for fine-tuning.</p>
  
  <p>Another source of error may come from the <code>Image</code> decoder found in this line of the code: <a href="https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py#L269" rel="nofollow noreferrer">https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py#L269</a></p>
  
  <p>If I set the number of channels to 3, the channels really ended up with 3 channels although there was only 1 channel initially. What happens to the information here?</p>