目录
仅是个人笔记,代码学习资源来源B站博主霹雳吧啦Wz的个人空间_哔哩哔哩_bilibili
一、 网络原理
1 堆叠多个3x3的卷积核
堆叠多个3x3的卷积核来替代大尺度卷积核 (减少所需参数)
两个3x3的卷积核替代5x5的卷积核,三个3x3的 卷积核替代7x7的卷积核
参数: 2*3*3 =18 --------- 5*5=25 3*3*3=27------------7*7=49
为何能替代?————相同的感受野
2 感受野
感受野(详见超链接)
3 网络架构
- conv的stride为1,padding为1
- maxpool的size为2,stride为2
卷积未改变特征图大小,ke_size=3,pad=1
每次是通过池化改变的;步距为2
特征提取(全连接之前):
224——112——56——28——14——7 通过5个池化
接入全连接: 512*7*7
二、 代码复现
绝大部分代码同01alexnet
- 优化器——— Adam优化器(详见超链接)
optimizer = optim.Adam(net.parameters(), lr=0.0001)
- tqdm进度条使用——tqdm(详见超链接)
train_bar = tqdm(train_loader, file=sys.stdout)
for step, data in enumerate(train_bar):
images, labels = data
optimizer.zero_grad()
outputs = net(images.to(device))
loss = loss_function(outputs, labels.to(device))
loss.backward()
optimizer.step()
running_loss += loss.item()
train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
epochs,
loss)
1 迁移学习
- 参数加载 (注意:使用别人预训练模型参数时,要注意别人的预处理方式)
- torch官方参数加载——使用weights参数(详见超链接)
net = vgg16(weights = torchvision.models.VGG16_Weights)
- 自己下载的/训练的,参数完全匹配 model.load_state_dict方法(详见超链接) torch.load方法(详见超链接) 参数完全匹配 ————就是字典的key必须完全一样名字,val形状相同
model = vgg(model_name="vgg16", num_classes=5).to(device) weights_path = "./vgg16Net.pth" model.load_state_dict(torch.load(weights_path, map_location=device))
- 参数不完全匹配
两种方法都行,哪个方便用哪个
使用下面的套路加载---本质都一样
用下面这个!!!!!!!!!!!!!!!!!!!!!!!!!
# 设备加载
device = torch.device(args.device if torch.cuda.is_available() else "cpu")
# 建立model
model = u2net_full()
# 查看model的初始化参数值
old_dic = model.state_dict()
# 加载.pth参数文件
weight_path = 'F:/.../u2net_full.pth'
pre_dic = torch.load(weight_path, map_location=device)
# 将.pth参数加载到model中,只会将字典名称完全一样以及shape相同的加载进去
# 返回model中未加载成功的参数 以及 .pth中多余的参数(与model不匹配)------strict=False
missing_keys, unexpected_keys = model.load_state_dict(pre_dic, strict=False)
print(missing_keys, unexpected_keys)
# 再次查看model的参数值,检查是否已经更换成功
new_dic = model.state_dict()
model.to(device)
- 模型修改
根据名称修改,修改前后特征图要满足输入输出要求
- 参数获取、冻结
参数、模型查看(详见超链接)
for m, n in net.named_parameters(): # m就是层的名称,n就是它的参数
# m的形式 eg: features.0.weight 、 features.0.bias 、 classifier.6.weight等等
# 卷积,全连接,才有weight、bias 池化、激活没有参数
if m == 'classifier.3.bias': # m是字符串格式,打印某一层的参数
print(m, n.shape)
if m == 'features.6.weight':
print(m, n.shape)
参数冻结
# 冻结net全部参数
for name, parameter in net.named_parameters():
parameter.requires_grad = False
# 冻结net部分参数
for name, parameter in net.named_parameters():
if 'key' in name:
parameter.requires_grad = False
2 分类网络准确率计算
for val_data in val_bar:
val_images, val_labels = val_data
outputs = net(val_images.to(device))
# (batch,类别数) 一个样本是一行,每一行是属于各个类别的概率
predict_y = torch.max(outputs, dim=1)[1]
# (batch) predict_y==(outputs每一行最大值的)索引
acc += torch.eq(predict_y, val_labels.to(device)).sum().item()
# 判断相等的个数
val_accurate = acc / val_num #一轮的准确率: 正确的样本数/总样本数
3 常用tensor变换等操作函数
- torch.max(详见超链接)
- torch.eq()(详见超链接)
- torch.flatten()(详见超链接)
维度变换:
torch.nn.flatten 开始展的默认维度值为1,torch.flatten默认是从0开始展。
.reshape .view()类似。方法会先展平再按照维度排列,不同于转置!!!
转置操作使用下面两个:
tensor.transpose(),只交换指定的两个维度的内容
tensor.permute()则可以一次性交换多个维度。
输入网络,BCHW
测试一张图片时是CHW,所以添加一个维度升维
torch.squeeze()
x = torch.randn(size=(2, 1, 2, 1, 2))
#shape(2, 1, 2, 1, 2)
# 1 把x中维度大小为1的所有维都删除
y = torch.squeeze(x)
#shape(2,2,2)
# 2 删除某一维
y = torch.squeeze(x,0) #第一维大小为2,不为1,因此结果删除不掉
#shape(2, 1, 2, 1, 2)
y = torch.squeeze(x,1) #x第二维大小是1,可以删掉
#shape(2, 2, 1, 2)
torch.unsqueeze()
y = torch.unsqueeze(x, 0) #在第0维扩展,第0维大小为1
y = torch.unsqueeze(x, -1) #在最后一维扩展,最后一维大小为1