作者|Bipin Krishnan P
編譯|VK
來源|Towards Data Science
介紹
Francois Chollet寫的《Deep Learning with Python》一書讓我進入了深度學習的世界,從那時起我就愛上了Keras的風格,
Keras是我的第一個框架,然后是Tensorflow,接著進入PyTorch,
老實說,在Keras的模型訓練中,我很興奮這個進度條,真是太棒了,

那么,為什么不嘗試把Keras訓練模型的經驗帶到PyTorch呢?
這個問題讓我開始了作業,最后我用所有那些花哨的進度條重現了Keras的Dense層、卷積層和平坦層,
模型可以通過堆疊一層到另一層來創建,并通過簡單地呼叫fit方法進行訓練,該方法類似于Keras的作業方式,
Keras的作業方式如下:
#一層一層疊起來
#采用輸入資料的形狀
inputs = keras.Input(shape=(784,))
l1 = layers.Dense(64, activation="relu")(inputs)
l2 = layers.Dense(64, activation="relu")(l1)
outputs = layers.Dense(10)(l2)
model = keras.Model(inputs=inputs, outputs=outputs)
#輸出模型摘要
model.summary()
#模型訓練和評估
model.fit(x_train, y_train, epochs=2)
model.evaluate(x_test, y_test)
1.匯入所需的庫
你可能不熟悉庫pkbar,它用于顯示類似Keras的進度條,
!pip install pkbar
import torch
from torch import nn
from torch import optim
from torch.autograd import Variable
from torchsummary import summary as summary_
import pkbar
import warnings
warnings.filterwarnings('ignore')
2.輸入層和dense層
輸入層只是以資料的單一實體的形式被傳遞到神經網路并回傳它,對于全連接的網路,它將類似于(1,784),對于卷積神經網路,它將是影像的尺寸(高度×寬度×通道),
使用大寫字母來命名python函式是違反規則的,但是我們暫時忽略它(Keras源代碼的某些部分使用相同的約定),
def Input(shape):
Input.shape = shape
return Input.shape
def get_conv_output(shape, inputs):
bs = 1
data = https://www.cnblogs.com/panchuangai/p/Variable(torch.rand(bs, *shape))
output_feat = inputs(data)
return output_feat.size(1)
def same_pad(h_in, kernal, stride, dilation):
return (stride*(h_in-1)-h_in+(dilation*(kernal-1))+1) / 2.0
Dense類通過傳遞該層的輸出神經元數量和激活函式來初始化,呼叫Dense層時,前一層作為輸入傳遞,
現在我們有了關于前一層的資訊,如果前一層是輸入層,則創建一個PyTorch線性層,其中輸入層回傳的形狀和輸出神經元的數量作為Dense類初始化期間的引數,
如果前一層是Dense層,我們通過在Dense類中增加一個PyTorch線性層和一個激活層來擴展神經網路,
如果前一層是卷積層或平坦層,我們將創建一個名為get_conv_output()的實用函式,通過卷積層和平坦層得到影像的輸出形狀,此維度是必需的,因為如果不向in_features引數傳遞值,則無法在PyTorch中創建線性層,
函式的作用是將影像形狀和卷積神經網路模型作為輸入,然后,它創建一個與影像形狀相同的虛擬張量,并將其傳遞給卷積網路(具有平坦層),并回傳從中輸出的資料的大小,該大小作為值傳遞給PyTorch線性層中的in_features引數,
class Dense(nn.Module):
def __init__(self, outputs, activation):
super().__init__()
self.outputs = outputs
self.activation = activation
def __call__(self, inputs):
self.inputs_size = 1
if type(inputs) == tuple:
for i in range(len(inputs)):
self.inputs_size *= inputs[i]
self.layers = nn.Sequential(
nn.Linear(self.inputs_size, self.outputs),
self.activation
)
return self.layers
elif isinstance(inputs[-2], nn.Linear):
self.inputs = inputs
self.layers = list(self.inputs)
self.layers.extend([nn.Linear(self.layers[-2].out_features, self.outputs), self.activation])
self.layers = nn.Sequential(*self.layers)
return self.layers
else:
self.inputs = inputs
self.layers = list(self.inputs)
self.layers.extend([nn.Linear(get_conv_output(Input.shape, self.inputs), self.outputs), self.activation])
self.layers = nn.Sequential(*self.layers)
return self.layers
3.平坦層
為了創建一個平坦層,我們將創建一個名為FlattenedLayer的自定義層類,它接受張量作為輸入,并在前向傳播期間回傳張量的平坦版本,
我們將創建另一個名為flatten的類,當呼叫這個層時,前面的層作為輸入傳遞,然后flatten類通過在前面的層上添加我們自定義創建的FlattenedLayer類來擴展網路,
因此,所有到達平坦層的資料都是使用我們自定義創建的平坦層進行平坦的,
class FlattenedLayer(nn.Module):
def __init__(self):
super().__init__()
pass
def forward(self, input):
self.inputs = input.view(input.size(0), -1)
return self.inputs
class Flatten():
def __init__(self):
pass
def __call__(self, inputs):
self.inputs = inputs
self.layers = list(self.inputs)
self.layers.extend([FlattenedLayer()])
self.layers = nn.Sequential(*self.layers)
return self.layers
4.卷積層
我們將通過傳入濾波器數量、內核大小、步長、填充、膨脹和激活函式來初始化Conv2d層,
現在,當呼叫Conv2d層時,前面的層被傳遞給它,如果前一層是Input layer,則是一個Pytorch conv2d層,其中提供了濾波器數量、內核大小、步長、填充,擴張和激活函式被創建,其中in_channels的值取自輸入形狀中的通道數,
如果前一層是卷積層,則通過添加一個PyTorch Conv2d層和激活函式來擴展前一層,激活函式的值取自前一層的out_channels ,
在填充的情況下,如果用戶需要保留從該層傳出的資料的維度,則可以將padding的值指定為“same”,而不是整數,
如果padding的值被指定為“same”,那么將使用一個名為same_pad()的實用函式來獲取padding的值,以保留給定輸入大小、內核大小、步長和膨脹的維度,
可以使用前面討論的get_conv_output()實用程式函式獲得輸入大小,
class Conv2d(nn.Module):
def __init__(self, filters, kernel_size, strides, padding, dilation, activation):
super().__init__()
self.filters = filters
self.kernel = kernel_size
self.strides = strides
self.padding = padding
self.dilation = dilation
self.activation = activation
def __call__(self, inputs):
if type(inputs) == tuple:
self.inputs_size = inputs
if self.padding == 'same':
self.padding = int(same_pad(self.inputs_size[-2], self.kernel, self.strides, self.dilation))
else:
self.padding = self.padding
self.layers = nn.Sequential(
nn.Conv2d(self.inputs_size[-3],
self.filters,
self.kernel,
self.strides,
self.padding,
self.dilation),
self.activation
)
return self.layers
else:
if self.padding == 'same':
self.padding = int(same_pad(get_conv_output(Input.shape, inputs), self.kernel, self.strides, self.dilation))
else:
self.padding = self.padding
self.inputs = inputs
self.layers = list(self.inputs)
self.layers.extend(
[nn.Conv2d(self.layers[-2].out_channels,
self.filters,
self.kernel,
self.strides,
self.padding,
self.dilation),
self.activation]
)
self.layers = nn.Sequential(*self.layers)
return self.layers
5.模型類
在構建了模型的體系結構之后,通過傳入輸入層和輸出層來初始化模型類,但是我已經給出了一個額外的引數,名為device,它在Keras中不存在,這個引數接受值為'CPU'或'CUDA',它將把整個模型移動到指定的設備,
model類的parameters方法用于回傳要給PyTorch優化器的模型引數,
model類有一個名為compile的方法,它接受訓練模型所需的優化器和丟失函式,模型類的摘要方法是借助torch的summary庫顯示所創建模型的摘要,
采用擬合方法對模型進行訓練,該方法以輸入特征集、目標資料集和epoch數為引數,它顯示由損失函式計算的損失和使用pkbar庫的訓練進度,
評估會計算驗證資料集的損失和精度,
當使用PyTorch資料加載程式加載資料時,將使用fit_generator、evaluate_generator 和predict_generator ,fit_generator 以訓練集資料加載器和epoch作為引數,evaluate_generator和predict_generator分別使用驗證集資料加載器和測驗資料加載器來衡量模型對未查看資料的執行情況,
class Model():
def __init__(self, inputs, outputs, device):
self.input_size = inputs
self.device = device
self.model = outputs.to(self.device)
def parameters(self):
return self.model.parameters()
def compile(self, optimizer, loss):
self.opt = optimizer
self.criterion = loss
def summary(self):
summary_(self.model, self.input_size, device=self.device)
print("Device Type:", self.device)
def fit(self, data_x, data_y, epochs):
self.model.train()
for epoch in range(epochs):
print("Epoch {}/{}".format(epoch+1, epochs))
progress = pkbar.Kbar(target=len(data_x), width=25)
for i, (data, target) in enumerate(zip(data_x, data_y)):
self.opt.zero_grad()
train_out = self.model(data.to(self.device))
loss = self.criterion(train_out, target.to(self.device))
loss.backward()
self.opt.step()
progress.update(i, values=[("loss: ", loss.item())])
progress.add(1)
def evaluate(self, test_x, test_y):
self.model.eval()
correct, loss = 0.0, 0.0
progress = pkbar.Kbar(target=len(test_x), width=25)
for i, (data, target) in enumerate(zip(test_x, test_y)):
out = self.model(data.to(self.device))
loss += self.criterion(out, target.to(self.device))
correct += ((torch.max(out, 1)[1]) == target.to(self.device)).sum()
progress.update(i, values=[("loss", loss.item()/len(test_x)), ("acc", (correct/len(test_x)).item())])
progress.add(1)
def fit_generator(self, generator, epochs):
self.model.train()
for epoch in range(epochs):
print("Epoch {}/{}".format(epoch+1, epochs))
progress = pkbar.Kbar(target=len(generator), width=25)
for i, (data, target) in enumerate(generator):
self.opt.zero_grad()
train_out = self.model(data.to(self.device))
loss = self.criterion(train_out.squeeze(), target.to(self.device))
loss.backward()
self.opt.step()
progress.update(i, values=[("loss: ", loss.item())])
progress.add(1)
def evaluate_generator(self, generator):
self.model.eval()
correct, loss = 0.0, 0.0
progress = pkbar.Kbar(target=len(generator), width=25)
for i, (data, target) in enumerate(generator):
out = self.model(data.to(self.device))
loss += self.criterion(out.squeeze(), target.to(self.device))
correct += (torch.max(out.squeeze(), 1)[1] == target.to(self.device)).sum()
progress.update(i, values=[("test_acc", (correct/len(generator)).item()), ("test_loss", loss.item()/len(generator))])
progress.add(1)
def predict_generator(self, generator):
self.model.train()
out = []
for i, (data, labels) in enumerate(generator):
out.append(self.model(data.to(self.device)))
return out
結尾
我用Dense層和卷積神經網路在CIFAR100、CIFAR10和MNIST資料集上測驗了代碼,它作業得很好,但還有很大的改進空間,
這是一個有趣的專案,我已經作業了3-4天,它真的突破了我用PyTorch編程的極限,
你可以在這里查看完整的代碼,并在上面提到的資料集上進行訓練,或者你可以自由地調整代碼以適合你在colab中的喜好:https://colab.research.google.com/github/bipinKrishnan/torchkeras/blob/master/functional_api_v1.ipynb
原文鏈接:https://towardsdatascience.com/recreating-keras-functional-api-with-pytorch-cc2974f7143c
歡迎關注磐創AI博客站:
http://panchuang.net/
sklearn機器學習中文官方檔案:
http://sklearn123.com/
歡迎關注磐創博客資源匯總站:
http://docs.panchuang.net/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/194814.html
標籤:其他
上一篇:回圈神經網路
