一、环境配置
opencv-python 4.1.2.30
Pillow 8.1.2
tensorboard 2.4.1
torch 1.4.0+cuda10.1
torchsummary 1.5.1
torchvision 0.5.0+cuda10.1
numpy 1.20.1
二、项目结构
预训练模型下载链接
https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth
数据集
链接:https://pan.baidu.com/s/1FUiLsw91DW8ssmnbmrxv5Q
提取码:0fgw
alexnet_inference.py:1000类Alexnet测试
alexnet_visualization.py:alexnet卷积核可视化 ,特征图可视化
train_alexnet.py:猫狗数据集上训练Alexnet
三、关键代码
1、torch.topk
torch.topk(input, k, dim=None, largest=True,sorted=True, out=None)
功能:找出前k大的数据,及其索引序号
• input:张量
• k:决定选取k个值
• dim:索引维度
返回:
• Tensor:前k大的值
• LongTensor:前k大的值所在的位置(找分类名称)
2、FiveCrop TenCrop
transforms.FiveCrop(size)
transforms.TenCrop(size, vertical_flip=False)
功能:在图像的上下左右以及中心裁剪出尺
寸为size的5张图片,TenCrop对这5张图片进行水平或者垂直镜像获得10张图片
• size:所需裁剪图片尺寸
• vertical_flip:是否垂直翻转
3、torchvision.utils.make_grid
make_grid(tensor, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)
功能:制作网格图像(可视化使用)
• tensor:图像数据, BCH*W形式
• nrow:行数(列数自动计算:B/行数)
• padding:图像间距(像素单位)
• normalize:是否将像素值标准化(0-1)—>[0.255]
• range:标准化范围
• scale_each:是否单张图维度标准化
• pad_value:padding的像素值
模型model.eval()作用是为了固定BN和dropout层,使得偏置参数不随着发生变化。因为当batchsize小时,如果没有固定,会对图像的失真有很大的影响
四、代码结构(详细代码见底部)
1、alexnet_inference.py
注意:模型接收4D张量、弃用LRN、 增加AdaptiveAvgPool2d、卷积核数量有所改变
1) 加载图片
img_tensor, img_rgb = process_img(path_img)
2)加载模型
alexnet_model = get_model(path_state_dict,True)
3)模型预测
outputs = alexnet_model(img_tensor)
4)获取类别
5)分类结果可视化
2. alexnet_visualizaton.py
1)卷积核可视化
2) 特征图可视化
3. train_alexnet.py
1) 构建DataLoader
2)构建模型
3)构建损失函数
4)构建优化器
5) 迭代训练
五、详细代码
1、alexnet_inference.py
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
import time
import json
import torch.nn as nn
import torch
import torchvision.transforms as transforms
from PIL import Image
from matplotlib import pyplot as plt
import torchvision.models as models
#BASE_DIR = os.path.dirname(os.path.abspath(__file__))#返回路径 path 的父目录名称
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
def img_transform(img_rgb, transform=None):
"""
将数据转换为模型读取的形式
:param img_rgb: PIL Image
:param transform: torchvision.transform
:return: tensor
"""
if transform is None:
raise ValueError("找不到transform!必须有transform对img进行处理")
img_t = transform(img_rgb)
return img_t
def load_class_names(p_clsnames, p_clsnames_cn):
"""
加载标签名
:param p_clsnames:
:param p_clsnames_cn:
:return:
"""
with open(p_clsnames, "r") as f:
class_names = json.load(f)
with open(p_clsnames_cn, encoding='UTF-8') as f: # 设置文件对象
class_names_cn = f.readlines()
return class_names, class_names_cn
def get_model(path_state_dict, vis_model=False):
"""
创建模型,加载参数
:param path_state_dict:
:return:
"""
model = models.alexnet() #模型的构建
pretrained_state_dict = torch.load(path_state_dict) #加载预训练模型
model.load_state_dict(pretrained_state_dict) #把预训练模型的参数放到模型上
model.eval()
if vis_model: #模型数据流的情况
from torchsummary import summary #观察模型数据流的情况
summary(model, input_size=(3, 224, 224), device="cpu") #生成虚拟的数据去模型中foward,记录foward中每一步网络层特征图的大小
model.to(device)
return model
def process_img(path_img):
# hard code
norm_mean = [0.485, 0.456, 0.406]
norm_std = [0.229, 0.224, 0.225]
inference_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop((224, 224)),
transforms.ToTensor(), #把[0-255]->[0-1]
transforms.Normalize(norm_mean, norm_std),
])
# path --> img
img_rgb = Image.open(path_img).convert('RGB')
# img --> tensor
img_tensor = img_transform(img_rgb, inference_transform)
img_tensor.unsqueeze_(0<