Когда мы говорим про длительные вычисления, всегда заходит речь о кешировании результатов выполнения.
И лучшим решением является сохранение кэша не в оперативной памяти (как это делает
functools.lru_cache), а запись на диск с помощью joblib.Memory.Итак,
joblib.Memory - декоратор, который оборачивает функцию, сохраняя кэш напрямую на диск. При вызове декоратор хэширует аргументы функции и проверяет, есть ли результат для хэша на диске. Если есть, то моментально загружает с диска и возвращает результат. В противном случае декоратор сохраняет результат на диск и возвращает результат.
Разберем на примере:
🔸Создаем объект памяти, куда будем сохранять наш кэш. За путь к кэшу отвечает атрибут
locationfrom joblib import Memory
import time
import numpy as np
memory = Memory(location='./cache_store', verbose=0)
🔸Декорирование функции происходит с помощью декоратора
@memory.cache. Для примера обернем очень "тяжелую" функцию, которая спит 10 секунд.@memory.cache
def foo(x, y):
time.sleep(10)
return x**2 + y**2
🔸Запустим тест 1 раз
x,y = np.ones((1000, 1)), np.ones((1000, 1))
res1 = foo(x,y)
🔸Код будет исполняться 10 секунд. Второй запуск уже будет использовать результаты кеширования:
x,y = np.ones((1000, 1)), np.ones((1000, 1))
res2 = foo(x,y)
🔸Код будет только разгружать уже предварительно рассчитанный результат работы модели.
✔️В качестве дополнительных техник можно использовать сжатие с помощью
compress, задавая параметр от 1 до 9, который держит баланс между скоростью чтения и размером.memory = Memory(location='./.cache_store', verbose=0, compress=3)
✔️Также, часто мы передаем в функцию аргументы, которые не влияют на результат вычислений, но меняют хеш. Например, флаг
verbose или количество потоков n_jobs. Если ты изменишь verbose=True на verbose=False, joblib подумает, что аргументы изменились, и пересчитает всё заново. Это нам не надо.Например для какой-то функции
process_data@memory.cache(ignore=['verbose', 'n_jobs'])
def process_data(data, param=1, verbose=False, n_jobs=4):
...
Однако, есть и неприятные эффекты.
❌Например, если внутри функции есть np.random без фиксации сида, кэширование "заморозит" первое случайное значение навсегда. Это может убить эксперимент.
Кэш можно удалить классическим
rm -rf, либо программно memory.clear(warn=False)По традиции, ставь 🔥, если понравилось!
#ds_лайфхаки
