1.導入相關庫
#about torch...
import torch
import torch.nn as nn
import torch
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader, Dataset
#using numpy
import numpy as np
#for data load or save
import pandas as pd
#visualize some datasets
import matplotlib.pyplot as plt
#check our work directory
import os
#to unzip datasets
import zipfile
2. 超參數設定
lr = 0.001 # learning_rate
batch_size = 100 # we will use mini-batch method
epochs = 10 # How much to train a model
- 随機種子
device = 'cuda' if torch.cuda.is_available() else 'cpu'
torch.manual_seed(1234)
if device =='cuda':
torch.cuda.manual_seed_all(1234)
加載訓練資料、測試資料
os.listdir('../input/dogs-vs-cats-redux-kernels-edition')
['train.zip', 'sample_submission.csv', 'test.zip']
os.makedirs('../data', exist_ok=True)
base_dir = '../input/dogs-vs-cats-redux-kernels-edition'
train_dir = '../data/train'
test_dir = '../data/test'
with zipfile.ZipFile(os.path.join(base_dir, 'train.zip')) as train_zip:
train_zip.extractall('../data')
with zipfile.ZipFile(os.path.join(base_dir, 'test.zip')) as test_zip:
test_zip.extractall('../data')
os.listdir(train_dir)[:5]
['dog.890.jpg', 'dog.1178.jpg', 'dog.7845.jpg', 'dog.4632.jpg', 'cat.3660.jpg']
import glob
train_list = glob.glob(os.path.join(train_dir,'*.jpg'))
test_list = glob.glob(os.path.join(test_dir, '*.jpg'))
len(train_list)
25000
檢查資料集
from PIL import Image
random_idx = np.random.randint(1,25000,size=10)
fig = plt.figure()
i=1
for idx in random_idx:
ax = fig.add_subplot(2,5,i)
img = Image.open(train_list[idx])
plt.imshow(img)
i+=1
plt.axis('off')
plt.show()
train_list[0].split('/')[-1].split('.')[0]
'dog'
int(test_list[0].split('/')[-1].split('.')[0])
10435
print(len(train_list), len(test_list))
25000 12500
from sklearn.model_selection import train_test_split
train_list, val_list = train_test_split(train_list, test_size=0.2)
圖檔增廣
- 在訓練前必須的操作,可以盡可能地避免overfitting
#data Augumentation
train_transforms = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
])
val_transforms = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
])
test_transforms = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor()
])
加載資料集
class dataset(torch.utils.data.Dataset):
def __init__(self,file_list,transform=None):
self.file_list = file_list
self.transform = transform
#dataset length
def __len__(self):
self.filelength = len(self.file_list)
return self.filelength
#load an one of images
def __getitem__(self,idx):
img_path = self.file_list[idx]
img = Image.open(img_path)
img_transformed = self.transform(img)
label = img_path.split('/')[-1].split('.')[0]
if label == 'dog':
label=1
elif label == 'cat':
label=0
return img_transformed,label
train_data = dataset(train_list, transform=train_transforms)
test_data = dataset(test_list, transform=test_transforms)
val_data = dataset(val_list, transform=test_transforms)
train_loader = torch.utils.data.DataLoader(dataset = train_data, batch_size=batch_size, shuffle=True )
test_loader = torch.utils.data.DataLoader(dataset = test_data, batch_size=batch_size, shuffle=True)
val_loader = torch.utils.data.DataLoader(dataset = val_data, batch_size=batch_size, shuffle=True)
print(len(train_data), len(train_loader))
20000 200
print(len(val_data), len(val_loader))
5000 50
#check our images shape
train_data[0][0].shape
torch.Size([3, 224, 224])
生成模型
- 3個卷積層 + 2個全連接配接層
class Cnn(nn.Module):
def __init__(self):
super(Cnn,self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(3,16,kernel_size=3, padding=0,stride=2),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.layer2 = nn.Sequential(
nn.Conv2d(16,32, kernel_size=3, padding=0, stride=2),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.layer3 = nn.Sequential(
nn.Conv2d(32,64, kernel_size=3, padding=0, stride=2),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.fc1 = nn.Linear(3*3*64,10)
self.dropout = nn.Dropout(0.5)
self.fc2 = nn.Linear(10,2)
self.relu = nn.ReLU()
def forward(self,x):
out = self.layer1(x)
out = self.layer2(out)
out = self.layer3(out)
out = out.view(out.size(0),-1)
out = self.relu(self.fc1(out))
out = self.fc2(out)
return out
model = Cnn().to(device)
model.train()
設定損失函數和優化器
optimizer = optim.Adam(params = model.parameters(),lr=0.001)
criterion = nn.CrossEntropyLoss()
訓練
epochs = 10
for epoch in range(epochs):
epoch_loss = 0
epoch_accuracy = 0
for data, label in train_loader:
data = data.to(device)
label = label.to(device)
output = model(data)
loss = criterion(output, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
acc = ((output.argmax(dim=1) == label).float().mean())
epoch_accuracy += acc/len(train_loader)
epoch_loss += loss/len(train_loader)
print('Epoch : {}, train accuracy : {}, train loss : {}'.format(epoch+1, epoch_accuracy,epoch_loss))
with torch.no_grad():
epoch_val_accuracy=0
epoch_val_loss =0
for data, label in val_loader:
data = data.to(device)
label = label.to(device)
val_output = model(data)
val_loss = criterion(val_output,label)
acc = ((val_output.argmax(dim=1) == label).float().mean())
epoch_val_accuracy += acc/ len(val_loader)
epoch_val_loss += val_loss/ len(val_loader)
print('Epoch : {}, val_accuracy : {}, val_loss : {}'.format(epoch+1, epoch_val_accuracy,epoch_val_loss))
og_probs = []
model.eval()
with torch.no_grad():
for data, fileid in test_loader:
data = data.to(device)
preds = model(data)
preds_list = F.softmax(preds, dim=1)[:, 1].tolist()
dog_probs += list(zip(list(fileid), preds_list))
dog_probs.sort(key = lambda x : int(x[0]))
dog_probs
idx = list(map(lambda x: x[0],dog_probs))
prob = list(map(lambda x: x[1],dog_probs))
submission = pd.DataFrame({'id':idx,'label':prob})
submission
id | label | |
1 | 0.838957 | |
1 | 2 | 0.896960 |
2 | 3 | 0.557805 |
3 | 4 | 0.887924 |
4 | 5 | 0.154988 |
... | ... | ... |
12495 | 12496 | 0.128617 |
12496 | 12497 | 0.299089 |
12497 | 12498 | 0.378285 |
12498 | 12499 | 0.827637 |
12499 | 12500 | 0.130367 |
12500 rows × 2 columns
submission.to_csv('result.csv',index=False)
檢視模型性能,可視化資料
import random
id_list = []
class_ = {0: 'cat', 1: 'dog'}
fig, axes = plt.subplots(2, 5, figsize=(20, 12), facecolor='w')
for ax in axes.ravel():
i = random.choice(submission['id'].values)
label = submission.loc[submission['id'] == i, 'label'].values[0]
if label > 0.5:
label = 1
else:
label = 0
img_path = os.path.join(test_dir, '{}.jpg'.format(i))
img = Image.open(img_path)
ax.set_title(class_[label])
ax.imshow(img)