首页 > 解决方案 > 根据所选参数记忆函数结果

问题描述

我有一个具有以下签名的函数:

def spectrogram(signal: numpy.ndarray, sampling_frequency=16000, win_len=512, hop=256, win_type='hanning')

该函数在输入(信号)上需要一个 numpy 数组,加上其他参数的数量,并输出一个 numpy 数组。它计算给定音频文件的频谱图以获得某些声学特征。对于每个文件,我将多次调用此函数,通常使用相同的参数,但并非总是如此。对于某些功能,我可能会更改hopor win_type。我正在考虑缓存结果,这样我就不会多次运行相同的计算。结果对每个文件有效。这些文件将与 joblib 并行处理。

我正在考虑根据文件名(这不是我通常在函数上使用的参数)和字段、、和sampling_frequencywin_len即NOT - 这可能是一个大数组并且它更有效)来记忆结果查看文件名,这是唯一的)。hopwin_typesignal

我怎样才能最好地记住结果?我见过的所有解决方案都根据提供的输入缓存结果;就我而言,我想根据选定的字段进行记忆。我在 Python 3.6 上。

标签: pythonnumpycachingmultiprocessing

解决方案


我决定通过添加两个元素来发布基于@Ethan 答案(+1 票)的我自己的答案:

  1. 缓存的边界。这是我的先决条件之一,这也是我无法接受 Ethan 回答的原因。后者是无限的,会很快耗尽我的记忆。

  2. 我觉得它更优雅;它使用了一个装饰器和一个为缓存而设计的模块(并捕获一些极端情况)。它更可重用,因此对其他人更友好。

from cachetools.keys import hashkey
from cachetools import cached, LRUCache

def mykey(signal, *args, **kwargs):
    key = hashkey(*args, **kwargs)
    return key

@cached(LRUCache(maxsize=6), key=mykey)
def spectrogram(signal: numpy.ndarray, filename, sampling_frequency=16000, win_len=512, hop=256, win_type='hanning')

本质上,我只是忽略了signal,而是将filename其作为缓存的额外参数。在某些情况下,甚至filename不需要。如果每个文件生成一个单独的进程,则不需要这种保护措施,因为无论如何进程之间都无法共享缓存。

奖金

我还决定尝试Memory使用 joblib,它也表现良好。这是一个片段:

from joblib import Memory

memory = Memory('cachedir', verbose=0, bytes_limit=100000)

@memory.cache
def spectrogram(signal: numpy.ndarray, sampling_frequency=16000, win_len=512, hop=256, win_type='hanning')

它的性能平均比第一个解决方案差 25%,因为:

  • 它写入磁盘
  • 它计算一个完整的哈希numpy.ndarray

考虑到上述情况,它仍然是一个很好的分数。


推荐阅读