<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      PyTorch之對類別張量進行one-hot編碼

      PyTorch之對類別張量進行one-hot編碼

      本文已授權極市平臺, 并首發于極市平臺公眾號. 未經允許不得二次轉載.

      前言

      one-hot 形式的編碼在深度學習任務中非常常見,但是卻并不是一種很自然的數據存儲方式。所以大多數情況下都需要我們自己手動轉換。雖然思路很直接,就是將類別拆分成一一對應的 0-1 向量,但是具體實現起來確實還是需要思考下的。實際上 pytorch 自身在nn.functional中已經提供了one_hot方法來快速應用。但是這并不能影響我們的思考與實踐:>!所以本文盡可能將基于 pytorch 中常用方法來實現one-hot編碼的方式整理了下,希望有用。

      主要的方式有這么幾種:

      • for循環
      • scatter
      • index_select

      for循環

      這種方法非常直觀,說白了就是對一個空白(全零)張量中的指定位置進行賦值(賦 1)操作即可。
      關鍵在于如何設定索引。
      下面設計了兩種本質相同但由于指定維度不同而導致些許差異的方案。

      def bhw_to_onehot_by_for(bhw_tensor: torch.Tensor, num_classes: int):
          """
          Args:
              bhw_tensor: b,h,w
              num_classes:
          Returns: b,h,w,num_classes
          """
          assert bhw_tensor.ndim == 3, bhw_tensor.shape
          assert num_classes > bhw_tensor.max(), torch.unique(bhw_tensor)
          one_hot = bhw_tensor.new_zeros(size=(num_classes, *bhw_tensor.shape))
          for i in range(num_classes):
              one_hot[i, bhw_tensor == i] = 1
          one_hot = one_hot.permute(1, 2, 3, 0)
          return one_hot
      
      
      def bhw_to_onehot_by_for_V1(bhw_tensor: torch.Tensor, num_classes: int):
          """
          Args:
              bhw_tensor: b,h,w
              num_classes:
          Returns: b,h,w,num_classes
          """
          assert bhw_tensor.ndim == 3, bhw_tensor.shape
          assert num_classes > bhw_tensor.max(), torch.unique(bhw_tensor)
          one_hot = bhw_tensor.new_zeros(size=(*bhw_tensor.shape, num_classes))
          for i in range(num_classes):
              one_hot[..., i][bhw_tensor == i] = 1
          return one_hot
      

      scatter

      該方法應該是網上大多數簡潔的one_hot寫法的常用形式了。其實際上主要的作用是向 tensor 中指定的位置上賦值。

      由于其可以使用專門構造的索引矩陣來作為索引,所以更加靈活。當然,靈活帶來的也就是理解上的困難。官方文檔中提供的解釋非常直觀:

      '''
      https://pytorch.org/docs/stable/generated/torch.Tensor.scatter_.html
      
      * (int dim, Tensor index, Tensor src)
       * (int dim, Tensor index, Tensor src, *, str reduce)
       * (int dim, Tensor index, Number value)
       * (int dim, Tensor index, Number value, *, str reduce)
      '''
      
      self[index[i][j][k]][j][k] = src[i][j][k]  # if dim == 0
      self[i][index[i][j][k]][k] = src[i][j][k]  # if dim == 1
      self[i][j][index[i][j][k]] = src[i][j][k]  # if dim == 2
      

      文檔中使用的是原地置換(in-place)版本,并且基于替換值為src,即 tensor 的情況下來解釋。實際上在我們的應用中主要基于原地置換版本并搭配替換值為標量浮點數value的形式。

      上述的形式中,我們可以看到,通過指定參數 tensor index,我們就可以將src(i,j,k)的值放置到方法調用者(這里是self)的指定位置上。該指定位置由index(i,j,k)處的值替換坐標(i,j,k)中的dim位置的值來構成(這里也反映出來了index tensor 的一個要求,就是維度數量要和selfsrc(如果src為 tensor 的話。后文中使用的是具體的標量值 1,即src替換為value)一致)。這倒是和one-hot的概念非常吻合。因為one-hot本身形式上的含義就是對于第i類數據,第i個位置為 1,其余位置為 0。所以對全零 tensor 使用scatter_是可以非常容易的構造出one-hottensor 的,即對對應于類別編號的位置放置 1 即可。

      對于我們的問題而言,index非常適合使用輸入的包含類別編號的 tensor(形狀為B,H,W)來表示。基于這樣的思考,可以構思出兩種不同的策略:

      def bhw_to_onehot_by_scatter(bhw_tensor: torch.Tensor, num_classes: int):
          """
          Args:
              bhw_tensor: b,h,w
              num_classes:
          Returns: b,h,w,num_classes
          """
          assert bhw_tensor.ndim == 3, bhw_tensor.shape
          assert num_classes > bhw_tensor.max(), torch.unique(bhw_tensor)
          one_hot = torch.zeros(size=(math.prod(bhw_tensor.shape), num_classes))
          one_hot.scatter_(dim=1, index=bhw_tensor.reshape(-1, 1), value=1)
          one_hot = one_hot.reshape(*bhw_tensor.shape, num_classes)
          return one_hot
      
      
      def bhw_to_onehot_by_scatter_V1(bhw_tensor: torch.Tensor, num_classes: int):
          """
          Args:
              bhw_tensor: b,h,w
              num_classes:
          Returns: b,h,w,num_classes
          """
          assert bhw_tensor.ndim == 3, bhw_tensor.shape
          assert num_classes > bhw_tensor.max(), torch.unique(bhw_tensor)
          one_hot = torch.zeros(size=(*bhw_tensor.shape, num_classes))
          one_hot.scatter_(dim=-1, index=bhw_tensor[..., None], value=1)
          return one_hot
      

      這兩種形式的差異的根源在于對形狀的處理上。由此帶來了scatter不同的應用形式。

      對于第一種形式,將B,H,W三個維度合并,這樣的好處是對通道(類別)的索引的理解變得直觀起來。

          one_hot = torch.zeros(size=(math.prod(bhw_tensor.shape), num_classes))
          one_hot.scatter_(dim=1, index=bhw_tensor.reshape(-1, 1), value=1)
      

      這里將類別維度和其他維度直接分離,移到了末位。通過dim指定該維度,于是就有了這樣的對應關系:

      zero_tensor[abc, index[abc][d]] = value  # d=0
      

      而在第二種情況下仍然保留了前面的三個維度,類別維度依然移動到最后一位。

          one_hot = torch.zeros(size=(*bhw_tensor.shape, num_classes))
          one_hot.scatter_(dim=-1, index=bhw_tensor[..., None], value=1)
      

      此時的對應關系是這樣的:

      zero_tensor[a,b,c, index[a][b][c][d]] = value # d=0
      

      另外在 pytorch 分類模型庫 timm 中,也使用了類似的方法:

      # https://github.com/rwightman/pytorch-image-models/blob/2c33ca6d8ce5d9257edf8cab5ab7ece81780aaf7/timm/data/mixup.py#L17-L19
      def one_hot(x, num_classes, on_value=1., off_value=0., device='cuda'):
          x = x.long().view(-1, 1)
          return torch.full((x.size()[0], num_classes), off_value, device=device).scatter_(1, x, on_value)
      

      index_select

      torch.index_select(input, dim, index, *, out=None) → Tensor
      
      - input (Tensor) – the input tensor.
      - dim (int) – the dimension in which we index
      - index (IntTensor or LongTensor) – the 1-D tensor containing the indices to index
      

      該函數如其名,就是用索引來選擇 tensor 的指定維度的子 tensor 的。

      想要理解這一方法的動機,實際上需要反過來,從類別標簽的角度看待one-hot編碼。

      對于原始從小到大排布的類別序號對應的one-hot編碼成的矩陣就是一個單位矩陣。所以每個類別對應的就是該單位矩陣的特定的列(或者行)。這一需求恰好符合index_select的功能。所以我們可以使用其實現one_hot編碼,只需要使用類別序號索引特定的列或者行即可。下面就是一個例子:

      def bhw_to_onehot_by_index_select(bhw_tensor: torch.Tensor, num_classes: int):
          """
          Args:
              bhw_tensor: b,h,w
              num_classes:
          Returns: b,h,w,num_classes
          """
          assert bhw_tensor.ndim == 3, bhw_tensor.shape
          assert num_classes > bhw_tensor.max(), torch.unique(bhw_tensor)
          one_hot = torch.eye(num_classes).index_select(dim=0, index=bhw_tensor.reshape(-1))
          one_hot = one_hot.reshape(*bhw_tensor.shape, num_classes)
          return one_hot
      

      性能對比

      整體代碼可見GitHub

      下面展示了不同方法的大致的相對性能(因為后臺在跑程序,可能并不是十分準確,建議大家自行測試)。可以看到,pytorch 自帶的函數在 CPU 上效率并不是很高,但是在 GPU 上表現良好。其中有趣的是,基于index_select的形式表現非常亮眼。

      1.10.0 GeForce RTX 2080 Ti
      
      cpu
      ('bhw_to_onehot_by_for', 0.5411529541015625)
      ('bhw_to_onehot_by_for_V1', 0.4515676498413086)
      ('bhw_to_onehot_by_scatter', 0.0686192512512207)
      ('bhw_to_onehot_by_scatter_V1', 0.08529376983642578)
      ('bhw_to_onehot_by_index_select', 0.05156970024108887)
      ('F.one_hot', 0.07366824150085449)
      
      gpu
      ('bhw_to_onehot_by_for', 0.005235433578491211)
      ('bhw_to_onehot_by_for_V1', 0.045584678649902344)
      ('bhw_to_onehot_by_scatter', 0.0025513172149658203)
      ('bhw_to_onehot_by_scatter_V1', 0.0024869441986083984)
      ('bhw_to_onehot_by_index_select', 0.002012014389038086)
      ('F.one_hot', 0.0024051666259765625)
      
      posted @ 2022-01-16 13:03  lart  閱讀(1069)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日本福利一区二区精品| 性姿势真人免费视频放| 久久精品国产亚洲av麻豆长发| 久久精品蜜芽亚洲国产av| 久久99精品久久久久久9| 无码人妻一区二区三区精品视频 | 亚洲av日韩在线资源| 国产精品久久久国产盗摄| 国产真实精品久久二三区| 亚洲香蕉伊综合在人在线| 精品少妇无码一区二区三批| 好深好湿好硬顶到了好爽| 黑人猛精品一区二区三区| 99久久国产一区二区三区| 无码人妻一区二区三区兔费| 扶风县| 放荡的少妇2欧美版| 国产另类ts人妖一区二区| 久久精品亚洲精品国产色婷| 高清无码爆乳潮喷在线观看| 在线观看人成视频免费| 天海翼激烈高潮到腰振不止| 在线天堂中文新版www| 午夜福利日本一区二区无码| 偷拍一区二区三区在线视频| 亚洲午夜精品国产电影在线观看| 97久久精品人人澡人人爽| 最新国产AV最新国产在钱| 在线看片免费人成视久网| 国产精品午夜福利合集| 欧美黑人粗暴多交高潮水最多| 亚洲av日韩av一区久久| 阿拉善右旗| 精品视频一区二区福利午夜| 亚洲国产精品久久久天堂麻豆宅男 | 综合色天天久久| 在线观看无码av五月花| 国产馆在线精品极品粉嫩| 久久天天躁狠狠躁夜夜2020老熟妇 | 国产资源精品中文字幕| 无码人妻丰满熟妇片毛片|