Введение
Далее приводится дружественный обзор важных концепций линейной алгебры и глубокого обучения, которые были упомянуты Джереми Ховардом в уроке 8 fast.ai 2019. Я разделил каждую концепцию на академическую часть и представление кода Python.
Скаляры, векторы, матрицы и тензоры
Скаляр — это всего лишь одно число. Он используется для контраста с массивами из нескольких чисел.
Вектор — это массив чисел.
Матрица представляет собой двумерный массив чисел, поэтому каждый элемент идентифицируется двумя индексами.
Тензор — это массив чисел, расположенных на регулярной сетке с переменным числом осей.
Умножение матриц
Одной из самых важных операций с матрицами является умножение двух матриц. Матричное произведение матриц A и B является третьей матрицей C. Чтобы это произведение было определено, A должно иметь такое же количество столбцов, сколько B имеет строк.
Обратите внимание, что стандартное произведение двух матриц — это не просто матрица, содержащая произведение отдельных элементов. Такая операция существует и называется поэлементным произведением или произведением Адамара и обозначается как:
Продукт Адамара используется в методах сжатия изображений, таких как JPEG. Он также известен как продукт Шура в честь немецкого математика Исая Шура. Продукт Адамара используется в ячейках LSTM (долговременная кратковременная память) рекуррентных нейронных сетей (RNN).
И это все, что вам нужно знать о продукте Адамара, поскольку это не тот способ, которым мы вычисляем прямое распространение в глубоком обучении. Мы используем умножение матриц для получения, например, матричное произведение C = AB как вычисление Cn,q как скалярное произведение между строкой n матрицы A и столбцом q из Б.
Код Python для умножения матриц будет выглядеть так:
def matmul(a,b): ar,ac = a.shape # n_rows * n_cols br,bc = b.shape assert ac==br c = torch.zeros(ar, bc) for i in range(ar): for j in range(bc): for k in range(ac): # or br c[i,j] += a[i,k] * b[k,j] return c
Поскольку приведенный выше код имеет два цикла внутри цикла, он работает медленно. Существует более быстрый способ умножения матриц, использующий принципы поэлементного вычисления. Это ускоряет расчет в 178 раз.
def matmul(a,b): ar,ac = a.shape br,bc = b.shape assert ac==br c = torch.zeros(ar, bc) for i in range(ar): for j in range(bc): # Any trailing “,:” can be removed c[i,j] = (a[i,:] * b[:,j]).sum() return c
Поскольку мы поняли, что циклы медленные, пришло время ввести концепцию широковещательной рассылки, которая широко используется в матричных операциях. Пожалуйста, ознакомьтесь с интересной и подробной статьей о вещании в PyTorch/Numpy.
Вещание
Термин широковещательная рассылка описывает, как обрабатываются массивы различной формы во время арифметических операций. Термин вещание был впервые использован Numpy.
Термин широковещательная передача описывает, как numpy обрабатывает массивы различной формы во время арифметических операций. С учетом определенных ограничений меньший массив «транслируется» по большему массиву, чтобы они имели с совместимые формы. Вещание предоставляет средства векторизации операций с массивами, так что зацикливание происходит в C, а не в Python. Он делает это без создания ненужных копий данных и обычно приводит к эффективной реализации алгоритма.
В дополнение к эффективности трансляции это позволяет разработчикам писать меньше кода, что обычно приводит к меньшему количеству ошибок и дает более высокую скорость в 3 195 раз по сравнению с чистым кодом Python:
def matmul(a,b): ar,ac = a.shape br,bc = b.shape assert ac==br c = torch.zeros(ar, bc) for i in range(ar): # c[i,j] = (a[i,:] * b[:,j]).sum() # previous c[i] = (a[i,None] * b).sum(dim=0) return c
Существует способ изменить приведенный выше код Python, используя соглашение о суммировании Эйнштейна, которое представляет операции с многомерными массивами простым способом.
Суммирование Эйнштейна
Вот хорошая и подробная статья о суммировании Эйнштейна. Пожалуйста, проверьте это.
Используя метод einsum в PyTorch для написания новой функции, мы можем достичь скорости вычислений в 16 000 раз выше, чем в исходном коде Python.
def matmul(a,b): return torch.einsum(‘ik,kj->ij’, a, b)
Однако лучший способ умножения матриц с точки зрения скорости и эффективности использования памяти — использовать метод matmul из PyTorch.
def matmul(a,b): return a.matmul(b)a.matmul(b)
=a@b
Это в 50 000 раз быстрее исходного кода.
___________________________________________________________________
Спасибо, что дочитали эту статью до конца и, надеюсь, она оказалась для вас полезной. Я впервые консолидирую знания в области глубокого обучения для создания контента.
Дополнительная благодарность за вдохновение принадлежит https://medium.com/@lankinen с его статьей.
Давайте продолжим изучение fast.ai.