如何在不完全重构代码时避免多尺度检测中的重复计算
问题分析与优化方案
你当前的核心问题是:在MultiscaleDetector遍历不同空间尺度sigma时,每次调用GaborDetector都会重复计算仅依赖时间参数tau的Gabor时间滤波器(h_ev和h_od),而之前尝试的lambda包装、内部函数加lru_cache都没起到有效优化作用——前者只是参数包装,根本没减少重复计算;后者因为内部函数每次调用GaborDetector都会被重新定义,导致缓存无法跨调用共享,等于没生效。
以下是两种无需大规模重构代码的优化方案:
方案一:将tau相关计算抽为独立的缓存函数
把仅依赖tau的滤波器计算逻辑移到GaborDetector外部,作为带lru_cache的独立函数,这样所有GaborDetector调用都会共享同一个缓存池,同一个tau值只会计算一次。
from functools import lru_cache import numpy as np import scipy.signal as scp # 独立的缓存函数,所有GaborDetector调用共享缓存 @lru_cache(maxsize=None) def compute_gabor_time_filters(tau): time = np.linspace(-2*tau, 2*tau, int(4*tau+1)) omega = 4/tau h_ev = np.exp(-time**2/(2*tau**2)) * np.cos(2*np.pi*omega*time) h_od = np.exp(-time**2/(2*tau**2)) * np.sin(2*np.pi*omega*time) h_ev /= np.linalg.norm(h_ev, ord=1) h_od /= np.linalg.norm(h_od, ord=1) return h_ev, h_od def GaborDetector(v, sigma, tau, threshold, num_points): """ Gabor Detector Keyword arguments: video -- input video (y_len, x_len, frames) sigma -- Gaussian kernel space standard deviation tau -- Gaussian kernel time standard deviation threshold -- Gabor response threshold """ # setup video video = v.copy() video = video.astype(float)/video.max() video = video_smoothen_space(video, sigma) # 直接调用缓存好的滤波器,避免重复计算 h_ev, h_od = compute_gabor_time_filters(tau) # compute the response response = (scp.convolve1d(video, h_ev, axis=2) ** 2) + (scp.convolve1d(video, h_od, axis=2) ** 2) points = interest_points(response, num=num_points, threshold=threshold, scale=sigma) return points
方案二:在MultiscaleDetector中预计算tau相关结果并传入
如果不想修改GaborDetector的核心逻辑结构,可以给它加一个可选参数,允许传入预先计算好的滤波器,然后在MultiscaleDetector中仅计算一次tau相关的滤波器,再在循环中复用。
修改后的GaborDetector
def GaborDetector(v, sigma, tau, threshold, num_points, precomputed_filters=None): """ Gabor Detector Keyword arguments: video -- input video (y_len, x_len, frames) sigma -- Gaussian kernel space standard deviation tau -- Gaussian kernel time standard deviation threshold -- Gabor response threshold precomputed_filters -- tuple of (h_ev, h_od), 若传入则跳过滤波器计算 """ # setup video video = v.copy() video = video.astype(float)/video.max() video = video_smoothen_space(video, sigma) # 优先使用预计算的滤波器 if precomputed_filters is not None: h_ev, h_od = precomputed_filters else: # 原有的滤波器计算逻辑,兼容未传参的场景 time = np.linspace(-2*tau, 2*tau, int(4*tau+1)) omega = 4/tau h_ev = np.exp(-time**2/(2*tau**2)) * np.cos(2*np.pi*omega*time) h_od = np.exp(-time**2/(2*tau**2)) * np.sin(2*np.pi*omega*time) h_ev /= np.linalg.norm(h_ev, ord=1) h_od /= np.linalg.norm(h_od, ord=1) # compute the response response = (scp.convolve1d(video, h_ev, axis=2) ** 2) + (scp.convolve1d(video, h_od, axis=2) ** 2) points = interest_points(response, num=num_points, threshold=threshold, scale=sigma) return points
修改后的MultiscaleDetector
def MultiscaleDetector(detector, video, sigmas, tau, num_points, threshold): """ Multiscale Detector Executes a detector at multiple scales. Detector has to be a function that takes a video as input, along with other parameters, and returns a list of interest points. Keyword arguments: detector -- function that returns interest points video -- input video (y_len, x_len, frames) sigmas -- list of scales """ # 预先计算一次tau相关的滤波器,循环中复用 time = np.linspace(-2*tau, 2*tau, int(4*tau+1)) omega = 4/tau h_ev = np.exp(-time**2/(2*tau**2)) * np.cos(2*np.pi*omega*time) h_od = np.exp(-time**2/(2*tau**2)) * np.sin(2*np.pi*omega*time) h_ev /= np.linalg.norm(h_ev, ord=1) h_od /= np.linalg.norm(h_od, ord=1) precomputed_filters = (h_ev, h_od) # 遍历尺度,传入预计算的滤波器 points = [] for sigm in sigmas: found = detector(video, sigm, tau, threshold, num_points, precomputed_filters=precomputed_filters) points.append(found) # filter the points, currently irrelevant return points
内容的提问来源于stack exchange,提问作者Stefanos Anagnostou
相关产品推荐
相关产品推荐

