首先,在本次搭建过程中。我们先下载需要使用到的数据集。下载完成之后可以发现,里面包含5种类型的花,每种类型有600-900张不等
http://download.tensorflow.org/example_images/flower_photos.tgz
import os
from shutil import copy, rmtree
import random
def mk_file(file_path: str):
if os.path.exists(file_path):
# 如果文件夹存在,则先删除原文件夹在重新创建
rmtree(file_path)
os.makedirs(file_path)
def main():
# 保证随机可复现
random.seed(0)
# 将数据集中10%的数据划分到验证集中
split_rate = 0.1
# 指向你解压后的flower_photos文件夹
cwd = os.getcwd()
data_root = os.path.join(cwd, "flower_data")
origin_flower_path = os.path.join(data_root, "flower_photos")
assert os.path.exists(origin_flower_path)
flower_class = [cla for cla in os.listdir(origin_flower_path)
if os.path.isdir(os.path.join(origin_flower_path, cla))]
# 建立保存训练集的文件夹
train_root = os.path.join(data_root, "train")
mk_file(train_root)
for cla in flower_class:
# 建立每个类别对应的文件夹
mk_file(os.path.join(train_root, cla))
# 建立保存验证集的文件夹
val_root = os.path.join(data_root, "val")
mk_file(val_root)
for cla in flower_class:
# 建立每个类别对应的文件夹
mk_file(os.path.join(val_root, cla))
for cla in flower_class:
cla_path = os.path.join(origin_flower_path, cla)
images = os.listdir(cla_path)
num = len(images)
# 随机采样验证集的索引
eval_index = random.sample(images, k=int(num*split_rate))
for index, image in enumerate(images):
if image in eval_index:
# 将分配至验证集中的文件复制到相应目录
image_path = os.path.join(cla_path, image)
new_path = os.path.join(val_root, cla)
copy(image_path, new_path)
else:
# 将分配至训练集中的文件复制到相应目录
image_path = os.path.join(cla_path, image)
new_path = os.path.join(train_root, cla)
copy(image_path, new_path)
print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="") # processing bar
print()
print("processing done!")
if __name__ == '__main__':
main()
import torch.nn as nn
import torch
# 创建一个AlexNet类,继承与nn.module父类
class AlexNet(nn.Module):
# 定义初始化函数,来定义网络在正向传播中所需要使用到的一些层结构
def __init__(self, num_classes=1000, init_weights=False):
super(AlexNet, self).__init__()
# 与demo不一样的是 nn.Sequential模块,可以将一系列的层结构进行打包,组合成新的结构
# features专门用于提取图像特征的结构
# nn.Sequential模块,可以对比上一个demo,self.模块名称,如果每个模块都需要这么定义的话。对于一个网络层次比较多的网络话
# 会比较麻烦,所以可以通过nn.Sequential函数,可以精简代码
self.features = nn.Sequential(
# 第一层 卷积核大小是11 所以kernel_size=11
# 使用了96个卷积核 由于我们的卷积核比较小,所以我们在这里只取它的一半,所达到的准确率也是基本一样的
# 第一层是rgb的彩色图像所以是3
nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2), # input[3, 224, 224] output[48, 55, 55]
# 经过nn.ReLU激活函数,这里的inplace可以理解为pytorch增加计算量。通过这个方法可以在内存中载入更大的内存
nn.ReLU(inplace=True),
# 池化层是没有池化核个数这个参数的
nn.MaxPool2d(kernel_size=3, stride=2), # output[48, 27, 27]
# 卷积默认的就是1 如果是1,就不需要写了
nn.Conv2d(48, 128, kernel_size=5, padding=2), # output[128, 27, 27]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[128, 13, 13]
# 第三个卷积层 上一层的输出时128,所以这边是128
nn.Conv2d(128, 192, kernel_size=3, padding=1), # output[192, 13, 13]
# 激活函数
nn.ReLU(inplace=True),
# 第四个卷积层
nn.Conv2d(192, 192, kernel_size=3, padding=1), # output[192, 13, 13]
nn.ReLU(inplace=True),
# 卷积层5
nn.Conv2d(192, 128, kernel_size=3, padding=1), # output[128, 13, 13]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[128, 6, 6]
)
# 包含我们后面的最后三层 - 全连接层也就是分类器
# 也是使用nn.Sequential将我们的全连接层 打包成一个新的模块
self.classifier = nn.Sequential(
# 可以在展平
# p代表随机失活的比例,默认等于0.5
nn.Dropout(p=0.5),
# 第一层全连接等于上一层的输出 上一层的输出是6*6*256,由于我们使用的只有一半,所以就是6*6*128.2048个节点个数
nn.Linear(128 * 6 * 6, 2048),
nn.ReLU(inplace=True),
# 以百分之50的概率 百分之50的比例失活神经元
nn.Dropout(p=0.5),
# 输入就等于上一层的输出
nn.Linear(2048, 2048),
nn.ReLU(inplace=True),
# num_classes输出就是我们数据集的类别的个数,默认等于1000。
nn.Linear(2048, num_classes),
)
# 初始化权重的权限,如果在搭建网络过程中等于true,就会进入初始化权重的函数
if init_weights:
self._initialize_weights()
# 定义正向传播过程,x就是输入进来的变量
def forward(self, x):
# 首先我们将输入进来的训练样本,输入到我们的features部件当中
x = self.features(x)
# flatten - 我们再将它进行展平处理,纬度是从index=1开始,1是channel开始展平为一纬向量
x = torch.flatten(x, start_dim=1)
# 展平之后,我们输入到我们的分类结构当中。就是我们后面定义的全连接层
x = self.classifier(x)
return x
# 初始化权重函数
def _initialize_weights(self):
# 遍历self.modules,继承nn.moudel这个父类
# 定义中说会返回一个迭代器,遍历每一层结构,
for m in self.modules():
# 判断是属于哪个类别,isinstance判断得到的是否是我们得到的所给定的类型
if isinstance(m, nn.Conv2d):
# 当我们这层是卷积层的话Conv2d,我们用kaiming_normal_初始化变量方法来定义我们卷积权重来进行初始化。
# 如果偏置不为空,我们用0来初始化
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
# 如果传进来是全连接成,那我们用normal_,通过正态分布给我们进行赋值。
# 正态分布的均值是0,方差是0.01,偏置fire是0
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)
import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from pytorch_classification.Test2_alexnet.model import AlexNet
import os
import json
import time
def main():
# 使用GPU训练
# 使用torch.device函数,来指定我们训练过程中的设备。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("using {} device.".format(device))
需要注意的是,对训练集的预处理,多了随机裁剪和水平翻转这两个步骤。可以起到扩充数据集的作用,增强模型泛化能力。
data_transform = {
# 当我们的key为训练集的时候,我们就返回训练集所需要使用的一系列预处理方法
# RandomResizedCrop随机裁剪
# RandomHorizontalFlip随机反转
# 转化为ToTenso r在进行一个标准化处理Normalize
"train": transforms.Compose([transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
# 对于验证集,我们只是Resize到我们的224*224,接着转化为一个ToTensor。同样进行标准化处理
"val": transforms.Compose([transforms.Resize((224, 224)), # cannot 224, must (224, 224)
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
对于之前的LeNet网络搭建中是使用的torchvision.datasets.CIFAR10和torch.utils.data.DataLoader()来导入和加载数据集。
# 导入训练集
train_set = torchvision.datasets.CIFAR10(root='./data', # 数据集存放目录
train=True, # 表示是数据集中的训练集
download=True, # 第一次运行时为True,下载数据集,下载完成后改为False
transform=transform) # 预处理过程
# 加载训练集
train_loader = torch.utils.data.DataLoader(train_set, # 导入的训练集
batch_size=50, # 每批训练的样本数
shuffle=False, # 是否打乱训练集
num_workers=0) # num_workers在windows下设置为0
data_root = os.path.abspath(os.path.join(os.getcwd(), "../..")) # get data root path
image_path = os.path.join(data_root, "data_set", "flower_data") # flower data set path
assert os.path.exists(image_path), "{} path does not exist.".format(image_path)
# 通过ImageFolder去加载我们的数据集
# transform数据预处理,传入train这个key,会传入训练集
train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),
transform=data_transform["train"])
# 打印训练集有多少张图片
train_num = len(train_dataset)
# 导入验证集并进行预处理
validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
transform=data_transform["val"])
val_num = len(validate_dataset)
validate_loader = torch.utils.data.DataLoader(validate_dataset,
batch_size=4, shuffle=False,
num_workers=nw)
为了方便在 predict 时读取信息,将 索引:标签 存入到一个 json 文件中
# 字典,类别:索引 {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
flower_list = train_dataset.class_to_idx
# 将 flower_list 中的 key 和 val 调换位置
cla_dict = dict((val, key) for key, val in flower_list.items())
# 将 cla_dict 写入 json 文件中
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:
json_file.write(json_str)
class_indices.json 文件内容如下:
{
"0": "daisy",
"1": "dandelion",
"2": "roses",
"3": "sunflowers",
"4": "tulips"
}
import torch
from pytorch_classification.Test2_alexnet.model import AlexNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json
data_transform = transforms.Compose(
[transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# load image
img = Image.open("../tulip.jpg")
plt.imshow(img)
# [N, C, H, W]
img = data_transform(img)
# expand batch dimension
img = torch.unsqueeze(img, dim=0)
# read class_indict
try:
json_file = open('./class_indices.json', 'r')
class_indict = json.load(json_file)
except Exception as e:
print(e)
exit(-1)
# create model
model = AlexNet(num_classes=5)
# load model weights
model_weight_path = "./AlexNet.pth"
model.load_state_dict(torch.load(model_weight_path))
model.eval()
with torch.no_grad():
# predict class
output = torch.squeeze(model(img))
predict = torch.softmax(output, dim=0)
predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()
参考:
https://blog.csdn.net/m0_37867091/article/details/107150142