Путаница с пакетами графических процессоров Nvidia в Julia, CuArrays и ArrayFire

Когда вы пишете [x]*3, вы получаете, по существу, список [x, x, x]. То есть список с 3 ссылками на тот же x. Когда вы затем изменяете этот сингл x, он отображается через все три ссылки на него.

Чтобы исправить это, вам нужно убедиться, что вы создаете новый список в каждой позиции. Один из способов сделать это -

[[1]*4 for n in range(3)]

, который будет повторно оценивать [1]*4 каждый раз, а не оценивать его один раз и делать 3 ссылки на 1 список.


Вы можете удивиться почему * не может создавать независимые объекты так, как это делает понимание списка. Это потому, что оператор умножения * работает с объектами, не видя выражений. Когда вы используете * для умножения [[1] * 4] на 3, * видит только 1-элементный список [[1] * 4], а не текст выражения [[1] * 4. * не имеет понятия, как делать копии этого элемента, не знаю, как переоценить [[1] * 4], и не подозревайте, что вы даже хотите копировать, и вообще, возможно, даже не было способа скопировать элемент.

Единственный вариант * - это сделать новые ссылки на существующий подсписчик вместо того, чтобы пытаться создавать новые подсписки. Все остальное было бы непоследовательным или требовало бы значительного пересмотра основополагающих решений по языковому дизайну.

Напротив, понимание списка переоценивает выражение элемента на каждой итерации. [[1] * 4 for n in range(3)] пересчитывает [1] * 4 каждый раз по той же причине [x**2 for x in range(3)] каждый раз переоценивает x**2. Каждая оценка [1] * 4 генерирует новый список, поэтому понимание списка делает то, что вы хотели.

Кстати, [1] * 4 также не копирует элементы [1], но это не имеет значения , так как целые числа неизменны. Вы не можете сделать что-то вроде 1.value = 2 и превратить 1 в 2.

-2
задан talonmies 25 March 2019 в 06:11
поделиться

1 ответ

Как объяснено в сообщении в блоге, которым вы поделились, это довольно просто, как указано ниже

Экосистема пакетов Julia уже содержит довольно много пакетов, связанных с GPU, нацеленных на разные уровни абстракции, как показано на рисунке 1 показывает. На самом высоком уровне абстракции пакеты, специфичные для домена, такие как MXNet.jl и TensorFlow.jl, могут прозрачно использовать графические процессоры в вашей системе. Более универсальная разработка возможна с ArrayFire.jl, и если вам нужна специализированная реализация CUDA линейной алгебры или алгоритма глубокой нейронной сети, вы можете использовать специфичные для поставщика пакеты, такие как cuBLAS.jl или cuDNN.jl. Все эти пакеты, по сути, являются обертками вокруг собственных библиотек и используют интерфейсы внешних функций (FFI) Джулии для вызова API библиотеки с минимальными издержками.

Пакеты CUDAdrv и CUDAnative предназначены для непосредственного использования API среды выполнения CUDA и написания ядер от самой Джулии. Я полагаю, что именно здесь CuArray пригодится - оборачивая нативные объекты Julia в доступный формат CUDA, грубо говоря.

ArrayFire, с другой стороны, является универсальной библиотекой, которая охватывает все (cuBLAS, cuSparse, cuSolve, cuFFT) CUDA предоставила доменные библиотеки в хороший интерфейс (функции). Помимо интерфейса к доменным библиотекам CUDA, ArrayFire сам по себе предоставляет множество других функций в области статистики, обработки изображений, компьютерного зрения и т. Д. Он имеет замечательную JIT-функцию , где код пользователя компилируется во время выполнения. ядро - проще говоря. ArrayFire.jl - это языковая привязка с некоторыми дополнительными улучшениями, характерными для Julia, на уровне оболочки.

В этом и заключается общая разница. С точки зрения разработчиков, использование библиотеки (например, ArrayFire) в основном снимает бремя поддержки API CUDA и поддержки / настройки ядер для достижения оптимальной производительности, что, на мой взгляд, занимает много времени.

PS. Я являюсь членом команды разработчиков ArrayFire.

0
ответ дан pradeep 25 March 2019 в 06:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: