基于广播机制计算图像数据集欧氏距离矩阵的问题咨询
单循环实现图像数据集欧氏距离矩阵的问题修复
你的单循环代码出错的核心原因是求和维度未正确指定:
- 朴素实现中,每次计算单个train样本与单个test样本的距离时,是对该样本的所有通道、像素维度求和;
- 但你当前的单循环代码里,
np.sum((x_test - x_train[i])**2)会把广播后所有元素的平方和加总为一个标量,而非对每个test样本单独求和,导致结果完全不符合预期。
修正后的单循环代码
import numpy as np num_train = 5 num_test = 5 x_train = np.random.random((5, 3, 10, 10)) x_test = np.random.random((5, 3, 10, 10)) dists = np.zeros((num_train, num_test)) # 单循环实现:指定求和维度为通道、高、宽 for i in range(num_train): squared_diff = (x_test - x_train[i]) ** 2 # 对每个test样本的(3,10,10)维度求和,得到长度为num_test的数组 sum_squared = np.sum(squared_diff, axis=(1, 2, 3)) dists[i] = np.sqrt(sum_squared)
验证正确性
可以和你的朴素实现对比结果,确认误差在浮点精度范围内:
# 朴素实现(用于对比) dists_naive = np.zeros((num_train, num_test)) for i in range(num_train): for j in range(num_test): dists_naive[i][j] = float(np.sum((np.array(x_train[i]) - np.array(x_test[j]))**2))**0.5 # 输出差值最大值(应接近0,如1e-16级别) print(np.max(np.abs(dists - dists_naive)))
进阶:完全无循环的广播实现
如果想彻底利用numpy广播特性,还可以去掉所有循环,直接通过维度扩展实现:
# 扩展维度让两个数组可以广播:(5,1,3,10,10) 和 (1,5,3,10,10) x_train_expanded = x_train[:, np.newaxis, :, :, :] x_test_expanded = x_test[np.newaxis, :, :, :, :] squared_diff = (x_train_expanded - x_test_expanded) ** 2 # 对通道、高、宽维度求和,得到(5,5)的距离矩阵 dists_no_loop = np.sqrt(np.sum(squared_diff, axis=(2, 3, 4)))
内容的提问来源于stack exchange,提问作者wooluk
相关产品推荐
相关产品推荐

