本学习笔记参考自B站up主霹雳吧啦Wz
代码均来自导师github开源项目WZMIAOMIAO/deep-learning-for-image-processing: deep learning for image processing including classification and object-detection etc. (github.com)
视频链接在这里:2.1 pytorch官方demo(Lenet)_哔哩哔哩_bilibili
AlexNet网络结构
AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevsky设计的。
其中也是首次再CNN中应用到了ReLU和Dropout
输入的数据特征为224×224×3,同时论文中采用双GPU并行运算的方法,我们就只采用单GPU,所以就运行下方图中的一半就好了。
1、Model
注意:pytorch框架中的Tensor通道排序为[batch_size, channel, height, width]
import torch.nn as nn
import torch
class AlexNet(nn.Module):
def __init__(self, num_classes=1000, init_weights=False): # init_weights为定义的初始化权重函数
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2), # input[3, 224, 224] output[48, 55, 55]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[48, 27, 27]
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]
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),
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]
)
self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(128 * 6 * 6, 2048),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
nn.Linear(2048, 2048),
nn.ReLU(inplace=True),
nn.Linear(2048, num_classes),
)
if init_weights:
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = torch.flatten(x, start_dim=1) # 展平维度开始为1,因为0是batch_size
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
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):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)
这里用到了一个nn.Sequential的函数来讲网络层打包在一起,避免了每个层都要写个self.,我们将卷积层和池化层打包成features特征层,全连接层打包成分类层。
其中Dropuot层是指按照指定的比率随机失活一定的神经元,来达到避免过拟合的情况
nn.Dropout(p=0.5) # p为失活比率
同时这一课中提到一个初始化权重的操作,关于初始化的详细操作可以自己查找
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
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):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)
2、train
博主个人觉得对于工程问题,训练模块的搭建比网络结构更加需要学习,是代码的能力(当然,这是本白目前的个人理解,轻点喷)
完整代码请在霹导师github中自行查找
本章中使用这一串代码将模型的训练挂载到GPU上运行
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
同时对训练集数据机型一个随机裁剪到224*224的格式,以及随机的旋转,目的是增强模型对数据的识别能力
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
对于验证集就只需要裁剪到224*224即可,不需要随机
transforms.Resize((224, 224))
由于这次使用的数据集不是pytorch官方提供的数据集,因此我们需要用到datasets.ImageFolder()这个函数去加载我们的图片数据
在训练前我们需要通过net.train()这个函数来开启训练模式,以及验证时使用net.val()来开启验证模式,原因主要是AlexNet网络中使用到了Dropout方法,我们只希望它在训练时候起作用随即失活参数,而不希望在预测时起作用
在训练过程中使用best_acc这个变量来记录精度最好的模型用于保存
if val_accurate > best_acc:
best_acc = val_accurate
torch.save(net.state_dict(), save_path)
我们使用tqdm这个包来显示训练的进度
train_bar = tqdm(train_loader, file=sys.stdout)
这里返回train_bar的还是是一个可迭代的对象,以便我们调用其中的数据
3、predict
预测前我们需要在训练文件夹里加入下面这段代码,用于保存分类的索引
# read class_indict
json_path = './class_indices.json'
assert os.path.exists(json_path), "file: '{}' dose not exist.".format(json_path)
with open(json_path, "r") as f:
class_indict = json.load(f)
其余的和之前的LeNet网络的预测无太大区别
需要注意的是我们在使用.numpy()函数前需要讲output挂在到cpu上,因为numpy并不支持cuda的模式
output = torch.squeeze(model(img.to(device))).cpu()



