筆者手寫了簡單的深度學習框架,這個小項目源於筆者學習pytorch的過程中對autograd的探索。項目名稱爲kitorch。該項目基於numpy實現,代碼的執行效率比cpu的pytorch要慢。雖然如此,我想對於初學者來說,有興趣的同學還是可以看一下的。本項目代碼見github。
由於學習自pytorch,筆者儘量使kitorch的 API接口風格與pytorch保持一致。本篇文章展示一個MNIST的例子:
import numpy as np
import kitorch as kt
from kitorch import nn,optim,functional as F
#使用torch加載數據
import torch
from torchvision import datasets, transforms
# #### 加載數據 #####
BATCH_SIZE=256
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=BATCH_SIZE, shuffle=True)
# ###########定義模型 #########################
class ConvNet(nn.Module):
def __init__(self):
super(ConvNet,self).__init__()
self.conv1 = nn.Conv2d(1,10,5) # 10, 24x24
self.bn1 = nn.BatchNorm2d(10)
self.conv2 = nn.Conv2d(10,20,3) # 128, 10x10
self.bn2 = nn.BatchNorm2d(20)
self.fc1 = nn.Linear(20*10*10,200)
self.bn3 = nn.BatchNorm1d(200)
self.fc2 = nn.Linear(200,10)
def forward(self,x:kt.Tensor):
# x: 512-1-28-28
batch_size = x.shape[0]
out = self.conv1(x) # 512-10-24-24
out = self.bn1(out)
out = F.relu(out)
out = F.maxpool2d(out,(2,2)) # 512-10-12-12
out = self.conv2(out) # 512-20-10-10
out = self.bn2(out)
out = F.relu(out)
out = out.reshape((batch_size,-1))
out = self.fc1(out)
out = self.bn3(out)
out = F.relu(out)
out = self.fc2(out)
return F.log_softmax(out,dim=1)
# ###########訓練和預測的過程############################
def train(model, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data,target = kt.from_numpy(data.numpy().astype(np.float64)),target.numpy()
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if(batch_idx+1)%100 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
def test(model,test_loader):
test_loss = 0
correct = 0
model.eval()
for data, target in test_loader:
data,target = kt.from_numpy(data.numpy().astype(np.float64)),target.numpy()
output = model(data)
test_loss += F.nll_loss(output, target).item() # 將一批的損失相加
result = output.data.argmax(axis=1)
correct += (result == target).sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.6f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
EPOCHS = 20
model = ConvNet()
#測試1:
# lr = [(3,0.05),(5,0.02),(7,0.001),(10,0.005),(15,0.001),(20,0.0005)]
# optimizer = optim.SGD(model.parameters(),lr,momentum=0.9)
# 測試2
# lr = [(3,0.05),(5,0.02),(7,0.001),(10,0.005),(15,0.001),(20,0.0005)]
# optimizer = optim.Adagrad(model.parameters(),lr=lr)
# 256, 20 epoch 可達到99.25%
optimizer = optim.Adadelta(model.parameters())
# 測試失敗
# optimizer = optim.RMSprop(model.parameters(),beta=0.5)
# 256, 20次可達到99.11%
# optimizer = optim.Adam(model.parameters())
for epoch in range(1, EPOCHS+1):
train(model, train_loader, optimizer, epoch)
test(model,test_loader)
執行結果
##最高結果
Test set: Average loss: 0.000085, Accuracy: 9938/10000 (99.38%)
Train Epoch: 19 [25344/60000 (42%)] Loss: 0.000414
Train Epoch: 19 [50944/60000 (85%)] Loss: 0.000137
## 耗時 Wall time: 26min 19s