Можно ли использовать только PyTorch без NumPy?

Если вы разрабатываете модели глубокого обучения, то наверняка сталкивались с вопросом: зачем нужен NumPy, если все операции можно выполнять в PyTorch?

В кодах fine‑tuning часто встречаются две строки:

import numpy as np
import torch

«Тензорные операции уже есть в PyTorch… зачем нужен NumPy?» «Похоже, концепции пересекаются, стоит ли изучать NumPy отдельно?»

Я тоже задавался этим вопросом, и на основе найденных ответов собрал материал.


1. Что именно различает NumPy и PyTorch?



Кратко: PyTorch можно рассматривать как «NumPy + автоградиент».

NumPy

  • Работает только на CPU.
  • Предоставляет массивы/матрицы, линейную алгебру, статистику – фактически «стандарт» для численных вычислений в Python.
  • Основной тип данных – ndarray.

PyTorch

  • API почти идентичен NumPy.
  • Может работать как на CPU, так и на GPU (CUDA).
  • Поддерживает автоградиент, что делает его пригодным для обучения нейросетей.

Разработчики PyTorch сознательно «подражали» синтаксису NumPy:

  • np.array([...])torch.tensor([...])
  • x_np.shapex_torch.shape
  • np.reshape(x, …)x_torch.view(…) или x_torch.reshape(…)

Изучая тензорные операции PyTorch, вы одновременно осваиваете стиль и синтаксис NumPy.


2. Нужно ли сначала изучать NumPy?

Многие учебники начинают с NumPy, но с практической точки зрения:

Никакой необходимости в предварительном изучении NumPy нет. PyTorch сразу же позволяет работать с тензорами.

Почему так?

  • Концепции формы, broadcasting и индексации почти одинаковы в NumPy и PyTorch.
  • В глубоких нейросетях вы в основном используете тензорные операции + автоградиент, которые реализованы только в PyTorch.

Если ваша цель – глубокое обучение, то:

  1. Сначала изучите манипуляции с тензорами в PyTorch.
  2. Когда увидите np.xxx, поймите, что это «CPU‑версия» той же операции.

3. Почему NumPy всё‑таки присутствует: «общий язык экосистемы»



Вопрос: «Если PyTorch мощнее, почему не использовать только его?»

Ответ: большинство научных и аналитических библиотек в Python построены вокруг NumPy.

3‑1. Предобработка данных

  • OpenCV, Pillow возвращают изображения как NumPy‑массивы.
  • pandas использует DataFrame.values / to_numpy().
  • Статистические пакеты принимают/выдают NumPy‑массивы.

То есть до того, как данные попадут в модель, они обычно обрабатываются в NumPy.

3‑2. Обучение/инференс

import numpy as np
import torch

x_np = ...  # результат предобработки
x_tensor = torch.from_numpy(x_np)  # преобразуем в тензор
x_tensor = x_tensor.to("cuda")

out = model(x_tensor)

3‑3. Визуализация/сохранение/последующая обработка

  • matplotlib рисует графики из NumPy‑массивов.
  • pandas сохраняет в CSV.
  • Простые статистические расчёты.

Для этого снова нужны NumPy‑массивы, поэтому тензоры переводятся обратно:

out_cpu = out.detach().cpu().numpy()

Частая ошибка: TypeError: can't convert cuda:0 device type tensor to numpy – тензор на GPU нельзя напрямую преобразовать в NumPy, нужно сначала переместить его на CPU.


4. Системный аспект: «Zero‑Copy» совместное использование памяти

x_np = np.random.randn(3, 3)
x_tensor = torch.from_numpy(x_np)  # здесь!

На самом деле данные не копируются:

  • torch.from_numpy(...) создаёт тензор, который «делит» память с NumPy‑массивом.
  • Перевод тензора в NumPy (x_tensor.numpy()) тоже делит память, если тензор находится на CPU.

Пример:

x_np = np.zeros((2, 2))
x_tensor = torch.from_numpy(x_np)

x_tensor[0, 0] = 1
print(x_np)
# [[1. 0.]
#  [0. 0.]]  ← NumPy‑массив тоже изменился

Таким образом, NumPy и PyTorch могут «видеть» одни и те же данные без лишних копирований.


5. Полный пример: простая классификация изображения

import cv2
import numpy as np
import torch

# 1. Загрузка изображения и предобработка (NumPy)
img = cv2.imread("cat.png")          # (H, W, C), BGR, NumPy array
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224))
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1))   # (C, H, W)

# 2. Преобразование в тензор и перенос на GPU (PyTorch)
x = torch.from_numpy(img)            # (3, 224, 224)
x = x.unsqueeze(0)                   # (1, 3, 224, 224)
x = x.to("cuda")

# 3. Инференс
with torch.no_grad():
    logits = model(x)
    probs = torch.softmax(logits, dim=1)

# 4. Перевод результата обратно в NumPy для дальнейшей обработки (NumPy)
probs_np = probs.cpu().numpy()
pred_class = np.argmax(probs_np, axis=1)[0]

Весь поток выглядит естественно: вход/выход – NumPy, обучение/инференс – PyTorch.


6. Итоги: как проще понять

  1. Изучение PyTorch – это как изучение «будущего NumPy». Тензорные операции и broadcasting в PyTorch почти идентичны NumPy.
  2. Никакой глубокой проработки NumPy не требуется для целей глубокого обучения. np.xxx в коде – просто CPU‑версия той же операции.
  3. В реальных проектах NumPy всё‑таки нужен: предобработка, визуализация, статистика. Поэтому часто видите torch.from_numpy, .numpy(), .cpu().
  4. Системный уровень: NumPy и PyTorch могут делить память (Zero‑Copy), что делает переходы быстрыми.

Теперь, когда вы видите код, просто помните:

  • Тензоры на GPU с автоградиентом – PyTorch.
  • Окружающие библиотеки и данные – NumPy.

Эти два мира плавно переходят друг в друга – это базовый навык современного Python‑разработчика глубокого обучения.

image