【问题标题】:Writing phenaki video to file: Expected numpy array with ndim `3` but got `4`将 phenaki 视频写入文件:预期带有 ndim `3` 的 numpy 数组,但得到了 `4`
【发布时间】:2022-11-10 23:54:29
【问题描述】:

我正在尝试将 Phenaki make_video 的输出写入 mp4 文件。我正在使用来自 github https://github.com/lucidrains/phenaki-pytorch/search?q=make_video 的这个 Phenaki 实现

phenaki = Phenaki(
    cvivit = cvivit,
    maskgit = maskgit
)


entire_video, scenes = make_video(phenaki, texts = [
    'blah blah',
], num_frames = (17, 14, 14), prime_lengths = (5, 5))

entire_video.shape # (1, 3, 17 + 14 + 14 = 45, 256, 256)
torchvision.io.write_video(filename= "test.mp4", video_array= entire_video, fps=24)

我得到的错误是

  File "/.../GitHub/phenaki-pytorch/run.py", line 49, in <module>
    torchvision.io.write_video(filename= "test.mp4", video_array= entire_video, fps=24)
  File "/opt/homebrew/lib/python3.10/site-packages/torchvision/io/video.py", line 132, in write_video
    frame = av.VideoFrame.from_ndarray(img, format="rgb24")
  File "av/video/frame.pyx", line 408, in av.video.frame.VideoFrame.from_ndarray
  File "av/utils.pyx", line 72, in av.utils.check_ndarray
ValueError: Expected numpy array with ndim `3` but got `4`

我究竟做错了什么?为什么 av.VideoFrame.from_ndarray 的 numpy 数组预期为 3 维?

【问题讨论】:

    标签: python pytorch torchvision generative pyav


    【解决方案1】:

    根据write_video 文档,video_array 参数格式是“包含单个帧的张量,作为 [T, H, W, C] 格式的 uint8 张量”。

    entire_video 的维度是 (1, 3, 45, 256, 128),所以有 5 个维度而不是 4 个维度。
    异常说 ndim 3 但得到 4(不是 4 和 5),因为在内部循环中检测到尺寸不匹配。

    维度的顺序也是错误的(3 应用颜色通道数,应该是最后一个维度)。
    entire_video 的类型也是错误的 - 类型是 float32 而不是 uint8
    假设entire_video 驻留在GPU 内存中,我们还必须在使用write_video 之前将张量复制到CPU 内存中。


    在使用write_video之前,我们可能会应用以下阶段:

    • 将视频从 GPU 内存复制到 CPU 内存(并删除冗余轴):

       entire_video = entire_video[0].detach().cpu()
      
    • float32 转换为 uint8 应用偏移和缩放。
      以下代码使用全局最小值和最大值(转换不是最佳的 - 用作示例):

       min_val = entire_video.min()
       max_val = entire_video.max()
       entire_video_as_uint8 = ((entire_video - min_val) * 255/(max_val min_val)).to(torch.uint8)
      
    • 将要排序的轴重新排序为 [T, H, W, C]:

      • 第一个轴应用帧索引(当有 45 个视频帧时,形状值为 45)。

      • 第二个轴应用行索引(当每帧有 256 行时,形状值为 256)。

      • 第三轴应用列索引(当每帧有 128 列时,形状值为 128)。

      • 第四轴应用颜色通道(形状值为 3,因为有 3 个颜色通道 - 红色、绿色和蓝色)。

          vid_arr = torch.permute(entire_video_as_uint8, (1, 2, 3, 0))
        

    完整的代码示例:

    import torch
    from phenaki_pytorch import CViViT, MaskGit, Phenaki
    from phenaki_pytorch import make_video
    import torchvision
    
    maskgit = MaskGit(
        num_tokens = 5000,
        max_seq_len = 1024,
        dim = 512,
        dim_context = 768,
        depth = 6,
    )
    
    cvivit = CViViT(
        dim = 512,
        codebook_size = 5000,
        image_size = (256, 128),  # video with rectangular screen allowed
        patch_size = 32,
        temporal_patch_size = 2,
        spatial_depth = 4,
        temporal_depth = 4,
        dim_head = 64,
        heads = 8
    )
    
    phenaki = Phenaki(
        cvivit = cvivit,
        maskgit = maskgit
    ).cuda()
    
    entire_video, scenes = make_video(phenaki, texts = [
        'blah blah'
    ], num_frames=(45, 14, 14), prime_lengths=(5, 5))
    
    print(entire_video.shape)  # (1, 3, 45, 256, 128)
    
    # Copy the video from the GPU memory to CPU memory.
    # Apply entire_video[0] for removing redundant axis.
    entire_video = entire_video[0].detach().cpu()  # https://stackoverflow.com/a/66754525/4926757
    
    # Convert from float32 to uint8, use global minimum and global maximum - this is not the best solution
    min_val = entire_video.min()
    max_val = entire_video.max()
    entire_video_as_uint8 = ((entire_video - min_val) * 255/(max_val-min_val)).to(torch.uint8)
    
    # https://pytorch.org/vision/stable/generated/torchvision.io.write_video.html
    # video_array - (Tensor[T, H, W, C]) – tensor containing the individual frames, as a uint8 tensor in [T, H, W, C] format
    # https://pytorch.org/docs/stable/generated/torch.permute.html
    vid_arr = torch.permute(entire_video_as_uint8, (1, 2, 3, 0))  # Reorder the axes to be ordered as [T, H, W, C]
    
    
    print(vid_arr.shape)  # (45, 3, 256, 128)
    torchvision.io.write_video(filename="test.mp4", video_array=vid_arr, fps=24)
    

    毕竟,创建的视频文件看起来像随机噪音......

    看起来这是make_video 的输出,与帖子主题无关。

    【讨论】:

      猜你喜欢
      • 2019-09-04
      • 2020-05-31
      • 1970-01-01
      • 2019-04-14
      • 2018-09-25
      • 2017-11-18
      • 2020-04-18
      • 2019-06-22
      相关资源
      最近更新 更多