Автор оригинала: Mihajlo Pavloski.
Учебник по нейронной сети TensorFlow
TensorFlow-это библиотека с открытым исходным кодом для приложений машинного обучения. Это система второго поколения Google Brain, после замены близкого источника Неверия, и используется Google как для исследовательских, так и для производственных приложений. Приложения TensorFlow могут быть написаны на нескольких языках: Python, Go, Java и C. Эта статья посвящена его версии Python и рассматривает установку библиотеки, базовые низкоуровневые компоненты и построение нейронной сети с нуля для выполнения обучения на реальном наборе данных.
Продолжительность обучения нейронных сетей глубокого обучения часто является узким местом в более сложных сценариях. Поскольку нейронные сети, а также другие алгоритмы ML в основном работают с матричными умножениями, их гораздо быстрее запускать на графических процессорах (GPU), а не на стандартных центральных процессорах (CPU).
TensorFlow поддерживает как процессоры, так и графические процессоры, и Google даже выпустила собственное специализированное оборудование для вычислений в облаке , называемое Tensor Processing Unit (TPU) , которое обеспечивает лучшую производительность среди различных процессоров.
Установка
Хотя процессоры доступны только в облаке, установка TensorFlow на локальном компьютере может быть нацелена как на процессорную, так и на графическую архитектуру обработки. Чтобы использовать версию GPU, ваш компьютер должен иметь видеокарту NVIDIA, а также удовлетворять еще нескольким требованиям .
В принципе, существует как минимум 5 различных вариантов установки с использованием: virtualenv, pip, Docker, Anaconda и установка из исходного кода.
- Установка с помощью virtualenv и Docker позволяет нам установить TensorFlow в отдельной среде, изолированной от других ваших библиотек Python.
- Anaconda-это дистрибутив Python, содержащий большой набор библиотек для научных вычислений, включая TensorFlow.
- pip рассматривается как “родной” установщик для пакетов Python без использования каких-либо отдельных сред.
- Наконец, установка из исходного кода проходит через Git и является лучшим способом выбора конкретной версии программного обеспечения, причем текущая стабильная версия TensorFlow-r1.4 (на момент написания этой статьи).
Самый распространенный и простой способ установки-через virtualenv и pip, поэтому они будут объяснены в этом посте.
Если вы какое-то время использовали Python, вы, вероятно, знаете pip. Вот как вы можете получить его на машине Ubuntu:
# Install pip sudo apt-get install python-pip python-dev # Python 2.7 sudo apt-get install python3-pip python3-dev # Python 3.x
Следующие строки объясняют установку TensorFlow на компьютере Ubuntu и Mac OSX:
# CPU support pip install tensorflow # Python 2.7 pip3 install tensorflow # Python 3.x # GPU support pip install tensorflow-gpu # Python 2.7 pip3 install tensorflow-gpu # Python 3.x
Вышеприведенные команды также будут работать на компьютере с Windows, но только для версий Python 3.5.x и 3.6.x.
Установка TensorFlow в отдельной среде может быть выполнена через virtualenv или conda (которая является частью Anaconda). Процесс в целом следует тем же линиям, что и выше, только на этот раз вам сначала нужно создать и активировать новую среду с помощью:
virtualenv --system-site-packages ~/tensorflow source ~/tensorflow/bin/activate
Это позволит сохранить все необходимые пакеты отдельно от тех, которые вы установили глобально в своей системе.
Основные компоненты API
Существуют различные API-интерфейсы, доступные для программирования TensorFlow. Самый низкий уровень известен как Core и работает с основными компонентами: тензорами, графами и сеансами.
API более высокого уровня, такие как tf.estimator
, созданы для упрощения рабочего процесса и автоматизации таких процессов, как управление наборами данных, обучение, оценка и т. Д. В любом случае, знание основных функций библиотеки жизненно важно для создания современных обучающих приложений.
Весь смысл основного API заключается в построении вычислительного графа , который содержит ряд операций, организованных в граф узлов. Каждый узел может иметь несколько тензоров (базовая структура данных) в качестве входных данных и выполняет над ними операции для вычисления выходных данных, которые впоследствии могут представлять собой входные данные для других узлов многоуровневой сети. Этот тип архитектуры подходит для приложений машинного обучения, таких как нейронные сети.
Тензоры
Тензоры – это базовая структура данных в TensorFlow, которая хранит данные в любом количестве измерений, подобно многомерным массивам в NumPy. Существует три основных типа тензоров: константы, переменные и заполнители.
- Константы являются неизменяемым типом тензоров. Их можно рассматривать как узлы без входных данных, выводящие единственное значение, которое они хранят внутри.
- Переменные – это изменяемый тип тензоров, значение которых может изменяться во время выполнения графика. В приложениях ML переменные обычно хранят параметры, которые необходимо оптимизировать (например, веса между узлами в нейронной сети). Переменные должны быть инициализированы перед запуском графика явным вызовом специальной операции.
- Заполнители – это тензоры, хранящие данные из внешних источников. Они представляют собой “обещание”, что значение будет предоставлено при запуске графика. В приложениях ML заполнители обычно используются для ввода данных в модель обучения.
Следующие несколько строк дают пример трех типов тензоров:
import tensorflow as tf tf.reset_default_graph() # Define a placeholder a = tf.placeholder("float", name='pholdA') print("a:", a) # Define a variable b = tf.Variable(2.0, name='varB') print("b:", b) # Define a constant c = tf.constant([1., 2., 3., 4.], name='consC') print("c:", c)
a: Tensor("pholdA:0", dtype=float32) b:c: Tensor("consC:0", shape=(4,), dtype=float32)
Обратите внимание, что тензоры не содержат значения в этой точке, и их значения могут быть доступны только при запуске графика в сеансе .
Графики
В этой точке график содержит только истинные тензоры, которые не связаны. Давайте проведем некоторые операции с нашими тензорами:
d = a * b + c d
dtype=float32>
Полученный результат снова является тензором с именем “add”, и наша модель теперь выглядит так, как показано на рисунке ниже. Вы можете исследовать свой график, а также другие параметры, используя встроенную функцию TensorFlow TensorBoard .
Рис. 1: График тензорного потока, состоящий из умножения и сложения.
Еще одним полезным инструментом для изучения вашего графика является следующий, который выводит все операции в нем.
# call the default graph graph = tf.get_default_graph() # print operations in the graph for op in graph.get_operations(): print(op.name)
pholdA varB/initial_value varB varB/Assign varB/read consC mul add
Сессий
Наконец, наш график должен быть запущен внутри сеанса. Обратите внимание, что переменные инициализируются заранее, в то время как тензор заполнителя получает конкретные значения через атрибут feed_dictionary
.
# Initialize variables init = tf.global_variables_initializer() # Run a session and calculate d sess = tf.Session() sess.run(init) print(sess.run(d, feed_dict={a: [[0.5], [2], [3]]})) sess.close()
[[ 2. 3. 4. 5.] [ 5. 6. 7. 8.] [ 7. 8. 9. 10.]]
Приведенный выше пример является довольно упрощенной моделью обучения. В любом случае, он показал, как основные компоненты tf
могут быть объединены в график и запущены в сеансе. Кроме того, он проиллюстрировал, как выполняются операции с тензорами различной формы.
В следующем разделе мы будем использовать Core API для построения нейронной сети для машинного обучения на реальных данных.
Нейросетевая модель
В этой части мы строим нейронную сеть обратной связи с нуля, используя основные компоненты TensorFlow. Мы сравниваем три архитектуры нейронной сети, которые будут различаться по количеству узлов в одном скрытом слое.
Набор данных Iris
Мы используем простой Iris dataset , который состоит из 150 примеров растений, каждое из которых имеет свои 4 измерения (используемые в качестве входных признаков) и свой тип (выходное значение, которое должно быть предсказано). Растение может принадлежать к одному из трех возможных типов (setosa, virginica и versicolor). Давайте сначала загрузим данные с сайта Tensorflow – они разбиты на обучающие и тестовые подмножества по 120 и 30 примеров в каждом.
# Import the needed libraries import numpy as np import pandas as pd import tensorflow as tf import urllib.request as request import matplotlib.pyplot as plt # Download dataset IRIS_TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv" IRIS_TEST_URL = "http://download.tensorflow.org/data/iris_test.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'species'] train = pd.read_csv(IRIS_TRAIN_URL, names=names, skiprows=1) test = pd.read_csv(IRIS_TEST_URL, names=names, skiprows=1) # Train and test input data Xtrain = train.drop("species", axis=1) Xtest = test.drop("species", axis=1) # Encode target values into binary ('one-hot' style) representation ytrain = pd.get_dummies(train.species) ytest = pd.get_dummies(test.species)
Модель и обучение
Форма входного и выходного слоев нашей нейронной сети будет соответствовать форме данных, то есть входной слой будет содержать четыре нейрона, представляющих четыре входных объекта, в то время как выходной слой будет содержать три нейрона из-за трех битов, используемых для кодирования вида растения в стиле one-hot . Например, вид “setosa” может быть закодирован вектором [1, 0, 0], “virginica” – вектором [0, 1, 0] и т. Д.
Мы выбираем три значения числа нейронов в скрытом слое: 5, 10 и 20, в результате чего размеры сети составляют (4-5-3), (4-10-3) и (4-20-3). Это означает, что наша первая сеть, например, будет иметь 4 входных нейрона, 5 “скрытых” нейронов и 3 выходных нейрона.
Рисунок 2: Наша трехслойная нейронная сеть обратной связи.
Приведенный ниже код определяет функцию, в которой мы создаем модель, определяем функцию потерь, которую необходимо минимизировать, и запускаем сеанс с 2000 итерациями, чтобы узнать оптимальные веса W_1
и W_2
. Как упоминалось ранее, входные и выходные матрицы подаются в тензоры tf.placeholder
, а веса представляются в виде переменных, поскольку их значения изменяются на каждой итерации. Функция потерь определяется как среднеквадратичная ошибка между нашим прогнозом y_est
и фактическим типом вида y
, а функция активации, которую мы используем, – это сигмоид . Функция create_train_model
возвращает изученные веса и выводит конечное значение функции потерь.
# Create and train a tensorflow model of a neural network def create_train_model(hidden_nodes, num_iters): # Reset the graph tf.reset_default_graph() # Placeholders for input and output data X = tf.placeholder(shape=(120, 4), dtype=tf.float64, name='X') y = tf.placeholder(shape=(120, 3), dtype=tf.float64, name='y') # Variables for two group of weights between the three layers of the network W1 = tf.Variable(np.random.rand(4, hidden_nodes), dtype=tf.float64) W2 = tf.Variable(np.random.rand(hidden_nodes, 3), dtype=tf.float64) # Create the neural net graph A1 = tf.sigmoid(tf.matmul(X, W1)) y_est = tf.sigmoid(tf.matmul(A1, W2)) # Define a loss function deltas = tf.square(y_est - y) loss = tf.reduce_sum(deltas) # Define a train operation to minimize the loss optimizer = tf.train.GradientDescentOptimizer(0.005) train = optimizer.minimize(loss) # Initialize variables and run session init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # Go through num_iters iterations for i in range(num_iters): sess.run(train, feed_dict={X: Xtrain, y: ytrain}) loss_plot[hidden_nodes].append(sess.run(loss, feed_dict={X: Xtrain.as_matrix(), y: ytrain.as_matrix()})) weights1 = sess.run(W1) weights2 = sess.run(W2) print("loss (hidden nodes: %d, iterations: %d): %.2f" % (hidden_nodes, num_iters, loss_plot[hidden_nodes][-1])) sess.close() return weights1, weights2
Хорошо, давайте создадим три сетевые архитектуры и построим функцию потерь по итерациям.
# Run the training for 3 different network architectures: (4-5-3) (4-10-3) (4-20-3) # Plot the loss function over iterations num_hidden_nodes = [5, 10, 20] loss_plot = {5: [], 10: [], 20: []} weights1 = {5: None, 10: None, 20: None} weights2 = {5: None, 10: None, 20: None} num_iters = 2000 plt.figure(figsize=(12,8)) for hidden_nodes in num_hidden_nodes: weights1[hidden_nodes], weights2[hidden_nodes] = create_train_model(hidden_nodes, num_iters) plt.plot(range(num_iters), loss_plot[hidden_nodes], label="nn: 4-%d-3" % hidden_nodes) plt.xlabel('Iteration', fontsize=12) plt.ylabel('Loss', fontsize=12) plt.legend(fontsize=12)
loss (hidden nodes: 5, iterations: 2000): 31.82 loss (hidden nodes: 10, iterations: 2000): 5.90 loss (hidden nodes: 20, iterations: 2000): 5.61
Рис. 3: Функция потерь за 2000 итераций для различных сетевых архитектур.
Мы видим, что сети с 20 скрытыми нейронами требуется больше времени, чтобы достичь минимума, что связано с ее более высокой сложностью. Сеть с 5 скрытыми нейронами застревает в локальном минимуме и не дает хороших результатов.
Во всяком случае, для такого простого набора данных, как Iris, даже небольшая сеть с 5 скрытыми нейронами должна быть в состоянии изучить хорошую модель. В нашем случае это было просто случайное событие, что модель застряла в локальном минимуме, и это не произойдет очень часто, если мы будем запускать код снова и снова.
Оценка модели
Наконец, давайте оценим наши модели. Мы используем изученные веса W_1
и W_2
и вперед распространяем примеры тестового набора. Метрика точности определяется как процент правильно предсказанных примеров.
# Evaluate models on the test set X = tf.placeholder(shape=(30, 4), dtype=tf.float64, name='X') y = tf.placeholder(shape=(30, 3), dtype=tf.float64, name='y') for hidden_nodes in num_hidden_nodes: # Forward propagation W1 = tf.Variable(weights1[hidden_nodes]) W2 = tf.Variable(weights2[hidden_nodes]) A1 = tf.sigmoid(tf.matmul(X, W1)) y_est = tf.sigmoid(tf.matmul(A1, W2)) # Calculate the predicted outputs init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) y_est_np = sess.run(y_est, feed_dict={X: Xtest, y: ytest}) # Calculate the prediction accuracy correct = [estimate.argmax(axis=0) == target.argmax(axis=0) for estimate, target in zip(y_est_np, ytest.as_matrix())] accuracy = 100 * sum(correct) / len(correct) print('Network architecture 4-%d-3, accuracy: %.2f%%' % (hidden_nodes, accuracy))
Network architecture 4-5-3, accuracy: 90.00% Network architecture 4-10-3, accuracy: 96.67% Network architecture 4-20-3, accuracy: 96.67%
В целом нам удалось достичь довольно высокой точности с помощью простой нейронной сети обратной связи, что особенно удивительно при использовании довольно небольшого набора данных.
Вы можете взглянуть на еще более простой пример использования высокоуровневого API Tensorflow здесь .
Ресурсы
Этот учебник охватывал лишь малую часть того, что может сделать TensorFlow. Вот несколько замечательных ресурсов, чтобы узнать больше о TensorFlow и глубоком обучении в целом:
Выводы
В этом посте мы представили библиотеку TensorFlow для машинного обучения, предоставили краткие руководства по установке, представили основные компоненты низкоуровневого Core API TensorFlow: Тензоры, графики и сеансы и, наконец, построили нейросетевую модель для классификации реальных данных набора данных Iris.
В общем, может потребоваться некоторое время, чтобы понять философию кодирования TensorFlow, поскольку это символическая библиотека, но как только вы познакомитесь с основными компонентами, это довольно удобно для создания приложений машинного обучения. В этом посте мы использовали низкоуровневый Core API для того, чтобы представить основные компоненты и иметь полный контроль над моделью, но обычно гораздо проще использовать API более высокого уровня, такой как tf.estimator
, или даже внешнюю библиотеку, такую как Keras .