Тензор - это начало

тензоры - это фундаментальная структура данных в PyTorch. Тензор - это
массив, то есть структура данных, хранящая набор чисел, доступных индивидуально с помощью индекса, который можно индексировать с помощью нескольких индексов.

список из трех чисел представлен на Python

очень легко получить доступ к первому элементу списка, используя соответствующий индекс, отсчитываемый от 0:

Однако, чтобы иметь дело с векторами чисел, такими как координаты 2D-линии, мы не используем список для этой задачи по нескольким причинам:

  • Python поместит их в коробку полноценного объекта Python с подсчетом ссылок и т.д .; это не проблема, если нам нужно сохранить небольшое количество из них, но выделение миллионов таких номеров становится очень неэффективным;
  • списки в Python предназначены для последовательных коллекций объектов: нет операций, определенных, скажем, для эффективного получения скалярного произведения двух векторов или суммирования векторов вместе; Кроме того, списки Python не имеют возможности оптимизировать расположение своего содержимого в памяти.
  • интерпретатор Python медленный по сравнению с тем, что можно достичь с помощью оптимизированного кода, написанного на скомпилированном низкоуровневом языке, таком как C,

По этим причинам NumPy является главной лошадью науки о данных, а не списком; Тензоры PyTorch, похожие на массивы NumPy, которые обеспечивают эффективную низкоуровневую реализацию числовых структур данных и связанных с ними операций, заключенных в удобный высокоуровневый API.

Давайте построим наш первый тензор PyTorch и посмотрим, как он выглядит:

что делает приведенный выше код?

ну, после импорта модуля мы вызвали функцию, которая создает факел
(одномерный) тензор размера 3, заполненный значением. Мы можем получить доступ к элементу, используя его индекс, основанный на 1.0 0, или присвоить ему новое значение.

Хотя он ничем не отличается от списка числовых объектов, под капотом все совершенно иначе. Списки Python или кортежи чисел - это
коллекции объектов Python, которые по отдельности размещаются в памяти. PyTorch Tensors или массивы NumPy, с другой стороны, представляют собой просмотр (обычно) непрерывных блоков памяти.

Тензоры и хранилища

мы начинаем получать подсказки о внутренней реализации: значения распределяются в непрерывных блоках памяти, управляемых экземплярами torch.Storage. Хранилище - это одномерный массив числовых данных, то есть непрерывный блок памяти, содержащий числа заданного типа, например или. PyTorch - это представление о том, что тензорное хранилище с плавающей запятой может индексироваться в это хранилище с использованием смещения и шагов по измерениям.

Несколько тензоров могут индексировать одно и то же хранилище, даже если они индексируют данные по-разному. Однако базовая память выделяется только один раз, поэтому создание альтернативных тензорных представлений для данных может быть выполнено быстро, независимо от размера данных, которыми управляет экземпляр Storage.

Давайте посмотрим, как индексация в хранилище работает на практике с нашими 2D-точками. Доступ к хранилищу для данного тензора можно получить с помощью свойства:

Несмотря на то, что тензор сообщает, что имеет 3 строки и 2 столбца, внутреннее хранилище представляет собой непрерывный массив размера 6. В этом смысле тензор просто знает, как преобразовать пару индексов в место в хранилище.

Мы редко, если вообще когда-либо, будем использовать экземпляры хранилища напрямую, но понимание взаимосвязи между тензором и базовым хранилищем очень полезно для понимания стоимости (или отсутствия таковой) определенных операций в дальнейшем. Это хорошая ментальная модель, о которой следует помнить, когда мы хотим написать эффективный код PyTorch.

Размер, вылет, шаги

Для индексации в хранилище тензоры полагаются на несколько частей информации, которые вместе с их хранилищем однозначно определяют их: размер, смещение хранилища и шаги. Размер (или форма, на языке NumPy) - это кортеж, указывающий, сколько элементов в каждом измерении представляет тензор. Смещение хранилища - это индекс в хранилище, соответствующий первому элементу тензора. Шаг - это количество элементов в хранилище, которые необходимо пропустить, чтобы получить следующий элемент по каждому измерению.

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

Результирующий тензор имеет смещение 2 в хранилище, а размер является экземпляром класса Size, содержащего один элемент, поскольку тензор одномерный. Важное примечание: это та же информация, что содержится в свойстве тензорных объектов. Наконец, шаг - это кортеж, указывающий количество элементов в хранилище, которые необходимо пропустить при увеличении индекса на 1 в каждом измерении. Например, наш тензор очков имеет шаг

Доступ к элементу в двумерном тензоре приводит к доступу к элементу i, j storage_offset + stride [0] * i + stride [1] * j в хранилище.

Это приводит к тому, что некоторые операции, такие как транспонирование тензора или извлечение суб-тензора, становятся недорогими, поскольку они не приводят к перераспределению памяти; вместо этого они заключаются в выделении нового тензорного объекта с другим значением для размера, смещения памяти или шагов.

Например:

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

Теперь попробуем транспонировать:

Мы можем легко проверить, что два тензора используют одно и то же хранилище:

и что они отличаются только формой и шагом

Это изображение ниже объясняет, как работает шаг.

Числовые типы

Вот некоторые комментарии числового типа для Tensor:

  • torch.float32 или torch.float: 32-битное число с плавающей запятой
  • torch.float64 или torch.double: 64-битная, с плавающей запятой двойной точности
  • torch.float16 или torch.half: 16 бит, с плавающей запятой половинной точности
  • torch.int8: 8-битные целые числа со знаком
  • torch.uint8: 8-битные целые числа без знака
  • torch.int16 или torch.short: 16-битные целые числа со знаком
  • torch.int32 или: 32-битные целые числа со знаком torch.int
  • torch.int64 или torch.long: 64-битные целые числа со знаком

Перенос тензоров на GPU

Каждый тензор Torch может быть передан (одному из) графическому процессору (-ам) для выполнения массовых параллельных быстрых вычислений. Все операции, которые будут выполняться с тензором, будут выполняться с использованием процедур, специфичных для графического процессора, которые поставляются с PyTorch.

Вот как мы можем создать тензор на графическом процессоре, указав соответствующий аргумент
конструктору:

Мы также можем скопировать тензор, созданный на CPU, на GPU, используя метод to:

Это возвращает новый тензор, который имеет те же числовые данные, но хранится в ОЗУ графического процессора, а не в обычной системной ОЗУ. Теперь, когда данные хранятся локально на графическом процессоре, мы начнем видеть упомянутые ранее ускорения при выполнении математических операций с тензором.

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

Резюме

  • Тензоры - это основная структура данных в PyTorch, они представляют собой многомерные массивы.
  • PyTorch имеет обширную стандартную библиотеку для создания тензоров, обработки и математических операций.
  • Все тензорные операции в PyTorch могут выполняться как на процессоре, так и на графическом процессоре без изменения кода.