import os
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import torch
from torch import nn
import torch.optim as optim
import torchvision
#pip install torchvision
from torchvision import transforms, models, datasets
#https://pytorch.org/docs/stable/torchvision/index.html
import imageio
import time
import warnings
import random
import sys
import copy
import json
from PIL import Image
data_dir = './flower_data/'
train_dir = data_dir + '/train'
valid_dir = data_dir + '/valid'
data_transforms = {
'train': transforms.Compose([transforms.RandomRotation(45),#随机旋转,-45到45度之间随机选
transforms.CenterCrop(224),#从中心开始裁剪 统一图像大小
transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转 p=0.5表示50%的可能性翻转一次
transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
transforms.ToTensor(), #转换成tensor格式
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#-均值,/标准差 用别人训练好的模型就要用别人类似的数据进行处理效果才会好,这里的均值和标准差和别人使用的保持一致
]),
'valid': transforms.Compose([transforms.Resize(256),#测试集的照片一般比训练集的大所以要做一个resize统一规格
transforms.CenterCrop(224),#和训练数据预处理保持一致
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
batch_size = 8
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}#构建数据集
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
class_names = image_datasets['train'].classes
image_datasets
dataloaders
with open('cat_to_name.json', 'r') as f:
cat_to_name = json.load(f)
注意tensor的数据需要转换成numpy的格式,而且还需要还原回标准化的结果才能展示
clone和detach的用法
Pytorch的Tensor变量与Numpy之间的转化
numpy.squeeze()函数
numpy中的squeeze()函数
numpy模块下的np.clip()的用法
def im_convert(tensor):
""" 展示数据"""
#现数据是tensor格式,要展示数据需要还原
image = tensor.to("cpu").clone().detach()
#实际上y = x.clone()类似于数学表达式中的y=x,但是在python里如果让y=x,是不会给y创建新的内存空间的,这就需要clone了
#或者也可以y = x+0和y=x*1,detach的效果其实就是将一个Tensor的requires_grad置为False,从效果上来看其实就是以该Tensor为根节点的计算子图在反向传播中不再会得到梯度。
image = image.numpy().squeeze()#squeeze()函数的功能是:从矩阵shape中,去掉维度为1的。例如一个矩阵是的shape是(5, 1),使用过这个函数后,结果为(5,)。
#利用squeeze()函数将表示向量的数组转换为秩为1的数组,这样利用matplotlib库函数画图时,就可以正常的显示结果了。
image = image.transpose(1,2,0)#tensor格式是c*h*w还原为h*w*c
image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406)) #还原标准化
image = image.clip(0, 1)
#在求对数损失函数时会用到log函数,对数函数要求对数必须大于零,而从计算中得到的数据可能存在等于0或等于1的情况,这是就会出现inf的数据,影响后续的处理
#为避免这样的情况出现,可以用到np.clip()
return image
fig=plt.figure(figsize=(20, 12))
columns = 4
rows = 2
dataiter = iter(dataloaders['valid'])#iter()生成一个迭代器遍历dataloaders['valid']中的所有值
inputs, classes = dataiter.next()
for idx in range (columns*rows):
ax = fig.add_subplot(rows, columns, idx+1, xticks=[], yticks=[])
ax.set_title(cat_to_name[str(int(class_names[classes[idx]]))])
plt.imshow(im_convert(inputs[idx]))
plt.show()
### 加载models中提供的模型,并且直接用训练的好权重当做初始化参数
- 第一次执行需要下载,可能会比较慢,我会提供给大家一份下载好的,可以直接放到相应路径
# 是否用GPU训练
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu: #if x is None=if not x:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
def set_parameter_requires_grad(model, feature_extracting):
if feature_extracting:
for param in model.parameters():
param.requires_grad = False
model_ft = models.resnet152()
model_ft