本文主要是有關convlstm的pytorch實現**的理解,原理請移步其他部落格。
在pytorch中實現lstm或者gru等rnn一般需要重寫cell,每個cell中包含某乙個時序的計算,也就是以下:
在傳統lstm中,lstm每次要呼叫t次cell,t就是時序的總長度,如果是n層lstm就相當於一共呼叫了n*t次cell
class convlstmcell(nn.module):
def __init__(self, input_size, input_dim, hidden_dim, kernel_size, bias):
"""initialize convlstm cell.
parameters
----------
input_size: (int, int)
height and width of input tensor as (height, width).
input_dim: int
number of channels of input tensor.
hidden_dim: int
number of channels of hidden state.
kernel_size: (int, int)
size of the convolutional kernel.
bias: bool
whether or not to add the bias.
"""super(convlstmcell, self).__init__()
self.height, self.width = input_size
self.input_dim = input_dim
self.hidden_dim = hidden_dim
self.kernel_size = kernel_size
self.padding = kernel_size[0] // 2, kernel_size[1] // 2
self.bias = bias
self.conv = nn.conv2d(in_channels=self.input_dim + self.hidden_dim,
out_channels=4 * self.hidden_dim,
kernel_size=self.kernel_size,
padding=self.padding,
bias=self.bias)
def forward(self, input_tensor, cur_state):
''':param input_tensor:[batch,dim,inp_height,inp_width]
:param cur_state: [h,c] h:[batch,dim,h,w]
:return:
'''h_cur, c_cur = cur_state
combined = torch.cat([input_tensor, h_cur], dim=1)
combined_conv = self.conv(combined)
cc_i, cc_f, cc_o, cc_g = torch.split(combined_conv, self.hidden_dim, dim=1)
i = torch.sigmoid(cc_i)
f = torch.sigmoid(cc_f)
o = torch.sigmoid(cc_o)
g = torch.tanh(cc_g)
c_next = f * c_cur + i * g
h_next = o * torch.tanh(c_next)
return h_next, c_next
def init_hidden(self, batch_size):
return (variable(torch.zeros(batch_size, self.hidden_dim, self.height, self.width)),
variable(torch.zeros(batch_size, self.hidden_dim, self.height, self.width)))
cell的實現主要如上,其中可以看出來,引數是通過一次conv2d的呼叫就申請好的,這裡是這樣理解的:
in_channels=self.input_dim + self.hidden_dim
out_channels=4 * self.hidden_dim
由於在計算 i f c o 時我們都引入了卷積運算,且運算的物件都是一樣的,要麼是對當前時序的輸入input要麼是對上一時刻的輸出h,所以wxi wxf wcf wxo的卷積核規模或者說引數的規模是相同的,是相同size的tensor,同理whi whf whc wco也是一樣。
在當前時刻,我們的輸入有input[batch,input_dim,h,w],h[batch,hidden_dim,h,w](這裡的input和h的hw是相同的,因為在設定卷積padding的時候約定了輸入的規模)然後我們通過torch.cat將輸入合併為[batch,input_dim+hidden_dim,h,w]
此時我們的核規模是[4*hidden_dim,input_dim+hidden_dim,kh,kw]
在卷積過程中,這裡參考pytorc**檔
這個公式可以理解為矩陣乘運算,不過矩陣乘運算中進行的是每個元素相乘相加,這裡的矩陣乘運算是矩陣中每個核和每個輸入的tensor進行卷積操作再相加。
舉個栗子
假設我們的輸入是28*28的手寫體,為了符合時序的要求,我們將手寫體劃分為16個時序的7*7,核大小設定為(3,3),此時我們的輸入輸出的dim都是1,所以以上的input=[batch,1,7,7] h=[batch,1,7,7] core=[4,2,3,3]
不考慮bias結果就如圖所示了,所以再經過一次split切割,就能拿到很多中間步驟的結果啦。
DFT 理解與python實現
我們知道傅利葉變換能夠將時域的訊號變換到頻域分析,但是我們在計算機應用時,常常是離散的訊號。如,用adc採集回來的模擬訊號,就變成了離散的訊號。這時我們要對訊號進行分析,就不能再使用傅利葉變換了,而要使用離散傅利葉變換,dft x k n 0n 1x n e j 2 k n nx k sum x n...
kmp演算法的理解與實現
kmp演算法曾被我戲稱為看毛片演算法,當時笑噴.大三那個時候硬著頭皮把演算法導論的kmp演算法啃完,弄懂了kmp演算法 的原理,甚至還寫出了 這幾天再次溫習的時候,發現忘得比較徹底。我總結,學演算法不能只對著書本學理論,而應該 用自己的理解去看清演算法的本質,最好用文字把你的理解記錄下來,這樣才能做...
java 多型的理解與實現
1 物件導向的三大特性 封裝 繼承 多型。從一定角度來看,封裝和繼承幾乎都是為多型而準備的。這是我們最後乙個概念,也是最重要的知識點。2 多型的定義 指允許不同類的物件對同一訊息做出響應。即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式。傳送訊息就是函式呼叫 3 實現多型的技術稱為 動態繫結...