RomanticQq

保持对生活的热爱,唯有生活不可被辜负

0%

github代码demo

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding: utf-8 -*-
"""
@time : 2022/8/22 20:58
@author : fuqiang
@file : dataset.py
@project : test
"""
import torch
from PIL import Image
import numpy as np
import pandas as pd
import torch.nn.functional as F


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class TrainDataset:
def __init__(self, data_path, width_height, classes):
self.df = pd.read_pickle(data_path)
self.w_h = width_height
self.classes = classes

def __getitem__(self, item):
image = self.df.iloc[item, 0]
label = self.df.iloc[item, 1]
image = Image.fromarray(image).resize((self.w_h, self.w_h), resample=Image.NEAREST)
image = np.array(image)
image = torch.from_numpy(image)
label = torch.tensor(label)
image = F.one_hot(image.to(torch.int64), 3)
# label = F.one_hot(label.to(torch.int64), self.classes)
image = np.array(image).transpose((2, 0, 1)).astype(dtype=np.float32)
image = torch.FloatTensor(image).contiguous()
# label = label.contiguous()
return image, label

def __len__(self):
return len(self.df)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# pkl、csv、xlsx等文件都可使用pandas进行读取,读取后都为dataframe数据类型
import pandas as pd
# 读取文件
df = pd.read_pickle('data/WM-811K-simple-test.pkl')
# 新增一列 列名为failureNum 并把原先列名为failureType的数据赋值给新列
df['failureNum'] = df.failureType
mapping = {'Center': 0, 'Donut': 1, 'Edge-Loc': 2, 'Edge-Ring': 3,
'Loc': 4, 'Near-full': 5, 'Random': 6, 'Scratch': 7, 'none': 8}
# 根据mapping映射关系对新列的数据内容进行修改
df = df.replace({'failureNum': mapping})
# 通过条件获取筛选过后的列
df = df[(df['failureNum'] >= 0) & (df['failureNum'] <= 8)]
# 对某一列进行删除
df = df.drop(['failureType'], axis=1)
# 对处理过后的数据进行保存
df.to_pickle('./data/WM-811K-torch.pkl')

1.删除仓库文件

先删除本地文件->git add -u

2.创建test分支

列出所有分支git branch -a(带*绿色的为当前分支,白色和绿色的为当前分支,红色所有远端分支)->创建test分支git branch test->切换分支git checkout test->提交分支git push origin test

3.把test分支合并到master分支

git merge test

4.删除test分支

切换非删除的分支
git branch -D test 删除本地分支
git push —delete test 删除远端分支 删除远端分支时,本地分支不会被删除

5.从github下载代码的时候一定要使用ssh地址,使用https地址的时候可能会出现问题

6.从仓库拉去代码

git pull

7.把代码推送到仓库

把文件添加到缓冲区 git add 文件名
把文件添加到本地仓库 git commit -a 本地提交的注释
把文件推送到仓库git push(origin 当前分支名)(亲测,如果是分支第一次提交不能省略,可能是因为要把新分支和代码同时推上去,否则括号内的内容可省)

8.恢复被修改的文件

git checkout .(恢复被修改的所有文件)
git checkout — 文件名/文件夹名(恢复被修改的文件名或则文件夹名)

9.内容回滚

git reset HEAD^ 所有内容回退到上一个版本
git reset HEAD^ 文件名 具体文件回退到上一个版本
git reset 哈希值 回退到产生这个哈希值的状态

10.如何拉取远端所有分支

get checkout -b 分支名 origin/分支名 切换到远端的分支并在本地命名

这些平时就已经够用了,更加高级的用法用到时可自行百度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import torch
import torch.nn as nn
import torch.nn.functional as F


class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv = nn.Conv2d(2, 1, 1)


net = CNN()


class Test(nn.Module):
def __init__(self, cnn):
super(Test, self).__init__()
self.conv = cnn.conv

def forward(self, x):
x = self.conv(x)
x = F.relu(x)
return x


a = torch.randn([1, 2, 3, 4])
test = Test(net)
res = test(a)
print(res)

Test类直接接受是CNN()实例化后的net,相当于把CNN()的网络结构作为参数传给了Test(),这样在CNN()中就不用写forward(),即使写了也不起作用,因为对于test对象来说,它的网络结构是Test()定义的,其前向传播必须在Test()中进行定义。

mro

mro是每一个类会把它所有的父类和自己做一个线性化serialization,也就是把所有的继承类和自己做一个排队,这个排队要保证自己是最高优先级。

1
2
3
4
5
6
7
8
9
# 定义两个父类
class A:
def say(self):
print("A")


class B:
def say(self):
print("B")
1
2
3
4
5
6
7
8
9
# 情况1
class M(A, B):
pass


m = M()
m.say() # A
# 此处M.mro()是M,A,B(因为在继承的时候A在前,所以A的优先级高于B)
# 因为m调用了say函数,会按照m所在类的mro的顺序从前到后在类里找say函数,先在类A里找到了,因此输出为A
1
2
3
4
5
6
7
8
9
10
11
12
13
# 情况2
class C(A):
pass


class M(C,B):
pass


m = M()
m.say() # A
# 此处M.mro()是M,C,A,B(因为在M继承C和B的时候先继承的C,所以C及C的父类的优先级都高于B)
# 因为m调用了say函数,会按照m所在类的mro的顺序从前到后在类里找say函数,先在类A里找到了,因此输出为A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 情况3
class C(A):
pass


class D(A):
def say(self):
print("D")


class M(C,D):
pass


m = M()
m.say() # D
# 此处M.mro()是M,C,D,A
# 因为M继承了C,D C继承了A D继承了A
# C,D都继承了A,那么A的优先级以A最后出现的位置为准
# 因此M,C,D,A先在D中找到了say函数
# 这可能有一个疑问:为什么C已经继承A了,那么C中不是应该有A中的say函数吗?为什么不是输出A?
# 在这里只有找到了类里真真正正存在的该函数才可以,继承关系是不可以的
1
2
3
4
5
6
7
8
9
10
11
12
13
# 情况4
class C(A, B):
pass


class D(B, A):
pass


class M(C, D):
pass

# 这样的写法是会报错的,因为当继承相同的父类时,顺序一定要相同

总结:

  1. 每个类只会按排列好的类的优先级去执行自己类里面的函数,若B继承A,B里面没有say函数而A里面有,那么即使B的优先级高,B也不能执行say函数,只能优先级到A时,自己调用自己类里的say函数;
  2. 当存在多继承时,在当前类的继承关系中先出现的类的优先级高(情况1);
  3. 当存在A被多个类继承时,A的优先级由最后一次出现的位置决定(情况3);

super

1
2
3
4
5
super(class, object/class).__init__([参数])
# 参数1:决定了在mro链上从哪个类的下一个开始查找__init__函数
# 参数2:决定了这一个函数bind到哪一个object或则class上,同时决定了使用哪一个mro
# 参数3:需给找到的__init__传的参数
# 参数1和参数2有时候是可以省略的,当省略时,参数1为当前的类名,参数2为该所在函数第一个参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A:
def __init__(self, name):
self.name = name


class B(A):
def __init__(self, name, age):
self.age = age
super(B, self).__init__(name)


c = B('xiaoming',16)
print(c.name)
print(c.age)
# 在类B中,super(B, self).__init__(name)和super().__init__(name)的作用是相同的
# super的执行流程(以本段代码中的super为例):首先它要从self这个object中拿到mro,然后
#从类B的后一个class开始查找__init__函数,当找到__init__函数后进行赋值,然后再把__init__函数bind到
#self上;在这个例子中,先通过self拿到mro(B,A),然后从B后面的类开始查找,即A类中有__init__函数,然后
#对__init__函数中的name进行赋值,并返回给self

self

在类内用类名和self的区别

  1. BN层的作用;
  2. faster-RCNN中roi pooling层是如何实现的;
  3. 处理图像的方法有哪些;
  4. YOLO和faster-RCNN的区别;
  5. YOLOv5各个功能模块的介绍;
  6. 常用的激活函数有哪些,有什么优点;
  7. IOU是如何定义的;
  8. 对Transformer的理解;
  9. 写一个处理数据集的类,1000张图片,缩放到100 * 100,格式为RGB,划分为训练集和验证集;
  10. 写一个简单的神经网络模型;

Bag of freebies(BOF)

Mosaic data augmentation

Mixup:让两张图片的像素值对应相加,生成一张新的图片;

Cutout:对一张图片的部分进行遮挡;

CutMix:把多张图片进行缩放,拼接到一张图片上;

数据增强

Random Erase:用随机值或训练集的平均像素替换图像的区域;

Hide and Seek:根据概率设置随机隐藏一些补丁;

Self-adversarial-training(SAT)

系数要足够小

DropBlock

之前是随机失活一个像素点,但是周围的像素点还存在,其实对整个图像的影响并不大;

现在随机吃掉一个区域,使网络的性能更好。

Label Smoothing

平滑标签,不让边界感那么强,可以提高图像的识别率;

这个0.1的系数是自己设置的;

IOU损失

GIOU损失

重点:是在不重叠的情况下,预测框向真实框前进,不重叠,不重叠!!!!

当重叠时,不能反应出来情况的好坏;

DIOU损失

CIOU损失

DIOU-NMS

SOFT-NMS

先不直接剔除,而是降低置信度,再给一次机会。

SPPNet

虽然输出的图像尺寸大小可能不一样,但是通过最大池化来满足最终输入特征图的大小是一样的。

CSPNet

把特征图平均分成两部分,一部分什么都不做,另外一部分经过卷积进行输出,虽然精度上可能有所降低,但是速度上会加快很多,但是结果表现精度可能并没有降低,还有一点点升高。

CBAM

Channel Attention Module:对不同特征图产生一个概率,这个概率值表示对不同特征图的关注度;

SAM:对于特征图的不同位置的注意力机制;

PAN

激活函数MISH

eliminate grid sensitivity

在σ(ty)前加上大于1的系数;

整体网络架构

迁移学习的基本策略

  • 构造数据集
    • 是否需要对数据进行处理
  • 初始化模型
    • 加载原始模型
  • 设置需要冻住的层
  • 是否需要GPU运算
  • 设置迭代器和损失函数
  • 进行训练
    • 加载需要迁移学习的模型
    • 对训练集进行训练
    • 对验证集进行应该验证
    • 保存验证集上准确率最高的模型
    • 保存模型

Darknet53

YOLOv3采用了Darknet53为主干网络;

多scale

在YOLOv3上设计了3种scale,分别为特征图大小13 13、26 26、52 * 52上进行大、中、小目标预测;

网络结构

Residual module

残差网络,会有A(保存原来的不进行任何操作),B两种通道,然后再合并,即使F(x)不起作用,还会保存以前的输出结果。

注:使用残差网络,不能保证效果一定有多大提升,但是至少不会差。

输出

  • YOLOv3网络的输入尺寸为 (m,416,416,3), 其中m代表每个batch中图像数目,m=1,代表每个batch处理1张输入图像;
  • YOLOv3分3个尺度进行预测, 3个尺度的特征图的大小依次为13X13,26X26以及52X52;
  • YOLOv3中每个cell预测3个bounding box,每个bounding box 可以表示为6元组 [公式]
  • 在COCO数据集中一共有80个类别,此时我们将c扩展成80维向量,这样我们每个bounding box可以用85维向量进行表示;
  • 特征图大小为13 13,可以预测169(13 13)个物体,然后依次类推;

先验眶的生成

先使用K-means方法生成9个先验框,然后按照大小进行排序,分给3个不同的scale。

logistic

Softmax实现物体单分类最后的评判, Softmax能够确保所有物体的预测概率之和为1,比如一个物体的预测是狗的概率是80%,那么是其他物体的概率之和为20%。这就是单标签概率。

然后,对于多标签预测,比如,一个物体是狗的概率是80%,是狼狗的概率是70%,是猎狗的概率是75%,像这样的分类判决,Softmax就无法胜任了。

YOLO V3使用了logistic激活函数替换了softmax函数,把物体的联合的多分类,变成独立的二分类,从而实现对物体多标签的支持
(此部分参考YOLO V3 - 网络结构、原理、改进的全新、全面、通俗、结构化讲解)

逻辑回归中的基本构造函数

在逻辑回归算法中,选用的基本函数就是sigmoid函数

该函数用于预测输入x后标签y的概率,注意,这里的x并非是数据集的原始数据输入,而是乘以了参数θ之后的值,即 x = X ⋅ θ,因此逻辑回归的基本函数为:

batch norm

舍弃全连接层和dropout,每次卷积后加入batch normalization。

batch norm的作用

具有统一规格的数据能让神经网络更好地学习到数据的规律;批归一化在非线性激活函数前,使梯度不会出线为0;

高分辨率预训练分类网络

目前的大部分检测模型都会使用主流分类网络(如vgg、resnet)在ImageNet上的预训练模型作为特征提取器,而这些分类网络大部分都是以小于256×256的图片作为输入进行训练的,低分辨率会影响模型检测能力。

YOLO v2将输入图片的分辨率提升448×448,为了使网络适应新的分辨率,YOLO v2先在ImageNet上以224×224进行训练,然后再以448×448的分辨率对网络进行10个epoch的微调,让网络适应高分辨率的输入。通过使用高分辨率的输入,YOLO v2的mAP提升了约4%。

采用Anchor Box

anchor box是通过对真实框聚类得到的,得到5种不同大小的anchor box。

anchor box只有w和h,没有中心点。

尺寸聚类

聚类的目的是为了提高选取的Anchor Box和同一个聚类下的gt框之间的IOU,采用的距离公式如下:

[公式]

  • centroid为聚类时被选作中心的bounding box
  • box为其他的bounding box

  • 对box进行K-means的步骤为:

    1. 随机选取K个box作为初始anchor;
    2. 使用IOU度量,将每个box分配给与其距离最近的anchor;
    3. 计算每个簇中所有box宽和高的均值,更新anchor;
    4. 重复2、3步,直到anchor不再变化,或者达到了最大迭代次数。

直接位置预测

img

tx,ty,tw,th是预测值,cx和cy是grid cell左上角位置,pw和ph是anchor box的值,通过计算即可得到预测框在特征图上的位置,从而得到在原图的位置;

t0是预测值,进行σ变换后作为置信度的值。

注:用IOU最大的去进行回归,Pr(object)的值是1,其余是0;

网络结构

YOLOv2采用了一个新的特征提取主干 Darknet-19,包括19个卷积层,5个maxpooling层;

特征融合

YOLO v1和YOLO v2输出对比

YOLOv2的输出是一个13 13 125的一个张量。

多尺度训练

训练尺度的大小必须为32的倍数,最小320,最大640;

使用多尺度训练时,然后只需要修改对最后检测层的处理就可以重新训练。

anchor box和bounding box的区别

  • anchor box是静止的框,随着神经网络的训练是不变的;
  • anchor box只有宽高,不需要中心点(也可以理解为中心点为grid cell左上角坐标)
  • bounding box是动态的框,它是根据预测值偏移量(tx,ty,tw,th)和anchor box生成的;
  • 在这里计算的是bounding box与GroundTruth之间的误差;
  • 若设GroundTruth在anchor box的偏移量为(dx,dy,dw,dh),那么误差为(tx,ty,tw,th)与(dx,dy,dw,dh)的误差;
  • 详细看YOLO v2和V3 关于设置生成anchorbox,Boundingbox边框回归的个人理解

训练阶段

  • 第一阶段:就是先在ImageNet分类数据集上预训练Darknet-19,此时模型输入为 224*224 ,共训练160个epochs;
  • 第二阶段:将网络的输入调整为 448*448 ,继续在ImageNet数据集上finetune分类模型,训练10个epochs,此时分类模型的top-1准确度为76.5%,而top-5准确度为93.3%;
  • 第三个阶段:修改Darknet-19分类模型为检测模型,移除最后一个卷积层、global avgpooling层以及softmax层,并且新增了三个 331024卷积层,同时增加了一个passthrough层,最后使用 11 卷积层输出预测结果,输出的channels数为:**num_anchors\(5+num_classes)** ,和训练采用的数据集有关系。由于anchors数为5,对于VOC数据集(20种分类对象)输出的channels数就是125。

损失函数