原代碼鏈接:ConvLSTM_pytorch
參考資料:
LSTM的引數解釋
Pytorch-LSTM輸入輸出引數
ConvLSTM引數詳解(Keras)
1.匯入pytorch
import torch
import torch.nn as nn
2.構建ConvLSTMCell
class ConvLSTMCell(nn.Module):
#這里面全都是數,衡量后面輸入資料的維度/通道尺寸
def __init__(self, input_dim, hidden_dim, kernel_size, bias):
super(ConvLSTMCell,self).__init__()
self.input_dim = input_dim
self.hidden_dim = hidden_dim
#卷積核為一個陣列
self.kernel_size = kernel_size
#填充為高和寬分別填充的尺寸
self.padding_size = kernel_size[0]//2,kernel_size[1]//2
self.bias = bias
self.conv = nn.Conv2d(self.input_dim + self.hidden_dim,
4 * self.hidden_dim,#4* 是因為后面輸出時要切4片
self.kernel_size,
padding=self.padding_size,
bias=self.bias)
def forward(self,input_tensor,cur_state):
h_cur,c_cur = cur_state
combined = torch.cat((input_tensor,h_cur),dim=1)
combined_conv = self.conv(combined)
cc_f,cc_i,cc_o,cc_g = torch.split(combined_conv, self.hidden_dim, dim=1)
#torch.sigmoid(),激活函式--
#nn.functional中的函式僅僅定義了一些具體的基本操作,
#不能構成PyTorch中的一個layer
#torch.nn.Sigmoid()(input)等價于torch.sigmoid(input)
f = torch.sigmoid(cc_f)
i = torch.sigmoid(cc_i)
o = torch.sigmoid(cc_o)
g = torch.tanh(cc_g)
#這里的乘是矩陣對應元素相乘,哈達瑪乘積
c_next = f*c_cur + i*g
h_next = o*nn.Tanh(c_next)
def init_hidden(self,batch_size, image_size):
heigth,weight = image_size
#回傳兩個是因為cell的尺寸與h一樣
return(torch.zeros(batch_size, self.hidden_dim, height, width, device=self.conv.weight.device),
torch.zeros(batch_size, self.hidden_dim, height, width, device=self.conv.weight.device))
在構建ConvLSTMCell時遇到的問題:
(1)模型引數
input_dim:輸入特征的維數,每一行輸入元素的個數,對應時間序列里每個詞向量的長度 ,如果輸入是圖片的話,就是影像的通道數,
hidden_dim:隱藏層狀態的維數,即隱藏層節點的個數
kernel_size:卷積核的尺寸
bias:偏置
(2)forward輸入引數
input_tensor:輸入影像本身,包括batch_size,h,w
cur_state:包含h,c;這里h,c與輸入x(input_tensor)的資料組成成分相同
(3)激活函式的使用區別
torch.nn.Sigmoid()(input)等價于torch.sigmoid(input),nn.functional中的函式僅僅定義了一些具體的基本操作,不能構成PyTorch中的一個layer,orch.nn.Sigmoid()(input)和torch.sigmoid(input)可以視為已經封裝好的類,而nn.functional.sigmoid只是一個運算的方法,僅僅執行sigmoid的運算,
具體區別見:torch.sigmoid() 與 torch.nn.Sigmoid() 對比 python
(4)init_hidden初始化回傳的引數
batch_size:批量處理的資料量大小
self.hidden_dim:隱藏層節點數
height:影像高
width:影像寬
device=self.conv.weight.device:選擇設備
因為初始化回傳的hidden與后面使用的hidden資料的組成成分是一樣的,又因為后面ht會當作后面層的xt作為輸入使用,所以與xt的組成成分應該也是一樣的,我照這樣理解,得到的以上引數的解釋,等我深刻理解以后,回來改正,
3.構建ConvLSTM
class ConvLstm(nn.Module):
def __init__(self,input_dim,hidden_dim,kernel_size,num_layers,batch_first=False,bias=False,return_all_layers=False):
super(ConvLstm,self).__init__()
self.input_dim = input_dim
self.hidden_dim = hidden_dim
self.kernel_size = kernel_size
self.num_layers = num_layers
self.batch_first = batch_first
self.bias = bias
self.return_all_layers = return_all_layers
#為了儲存每一層的引數尺寸
cell_list = []
for i in range(0,num_layers):
#注意這里利用lstm單元得出到了輸出h,h再作為下一層的輸入,依次得到每一層的資料維度并儲存
cur_input_dim = input_dim if i == 0 else self.hidden_dim[i-1]
cell_list.append(ConvLSTMCell(input_dim = cur_input_dim,
hidden_dim = self.hidden_dim,
kernel_size = self.kernel_size,
bias = self.bias
))
#將上面回圈得到的每一層的引數尺寸/維度,儲存在self.cell_list中,后面會用到
#注意這里用了ModuLelist函式,模塊化串列
self.cell_list = nn.ModuleList(cell_list)
#這里forward有兩個輸入引數,input_tensor 是一個五維資料
#(t時間步,b輸入batch_ize,c輸出資料通道數--維度,h,w影像高乘寬)
#hidden_state=None 默認剛輸入hidden_state為空,等著后面給初始化
def forward(self,input_tensor,hidden_state=None):
#先調整一下輸出資料的排列
if not self.batch_first:
input_tensor = input_tensor.permute(1,0,2,3,4)
#取出圖片的資料,供下面初始化使用
b,_,_,h,w = input_tensor.size()
#初始化hidd_state,利用后面和lstm單元中的初始化函式
hidden_state = self._init_hidden(batch_size=b,image_size=(h, w))
#儲存輸出資料的串列
layer_output_list = []
layer_state_list = []
seq_len = input_tensor.size(1)
#初始化輸入資料
cur_layer_input = input_tensor
for layer_idx in range(self.num_layers):
h,c = hidden_state[layer_idx]
output_inner = []
for t in range(seq_len):
#每一個時間步都更新 h,c
#注意這里self.cell_list是一個模塊(容器)
h,c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:,t,:,:,:],cur_state=[h,c])
#儲存輸出,注意這里 h 就是此時間步的輸出
output_inner.append(h)
#這一層的輸出作為下一次層的輸入,
layer_output = torch.stack(output_inner, dim=1)
cur_layer_input = layer_output
layer_output_list.append(layer_output)
#儲存每一層的狀態h,c
layer_state_list.append([h,c])
#選擇要輸出所有資料,還是輸出最后一層的資料
if not self.return_all_layers:
layer_output_list = layer_output_list[-1:]
last_state_list = last_state_list[-1:]
return layer_output_list, last_state_list
def _init_hidden(self, batch_size, image_size):
init_states = []
for i in range(self.num_layers):
init_states.append(self.cell_list[i].init_hidden(batch_size, image_size))
return init_states
在構建ConvLSTM時遇到的問題:
(1)模型引數
input_dim:輸入特征維數
hidden_dim:隱藏層狀態的維數(隱藏層節點的個數)
kernel_size:卷積核尺寸
num_layers:層,理解為網路深度
batch_first:控制t(時間步長)放在首維還是第二維,官方不推薦我們把batch放在第一維
bias:偏置
return_all_layers:是否回傳全部層
(2)forward引數
t:時間步長度(seq_len)
b:batch_size,批量處理的資料量大小
c:通道數(R,G,B)
h:圖片高
w:圖片寬
(3)_init_hidden(self, batch_size, image_size)
這個函式要呼叫ConvLSTMCell中的init_hidden函式,最終得到初始的hidden_state,注意每一層的hidden_state初始化都有重新定義,每層輸出的h作為x,但在第二層時間步的第一個h還是需要初始化,
插入一張圖片方便理解:
end
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/200980.html
標籤:java
下一篇:python基礎之安裝第三方庫
