Я пытаюсь обучить классификатор изображений resnet18 на большом количестве культур по помеченным данным Google Streeview.Я следую вместе с этим уроком .У меня есть два набора данных: одно из примерно ~ 20 000 изображений и одно из приблизительно ~ 100 000 изображений.Оба набора данных хранятся в одном и том же формате, и оба были загружены в соответствующие корзины Google Cloud Storage.Затем я смонтировал оба этих блока в домашнем каталоге своей виртуальной машины, используя gcsfuse
с флагом --implicit-dirs
.
Затем я запускаю файл train.py
на моей виртуальной машине Google Compute Engine, которая была создана из Изображение VM для глубокого обучения на облачном рынке Google.Виртуальная машина имеет один виртуальный ЦП, один графический процессор Nvidia Tesla K80, 3,75 ГБ памяти и 100 ГБ постоянного диска.
Когда я запускаю обучающий скрипт, я не изменяю ничего, кроме указания правильной переменной dataset_dirgcsfuse
-монтированный каталог на виртуальной машине.
Когда я запускаю train.py
в каталоге 100k crop, он запускается относительно быстро, причем одна эпоха занимает ~ 30 минут.Я прыгаю в top
, пока он работает, и загрузка ЦП довольно высока, оставаясь на уровне около 90%.
Однако, при использовании той же виртуальной машины, когда я запускаю train.py
в каталоге с урожаем 20 КБ, он работает оченьмедленнее, с одной эпохой, занимающей 6-7 часов, несмотря на меньший размер набора данных.В этом случае загрузка ЦП никогда не превышает 5%.
Я не могу понять, что вызывает замедление, поскольку ничто (насколько я могу судить) не отличается между двумя запусками, за исключением наборов данных,которые оба отформатированы одинаково.Я использую тот же pytorch
dataloader с тем же количеством потоков.Оба блока GCS находятся в одной и той же области, us-west1
, которая является той же областью, что и мой экземпляр виртуальной машины.
Кажется вероятным, что каким-то образом один сегмент ограничен по IO относительно другого блока, но я не могу понять,почему.
Любые мысли приветствуются!
Мой train.py
файл находится ниже.
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy
from collections import defaultdict
data_transforms = {
'Test': transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'Val': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
data_dir = 'home/gweld/sliding_window_dataset/'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
data_transforms[x])
for x in ['Test', 'Val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
shuffle=True, num_workers=4)
for x in ['Test', 'Val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['Test', 'Val']}
class_names = image_datasets['Test'].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch, num_epochs - 1))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['Test', 'Val']:
if phase == 'Test':
scheduler.step()
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
running_loss = 0.0
running_corrects = 0
class_corrects = defaultdict(int)
class_totals = defaultdict(int)
# Iterate over data.
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# zero the parameter gradients
optimizer.zero_grad()
# forward
# track history if only in train
with torch.set_grad_enabled(phase == 'Test'):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
# backward + optimize only if in training phase
if phase == 'Test':
loss.backward()
optimizer.step()
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
for index, pred in enumerate(preds):
actual = labels.data[index]
class_name = class_names[actual]
if actual == pred: class_corrects[class_name] += 1
class_totals[class_name] += 1
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]
print('{} Loss: {:.4f} Acc: {:.4f}'.format(
phase, epoch_loss, epoch_acc))
if phase == 'Val':
print("Validation Class Accuracies")
for class_name in class_totals:
class_acc = float(class_corrects[class_name])
class_acc = class_acc/class_totals[class_name]
print("{:20}{}%".format(class_name, 100*class_acc))
print("\n")
# deep copy the model
if phase == 'Val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
print()
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
# load best model weights
model.load_state_dict(best_model_wts)
return model
model_ft = models.resnet18(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 5) # last arg here, # classes? -gw
model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
# Train and evaluate
# ^^^^^^^^^^^^^^^^^^
print('Beginning Training on {} train and {} val images.'.format(dataset_sizes['Test'], dataset_sizes['Val']))
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,
num_epochs=25)
torch.save(model_ft.state_dict(), 'models/test_run_resnet18.pt')