joblib и mmap: загрузить массивы модели без полной копии
Несколько локальных работников загружают одну большую модель. Если каждый читает все массивы в собственную память, запуск быстро упирается в RAM. Для подходящих массивов joblib поддерживает отображение файла в память.
Отображение работает с массивами, а не со всем объектом
joblib.load с mmap_mode="r" восстанавливает подходящие массивы как NumPy memmap. Их данные читаются из отображённого файла, и операционная система может совместно использовать страницы между процессами. Python-объекты вокруг массивов и промежуточные результаты predict при этом не становятся общими автоматически.
Файл должен быть сохранён без сжатия. Сжатый поток нельзя непосредственно отобразить как массив с нужными смещениями. Поэтому выбор между меньшим размером на диске и возможностью mmap делают на этапе dump. Режим r запрещает изменять отображённые данные через такой массив.
Проверить конкретный обученный массив
В примере LinearRegression создаёт coef_. После сохранения и загрузки проверяем его реальный тип, признак writeable и прогноз. Небольшой массив нужен, чтобы показать механизм; численного выигрыша памяти такой размер не обещает. Для вашей модели сначала проверьте, какие её части действительно стали memmap.
Создаётся только доверенный локальный артефакт. joblib использует pickle-механизм, поэтому выбирать mmap вместо обычной загрузки не значит менять требования к происхождению файла. Загружайте модель из своей контролируемой сборки в совместимом окружении.
import gc
from pathlib import Path
from tempfile import TemporaryDirectory
import joblib
import numpy as np
from sklearn.linear_model import LinearRegression
model = LinearRegression().fit([[0], [1], [2], [3]], [1, 3, 5, 7])
with TemporaryDirectory() as directory:
path = Path(directory) / "model.joblib"
joblib.dump(model, path, compress=0)
loaded = joblib.load(path, mmap_mode="r")
assert isinstance(loaded.coef_, np.memmap)
assert not loaded.coef_.flags.writeable
predicted = loaded.predict([[4]])[0]
assert abs(predicted - 9) < 1e-9
print(type(loaded.coef_).__name__, float(predicted))
del loaded
gc.collect()Сохранить файл на всё время работы
Отображённый массив зависит от файла. Не заменяйте содержимое артефакта на месте во время работы процессов. Для нового релиза используйте новый путь, а старый удаляйте после завершения потребителей. На Windows открытое отображение также может мешать удалению файла, поэтому в примере ссылка освобождается до очистки временного каталога.
Для реального выбора измерьте память всех работников и время первого и повторного прогноза. Отображение переносит часть расходов на чтение страниц по мере обращения. Оно не ускоряет любой алгоритм и не устраняет память, которую estimator выделяет для результата и промежуточных вычислений. Проверка должна охватывать полный рабочий запрос.
Закрепить базовую операцию
В открытом уроке сохранения через joblib вы пройдёте dump, load и прогноз восстановленной модели. Затем измените способ хранения и проверьте, какие массивы вашей модели поддерживают отображение. Откройте урок «Сохранение обученной модели через joblib». Затем вернитесь к сценарию статьи и проверьте его на своём небольшом наборе. Посмотрите программу курса первой ML-модели, чтобы пройти путь от обучения к использованию результата.
Продолжить на практике
- Машинное обучение с нуля на Python: первая модель ↗
Бесплатный курс машинного обучения на Python: обучите первую модель в scikit-learn, проверьте её качество и решите 106 задач в браузере.
