SVD MemoryError в Python

Я хочу выполнить SVD на большом массиве M[159459,159459].

Поскольку вычисление SVD зависит от входной матрицы формы (159459,159459), это здесь не соответствует моей цели.

Я пытался использовать:

  • scipy.linalg.svd
  • scipy.linalg.svd(check_finite=False)
  • поменяй драйвер на lapack_driver='gesvd
  • numpy.linalg.svd

Однако я всегда получаю MemoryError. Наконец, я хочу вычислить полный SVD, потому что я хочу выполнить анализ Procrustes, т.е. если M — это матрица, которая у меня есть сейчас, мне нужно M = USV'

import numpy as np
from scipy import linalg

#M = np.load("M.npy")
M = np.random.rand(159459,159459)
U, s, Vh = linalg.svd(M, check_finite=False, lapack_driver='gesvd)

Все терпит неудачу.

Детали моей системы:

$ cat /proc/meminfo
MemTotal: 527842404 kB
MemFree: 523406068 kB
MemAvailable: 521659112 kB


person seralouk    schedule 06.07.2019    source источник
comment
Помогает ли использование mmaps NumPy вместо загрузки ввод в память? (Если вы еще этого не сделали, но я не уверен, сколько вычислений не на месте происходит в SVD). Конечно, при использовании mmap следует ожидать значительно большего времени вычислений.   -  person norok2    schedule 06.07.2019
comment
Я не пробовал это. Я это проверю   -  person seralouk    schedule 06.07.2019
comment
Небольшую приблизительную матрицу Прокруста можно найти в TruncatedSVD в scikit-учиться; начните с n_components=1000 или около того.   -  person denis    schedule 26.11.2019


Ответы (1)


Размер памяти имеет значение, затраты на задержку повредят вам следующим:

Учитывая mM.shape == [159459, 159459],
данное mM.dtype по умолчанию равно float(64)
потребуется около:
203.42 [GB] для оригинала mM[159459, 159459], плюс
203.42 [GB] для вычисляемого mU[159459, 159459], плюс
203.42 [GB] для вычисляемого Vh[159459, 159459]< /strong>
0.0013 [GB] для вычисляемого vS[159459]

Самый дешевый шаг, попытка линейного уменьшения масштаба в 2 (и не более 4) раза с float64 до float32 или даже float16 не меняет правила игры и даже сильно наказывается numpy неэффективностью (если не выполняется внутренне обратно -преобразования до float64 снова - мои собственные попытки были настолько кровоточащими в этом, что я делюсь полученным недовольством здесь, чтобы не повторять свои собственные ошибки при попытке начать с самого низкого висящего фрукта в первую очередь ... )

В случае, если ваш анализ может работать только с вектором vS, только флаг .svd( ..., compute_uv = False, ... ) позволит избежать создания пространства для примерно ~ 1/2 [TB] распределения ОЗУ, не возвращая ( и, следовательно, не резервируя пространство для них ) экземпляры mU и Vh.

Даже такой случай не означает, что ваш SLOC выживет, как в почти заявленной 0.5 TB RAM-системе. Обработка scipy.linalg.svd() будет выделять внутренние рабочие ресурсы, которые находятся за пределами вашей области кодирования (конечно, если вы не рефакторите и не перепроектируете модуль scipy.linalg самостоятельно, что справедливо считать очень вероятным, если не уверенным) и контроль конфигурации . Итак, имейте в виду, что даже когда вы тестируете compute_uv = False-режим обработки, .svd() все равно может выдать ошибку, если ему не удастся внутренне выделить необходимые внутренне используемые структуры данных, которые не соответствуют текущей оперативной памяти.

Это также означает, что даже использование numpy.memmap(), которое может быть успешным приемом для разгрузки представления исходного mM в оперативной памяти (избегая какой-то замечательной части первого требуется 203.4 [GB] от сидения и блокировки использования оперативной памяти хоста), но за использование этого трюка вам придется заплатить.

Мои эксперименты в меньших масштабах .memmap, используемых для матричной обработки и оптимизации машинного обучения, приводят к 1E4 ~ 1E6 более медленной обработке, потому что, несмотря на интеллектуальное кэширование, numpy.memmap()-экземпляры зависят от дисковый ввод-вывод.

Наилучший результат дает использование передовых устройств хранения данных размером TB, состоящих только из твердотельных накопителей, размещенных непосредственно на вычислительном устройстве на какой-либо быстрой шине доступа с малой задержкой M.2 или PCIx16.

Последний опыт, который, возможно, пока не хочется здесь слышать:

Использование большей оперативной памяти на хосте, что означает использование вычислительного устройства на несколько ТБ, — это самый безопасный способ пойти дальше. Тестирование предложенных выше шагов поможет, если снижение производительности и дополнительные расходы не выходят за рамки бюджета вашего проекта. Если нет, воспользуйтесь центром высокопроизводительных вычислений в своей альма-матер или в ближайшем исследовательском центре вашего проекта, где такие вычислительные устройства с несколькими терабайтами используются обычно.

person user3666197    schedule 06.07.2019
comment
Спасибо за ваш ответ. Так что простого и прямого пути пока нет. Мне нужно вычислить U и V, а не только S, поэтому .svd( ..., compute_uv = False) не применимо к моему случаю. - person seralouk; 06.07.2019
comment
Всегда добро пожаловать @serafeim Для этого есть устройства с несколькими ТБ, обратитесь к коллегам по проекту за соответствующими ресурсами HPC. - person user3666197; 06.07.2019