How to save images that have more than 3 channels

username: NishantN
cooked: <p>I am using torch.utils.save_image() to save an image that has 5 channels. The image is formed by concatenating 12 images together across dim 3. The current dimensions of the image are (16, 5, 128, 1536) with 16 being the batch size.</p>
<p>Code:</p>
<pre><code class="lang-auto">r = self.denorm(x_concat.data.cpu())
save_image(r, sample_path, nrow=1, padding=0)
</code></pre>
<p>The code is giving this error:</p>
<pre><code class="lang-auto">Traceback (most recent call last):
  File "main.py", line 137, in &lt;module&gt;
    main(config)
  File "main.py", line 48, in main
    solver.train()
  File "/solver.py", line 366, in train
    save_image(r, sample_path, nrow=1, padding=0)
  File "/torchvision/utils.py", line 129, in save_image
    im = Image.fromarray(ndarr)
  File "/PIL/Image.py", line 2751, in fromarray
    raise TypeError("Cannot handle this data type: %s, %s" % typekey) from e
TypeError: Cannot handle this data type: (1, 1, 5), |u1
</code></pre>
<p>I am assuming the error is due to the channels being 5 since this worked previously for a set of images that had channels = 3.</p>
<p>pytorch version = 1.7.0<br>
python version = 3.7.10</p>

username: ptrblck
cooked: <p>I don’t think a native image format using 5 channels exists, so you would not be able to store this type of data as an image. I don’t know what your data represents, but you could store the tensor directly via <code>torch.save</code>.</p>

username: atom_ant
cooked: <p>I have a similar issue that I will bring up in this older post.</p>
<p>I am using a Unet architecture with hyperspectral data of up to 200 channels. I am using the Unet to reduce the number of bands need for segmentation. Up to 16 class labels are provided and I have used one-hot encoding to train my model.</p>
<p>The resultant tensor from my decoder is of shape [2, 16, 128, 128] where 16 is the one-hot encoding and 128x128 is obviously the image size. I cannot figure out how to save the image itself from a tensor in a grayscale format.</p>
<p>The following are things I have tried to resolve this:</p>
<ol>
<li>
<p>Take the max value along the channel dimension (axis=1) then save the image. Results in a tensor of shape [2, 128, 128] and I get RuntimeError: result type Float can’t be cast to the desired output type __int64</p>
</li>
<li>
<p>To fix the data type and change the tensor size to [2, 1, 128, 128] as I would expect for a grayscale conversion, I tried torch.reshape(decoded_imgs, (2,1,128,128)).type(torch.long) and got the same error as before.</p>
</li>
<li>
<p>Using a different transformation with torchvision.transforms.Grayscale()(decoded_img) I received this: TypeError: Input image tensor permitted channel values are [1, 3], but found 16.</p>
</li>
<li>
<p>Since the Grayscale() function only accepts channels of size 1 or 3, I performed steps 1 and 2 again then 3 and got the same error shown in step 1.</p>
</li>
</ol>
<p>Any guidance is greatly appreciated.</p>

username: alepistola
cooked: <p>If the output of your model is a tensor of shape [2, 16, 128, 128] (batch_size, output_channels, height, width) my question is why you need 16 channels?<br>
Anyway, if the max along the channel dimension <code>original_tensor.max(dim=1, keepdim=True)</code> is what you need, but you get that runtime error, maybe your output is a logits tensor.<br>
You can try to add a sigmoid function and then a discretization one:</p>
<pre><code class="lang-auto">logits = self.forward(image)
prob_img = logits_mask.sigmoid()
pred_img = (prob_img &gt; 0.5).int()
</code></pre>
<p>At this point you should have a binary tensor</p>