ReID 终归还是排序问题,Rank 是排序命中率核心指标。Rank1 是首位命中率,就是排在第一位的图有没有命中他本人,Rank5 是 1-5 张图有没有至少一张命中他本人。
这里放了两组图,图片 1 和图片 2 是检索图,第一组图在底库中有 5 张图,下面有 5 个数字,我们假设它的检索位置,排在第 1 位、第 3 位、第 4 位、第 8 位,第 20 位,第二张图第 1 位、第 3 位、第 5 位。
它的 mAP 是怎么算的?对于第一张图平均精度有一个公式在下面,就是 0.63 这个位置。第一张是 1 除以 1,第二张是除以排序实际位置,2 除以 3,第三个位置是 3 除以 4,第四个是 4 除以 8,第五张图是 5 除以 20,然后把它们的值求平均,再总除以总的图片量,最后得出的 mAP 值大概是 0.63。
同样的算法,算出图片 2 的精度是 0.756。最后把所有图片的 mAP 求一个平均值,最后得到的 mAP 大概是 69.45。从这个公式可以看到,这个检索图在底库中所有的图片都会去计算 mAP,所以最好的情况是这个人在底库中所有的图片都排在前面,没有任何其他人的照片插到他前面来,就相当于同一个人所有的照片距离都是最近的,这种情况最好,这种要求是非常高的,所以 mAP 是比较能够综合体现这个模型真实水平的指标。
参考:
https://www.cnblogs.com/gmhappy/p/11864020.html
2、rankn和mAP
搜索结果中最靠前(置信度最高)的n张图有正确结果的概率。
例如: lable为m1,在100个样本中搜索。
如果识别结果是m1、m2、m3、m4、m5……,则此时rank-1的正确率为100%;rank-2的正确率也为100%;rank-5的正确率也为100%;如果识别结果是m2、m1、m3、m4、m5……,则此时rank-1的正确率为0%;rank-2的正确率为100%;rank-5的正确率也为100%;如果识别结果是m2、m3、m4、m5、m1……,则此时rank-1的正确率为0%;rank-2的正确率为
1.入门级简单使用
泡菜模块的简单使用,不止是列表对象,其他的比如字典,tuple等都可以保存为pkl文件,pkl是一种二进制文件:
>>> import pickle>>>>>> my_list=[1,2,3,'loss']>>> pickle_file=open('mylist.pkl','wb')#默认地址,在windows下应该是python解释器的位置,ubuntu则直接放在了/home/lb#>>> pickle_file=open('/home/lb/安装包/second.pkl','wb')# 也可以这样,指定文件位置>>> pickle.dump(my_list,pickle_file)>>> pickle_file.close()>>>>>> pickle_file=open('mylist.pkl','rb')>>> my_list2=pickle.load(pickle_file)>>> print(my_list2)[1, 2, 3, 'loss']>>>
2.pkl文件实际应用
一种应用主要是保存深度学习网络的模型,或者只保存其参数parameters:
(1)保存模型:
# 2 ways to save the nettorch.save(net1, 'net.pkl') # save entire nettorch.save(net1.state_dict(), 'net_params.pkl') # save only the parameters
(2)加载模型:
a)直接加载模型,缺点是占用较大空间:
net2 = torch.load('net.pkl')#然后网络net2就可以正常使用了,比如prediction = net2(x)
b)只加载网络权重参数,这种情况下,参数占用的空间比模型小,缺点就是加载时,需要自己先搭建一个跟需要加载的网络结构一样的网络,再加载网络参数:
# restore only the parameters in net1 to net3net3 = torch.nn.Sequential(torch.nn.Linear(1, 1
傅立叶级数:
任何周期函数都可以表示成为不同频率的正弦或者余弦之和的形式,每个正弦余弦的乘以不同的系数.
傅立叶变换
傅立叶变换,表示能将满足一定条件的某个函数表示成三角函数(正弦和/或余弦函数)或者它们的积分的线性组合。定义为:
性质
(1)线性性质
(2)尺度变换性质
(3)对偶性质
(4)平移性质
的傅立叶变换为:
(5)微分性质
(6)时域卷积
(7)频域卷积
(8)Parseval定理
(9)Plancherel定理
p134
在进行模拟/数字信号的转换过程中,当采样频率fs.max大于信号中最高频率fmax的2倍时(fs.max>2fmax),采样之后的数字信号完整地保留了原始信号中的信息,一般实际应用中保证采样频率为信号最高频率的2.56~4倍;采样定理又称奈奎斯特定理。
图像的频率:灰度值变化剧烈程度的指标,是灰度在平面空间上的梯度。
(1)什么是低频?
低频就是颜色缓慢地变化,也就是灰度缓慢地变化,就代表着那是连续渐变的一块区域,这部分就是低频. 对于一幅图像来说,除去高频的就是低频了,也就是边缘以内的内容为低频,而边缘内的内容就是图像的大部分信息,即图像的大致概貌和轮廓,是图像的近似信息。
(2)什么是高频?
反过来, 高频就是频率变化快.图像中什么时候灰度变化快?就是相邻区域之间灰度相差很大,这就是变化得快.图像中,一个影像与背景的边缘部位,通常会有明显的差别,也就是说变化那条边线那里,灰度变化很快,也即是变化频率高的部位.因此,图像边缘的灰度值变化快,就对应着频率高,即高频显示图像边缘。图像的细节处也是属于灰度值急剧变化的区域,正是因为灰度值的急剧变化,才会出现细节。另外噪声(即噪点)也是这样,在一个像素所在的位置,之所以是噪点,就是因为它与正常的点颜色不一样了,也就是说该像素点灰度值明显不一样了,,也就是灰度有快速地变化
#1.自建模块
创建一个文件夹,在里面放入作为模块的py文件,这个文件夹可以作为一个包
当没有__init__.py文件时,这时可以直接import 包,但是不能通过先使用 import 包名 然后再包名.模块来访问包里的模块.因为这时认为包为一个模块,而包是一个文件夹,并不是模块。
可以通过 import pack.module或者 from pack import module来导入pack文件夹(也叫做包)中的模块(py文件),或者在__init__.py文件中加载相应的模块即可(from . import test1 #test1为包中的一个py文件)
后面就是这种情况.
#2.引入包,并调用里面的模块
① import 包名.模块名
② from 包名 import * ps:此时只能使用__init__.py中__all__中允许调用的模块
③ from 包名 import 模块名
特别的,如果想导入模块中的类(或者函数,变量等),不能使用:
import pack.module.class # 会提示没有相应的pack.module.class模块
应该使用:
from pack.module import class#from pack.module import * #这种会导入module中所有的变量
总之,能直接import的是包和模块,能from ...import 的,是模块和类,变量等
#3. 包中的__init__.py文件
__init__.py控制着包的导入行为,某个文件夹放入__init__.py,说明这个文件夹是个包
① 若__init__.py为空
仅仅导入包,并不导入模块
② __init__.py中的 __all__
__all__只控制from 包名 import *中导入的模块,它不仅在第一时间展现了模块的内容大纲,而且也更清晰的提供了外部访问接口。详细参考:https://blog.csdn.net/hang916/article/details/79474821
但是,实际上只要from . import test1就可以不用管__all__.
(一)stack()
stack()实际上就是堆叠,拼接的意思,针对单个ndarray(torch.cat()函数也是拼接的意思,但是针对的两个tensor),它所做的工作就是将原来的元素,按照axis的值,取出来打包,重新堆叠形成新的ndarray,可以看下面的例子:
当执行np.stack(arrays, axis=0)时,取出第一维的1、2、3、4,打包,[1, 2, 3, 4],其余的类似,然后结果如下:
>>> arrays = [[1,2,3,4], [5,6,7,8]]>>> arrays=np.array(arrays)>>> np.stack(arrays,axis=0)array([[1, 2, 3, 4],[5, 6, 7, 8]])
当执行np.stack(arrays, axis=1)时,先对arrays中的第二维进行“打包”,也即是将1、5打包成[1, 5],其余的类似,结果如下:
>>> np.stack(arrays, axis=1)array([[1, 5],[2, 6],[3, 7],[4, 8]])
有这个“打包”的概念后,对于三维,或者更高维的数组堆叠也不难理解了.
理解stack的要点:(1)stack前后,对于堆叠的各部分来说,轴的数量相应的增加(2)特定axis轴上,索引相同的数据,打包在一起,因此在新增的特定轴上的索引数量(针对于原来stack()内的各个部分的维度来说的),也会相应的增加,如下
>>> a = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])>>> b = np.array([[4, 5, 6], [4, 5, 6], [4, 5, 6]])>>> a.shape(3, 3)>>> b.shape(3, 3)>>> np.stack((a, b), axis=0).shape #这是针对两个ndarray的情况,实际上与单个ndarray情况是一致的,单个ndarray也可以堪(2, 3, 3)>>> np.stack((a, b), axis=1
第一次:
1.编程将一幅图像降质为多个低空间分辨率的图像;
2.编程将一幅256灰度级的灰度图像分解为不同灰度的分辨率(128,64,32,16,8,4,2)的图像;
3.编程实现图像差分,多幅图像相加去噪.
第二次:
1.编程统计任何一副图像的直方图并显示
2.编程实现图像均衡化和图像规格化
3.编程实现图像均值滤波,中值滤波
参考资料:
https://morvanzhou.github.io/tutorials/data-manipulation/np-pd/3-1-pd-intro/
https://blog.csdn.net/xiaodongxiexie/article/details/53108959
如果用 python 的列表和字典来作比较, 那么可以说 Numpy 是列表形式的,没有数值标签,而 Pandas 就是字典形式。Pandas是基于Numpy构建的,让Numpy为中心的应用变得更加简单。
要使用pandas,首先需要了解他主要两个数据结构:Series和DataFrame
Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引。于是会自动创建一个0到N-1(N为长度)的整数型索引:
import numpy as npimport pandas as pdprint(pd.Series([1,2,np.nan,'like']))
输出:
0 11 22 NaN3 likedtype: object
DataFrame的本质是行(index)列(column)索引+多列数据.
DataFrame 是有多个列的数据表,每个列拥有一个 label,当然,DataFrame 也有索引
DataFrame是一个表格型的数据结构,它包含有一组有序的列,每列可以是不同的值类型(数值,字符串,布尔值等)。DataFrame既有行索引也有列索引, 它可以被看做由Series组成的大字典。
import numpy as npimport pandas as pd#convert string to Timestampdate=pd.date_range('20181001',end='20181006',periods=6)data=pd.DataFrame(np.random.randn(6,4),index=date,columns=['a','b','c','d'])print(data)
结果
1.前向传播
最大子采样函数取区域内所有神经元的最大值(max-pooling)。
以下图为例,输入数据为4*4,input_width=4,采样核kernel_size为2,stride为2,padding=0。输出数据大小out_width类似卷积层的计算方法如下:
前向传播中不仅要计算pool区域内的最大值,还要记录该最大值所在输入数据中的位置,目的是为了在反向传播中,需要把梯度值传到对应最大值所在的位置。
2.反向传播
还是引用上图,通过前向传播已知,梯度值对应上一层输出的最大值位置。具体过程如下:
Cross Entropy(也就是交叉熵)Loss:交叉熵损失函数,通常用于多分类,其中是one_hot标签,是softmax层的输出结果,交叉熵损失定义为:
Negative Log Liklihood(NLL) Loss:负对数似然损失函数,X是的输出,是对应的标签位置
损失函数NLLLoss() 的 输入 是一个对数概率向量和一个目标标签,并对应位置相乘相加,最后再取负(也就是说,这里的,,对于独热码来说,实际上就是取的X中,对应于label中为1的那个x). 它不会为我们计算对数概率,适合最后一层是log_softmax()(log_softmax也就是对softmax的输出取对数)的网络. 损失函数 CrossEntropyLoss() 与 NLLLoss()类似, 唯一的不同是它为我们去做 softmax并取对数.可以理解为:
CrossEntropyLoss()=log_softmax() + NLLLoss()
代码则为:
import t
python作为一个动态语言其函数的参数也很“动态”。
参数可能有的情况:必选参数、默认参数、可变参数、关键字参数、命名关键字参数
function(a,b=1,*c,**d,*,e)
就是固定的参数,函数中定义多少个参数,调用函数的时候后就传递多好个参数。
#1.正常参数def power(x,n):sum=0while(n>1):sum=sum+x*xn=n-1return sumprint(power(2,5))#输出16
首先注意:
(1)默认参数要放在最后面,不然会有误会,编译器不知道从哪个数开始算他不是默认参数
(2)默认参数必须指向不变对象
当函数中有部分参数的值在大部分时间是固定的时候,可以预先给它一个值。不用每一次都输入。当然有特殊情况的时候依然可以给它附一个新的值。
#2.默认参数def power(x,n=5):sum=0while n>1:sum=sum+x*xn=n-1return sumprint(power(2))#输出16
第1种方式:
可变的参数指的是列表(list),元组(tuple).因为其中的数据是可以改变的,将列表和元组作为参数传入函数中,所以函数的参数也是可变的。要定义可变参数,仅需在参数名之前添加一个星号(*)。在函数内部,这些参数被包装为一个 tuple
例如:power函数
使用 * 放在参数名前,作为可变参数的标志
## 3,可变参数,表示参数可以改变,比如下面的*number,相当于构成了一个tuple,这个tuple的名字是numberdef calc(*number):sum =0for n in number:print(n)print(number)return sumnumber1=[1,5,6,7]number2=[8,9,11,34]print(calc(numb