У меня была потрясающая забавная запись нейронного сетевого программного обеспечения в 90-х годах, и я стремился попробовать создать некоторые с помощью Tensorflow.
Poogle’s Machine Intelligence Framework – это новая жаркость прямо сейчас. А когда Tensorflow стал установлен на Raspberry Pi, работая с этим стало очень легко сделать. За короткое время я сделал нейронную сеть, которая рассчитывает в двоичной. Поэтому я думал, что пройду на то, что я понял. Надеюсь, это облегчает кому-либо еще, кто хочет попробовать это, или для тех, кто просто хочет, чтобы некоторые представления о нейронных сетях.
Что такое Tensorflow?
Чтобы процитировать веб-сайт Tensorflow, Tensorflow – это «Библиотека программного обеспечения с открытым исходным кодом для численного вычисления с использованием графов потока данных». Что мы подразумеваем под «графиками потока данных»? Ну, это действительно удивительная часть. Но прежде чем мы сможем ответить на это, нам нужно немного поговорить о структуре для простой нейронной сети.
Бинарная счетчик нервной сети
Основы нейронной сети
Простая нейронная сеть имеет несколько блоков ввода, где идет вход. Он также имеет скрытые единицы, так называемые из-за перспективы пользователя, они буквально скрыты. И есть выходные единицы, из которых мы получаем результаты. С другой стороны также являются устройствами смещения, которые могут помочь контролировать значения, испускаемые из скрытых и выходных единиц. Подключение всех этих единиц – это куча весов, которые являются просто числами, каждый из которых связан с двумя единицами.
Как мы прививайте интеллект в эту нейронную сеть, предназначено для назначения всех этих весов. Вот что делает обучение нейронной сети, находит подходящие значения для этих весов. После того, как в нашем примере на нашем примере мы установим входные единицы в двоичные цифры 0, 0, а 0 соответственно, Tensorflow сделает вещи со всем между ними, а выходные блоки волшебны содержат двоичные цифры 0, 0 и 1 соответственно. Если вы пропустили это, он знал, что следующий номер после двоичного 000 был 001. Для 001 он должен выплюнуть 010 и так до 111, где он выплюнет 000. После того, как эти веса установлены соответствующим образом, это знаю, как посчитать.
Бинарная счетчик нервной сети с матрицами
Один шаг в «запущенном» нейронной сети состоит в том, чтобы умножить значение каждого веса по значению его входного устройства, а затем для хранения результата в соответствующем скрытом блоке.
Мы можем перерисовать единицы и весы как массивы, или что называются списки в Python. С точки зрения математики, они матрицы. Мы перерисованы только часть их на диаграмме. Умножение входной матрицы с матрицей веса включает в себя простое размножение матрицы, что приводит к пяти элементам скрытой матрице / списка / массива.
От матриц до тензоров
В Tensorflow эти списки называются тензорами. И этап умножения матрицы называется операцией, или OP в программисту – говорят, что термин вам придется привыкнуть к тому, что вы планируете прочитать документацию Tensorflow. Принимая его дальше, вся нейронная сеть – это коллекция тензоров и операционных операций, которые работают на них. Всего они составляют график.
Полный график бинарных счетчиков
Уровень1 расширился
Здесь показано, что снимки, взятые из Tensorboard, инструмент для визуализации графика, а также изучения ценностей тензора во время и после тренировки. Тензуры – это линии, и написанные на линиях – это теплорные размеры. Подключение тензоров – это все OPS, хотя некоторые из вещей, которые вы видите, можно дважды щелкнуть, чтобы расширить более подробную информацию, как мы сделали для Layer1 во втором снимке.
В самом нижнем дне X, имя, которое мы дали для Plachholder op, который позволяет нам предоставлять значения для входного тензора. Линия, идущая вверх и слева от него – входной тензор. Продолжайте следовать за этой линией, и вы найдете Matmul OP, который делает умножение матрицы с этим входным тензором и тензором, которая является другой линией, ведущей в Matmul OP. Этот тензор представляет веса.
Все это было просто, чтобы дать вам почувствовать, какой график и его тензоры и опс, дающие вам лучшее представление о том, что мы подразумеваем под TenSorflow, являющимся «библиотекой программного обеспечения для численного вычисления с использованием графов потока данных». Но почему мы хотели бы создать эти графики?
Зачем создавать графики?
API в настоящее время стабильно является одним для Python, интерпретируемый язык. Нейронные сети вычислить интенсивным, и большая могла иметь тысячи или даже миллионы весов. Вычисление, интерпретируя каждый шаг займет навсегда.
Таким образом, мы вместо этого мы создаем график, состоящий из тензоров и OPS, описывающих макет нейронной сети, все математические операции и даже начальные значения для переменных. Только после того, как мы создали этот график, то мы передаем его к тому, что Tensorflow вызывает сеанс. Это известно как отсроченное исполнение. Ссылка запускает график, используя очень эффективный код. Не только это, но многие операции, такие как Matrix умножение, представляют собой те, которые могут быть сделаны на поддерживаемом GPU (графический блок обработки), и сеанс сделает это для вас. Кроме того, Tensorflow это бУил, чтобы иметь возможность распространять обработку на нескольких машинах и / или графических процессе. Давая ему полный график позволяет это сделать это.
Создание бинарного счетчика
И вот код для нашей бинарной счетчики нейронной сети. Вы можете найти полный исходный код на этой странице GitHub. Обратите внимание, что в нем дополнительный код для сохранения информации для использования с Tensorboard.
Мы начнем с кода для создания графика тензоров и OPS.
Импорт Tensorflow AS TF
sess = tf.interactsessionsion ()
Num_inputs = 3.
Num_hidden = 5.
Num_outputs = 3.
Сначала импортируем модуль Tensorflow, создайте сеанс для использования позже, и, чтобы сделать наш код более понятным, мы создаем несколько переменных, содержащих количество единиц в нашей сети.
x = tf.paceholder (tf.float32, form = [none, num_inputs], name = ‘x’)
y_ = tf.jachholder (tf.float32, form = [none, num_outputs], name = ‘y_’)
Затем мы создаем заполнители для наших входных и выходных единиц. Заполнителем – это Tensorflow op для вещей, которые мы предоставим ценности напустя. X и Y_ теперь тензоры в новом графике, и у каждого есть, связанный с ним заполнитель.
Вы можете задаться вопросом, почему мы определяем формы как [none, num_inputs] и [none, num_outputs], два мерных списка и почему нет для первого измерения? В обзоре нейронных сетей выше похоже, что мы дадим ему один ввод за раз и тренируйте его, чтобы создать данный выход. Это более эффективно, хотя, если мы дадим его несколько пар ввода / вывода одновременно, что называется пакетным. Первое измерение предназначено для количества пар входных / выводов в каждой партии. Мы не будем знать, сколько находятся в партии, пока мы на самом деле не дали позже. И на самом деле мы используем тот же график для обучения, тестирования и для фактического использования, поэтому размер партии не всегда будет таким же. Таким образом, мы используем объект заполнителя Python None для размера первого измерения.
W_fc1 = tf.trunced_normal ([num_inputs, num_hidden], средний = 0,5, stddev = 0,707)
W_fc1 = tf.variable (w_fc1, name = ‘w_fc1’)
b_fc1 = tf.trunced_normal ([num_hidden], средний = 0,5, stddev = 0,707)
b_fc1 = tf.variable (b_fc1, name = ‘b_fc1’)
h_fc1 = tf.nn.relu (tf.matmul (x, w_fc1) + b_fc1)
Затем следует создание слоя одного из нейронного сетевого графика: веса W_FC1, предубеждения B_FC1 и скрытые единицы H_FC1. «FC» – это соглашение, означающее «полностью подключенное», поскольку вес соединяет каждый блок ввода к каждому скрытому устройству.
tf.trunced_normal приводит к ряду ops и тензоров, которые позже будут назначать нормализованные случайные числа для всех весов.
Переменная OPS приводится значение для выполнения инициализации с случайными числами в этом случае и сохранять свои данные по нескольким прогонам. Они также удобны для сохранения нейронной сети в файл, то, что вы захотите сделать, как только это обучено.
Вы можете увидеть, где мы будем делать умножение матрицы, используя Matmul OP. Мы также вставляем ADD OP, который добавит на весы смещения. RELU OP выполняет то, что мы называем функцией активации. Умножение матрицы и добавление являются линейными операциями. Существует очень ограниченное количество вещей, которые неистовая сеть может научиться использовать только линейные операции. Функция активации обеспечивает некоторую нелинейность. В случае функции активации RELU она устанавливает любые значения, которые меньше нуля до нуля, и все остальные значения остаются без изменений. Поверьте, или нет, делать это открывает весь другой мир вещей, которые можно узнать.
W_fc2 = tf.trunced_normal ([num_hidden, num_outputs], средний = 0,5, stddev = 0,707)
W_fc2 = tf.variable (w_fc2, name = ‘w_fc2’)
b_fc2 = tf.treunged_normal ([num_outputs], среднее значение = 0,5, stddev = 0,707)
b_fc2 = tf.variable (b_fc2, name = ‘b_fc2’)
y = tf.matmul (h_fc1, w_fc2) + b_fc2
Вес и предубеждения для двух слоев устанавливаются так же, как для слоя, но выходной слой отличается. Мы снова сделаем умножение матрицы, на этот раз умножая веса и скрытые единицы, а затем добавляя весы смещения. Мы оставили функцию активации для следующего бита кода.
Результаты = tf.sigmoid (y, name = ‘результаты’)
cross_entropy = tf.recuce_mean (
tf.nn.sigmoid_cross_entropy_with_logits (логиты = y, метки = y_))
Сигмоид – это еще одна функция активации, такая как RELU, которую мы столкнулись с вышеупомянутой, там обеспечить нелинейность. Я использовал Sigmoid здесь частично, потому что уравнение сигмоида приводит к значениям от 0 до 1, идеально подходит для нашего бинарного прибора. Я также использовал это, потому что это хорошо для выходов, где более одного выходного устройства могут иметь большое значение. В нашем случае для представления двоичного номера 111, все выходные устройства могут иметь большие значения. При выполнении классификации изображений мы хотели бы, чтобы что-то совсем другое, мы хотели бы только один выходной блок для огня с большим значением. Например, мы бы хотели, чтобы выходной блок, представляющий жирафы, чтобы иметь большое значение, если изображение содержит жираф. Что-то вроде Softmax было бы хорошим выбором для классификации изображений.
На тесной проверке похоже, что есть некоторое дублирование. Кажется, мы вставляем сигмоид дважды. Мы на самом деле создаем два разных, параллельных oUtputs здесь. Tensor Tensor_entropy будет использоваться во время тренировки нейтральной сети. Tensor результатов будет использоваться, когда мы будем использовать нашу обученную нейронную сеть позже для того, что она создана, для удовольствия в нашем случае. Я не знаю, является ли это лучшим способом сделать это, но это так, как я придумал.
urs_step = tf.train.rmspropoptimizer (0.25, импульс = 0,5) .minimize (cross_entropy)
Последнее произведение мы добавляем к нашему графику, это тренировка. Это OP или OPS, который настроит все веса на основе данных обучения. Помните, мы все еще просто создаем график здесь. Фактическое обучение произойдет позже, когда мы запустим график.
Есть несколько оптимизаторов, чтобы выбрать. Я выбрал TF.train.rmspropoptimizer, потому что, как и сигмоид, он хорошо работает для случаев, когда все выходные значения могут быть большими. Для классификации вещей, как при выполнении классификации изображений, tf.train.gradientsentscentsoptimizer может быть лучше.
Обучение и использование двоичного счетчика
Создав график, пришло время сделать тренинг. Как только это обучено, мы можем использовать его.
inputVals = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1] С
[1, 1, 0], [1, 1, 1]]
TargetVals = [[0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0] С
[1, 1, 1], [0, 0, 0]]
Во-первых, у нас есть некоторые учебные данные: ввода и целеводы. Ввода содержит входные данные, а для каждого есть соответствующие целевое значение целевойВи. Для ввода [0] у нас есть [0, 0, 0], а ожидаемый выход – это целевойВи [0], что представляет собой [0, 0, 1] и так далее.
Если do_tring == 1:
sess.run (tf.global_variables_initializer ())
Для I в пределах (10001):
Если я% 100 == 0:
urs_error = cross_entropy.eval (feed_dict = {x: inputvals, y_: tradevals})
Печать («Step% D, Ошибка обучения% G»% (I, urch_Error)))
Если urch_Error <0.0005:
перерыв
SESS.RUN (urch_step, feed_dict = {x: invincals, y_: tradevals})
Если save_traine == 1:
Печать («Сохранение нейронной сети до% s. *»% (Save_file))
Saver = tf.train.saver ()
Saver.save (SESS, SAVE_FILE)
do_tring и save_traine могут быть закреплены и изменены для каждого использования или могут быть установлены с использованием аргументов командной строки.
Сначала мы проходим все эти переменные OPS и у них инициализируют их тензоры.
Затем до 10001 раз мы запускаем график снизу до тензора Train_Step, последнее, что мы добавили на наш график. Мы пропускаем ввода и целевые знаки для round_step OP или OPS, которые мы добавили с помощью RMSPropOPTimizer. Это шаг, который регулирует все веса, такие что данные ввода приведут к чему-то близкому к соответствующим целевым выходам. Если ошибка между целевыми выходами и фактическими выходами становится достаточно маленькой, то мы вырываемся из цикла.
Если у вас есть тысячи пар ввода / вывода, вы можете придать им подмножество их за раз, пакет, которую мы говорили ранее. Но здесь у нас только восемь, и поэтому мы даем все их каждый раз.
Если мы хотим, мы также можем сохранить сеть в файл. Как только он хорошо обучен, нам не нужно тренировать его снова.
остальное: #, если мы не тренируемся, мы должны загружаться из файла
Печать («Загрузка нейронной сети от% S»% (Save_File))
Saver = tf.train.saver ()
Saver.restore (SESS, SAVE_FILE)
# Примечание. Восстановить оба нагрузки и инициализации переменных
Если мы не тренируемся, то мы вместо этого загружаем тренированную сеть из файла. Файл содержит только значения для тензоров, которые имеют переменную OPS. Это не содержит структуру графика. Так что даже при запуске уже обученного графика нам все еще нужен код для создания графика. Существует способ сохранить и загружать графики из файлов с использованием метаграфий, но мы не делаем этого здесь.
Печать ('\ ncounting, начиная с: 0 0 0')
res = sess.run (результаты, feed_dict = {x: [[0, 0, 0]]})
Печать (% G% G% G '% (Res [0] [0], RES [0] [1], RES [0] [2])))
0