Найти в Дзене
Цифровая Переплавка

🤖 NumPy: революция, ставшая головной болью

Все, кто хоть раз сталкивался с Python, знают библиотеку NumPy. Многие даже считают её обязательной частью жизни любого дата-саентиста и разработчика нейросетей. Но автор статьи «I don't like NumPy» утверждает, что её дизайн и подходы стали причиной регулярной головной боли для тех, кто работает с массивами в Python. Давайте разберёмся, почему же автор так недоволен этой легендарной библиотекой. NumPy появилась ещё в 2005 году и стала прорывом благодаря своей скорости и удобству работы с массивами. Казалось, всё идеально: ✨ Нужно решить систему уравнений? Просто пишешь: y = np.linalg.solve(A, x) и наслаждаешься простотой. ✨ Хочешь сложить два массива разной формы? NumPy автоматически «подгоняет» их размеры благодаря механизмам broadcasting. Однако, как всегда бывает с любовью, со временем стали заметны недостатки, которые раньше скрывались за идеализацией. Автор статьи выделяет три главные проблемы NumPy: Broadcasting — это механизм автоматического расширения массивов до нужной формы д
Оглавление
Датасаентист держится за голову, глядя на монитор с ошибками NumPy — визуальный протест против запутанности библиотеки.
Датасаентист держится за голову, глядя на монитор с ошибками NumPy — визуальный протест против запутанности библиотеки.

Все, кто хоть раз сталкивался с Python, знают библиотеку NumPy. Многие даже считают её обязательной частью жизни любого дата-саентиста и разработчика нейросетей. Но автор статьи «I don't like NumPy» утверждает, что её дизайн и подходы стали причиной регулярной головной боли для тех, кто работает с массивами в Python.

Давайте разберёмся, почему же автор так недоволен этой легендарной библиотекой.

😍 Сначала любовь…

NumPy появилась ещё в 2005 году и стала прорывом благодаря своей скорости и удобству работы с массивами. Казалось, всё идеально:

✨ Нужно решить систему уравнений? Просто пишешь:

y = np.linalg.solve(A, x)

и наслаждаешься простотой.

✨ Хочешь сложить два массива разной формы? NumPy автоматически «подгоняет» их размеры благодаря механизмам broadcasting.

Однако, как всегда бывает с любовью, со временем стали заметны недостатки, которые раньше скрывались за идеализацией.

😡 …потом ненависть

Автор статьи выделяет три главные проблемы NumPy:

📐 1. Broadcasting: магия, которая сбивает с толку

Broadcasting — это механизм автоматического расширения массивов до нужной формы для выполнения операций. С одной стороны, это удобно:

A = np.array([[1,2],[3,4],[5,6]])
B = np.array([10,20])
C = A * B # автоматически «растягивает» B

Но как только вы пытаетесь сделать нечто более сложное, broadcasting превращается в хаос. Например, попробуйте решить 100 систем линейных уравнений сразу:

Как правильно?

  • linalg.solve(A,x)
  • linalg.solve(A.T,x.T)
  • linalg.solve(A,x[:,:,None])[:,:,0]

Никто не знает. Документация не помогает, приходится гадать.

🌀 2. Индексация: таинственная логика

Возьмём пример с индексами:

A = np.ones((10,20,30,40))
i = np.array([1,2,3])
j = np.array([[0],[1]])
B = A[:,i,j,:]

Какой размер у массива B?
🔮 Ответ: 10×2×3×40.

А теперь:

C = A[:,:,i,j]
D = A[:,i,:,j]
E = A[:,1:4,j,:]

Понимание этих форматов требует детального изучения 5000-словной документации. Даже лучшие ИИ-модели ошибаются в этом.

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

🎲 3. Функции NumPy: нет единой логики

Функции вроде np.linalg.solve и np.tensordot работают совершенно по-разному, у каждой своя логика и правила:

  • 🧩 np.linalg.solve — непонятные конвенции.
  • 🎯 np.einsum — мощный, но требующий изучения мини-язык.

Автор признаётся, что единственный по-настоящему полезный инструмент NumPy — это np.einsum, который, кстати, использует индексы напрямую, отказываясь от «магического» broadcasting. Иронично, правда?

📌 Типичный пример: Attention в нейросетях

В современной разработке нейросетей постоянно используется self-attention. Посмотрите, как просто было бы реализовать multi-head attention, если бы можно было использовать циклы:

for n in range(n_head):
output = attention(X, W_q[n,:,:], W_k[n,:,:], W_v[n,:,:])

Но циклы медленные, и приходится использовать полностью векторизованную версию на NumPy, которая выглядит вот так:

Q = np.einsum('si,hij->hsj', X, W_q)
K = np.einsum('si,hik->hsk', X, W_k)
scores = Q @ K.transpose(0, 2, 1) / np.sqrt(d_k)

И это пугает даже опытных разработчиков.

🤔 Так где же NumPy свернул не туда?

Автор считает, что главная ошибка NumPy — отказ от явных индексов и попытка заменить их broadcasting'ом. В итоге всё стало либо слишком неявным, либо слишком запутанным.

  • 🕳️ Вместо явных и простых циклов — загадочные правила трансляции форм.
  • 🧙 Вместо ясного кода — головоломки с индексами и broadcasting.

Он призывает к созданию нового подхода, где всё будет чётко и очевидно:

  • ✅ Легко понять, как сделать нужную операцию.
  • ✅ Легко понять, что именно делает написанный код.

🌅 Что дальше? Личное мнение

На мой взгляд, автор прав: NumPy стал слишком сложным и непрозрачным инструментом. Попытка спрятать сложность за «магическими» механизмами, вроде broadcasting, обернулась тем, что разработчики тратят слишком много времени на разгадку головоломок.

Решением могла бы стать библиотека, где индексы и размеры явно контролируются и легко читаются. Возможно, именно такую библиотеку автор и собирается представить в будущем.

Хотя, безусловно, NumPy сыграл огромную роль в развитии Python и Data Science, сейчас пришло время двигаться дальше, к более прозрачным и дружелюбным инструментам.

🔗 Оригинал статьи: I don't like NumPy
🔗
Документация NumPy (для отважных): NumPy Docs
🔗
Einops — альтернативный инструмент для работы с массивами: Einops