1.创建transform的字典
1.输入为PIL的图像(array也行),转换为Tensor (0—255的[H,W,C] —> 0~1 的 [C,H,W])
2. compose将多个变换组合起来
3.
data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(input_size),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
transforms.Resize(input_size),
transforms.CenterCrop(input_size),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
2.读取文件夹路径
image_datasets
是一个字典,
root
里面使用了ImageFolder类,这个里面还有transform方法
实例化对象
第一个参数为“root
”
第二个为"transform
"
data_dir = "./data/hymenoptera_data"
# Create training and validation datasets
# ImageFoler类的构造函数,先有文件名读取,再进行transform操作,前面定义过data_transforms
"""A generic data loader where the images are arranged in this way """
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']}
# Create training and validation dataloaders
dataloaders_dict = {
x: DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True, num_workers=0) for x in
['train', 'val']}
# Send the model to GPU
3.训练
- 因为在封装的函数中,传递的实参
dataloader[phase]
,这里是一个字典 - 这个len ,
len(dataloaders[phase].dataset)
这里的参数 - 注意如何保存训练过程中的最佳参数列表
for phase in ['train', 'val']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
running_loss = 0.0
running_corrects = 0
# 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
# ()参数为True则打开梯度,为False则关闭梯度
with torch.set_grad_enabled(phase == 'train'):
if is_inception and phase == 'train':
outputs, aux_outputs = model(inputs)
loss1 = criterion(outputs, labels)
loss2 = criterion(aux_outputs, labels)
loss = loss1 + 0.4 * loss2
else:
outputs = model(inputs)
loss = criterion(outputs, labels)
_, preds = torch.max(outputs, 1)
if phase == 'train':
loss.backward()
optimizer.step()
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloaders[phase].dataset)
epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model
if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
if phase == 'val':
val_acc_history.append(epoch_acc)
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)
4. 加载预训练模型后再更改输出层
model_ft = None
input_size = 0
if model_name == "resnet":
""" Resnet18
已经把参数导入了,相当于直接保存
"""
model_ft = models.resnet18(pretrained=use_pretrained)
"""下面的函数,是在上面声明了的,直接冻结所有的变量梯度"""
set_parameter_requires_grad(model_ft, feature_extract)
""" 更改输出层 """
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, num_classes)
input_size = 224