Нет абсолютно никаких сомнений в том, что язык программирования Python сделал программирование простым и приятным. Специально для людей, работающих в области машинного обучения (ML), Python становится инструментом торговли. ML широко использует матрицы, для которых в Python имеется достаточная поддержка. Более того, с такими библиотеками, как Numpy и Pandas, обработка матриц через списки становится очень простой и интуитивно понятной. Однако эта интуитивная абстракция Python часто также становится причиной его непреднамеренной обманчивой природы. Если быть точным, я говорю о списках Python!

Часто при создании наших моделей ML нам приходится иметь дело с вложенными списками (для реализации весов, входных данных и т. д.), содержимое которых может меняться в ходе обучения/построения модели. Однако существует несколько методов создания вложенных списков, и именно в этом заключается загвоздка. Итак, давайте создадим один такой вложенный список и поймем, в чем проблема:

import matplotlib.pyplot as plt #to graphically analyse our list
col = 10
row = 10
nested_list = [[0]*col]*row
print(nested_list)

Выход:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

Мы только что создали вложенный список, состоящий из 10 столбцов и 10 строк. Давайте теперь визуализируем этот список.

plt.imshow(nested_list)
plt.show()

Выход:

Хорошо, как и ожидалось; мы создали темное квадратное изображение шириной и высотой по 10 пикселей каждое (каждый пиксель имеет значение 0). Теперь пришло время зажечь его! Начнем с верхнего правого пикселя, то есть пикселя в 0-й строке и 9-м столбце. Давайте присвоим этому пикселю значение 1 и увидим, что эта область загорается, а остальная часть остается темной!

nested_list[0][9] = 1
plt.imshow(nested_list)
plt.show()

Выход:

Что? Мы не собирались этого! Хорошо, давайте еще раз проверим наш код... Итак, мы проиндексировали пиксель в последнем столбце первой строки через ‘list_of_list[0][9]’, тогда должен светиться только этот пиксель. Почему вся колонка светится? Скорее, мы ожидали следующее изображение:

Так что же пошло не так?

Неправильное наше понимание вложенного списка, который мы создали. На самом деле, в нашем списке, который был создан как '[[0]*col]*row', каждая строка является не чем иным, как ссылкой на один и тот же список '[[0]*col] '. Итак, какие бы изменения мы ни вносили в любую из ссылок, они отражаются во всех строках. Таким образом, хотя мы изменили последний пиксель первой строки, изменение отразилось на всех оставшихся ссылках, тем самым подсветив последний столбец всех строк! Это можно понять из приведенного ниже кода:

child_list = [0,0,0]
nested_list = [child_list,child_list,child_list]
print("Nested list:",nested_list)
child_list[1] = 2
print("Nested list after manipulating child list",nested_list)
nested_list[0][0] = 3
print("Nested list after manipulating Nested list:",nested_list)
print("Child list after manipulating Nested list:",child_list)

Выход:

Nested list: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Nested list after manipulating child list [[0, 2, 0], [0, 2, 0], [0, 2, 0]]
Nested list after manipulating Nested list: [[3, 2, 0], [3, 2, 0], [3, 2, 0]]
Child list after manipulating Nested list: [3, 2, 0]

Как видно из приведенного выше вывода, вложенный список и его дочерний список (созданный с использованием ссылок) тесно связаны. При таком сценарии любое изменение на уровне дочернего списка или на уровне вложенного списка влияет на все ссылки дочернего списка и, следовательно, на весь вложенный список. Эта небольшая проблема, если ее не понять, может заразить ваши большие модели машинного обучения, особенно во время инициализации весов. Я встречал многих своих коллег-энтузиастов машинного обучения, которые работают над пользовательскими моделями и иногда вынуждены сами писать определенные части цикла машинного обучения. Они часто сталкиваются с такими проблемами, потому что после инициализации весов черный ящик ML (в частности, нейронной сети) не дает им большой свободы для отслеживания изменений весов. Таким образом, к тому времени, когда они заканчивают обучение, модель демонстрирует совершенно неожиданное поведение из-за обсуждаемой выше проблемы. Затем им требуются дни, чтобы добраться до уровня «списков», чтобы понять и исправить реальную проблему!

Решение:

Одна из самых крутых вещей в Python, которая выделяет его среди других, — это понимание списков. И именно так мы решим эту проблему!

Итак, теперь давайте создадим наш вложенный список следующим образом

col = 10
row = 10
nested_list = [[0]*col for row_indx in range(row)] #list comprehension
print(nested_list)

Выход:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

Давайте совершим прыжок веры прямо сейчас! Просто сделайте верхний правый пиксель светящимся следующим образом:

nested_list[0][9] = 1
plt.imshow(nested_list)
plt.show()

Выход:

Вуаля! Мы написали точно такой же код для работы с вложенным списком, как и раньше, но на этот раз получили то, что хотели. Итак, как с этим справляется понимание списка? Это просто! каждый дочерний список «генерируется» iterable понимания списка. Таким образом, компоненты вложенного списка больше не являются простыми ссылками на один и тот же список, а представляют собой разные объекты сами по себе. Таким образом, мы можем манипулировать каждым из этих компонентов (дочерних списков) по отдельности, не влияя на другие! Итак, теперь, когда у вас есть это понимание, используйте эти два метода создания списка в соответствии с вашим желанием. Обратите внимание, что первый метод иногда может быть желательным.

Я надеюсь, что так же, как этот пиксель, могут загореться и ваши собственные нейроны! 💡

Ой! Я дал вам другой взгляд на нейронные сети? Я думаю, вам может понравиться: Краткий экскурс в человеческий мозг и машинное обучение для начинающих!

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord . Заинтересованы в хакинге роста? Ознакомьтесь с разделом Схема.