PyTorch入門-配列次元およびsqueeze、unsqueeze

31022 ワード

PyTorchを初めて学ぶと,ここの配列次元系はmatlabよりも複雑で,自分の理解が不十分であり,この問題はsqueeze,unsqueezeの2つの関数に触れるとより顕著であると考えられる.
今日はふと理解が精進したような気がして、執筆記録を書きました.
配列、行列、ベクトル
この3つの語の区別の問題は前にすでに投げ出されたことがあるので、ここではわざわざもう一度話します.
  • ベクトル:1次元配列
  • 行列:2 D配列
  • 配列:1次元、2次元配列、高次元配列を含む
  • 一般化すると、配列はマトリクスとベクトルを含み、マトリクスはベクトルも含む.ただし,長さ1の次元を省略したため,ベクトル,マトリクスの2つの説を提案した.
    matlabではベクトルと行列の違いは基本的に無視できるが,高次元配列はn個の2次元配列に分けて示す必要があるため,それほど直感的ではないかもしれないが,より高次元の行列も実際には少ない.
    Tensor
    Tensorの中国語訳は「テンソル」と言います.理解に支障をきたす「元凶」とは、PyTorchで配列を定義する際に縦方向の拡張を表す記号;がないことだと思います.私たちは時々何行かの列を言うこともありますが、実際には明確な「行列」概念はまったく存在せず、「ネスト」と呼ぶのがもっと適切だと思います.
    a = torch.rand(1, 2, 2, 2)
    print(a)
    print(a.size())
    ------------------
    tensor([[[[0.4160, 0.7013],
              [0.3883, 0.6756]],
    
             [[0.6303, 0.0144],
              [0.1027, 0.8542]]]])
    torch.Size([1, 2, 2, 2])
    

    上記の例を見ると,4次元配列はmatlabであればn個の2次元配列(行列)に分解して示す.しかし、ここはネストされた形式で一度に出力されています.最初は少し乱れていたと思いますが、今日は出力の中括弧の階層が配列の階層を完璧に表現していることに気づきました.
    PyTorchでは、高次元配列の定義とmatlabでは異なります.
    matlabの最初の2つの数はそれぞれ行、列数であり、後ろはより高い次元の次元長であり、上の(1, 2, 2, 2)の例を挙げると、2*21*2、すなわち1行2列の行列であるべきである.
    PyTorchの各数字は左から右へそれぞれ外から内への階層に対応する.(a,b,c,d)は、最外層配列がa個の要素(要素自体も配列であり、最内層までしか通常の数ではない)を含み、a個の要素がそれぞれb個のサブ配列を含み、b個のサブ配列がそれぞれc個のサブ配列を含み、c個のサブ配列がそれぞれd個の要素を含むことを示す.
    次にかっこを合わせてみます.
  • 最外層の中括弧:配列の象徴であり、何次元の配列でも最外には中括弧があるので、最外の中括弧自体には次元情報は含まれていません.
  • 第2層:垂直方向に観察され、1層のみであり、この次元長が1であることを示す((a,b,c,d)のaに対応する).
  • 第3層:垂直方向に2層観察され、この次元長が2であることを示す((a,b,c,d)のbに対応する).
  • 第4層:垂直方向に観察すると、前層は2層あるため、pycharmの出力も非常に親切に上下2つに分かれており、私たちは第1のブロックを見るだけでよく、明らかに2層であり、この次元の長さが2((a,b,c,d)中のcに対応する)であることを示している.
  • 第5層:最内層でもあり、中かっこを勝手に選択し、中は横に並んでいて、カンマで区切られた2つの数で、この次元の長さが2であることを説明します((a,b,c,d)中のdに対応します).

  • 上記の過程では「行列」の概念は全く考慮されておらず、PyTorchでは逆に迷いにくいと思います.次にもう一つ例を挙げます.
    a = torch.rand(2, 3, 4, 5)
    print(a)
    print(a.size())
    -----------------------
    tensor([[[[0.3689, 0.0515, 0.4698, 0.8608, 0.2939],
              [0.6328, 0.7154, 0.4514, 0.8239, 0.3587],
              [0.5970, 0.1604, 0.0033, 0.8885, 0.3629],
              [0.2186, 0.9431, 0.2264, 0.3357, 0.3118]],
    
             [[0.8402, 0.7487, 0.8137, 0.0692, 0.9861],
              [0.1275, 0.5480, 0.3803, 0.3801, 0.6754],
              [0.7389, 0.3532, 0.5560, 0.4056, 0.2368],
              [0.1113, 0.3072, 0.6570, 0.1285, 0.6331]],
    
             [[0.0912, 0.3514, 0.2731, 0.9596, 0.1936],
              [0.3107, 0.4428, 0.9672, 0.0778, 0.6484],
              [0.3629, 0.7911, 0.9783, 0.7051, 0.5235],
              [0.1730, 0.8745, 0.1580, 0.3193, 0.8202]]],
    
    
            [[[0.4327, 0.4810, 0.0056, 0.8400, 0.3263],
              [0.1467, 0.8376, 0.0766, 0.5909, 0.4188],
              [0.3555, 0.7011, 0.2004, 0.2605, 0.5205],
              [0.6036, 0.8388, 0.0610, 0.1489, 0.9452]],
    
             [[0.5051, 0.0161, 0.3363, 0.1939, 0.9949],
              [0.7931, 0.2976, 0.6276, 0.3221, 0.1810],
              [0.7623, 0.5226, 0.7116, 0.4818, 0.5510],
              [0.9556, 0.3049, 0.3479, 0.9650, 0.6561]],
    
             [[0.8363, 0.0121, 0.5926, 0.7543, 0.4924],
              [0.2830, 0.3250, 0.7983, 0.2548, 0.3496],
              [0.2930, 0.8676, 0.3479, 0.1776, 0.7081],
              [0.4618, 0.9499, 0.9068, 0.7570, 0.2282]]]])
    torch.Size([2, 3, 4, 5])
    

    この出力結果を階層的な目で見ると、瞬間的にはっきりしています!最外層の中括弧は、配列の象徴であり、管を使わず、次の層は、垂直方向に2つの中括弧があり、最初の2に対応している.次の層は、垂直方向に3つの中かっこがあり、2つ目の3に対応しています.もう1階、4中括弧、対応4;最内層は、5つの数で、最後の5に対応します.
    「行列」という概念が残っていれば、この層の中括弧に囲まれていると思います.
    sizeの出力に合わせて見ると、より理解に役立ちます.
    squeeze、unsqueeze
    上の概念がなければ、squeeze、unsqueezeの2つの関数の使い方を見ると、意味しか分からないと思います.1つの次元を下げて1つの次元を上げますが、具体的な詳細(dimの値)は理解しにくいです.
    今日の午前中は違うdimの場合のunsqueezeの出力結果をじっと見つめて昼間を見ていたら、完全に雲里霧中!!いったい増加した長さ1の次元はどこに追加されましたか?
    ここには2つの問題があります.1つはdimがどのように機能しているのか分からないことです.二つ目はTensorの次元をどう見るか分からないことです.そうしないと、多く出てきた1つの次元がどこにあるか知ることができるに違いありません.
    2つ目の問題は簡単で、上のsize関数を使って、Tensorの次元情報を直接出力することができます.
    最初の質問は、答えるべきことに啓発されました.2つの関数について詳しく説明します.
    squeeze
    ≪アクション|Actions|oraolap≫:1つ以上の次元を消去します.指定した次元の長さ=1の場合にのみ有効になります.
    使用方法:
  • a.squeeze(0):1番目の次元を消去(ここでのインデックスは0から始まり、配列インデックスと同じ)
  • a.squeeze(0,2):第1、3次元
  • を消去
  • a.squeeze():すべての長さ=1の次元
  • を消去する.
    再宣言:指定した次元の長さが1でない場合、エラーは報告されませんが、何の役にも立ちません.
    a = torch.rand(1, 2, 1, 4, 5)
    b = a.squeeze(0)
    c = a.squeeze(1)
    d = a.squeeze()
    print(a.size())
    print(b.size())
    print(c.size())
    print(d.size())
    -------------------
    torch.Size([1, 2, 1, 4, 5])  #      
    torch.Size([2, 1, 4, 5])  #        =1,   
    torch.Size([1, 2, 1, 4, 5])  #  2     =2,    
    torch.Size([2, 4, 5])  #  1、3    =1       
    

    具体的な配列は出力しないので、sizeを直接見たほうがいいと思います.私はあまり説明しないで、上の使い方の説明と結びつけて、みんながもっと理解できると信じています.
    注:1つのn次元マトリクスの場合、dimの値の範囲は-n~n-1である.n-1の由来はよく知られていますが、インデックスが0から始まるため、-nの由来はインデックスも逆順序にすることができ、上のa配列に対してa.squeeze(-1)は消去長=5の次元(もちろん役に立たない)、a.squeeze(-5)は消去最左辺長=1の次元を表すからです.この使い方は配列の長さが長すぎて逆インデックスが必要な場合に使われるかもしれませんが、この場合は少ないと信じています.
    unsqueeze
    ≪アクション|Action|oraolap≫:長さ=1の次元を追加します.
    使用法:a.unsqueeze(t)で、t+1番目の空席(2つの次元の間に空席があり、1番目の次元の前と最後の次元の後ろにそれぞれ空席がある)に次元を追加します.
    注意:一度に1つしか追加できません.つまり、a.unsqueeze(m,n)ではなく、1つの入力しか追加できません.
    a = torch.rand(2, 2, 2, 2, 2)
    b = a.unsqueeze(0)
    c = a.unsqueeze(1)
    d = a.unsqueeze(2)
    ----------------
    torch.Size([2, 2, 2, 2, 2])
    torch.Size([1, 2, 2, 2, 2, 2])
    torch.Size([2, 1, 2, 2, 2, 2])
    torch.Size([2, 2, 1, 2, 2, 2])
    

    ここのdimの値範囲は-(n+1)~nで、正負の範囲はすべてsqueezeより1つの数広くて、よく理解しています:5人が1列に立って、真ん中に6つの空席があります.ここまで来たらもっと私の前の「t+1番目の空席」がどういう意味か理解してくれるはずです.
    まとめ
    unsqueezeに触れたばかりで、入力不要のdimの出力値を見て考え込んで、dimが何をコントロールしているのか肉眼で解析しようとした.次元はいったいどこに加わったのか.dimの値範囲が変化できることさえ分かった!さらに崩壊する.
    最も重要な理解上の突破は,ネスト関係,ネスト階層の観点からTensor高次元配列を理解し,「行列」の概念を捨てることであると考えられる.「次元」の概念を理解したと言います.
    「次元」の概念を理解した後、振り返ってusqueezeとunsqueezeを見て、指定された位置で次元を加減しただけで、配列を負けずにsizeを直接見る必要はなく、これまでの困惑は一掃された.