!转载请注明原文地址!——东方旅行者
更多行人重识别文章移步我的专栏:行人重识别专栏
本文目录
- distance.py
- 一、distance.py作用
- 二、distance.py编写思路
- 三、代码
distance.py
一、distance.py作用
本文件用于计算局部特征距离矩阵,使用局部对齐最小距离算法或直接返回原始距离(欧氏距离或余弦距离)矩阵。
二、distance.py编写思路
主函数low_memory_local_dist,将输入特征张量x,y进行分块(分而治之思想),防止大量数据溢入内存,并调用low_memory_matrix_op计算局部特征距离矩阵。输入query集或gallery集局部特征张量x、query集或gallery集局部向量特征张量y、是否使用局部对齐最小距离算法bool类型变量aligned默认为True。输出局部特征距离矩阵dismat。
函数low_memory_matrix_op根据x_split_axis, y_split_axis, x_num_splits, y_num_splits四个参数对张量x,y进行分块,然后对每一个分块使用指定的函数func计算距离矩阵,然后将距离矩阵进行横向、纵向拼接,得到总的距离矩阵并返回。输入形成距离矩阵的函数func、query集或gallery集局部特征张量x、query集或gallery集局部向量特征张量y、张量x的分块的轴x_split_axis、张量y的分块的轴y_split_axis、张量x的分块数量x_num_splits、张量y的分块数量y_num_splits、是否使用局部对齐最小距离算法bool类型变量aligned,默认为True。输出距离矩阵mat。
函数local_dist根据张量x,y的维度分别使用不同的函数进行距离矩阵计算。输入query集或gallery集局部特征张量x、query集或gallery集局部向量特征张量y、是否使用局部对齐最小距离算法bool类型变量aligned。输出距离矩阵计算函数返回值。
函数meta_local_dist根据张量x,y先计算原始距离矩阵然后对距离矩阵进行处理(可以选用局部对齐最小距离算法也可以不用)得到结果距离矩阵。输入query集或gallery集局部特征张量x、query集或gallery集局部向量特征张量y、是否使用局部对齐最小距离算法bool类型变量aligned。输出距离矩阵。
函数parallel_local_dist根据张量x,y先计算原始距离矩阵然后对距离矩阵进行处理(可以选用局部对齐最小距离算法也可以不用)得到结果距离矩阵。输入query集或gallery集局部特征张量x、query集或gallery集局部向量特征张量y、是否使用局部对齐最小距离算法bool类型变量aligned。输出距离矩阵。
函数compute_dist用于计算两矩阵的欧氏距离或余弦距离。输入矩阵1array1,规模[m1, n]、矩阵2array2,规模[m2, n]、距离的类型type,可选’cosine’或’euclidean’。输出距离矩阵dist,规模[m1, m2]。
函数normalize用于辅助计算矩阵余弦距离。
函数shortest_dist使用局部对齐最小距离算法计算结果距离矩阵。输入距离矩阵dist_mat,该距离要么是欧氏距离,要么是余弦距离,dist_mat有如下可能的维度1) [m, n]、2) [m, n, N], N是batch_size、3) [m, n, *], *代表增加的维度。输出距离矩阵dist,对应上面的三种情况1) 标量、2) 矩阵,规模为[N]、3) 矩阵,规模为[*]。
函数unaligned_dist直接根据原始距离矩阵返回结果距离矩阵。输入距离矩阵dist_mat,该距离要么是欧氏距离,要么是余弦距离,dist_mat有如下可能的维度1) [m, n]、2) [m, n, N], N是batch_size、3) [m, n, *], *代表增加的维度。输出距离矩阵dist,对应上面的三种情况1) 标量、2) 矩阵,规模为[N]、 3) 矩阵,规模为[*]。
三、代码
import numpy as np
"""
本文件用于计算局部特征距离矩阵,使用局部对齐最小距离算法
"""
def low_memory_local_dist(x, y, aligned=True):
"""
主函数low_memory_local_dist,将输入特征张量x,y进行分块(分而治之思想),防止大量数据溢入内存,并调用low_memory_matrix_op计算局部特征距离矩阵
输入:
1.query集或gallery集局部特征张量x
2.query集或gallery集局部向量特征张量y
3.是否使用局部对齐最小距离算法bool类型变量aligned默认为True
输出:
1.局部特征距离矩阵dismat
"""
print('Computing local distance...')
x_num_splits = int(len(x) / 200) + 1#计算张量x的分块数量
y_num_splits = int(len(y) / 200) + 1#计算张量y的分块数量
#若下函数运行过程爆出内存溢出,则增加x_num_splits与y_num_splits
dismat = low_memory_matrix_op(local_dist, x, y, 0, 0, x_num_splits, y_num_splits, aligned=aligned)#默认在0轴上分块,按行分块即若干行一块
return dismat
def low_memory_matrix_op(func, x, y, x_split_axis, y_split_axis, x_num_splits, y_num_splits, aligned=True):
"""
函数low_memory_matrix_op根据x_split_axis, y_split_axis, x_num_splits, y_num_splits四个参数对张量x,y进行分块,
然后对每一个分块使用指定的函数func计算距离矩阵,然后将距离矩阵进行横向、纵向拼接,得到总的距离矩阵并返回
输入:
1.形成距离矩阵的函数func
2.query集或gallery集局部特征张量x
3.query集或gallery集局部向量特征张量y
4.张量x的分块的轴x_split_axis
5.张量y的分块的轴y_split_axis
6.张量x的分块数量x_num_splits
7.张量y的分块数量y_num_splits
8.是否使用局部对齐最小距离算法bool类型变量aligned,默认为True
输出:
1.距离矩阵mat
"""
#存储结果的矩阵mat,因为是按行分块,所以第一维为空,第二维为x的分块数量
mat = [[] for _ in range(x_num_splits)]
#对于分块的每一部分
for i, part_x in enumerate(np.array_split(x, x_num_splits, axis=x_split_axis)):
for j, part_y in enumerate(np.array_split(y, y_num_splits, axis=y_split_axis)):
part_mat = func(part_x, part_y, aligned)#调用func函数计算该分块的距离矩阵
mat[i].append(part_mat)#将分块计算所得距离矩阵加入结果中
mat[i] = np.concatenate(mat[i], axis=1)#在1轴上进行数组水平拼接(横向拼接)
mat = np.concatenate(mat, axis=0)#在0轴上进行数组垂直拼接(纵向拼接)
#返回计算完毕的距离矩阵
return mat
def local_dist(x, y, aligned):
"""
函数local_dist根据张量x,y的维度分别使用不同的函数进行距离矩阵计算
输入:
1.query集或gallery集局部特征张量x
2.query集或gallery集局部向量特征张量y
3.是否使用局部对齐最小距离算法bool类型变量aligned
输出:
1.距离矩阵计算函数返回值
"""
#若张量x,y都是二维
if (x.ndim == 2) and (y.ndim == 2):
return meta_local_dist(x, y, aligned)
#若张量x,y都是三维
elif (x.ndim == 3) and (y.ndim == 3):
return parallel_local_dist(x, y, aligned)
#否则报错,输入规模不支持
else:
raise NotImplementedError('输入规模不支持距离矩阵计算.')
def meta_local_dist(x, y, aligned):
"""
函数meta_local_dist根据张量x,y先计算原始距离矩阵然后对距离矩阵进行处理(可以选用局部对齐最小距离算法也可以不用)得到结果距离矩阵
输入:
1.query集或gallery集局部特征张量x
2.query集或gallery集局部向量特征张量y
3.是否使用局部对齐最小距离算法bool类型变量aligned
输出:
1.距离矩阵
"""
#先计算欧氏距离的距离矩阵
eu_dist = compute_dist(x, y, 'euclidean')
#对距离矩阵进行归一化
dist_mat = (np.exp(eu_dist) - 1.) / (np.exp(eu_dist) + 1.)
#如果声明使用局部对齐最小距离算法,则使用shortest_dist函数
if aligned:
dist = shortest_dist(dist_mat[np.newaxis])[0]
#如果声明不使用局部对齐最小距离算法,则使用unaligned_dist函数
else:
dist = unaligned_dist(dist_mat[np.newaxis])[0]
return dist
def parallel_local_dist(x, y, aligned):
"""
函数parallel_local_dist根据张量x,y先计算原始距离矩阵然后对距离矩阵进行处理(可以选用局部对齐最小距离算法也可以不用)得到结果距离矩阵
输入:
1.query集或gallery集局部特征张量x
2.query集或gallery集局部向量特征张量y
3.是否使用局部对齐最小距离算法bool类型变量aligned
输出:
1.距离矩阵
"""
#获取张量x,y的规模
M, m, d = x.shape
N, n, d = y.shape
#改变张量x,y的规模,将其变成2维
x = x.reshape([M * m, d])
y = y.reshape([N * n, d])
#距离矩阵[M × m,N × n]
#先计算欧氏距离的距离矩阵
dist_mat = compute_dist(x, y, type='euclidean')
#对距离矩阵进行归一化
dist_mat = (np.exp(dist_mat) - 1.) / (np.exp(dist_mat) + 1.)
#将距离矩阵规模从[M × m,N × n]变为[M, m, N, n]再变为[m, n, M, N]
dist_mat = dist_mat.reshape([M, m, N, n]).transpose([1, 3, 0, 2])
#如果声明使用局部对齐最小距离算法,则使用shortest_dist函数
if aligned:
dist_mat = shortest_dist(dist_mat)
#如果声明不使用局部对齐最小距离算法,则使用unaligned_dist函数
else:
dist_mat = unaligned_dist(dist_mat)
return dist_mat
def compute_dist(array1, array2, type='euclidean'):
"""
函数compute_dist用于计算两矩阵的欧氏距离或余弦距离
输入:
1.矩阵1array1,规模[m1, n]
2.矩阵2array2,规模[m2, n]
3.距离的类型type,可选'cosine'或'euclidean'
输出:
1.距离矩阵dist,规模[m1, m2]
"""
assert type in ['cosine', 'euclidean']
#如果指定type == 'cosine',则计算余弦距离
if type == 'cosine':
array1 = normalize(array1, axis=1)#分步计算余弦距离
array2 = normalize(array2, axis=1)#分步计算余弦距离
dist = np.matmul(array1, array2.T)#矩阵相乘
return dist
#如果指定type == 'euclidean',则计算欧氏距离
else:
#矩阵A,B欧氏距离等于√(A^2 + (B^T)^2 - 2A(B^T))
#计算A^2
square1 = np.sum(np.square(array1), axis=1)[..., np.newaxis]
#计算(B^T)^2
square2 = np.sum(np.square(array2), axis=1)[np.newaxis, ...]
#计算A^2 + (B^T)^2- 2A(B^T)
squared_dist = - 2 * np.matmul(array1, array2.T) + square1 + square2
#将矩阵中负数置为0
squared_dist[squared_dist < 0] = 0
#计算√(A^2 + (B^T)^2 - 2A(B^T))
dist = np.sqrt(squared_dist)
return dist
def normalize(nparray, order=2, axis=0):
"""
函数normalize用于辅助计算矩阵余弦距离
"""
#求矩阵的范数,默认order=2, axis=0求整个矩阵的2范数
norm = np.linalg.norm(nparray, ord=order, axis=axis, keepdims=True)
return nparray / (norm + np.finfo(np.float32).eps)
def shortest_dist(dist_mat):
"""
函数shortest_dist使用局部对齐最小距离算法计算结果距离矩阵
输入:
1.距离矩阵dist_mat,该距离要么是欧氏距离,要么是余弦距离
dist_mat有如下可能的维度:
1) [m, n]
2) [m, n, N], N是batch_size
3) [m, n, *], *代表增加的维度
输出:
1.距离矩阵dist
对应上面的三种情况:
1) 标量
2) 矩阵,规模为[N]
3) 矩阵,规模为[*]
"""
#获取矩阵前两维的数值
m, n = dist_mat.shape[:2]
#局部对齐最小距离算法
dist = np.zeros_like(dist_mat)
for i in range(m):
for j in range(n):
if (i == 0) and (j == 0):#初始化边界
dist[i, j] = dist_mat[i, j]
elif (i == 0) and (j > 0):#当i为0时,最小距离只有一种,该种情况属于距离矩阵边界
dist[i, j] = dist[i, j - 1] + dist_mat[i, j]
elif (i > 0) and (j == 0):#当j为0时,最小距离只有一种,该种情况属于距离矩阵边界
dist[i, j] = dist[i - 1, j] + dist_mat[i, j]
else:#在位于距离矩阵内部时,可以选择从上方或从左侧的距离,所以选取其中更小的距离
dist[i, j] =np.min(np.stack([dist[i - 1, j], dist[i, j - 1]], axis=0), axis=0)+dist_mat[i, j]
dist = dist[-1, -1].copy()#最后返回距离矩阵右下角元素,即为两局部特征张量的局部对齐最小距离
return dist
def unaligned_dist(dist_mat):
"""
函数unaligned_dist直接根据原始距离矩阵返回结果距离矩阵
输入:
1.距离矩阵dist_mat,该距离要么是欧氏距离,要么是余弦距离
dist_mat有如下可能的维度:
1) [m, n]
2) [m, n, N], N是batch_size
3) [m, n, *], *代表增加的维度
输出:
1.距离矩阵dist
对应上面的三种情况:
1) 标量
2) 矩阵,规模为[N]
3) 矩阵,规模为[*]
"""
#获取矩阵第一维的数值
m = dist_mat.shape[0]
dist = np.zeros_like(dist_mat[0])
for i in range(m):
dist[i] = dist_mat[i][i]#不做任何处理,直接返回计算得到的原始距离
dist = np.sum(dist, axis=0).copy()#只是将局部特征的距离进行线性加和,没有使用局部对齐最小距离算法
return dist
评论(0)
您还未登录,请登录后发表或查看评论