之所以常看见这样的写法,是因为该程序可能有“单独执行”(例如执行一些单元测试)与“被引用”两种情况,鉴于这两种情况中__name__的值是不同的:当一个模块被直接执行时,其__name__必然等于__main__;当一个模块被引用时,其__name__必然等于文件名(不含.py)。所以利用判断__name__== 'main’的真假就可以将这两种情况区分出来。
if __name__ == '__main__':
image_size = 64 ##图像统一缩放大小
crop_size = 48 ##图像裁剪大小,即训练输入大小
nclass = 4 ##分类类别数
model = simpleconv3(nclass) ##创建模型
## 模型缓存接口
if not os.path.exists('models'):
os.mkdir('models')
## 检查GPU是否可用,如果是使用GPU,否使用CPU
use_gpu = torch.cuda.is_available()
if use_gpu:
model = model.cuda()
print(model)
## 创建数据预处理函数,训练预处理包括随机裁剪缩放、随机翻转、归一化,验证预处理包括中心裁剪,归一化
data_transforms = {
'train': transforms.Compose([
transforms.RandomSizedCrop(48),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])
]),
'val': transforms.Compose([
transforms.Scale(image_size),
transforms.CenterCrop(crop_size),
transforms.ToTensor(),
transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])
]),
}
## 使用torchvision的dataset ImageFolder接口读取数据
data_dir = './data' ##数据目录
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
data_transforms[x]) for x in ['train', 'val']}
#data_transforms 在前面已经定义 是一个字典
## 创建数据指针,设置batch大小,shuffle,多进程数量
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x],
batch_size=64,
shuffle=True,
num_workers=4) for x in ['train', 'val']}
## 获得数据集大小
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
## 优化目标使用交叉熵,优化方法使用带动量项的SGD,学习率迭代策略为step,每隔100个epoch,变为原来的0.1倍
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
step_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=100, gamma=0.1)
model = train_model(model=model,
criterion=criterion,
optimizer=optimizer_ft,
scheduler=step_lr_scheduler,
num_epochs=10)
torch.save(model.state_dict(),'models/model.pt')
为了保证可以复现,随机种子相同
在硬件设备(CPU、GPU)不同时,完全的可复现性无法保证,即使随机种子相同。但是,在同一个设备上,应该保证可复现性。具体做法是,在程序开始的时候固定torch的随机种子,同时也把numpy的随机种子固定。
np.random.seed(0)
torch.manual_seed(0)
torch.cuda.manual_seed_all(0)
#保证每次生成随即数组相同
torch.backends.cudnn.benchmark = False
将上面的值设置为True,Pytorch就会针对模型的卷积层进行预先的优化,即针对每一层卷积都寻找最快的实现算法,进而提升整体效率。如此,便可在模型启动的时候额外增加一点预处理时间,而大幅度减少整体训练时间。
影响卷积运算速度的因素有卷积层本身的参数,如卷积核尺寸,步长,填充,输出通道个数。 输入的参数,如输入的通道数,宽,高等
因此如果上面影响卷积速度的参数频繁的变化,
则将torch.backends.cudnn.benchmark设置为True就不是明智的选择。因为在每次变化之后,算法都会重新预处理,预处理如果做太多次,也是很浪费时间的。
大部分的卷积神经网络的模型卷积层参数和输入参数都是固定的,因此可以利用上述方式提高效率。
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.deterministic顾名思义,将这个 flag 置为True的话,每次返回的卷积算法将是确定的,即默认算法。如果配合上设置 Torch
的随机种子为固定值的话,应该可以保证每次运行网络的时候相同输入的输出是固定的
dataset=torchvision.datasets.ImageFolder
本文链接:https://blog.csdn.net/taylorman/article/details/118631209
dataset=torchvision.datasets.ImageFolder(
root, transform=None,
target_transform=None,
loader=<function default_loader>,
is_valid_file=None)
参数详解:
-
root:图片存储的根目录,即各类别文件夹所在目录的上一级目录。
-
transform:对图片进行预处理的操作(函数),原始图片作为输入,返回一个转换后的图片。
-
target_transform:对图片类别进行预处理的操作,输入为 target,输出对其的转换。如果不传该参数,即对 target 不做任何转换,返回的顺序索引 0,1, 2…
-
loader:表示数据集加载方式,通常默认加载方式即可。
-
is_valid_file:获取图像文件的路径并检查该文件是否为有效文件的函数(用于检查损坏文件)
返回的dataset都有以下三种属性: -
self.classes:用一个 list 保存类别名称
-
self.class_to_idx:类别对应的索引,与不做任何转换返回的 target 对应
-
self.imgs:保存(img-path, class) tuple的 list
dos.path.join()函数合并目录的操作
会从第一个以”/”开头的参数开始拼接,之前的参数全部丢弃。
os.path.join("aa","/bb","ccc.txt")
结果:
'/bb/ccc.txt'
torch.utils.data.DataLoader
-
作用:torch.utils.data.DataLoader 主要是对数据进行 batch 的划分。
数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集。在训练模型时使用到此函数,用来 把训练数据分成多个小组 ,此函数 每次抛出一组数据 。直至把所有的数据都抛出。就是做一个数据的初始化。 -
好处:
使用DataLoader的好处是,可以快速的迭代数据。用于生成迭代数据非常方便。 -
注意:
除此之外,特别要注意的是输入进函数的数据一定得是可迭代的。如果是自定的数据集的话可以在定义类中用def__len__、def__getitem__定