Pytorch、行列のエントリに1つのベクトルの順列を追加するときに、forループを取り除きますか?

Aug 20 2020

私はこのペーパーを実装しようとしていますが、この簡単な手順に固執しています。これは注意を払う必要がありますが、私がこだわっているのは、forループを使用せずに行列に追加されたベクトルの順列を実装する方法です。

注意スコアには、学習されたバイアスベクトルが追加されています。理論は、スコアが表す2つのトークンの相対位置(ji)をエンコードするというものです。

したがって、alphaはT x T行列であり、Tは転送されるバッチに依存し、Bは学習されたバイアスベクトルであり、その長さは固定され、2Tと同じ大きさである必要があります。私が信じている私の現在の実装は、この論文が示唆していることを実行します。

    def __init__(...):
       ...
        self.bias = torch.nn.Parameter(torch.randn(config.n),requires_grad = True)
        stdv = 1. / math.sqrt(self.bias.data.size(0))
        self.bias.data.uniform_(-stdv, stdv)
     def forward(..)
        ...
        #n = 201  (2* max_seq_len + 1)

        B_matrix = torch.zeros(self.T, self.T) # 60 x 60
        for i in range(self.T):
          B_matrix[i] = self.bias[torch.arange(start=n//2-i, end=n//2-i+T)])]

        attention_scores = attention_scores + B_matrix.unsqueeze(0)
        # 64 x 60 x 60   
        ...

これが唯一の関連部分です

B_matrix = torch.zeros(self.T, self.T) # 60 x 60
        for i in range(self.T):
          B_matrix[i] = self.bias[torch.arange(start=n//2-i, end=n//2-i+T)])]

基本的に、forループを使用して各行を調べないようにします。

しかし、このモデルが非常に大きい場合、これは本当に非効率的でコストがかかるに違いないことを私は知っています。学習したバイアスベクトルの順列を取得するために、各行に対して明示的なforループを実行しています。

誰かがおそらくスマート放送を通して、より良い方法で私を助けることができますか?

それについて考えた後、ゼロ行列をインスタンス化する必要はありませんが、それでもforループを取り除くことはできませんか?また、B_matrixはタイル化されたbベクトルとはサイズが異なるため、gatherを使用できません。

functor = lambda i : bias[torch.arange(start=n//2-i, end=n//2-i+T)]
B_matrix = torch.stack([functor(i) for i in torch.arange(T)])

回答

2 jodag Aug 21 2020 at 12:57

nコードに何が含まれているのか理解できませんでしたが、次の例を使用torch.meshgridすると、探しているものが得られると思います。

仮定する

n, m = 10, 20   # arbitrary
a = torch.randn(n, m)
b = torch.randn(n + m)

その後

for i in range(n):
    for j in range(m):
        a[i, j] = a[i, j] + b[n - i + j]

と同等です

ii, jj = torch.meshgrid(torch.arange(n), torch.arange(m))
a = a + b[n - ii + jj]

後者は場違いの操作ですが、これは通常は良いことです。実際にインプレース操作が必要な場合は、に置き換えa =てくださいa[...] =

これは、と同じ形状のテンソルを使用してインデックスを作成する整数配列インデックスの例であることに注意してください。ba