У конвейеров машинного обучения производственного уровня загрузка ЦП примерно такая же, почти 24 часа в сутки, 7 дней в неделю, 365 дней в году:
![введите описание изображения здесь](https://i.stack.imgur.com/nqJt4.png)
Проверьте показатели состояния как CPU%
, так и других ресурсов на этом узле.
В чем моя ошибка?
Прочитав ваш профиль, это был потрясающий момент, сэр:
Я ученый-компьютерщик, специализирующийся на алгоритмах и данных. анализ по обучению и универсал по натуре. Мой набор навыков сочетает сильную научную подготовку с опытом в области архитектуры программного обеспечения и разработки, особенно решений для анализа больших данных < / сильный>. Я предлагаю услуги по консультированию и развитию, и мне нужны сложные проекты в области науки о данных.
Проблема ЯВЛЯЕТСЯ глубоко детерминированной уважением к элементарным правилам алгоритмов Computer Science +.
Проблема НЕ требует сильной научной подготовки, а требует здравого смысла.
Проблема НЕ в каких-либо особенно больших данных, но требует, чтобы понюхал, как все работает на самом деле.
![введите описание изображения здесь](https://i.stack.imgur.com/viluQ.png)
Факты
или
Эмоции? ... это вопрос! (Трагедия Гамлета, принца Дании)
Могу я быть честным? Давайте всегда отдавать предпочтение ФАКТАМ:
Шаг № 1:
Никогда не нанимайте и не увольняйте всех и каждого Консультанта, который не уважает факты (ответ, упомянутый выше, ничего не подсказывает, тем меньше обещает). Игнорирование фактов может быть "грехом успеха" в PR / MARCOM / рекламе / медиа-бизнесе (в случае, если Заказчик терпит такую нечестность и / или привычку манипулировать), но не в научно справедливые количественные области. Это непростительно.
Шаг № 2:
Никогда не нанимайте и не увольняйте каждого консультанта, заявившего, что у него есть опыт в архитектуре программного обеспечения, особенно в решениях для ... больших данных em >, но не обращает внимания на совокупную сумму всех дополнительных накладных расходов, которые будут вноситься каждым из соответствующих элементов системной архитектуры, как только обработка начинает распределяться по некоторому пулу оборудования. и программные ресурсы. Это непростительно.
Шаг № 3:
Никогда не нанимайте и не увольняйте каждого консультанта, который становится пассивно-агрессивным, когда факты не соответствуют его / его желаниям, и начинает обвинять другого знающего человека, который уже оказал помощь. рука скорее "улучшить (свои) коммуникативные навыки" вместо того, чтобы учиться на ошибках. Конечно, умение может помочь выразить очевидные ошибки каким-либо другим способом, но гигантские ошибки останутся гигантскими ошибками, и каждый ученый, честно признавая свое научное звание, должен НИКОГДА прибегать к нападайте на помощника коллеги, а лучше начните искать причину ошибок, одну за другой. Этот ---
@sascha ... Могу я предложить вам сделать небольшой перерыв в stackoverflow, чтобы остыть, поработать немного над межличностным коммуникативные навыки
--- был не чем иным, как прямым и интеллектуально неприемлемым неприятным фолом для @sascha.
Далее, игрушки
Важные факты об архитектуре, ресурсах и планировании процессов:
Императивная форма синтаксического конструктора запускает огромное количество действий:
joblib.Parallel( n_jobs = <N> )( joblib.delayed( <aFunction> )
( <anOrderedSetOfFunParameters> )
for ( <anOrderedSetOfIteratorParams> )
in <anIterator>
)
Чтобы хотя бы догадаться, что происходит, научно справедливый подход заключался бы в тестировании нескольких репрезентативных случаев, сравнительном анализе их фактического выполнения, сборе количественно подтвержденных фактов и построении гипотезы о модели поведения и ее основных зависимостях от CPU_core-count, от размера RAM. , по <aFunction>
-сложности и конвертам распределения ресурсов и т. д.
Тестовый пример A:
def a_NOP_FUN( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is indeed to do nothing at all,
so as to be able to benchmark
all the process-instantiation
add-on overhead costs.
"""
pass
##############################################################
### A NAIVE TEST BENCH
##############################################################
from zmq import Stopwatch; aClk = Stopwatch()
JOBS_TO_SPAWN = 4 # TUNE: 1, 2, 4, 5, 10, ..
RUNS_TO_RUN = 10 # TUNE: 10, 20, 50, 100, 200, 500, 1000, ..
try:
aClk.start()
joblib.Parallel( n_jobs = JOBS_TO_SPAWN
)( joblib.delayed( a_NOP_FUN )
( aSoFunPAR )
for ( aSoFunPAR )
in range( RUNS_TO_RUN )
)
except:
pass
finally:
try:
_ = aClk.stop()
except:
_ = -1
pass
print( "CLK:: {0:_>24d} [us] @{1: >3d} run{2: >5d} RUNS".format( _,
JOBS_TO_SPAWN,
RUNS_TO_RUN
)
)
Собрав достаточно репрезентативные данные по этому случаю NOP на разумно масштабируемом 2D-ландшафте [ RUNS_TO_RUN, JOBS_TO_SPAWN]
-декартовых пространств DataPoints, чтобы получить хотя бы некоторый опыт из первых рук о фактических системных затратах на запуск фактически пустых процессов » служебные нагрузки, связанные с императивно проинструктированным joblib.Parallel(...)( joblib.delayed(...) )
-синтаксическим конструктором, порождаются в системном планировщике всего несколько joblib
управляемых a_NOP_FUN()
экземпляров.
Давайте также согласимся с тем, что все проблемы реального мира, включая модели машинного обучения, являются более сложными инструментами, чем только что протестированный a_NOP_FUN()
, хотя в обоих случаях вам придется оплатить уже оцененные контрольные расходы накладных расходов ( даже если заплатили за получение буквально нулевого продукта).
Таким образом, из этого простейшего случая последует научно обоснованная и тщательная работа, уже показывающая сравнительные затраты всех связанных накладных расходов на настройку наименьшего когда-либо joblib.Parallel()
штрафа sine-qua-non в направлении, где реальные алгоритмы в реальном времени - лучшие с следующим добавлением все большего и большего размера "полезной нагрузки" в цикл тестирования:
Тестовый пример B:
def a_NOP_FUN_WITH_JUST_A_MEM_ALLOCATOR( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
a MEM-allocation
so as to be able to benchmark
all the process-instantiation
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.zeros( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
return aMemALLOC[2:3,3,4,5]
Опять же,
собирает достаточно репрезентативные количественные данные о затратах на фактическое выделение MEM удаленных процессов, выполнив a_NOP_FUN_WITH_JUST_A_MEM_ALLOCATOR()
некоторый разумно широкий ландшафт SIZE1D
-масштабирования,
снова
над разумно масштабируемым 2D-ландшафтом из [ RUNS_TO_RUN, JOBS_TO_SPAWN]
декартовых пространств DataPoints, чтобы коснуться нового измерения в масштабировании производительности, в рамках расширенного эксперимента PROCESS_under_TEST внутри инструмента joblib.Parallel()
с черным ящиком, оставляя его магию еще нераскрытой.
Тестовый пример C:
def a_NOP_FUN_WITH_SOME_MEM_DATAFLOW( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
a MEM-allocation plus some Data MOVs
so as to be able to benchmark
all the process-instantiation + MEM OPs
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.ones( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
aMemALLOC[:,:,:,:]*= 0.1234567
aMemALLOC[:,3,4,:]+= aMemALLOC[4,5,:,:]
aMemALLOC[2,:,4,:]+= aMemALLOC[:,5,6,:]
aMemALLOC[3,3,:,:]+= aMemALLOC[:,:,6,7]
aMemALLOC[:,3,:,5]+= aMemALLOC[4,:,:,7]
return aMemALLOC[2:3,3,4,5]
Бац, проблемы, связанные с архитектурой, постепенно начинают проявляться:
Вскоре можно заметить, что не только статический размер имеет значение, но и MEM-транспорт BANDWIDTH (аппаратно-аппаратный) начнет вызывать проблемы, так как перемещение данных из / в ЦП в / из MEM стоит ну ~ 100 .. 300 [ns]
, намного больше, чем любая умная перетасовка нескольких байтов «внутри» CPU_core, {CPU_core_private | CPU_core_shared | CPU_die_shared} -cache только иерархия-архитектура (и любая нелокальная передача NUMA вызывает дополнительные проблемы того же порядка).
![введите описание изображения здесь](https://i.stack.imgur.com/xCqqv.jpg)
Все вышеперечисленные тестовые примеры еще не потребовали больших усилий от процессора.
Итак, начнем жечь масло!
Если все вышеперечисленное подходит для того, чтобы начать чувствовать запах того, как на самом деле работают вещи под капотом, он станет уродливым и грязным.
Тестовый пример D:
def a_CPU_1_CORE_BURNER_FUN( aNeverConsumedPAR ):
""" __doc__
The intent of this FUN() is to do nothing but
add some CPU-load
to a MEM-allocation plus some Data MOVs
so as to be able to benchmark
all the process-instantiation + MEM OPs
add-on overhead costs.
"""
import numpy as np # yes, deferred import, libs do defer imports
SIZE1D = 1000 # here, feel free to be as keen as needed
aMemALLOC = np.ones( ( SIZE1D, # so as to set
SIZE1D, # realistic ceilings
SIZE1D, # as how big the "Big Data"
SIZE1D # may indeed grow into
),
dtype = np.float64,
order = 'F'
) # .ALLOC + .SET
aMemALLOC[2,3,4,5] = 8.7654321 # .SET
aMemALLOC[3,3,4,5] = 1.2345678 # .SET
aMemALLOC[:,:,:,:]*= 0.1234567
aMemALLOC[:,3,4,:]+= aMemALLOC[4,5,:,:]
aMemALLOC[2,:,4,:]+= aMemALLOC[:,5,6,:]
aMemALLOC[3,3,:,:]+= aMemALLOC[:,:,6,7]
aMemALLOC[:,3,:,5]+= aMemALLOC[4,:,:,7]
aMemALLOC[:,:,:,:]+= int( [ np.math.factorial( x + aMemALLOC[-1,-1,-1] )
for x in range( 1005 )
][-1]
/ [ np.math.factorial( y + aMemALLOC[ 1, 1, 1] )
for y in range( 1000 )
][-1]
)
return aMemALLOC[2:3,3,4,5]
![введите описание изображения здесь](https://i.stack.imgur.com/ifsni.png)
По-прежнему ничего экстраординарного по сравнению с обычным уровнем полезной нагрузки в области многомерного пространства машинного обучения, где все измерения { aMlModelSPACE, aSetOfHyperParameterSPACE, aDataSET }
-пространства состояний влияют на объем требуемой обработки (некоторые имеющий O( N )
, некоторую другую O( N.logN )
сложность), где почти сразу, где хорошо спроектировано, вскоре задействуется больше, чем одно ядро CPU_core, даже при выполнении одного "задания".
Поистине неприятный запах начинается, когда наивные (чтение ресурсов-использование нескоординировано) смеси загрузки ЦП переходят в путь и когда смеси связанных с задачами загрузки ЦП начинают смешиваться с наивными (чтение ресурсов-использование несогласованно) Процессы O / S-планировщика вынуждены бороться за общие (прибегающие к простой политике совместного использования) ресурсы - то есть MEM (введение SWAP как HELL), CPU (введение промахов кэша и повторной выборки MEM (да, с SWAP) добавлены штрафы), не говоря уже об уплате каких-либо сборов за задержку, превышающих ~ 15+ [ms]
, если кто-то забывает и позволяет процессу коснуться fileIO
- (5 ( !) - на порядки медленнее + общее + чистое-[SERIAL]
по своей природе устройство. Никакие молитвы здесь не помогут (SSD включен, всего на несколько порядков меньше, но все равно ад & запускать устройство невероятно быстро в его могилу износа + слезы).
Что произойдет, если все порожденные процессы не поместятся в физическую оперативную память?
Подкачка виртуальной памяти и свопы начинают буквально портить остальную часть, пока что как-то «просто» - по совпадению- (читай: слабо скоординированная) - [CONCURRENTLY]
-планированная обработка (читай: далее- снижение индивидуальных показателей ПРОЦЕССА в рамках ТЕСТИРОВАНИЯ).
Все может так скоро пойти навстречу хаосу, если не будет находиться под должным контролем и надзором.
Опять же - факт имеет значение: облегченный класс монитора ресурсов может помочь:
aResRECORDER.show_usage_since0() method returns:
ResCONSUMED[T0+ 166036.311 ( 0.000000)]
user= 2475.15
nice= 0.36
iowait= 0.29
irq= 0.00
softirq= 8.32
stolen_from_VM= 26.95
guest_VM_served= 0.00
Точно так же немного более богатый сконструированный монитор ресурсов может сообщать о более широком контексте O / S, чтобы увидеть, где дополнительные условия кражи ресурсов / конкуренции / гонки ухудшают фактически достигнутый поток процесса:
>>> psutil.Process( os.getpid()
).memory_full_info()
( rss = 9428992,
vms = 158584832,
shared = 3297280,
text = 2322432,
lib = 0,
data = 5877760,
dirty = 0
)
.virtual_memory()
( total = 25111490560,
available = 24661327872,
percent = 1.8,
used = 1569603584,
free = 23541886976,
active = 579739648,
inactive = 588615680,
buffers = 0,
cached = 1119440896
)
.swap_memory()
( total = 8455712768,
used = 967577600,
free = 7488135168,
percent = 11.4,
sin = 500625227776,
sout = 370585448448
)
Wed Oct 19 03:26:06 2017
166.445 ___VMS______________Virtual Memory Size MB
10.406 ___RES____Resident Set Size non-swapped MB
2.215 ___TRS________Code in Text Resident Set MB
14.738 ___DRS________________Data Resident Set MB
3.305 ___SHR_______________Potentially Shared MB
0.000 ___LIB_______________Shared Memory Size MB
__________________Number of dirty pages 0x
И последнее, но не менее важное: почему можно легко заплатить больше, чем заработать взамен?
Помимо постепенно накапливаемых свидетельств того, как накладные расходы на реальное развертывание системы накапливают затраты, недавно повторно сформулированный закон Амдала, расширенный таким образом, чтобы покрыть как дополнительные накладные расходы, так и "атомарность процесса" определения размеров других неделимых частей, определяет максимальный порог дополнительных затрат, это может быть разумно оплаченным, если некоторая распределенная обработка должна обеспечить любое вышеупомянутое >= 1.00
ускорение вычислительного процесса.
Несоблюдение явной логики переформулированного закона Амдала приводит к тому, что процесс протекает хуже, чем если бы он был обработан с использованием чистого [SERIAL]
планирования процесса (а иногда и из-за плохого проектирования и / или практика операций может выглядеть так, как если бы это был случай, когда метод joblib.Parallel()( joblib.delayed(...) )
«блокирует процесс»).
person
user3666197
schedule
29.11.2017
n_jobs
. Например:sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion=’gini’, max_depth=None, n_jobs=-1)
При этом не будет обучаться несколько моделей одновременно, но будет обучена одна модель на нескольких ядрах, что потенциально ускорит вашу реализацию. - person collector   schedule 29.11.2017joblib.Parallel()
перед тем, как проголосовать против на основании количественно подтвержденного разногласия, или это было актом чистая ненависть? - person user3666197   schedule 30.11.2017