Theano в глубоком обучении

Основы Theano. Переменные, функции, оптимизация выражений

Здравствуйте и вновь добро пожаловать на занятия по теме «Обработка данных: практическое глубокое обучение в Theano и TensorFlow».

В этой лекции мы рассмотрим основы библиотеки Theano. Мы рассмотрим Theano достаточно подробно, чтобы вы без особых проблем смогли создать собственную нейронную сеть, а в следующей лекции мы построим нейронную сеть с использованием Theano и проверим её на наших данных. Если вы хотите получить используемый в этой лекции код, перейдите по адресу, найдите папку ann_class2 и в ней файл theano1.py.

Итак, запустим файл в Iphyton, чтобы вы могли видеть, что будет происходить. Дело в том, что множество новых идей и вещей будут работать не так, как можно было бы ожидать в обычном Phyton. Я не буду показывать, как установить Theano, поскольку это весьма несложно – просто зайдите на сайт и следуйте инструкциям. До сих пор я ни разу не слышал, чтобы у кого-то при этом возникали проблемы.

После этого первое, о чём мы поговорим, – это переменные Theano. Поскольку мы настолько часто будем использовать тензоры Theano, то будем обозначать библиотеку Theano через большое Т:

import theano.tensor as T

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

c = T.scalar(‘c’)

То же самое мы можем сделать для вектора:

v = T.vector(‘v’)

И для матрицы:

A = T.matrix(‘A’)

В Theano есть и тензоры, размерности которых достаточно равняться трём. Вы можете столкнуться с ними, если будете работать с неплоскими изображениями вроде тех, которыми мы уже пользовались. В таком случае у нас будет вектор длиной в 784 элемента, который должен быть переформатирован в размерность 28х28, чтобы иметь возможность просматривать изображения. Если вы хотите сохранить изображения в виде квадратов и у вас есть N изображений, то получится размерность Nx28x28, что и является трёхмерным тензором. Если же у вас есть три цветовых канала, например красный, зелёный и синий, то получится тензор с размерностью Nx3x28x28, являющийся четырёхмерным тензором. В этом курсе мы не будем работать с тензорами, поэтому это всё, что я хотел о них рассказать.

Обратите внимание, что все созданные мною переменные не имеют текущих значений. Все созданные переменные являются лишь символами, но мы можем проводить над ними алгебраические операции. В качестве примера давайте проведём операцию скалярного произведения между A и v:

w = A.dot(v)

На самом деле никакой операции умножения мы не провели, поскольку она невозможна ввиду того, что ни A, ни v до сих пор не имеют никаких значений. Как же установить значения для A и v и найти результат w? Вот тут-то и вступают в игру функции Theano. Импортируем высокоуровневый модуль Theano, используя который, мы можем создавать функции Theano:

import theano

Каждое создание функции определяет входные и исходящие величины:

matrix_times_vector = theano.function(inputs=[A,v], outputs=w)

Импортируем теперь библиотеку Numpy, чтобы создать действительные массивы и вызвать функцию:

import numpy as np

A_val = np.array([[1,2], [3,4]])

v_val = np.array([5,6])

А вот так мы вызываем функцию и получаем ожидаемый результат:

w_val = matrix_times_vector(A_val, v_val)

print w_val

Пока что ничего особенного, не так ли?

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

В Theano обычные переменные являются необновляемыми. Для создания обновляемой переменной нам необходимо создать то, что называется общей переменной (shared variable). Этим и займёмся.

x = theano.shared(20.0, ‘x’)

Здесь первым параметром является первоначальное значение переменной, а вторым – её имя.

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

cost = x*x + x +1

Теперь давайте объясним Theano, как мы хотим обновить значение x, предложив выражение для обновления:

x_update = x – 0.3*T.grad(cost, x)

Что замечательно в Theano, так это то, что она автоматически вычисляет градиент. Функция grad имеет два параметра: первый – это функция, чей градиент мы хотим найти, а второй – переменная, относительно которой мы ищем градиент. При этом в качестве второго параметра вы можете подставить несколько переменных в виде списка.

Теперь давайте создадим простенькую обучающую функцию, похожую на предыдущую, но с тем исключением, что добавим в неё новый аргумент updates. Аргумент updates содержит список кортежей; каждый из кортежей включает два элемента: первый – обновляемая общая переменная, а второй – используемое для обновления выражение.

train = theano.function(inputs=□, outputs=cost, updates=[(x, x_update)])

Таким образом, в функции нет входных величин, и позже вы поймёте, почему.

Итак, мы создали функцию для обучения, но на самом деле ещё не вызвали.

Обратите внимание, что x является не входной величиной, а величиной, которая будет обновляться. В дальнейших примерах входящими величинами будут данные и метки. Таким образом, параметр inputs использует данные и метки, а параметр updates использует параметры модели с их обновлениями.

Теперь нам необходимо написать цикл для вызова обучающей функции:

for i in xrange(25):

cost_val = train()

print cost_val

Всё сошлось довольно быстро. Обратите внимание, что мы пришли к ожидаемому значению функции затрат и можем вывести на экран оптимальное значение x, использовав функцию get_value:

x.get_value()

Это значение и ожидалось.

Построение нейронной сети в Theano

Теперь настало время создать нейронную сеть в Theano, используя основы, которые мы изучили в предыдущей лекции. Если вы не хотите писать код самостоятельно, а лишь просмотреть его, перейдите по адресy и найдите папку ann_class2. Соответствующий файл называется theano2.py.

Итак, первым делом мы импортируем все обычные библиотеки, включая на этот раз и Theano, а также Matplotlib, чтобы иметь возможность построить график логарифма функции правдоподобия. Кроме того, из файла util.py импортируем функции

get_normalized_data и y2indicator.

import numpy as np

import theano

import theano.tensor as T

import matplotlib.pyplot as plt

from util import get_normalized_data, y2indicator

Далее мы определим функцию error_rate, возвращающую лишь среднее значение случаев, когда p ≠ t.

def error_rate(p, t):

return np.mean(p != t)

Новые версии библиотеки Theano имеют встроенную функцию relu, но на случай, если у вас таких версий нет, мы определим её сами.

def relu(a):

return a * (a > 0)

Обе эти функции используют значения «истина» и «ложь» и преобразуют их в числа.

Первым этапом, как обычно, идёт получение данных. Мы используем все те же параметры, которые установили в предыдущих примерах, поэтому на самом деле их можно просто скопировать из предыдущего файла.

def main():

    X, Y = get_normalized_data()

    max_iter = 20

    print_period = 10

    lr = 0.00004

    reg = 0.01

    Xtrain = X[:-1000,]

    Ytrain = Y[:-1000]

    Xtest  = X[-1000:,]

    Ytest  = Y[-1000:]

    Ytrain_ind = y2indicator(Ytrain)

    Ytest_ind = y2indicator(Ytest)

    N, D = Xtrain.shape

    batch_sz = 500

    n_batches = N // batch_sz

    M = 300

    K = 10

    W1_init = np.random.randn(D, M) / 28

    b1_init = np.zeros(M)

    W2_init = np.random.randn(M, K) / np.sqrt(M)

    b2_init = np.zeros(K)

Следующий этап – создание переменных и выражений Theano, причём все значения весовых коэффициентов и свободных членов будут общими переменными.

thX = T.matrix(‘X’)

thT = T.matrix(‘T’)

W1 = theano.shared(W1_init, ‘W1’)

b1 = theano.shared(b1_init, ‘b1’)

W2 = theano.shared(W2_init, ‘W2’)

b2 = theano.shared(b2_init, ‘b2’)

Вызовем также функции relu и софтмакс – Theano имеет встроенную функцию софтмакс.

thZ = relu( thX.dot(W1) + b1 )

thY = T.nnet.softmax( thZ.dot(W2) + b2 )

Кроме того, определим в Theano нашу функцию затрат, включая и выражение для регуляризации. Мы можем так записать, поскольку Theano автоматически выполняет дифференцирование и нам нет нужды проводить его вручную.

cost = -(thT * T.log(thY)).sum() + reg*((W1*W1).sum() + (b1*b1).sum() + (W2*W2).sum() + (b2*b2).sum())

Нам также понадобится переменная prediction, чтобы вычислить коэффициент ошибок.

prediction = T.argmax(thY, axis=1)

Далее запишем выражения для обновления значений весовых коэффициентов и свободных членов.

update_W1 = W1 – lr*T.grad(cost, W1)

update_b1 = b1 – lr*T.grad(cost, b1)

update_W2 = W2 – lr*T.grad(cost, W2)

update_b2 = b2 – lr*T.grad(cost, b2)

Теперь создадим функцию train, являющуюся функцией Theano. Обратите внимание, что эта функция не имеет исходящих величин.

train = theano.function(

inputs=[thX, thT],

updates=[(W1, update_W1), (b1, update_b1), (W2, update_W2), (b2, update_b2)],

)

И заодно создадим функцию get_prediction, ведь мы всегда так делаем для проверочного набора данных.

get_prediction = theano.function(

inputs=[thX, thT],

outputs=[cost, prediction],

)

Далее используем цикл из предыдущего примера, но с использованием написанных нами функций Theano, и выведём всё на экран.

LL = []

for i in xrange(max_iter):

for j in xrange(n_batches):

Xbatch = Xtrain[j*batch_sz:(j*batch_sz + batch_sz),]

Ybatch = Ytrain_ind[j*batch_sz:(j*batch_sz + batch_sz),]

train(Xbatch, Ybatch)

 

if j % print_period == 0:

  cost_val, prediction_val = get_prediction(Xtest, Ytest_ind)

  err = error_rate(prediction_val, Ytest)

    print(“Cost / err at iteration i=%d, j=%d: %.3f / %.3f” % (i, j, cost_val, err))

      LL.append(cost_val)

    plt.plot(LL)

    plt.show()

if __name__ == ‘__main__’:

main()

Итак, запустим программу. Кажется, всё работает, как ожидалось.

Андрей Никитенко
Андрей Никитенко
Задать вопрос эксперту
Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Share via
Copy link