ИНС на основе классов в Theano

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

Мы продолжаем рассматривать наш пример с распознаванием выражения лица.

Если вы не хотите писать код самостоятельно, а сразу просмотреть его окончательную версию, зайдите в репозитарий Github и найдите файл ann_theano.py.

Как обычно, нам понадобятся библиотеки NumPy, Matplotlib и Theano. Из файла util.py мы импортируем функции getData, getBinaryData – сугубо чтобы проверить функцию на небольшом наборе данных, y2indicator, error_rate, relu – только для того случая, если у вас старая версия Theano, в которой не встроена эта функция, и init_weight_and_bias. Из sklearn.utils нам понадобится функция shuffle, чтобы перемешивать данные и не использовать каждый раз один и тот же их набор.

import numpy as np

import theano

import theano.tensor as T

import matplotlib.pyplot as plt

from util import getData, getBinaryData, y2indicator, error_rate, relu, init_weight_and_bias

from sklearn.utils import shuffle

Функция main совершенно тривиальна. Мы создадим искусственную нейронную сеть (ИНС) с 2 000 узлов в первом скрытом слое и с 1 000 узлов – во втором. Мы также создадим функцию fit, в качестве аргументов принимающую наши X и Y.

def main()

    X, Y = getData()

    model = ANN([2000, 1000])

    model.fit(X, Y, show_fig=True)

if __name__ == ‘__main__’:

    main()

Теперь создадим для скрытого слоя соответствующий класс, чтобы впоследствии было легче добавлять любое количество скрытых слоёв. При этом создадим общие переменные Theano self.W и self.b, так что каждый скрытый слой будет иметь собственные значения весовых коэффициентов и свободных членов. Функция init_weight_and_bias создаст W размерностью M1xM2 и b размерностью M2. Кроме того, определим функцию forward – в данном случае она будет использовать функцию relu.

class HiddenLayer(object):

def __init__(self, M1, M2, an_id):

  self.id = an_id

  self.M1 = M1

  self.M2 = M2

 W, b = init_weight_and_bias(M1, M2)

  self.W = theano.shared(W, ‘W_%s’ % self.id)

  self.b = theano.shared(b, ‘b_%s’ % self.id)

  self.params = [self.W, self.b]

def forward(self, X):

return relu(X.dot(self.W) + self.b)

Это всё, что касается скрытого слоя.

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

class ANN(object):

    def __init__(self, hidden_layer_sizes):

        self.hidden_layer_sizes = hidden_layer_sizes

    def fit(self, X, Y, learning_rate=10e-7, mu=0.99, decay=0.999, reg=10e-12, epochs=400, batch_sz=100, show_fig=False):

        learning_rate = np.float32(learning_rate)

Теперь определим валидационный набор данных. На случай, если вы захотите запустить код с помощью графического процессора, переведём наши данные в float32. В качестве валидационного набора оставим последние 1 000 наблюдений (примеров).

# make a validation set

X, Y = shuffle(X, Y)

X = X.astype(np.float32)

Y = Y.astype(np. float32)

Xvalid, Yvalid = X[-1000:], Y[-1000:]

X, Y = X[:-1000], Y[:-1000]

Следующий этап – инициация скрытых слоёв.

# initialize hidden layers

N, D = X.shape

K = len(set(Y))

self.hidden_layers = []

M1 = D

count = 0

for M2 in self.hidden_layer_sizes:

h = HiddenLayer(M1, M2, count)

self.hidden_layers.append(h)

M1 = M2

count += 1

W, b = init_weight_and_bias(M1, K)

self.W = theano.shared(W, ‘W_logreg’)

 self.b = theano.shared(b, ‘b_logreg’)

Далее – сбор всех параметров, необходимых для градиентного спуска.

self.params = [self.W, self.b]

for h in self.hidden_layers:

self.params += h.params

Для увеличения скорости градиентного спуска нам нужен импульс.

# for momentum

dparams = [theano.shared(np.zeros(p.get_value().shape)) for p in self.params]

Теперь – код для метода адаптивного скользящего среднего градиента (RMSprop).

# for rmsprop

cache = [theano.shared(np.zeros(p.get_value().shape, dtype=np.float32)) for p in self.params]

Далее определяем наши функции и переменные Theano.

# set up theano functions and variables

thX = T.fmatrix(‘X’)

thY = T.ivector(‘Y’)

pY = self.th_forward(thX)

Сразу же определяем функцию затрат с учётом регуляризации.

rcost = reg*T.sum([(p*p).sum() for p in self.params])

cost = -T.mean(T.log(pY[T.arange(thY.shape[0]), thY])) + rcost

prediction = self.th_predict(thX)

cost_predict_op = theano.function(

inputs=[thX, thY],

outputs=[cost, prediction]

)

Теперь определяем выражения для обновления весовых коэффициентов.

updates = [

 (c, decay*c + (1-decay)*T.grad(cost, p)) for p, c in zip(self.params, cache)

  ] + [

(p, p + mu*dp – learning_rate*T.grad(cost, p)/T.sqrt(c + 10e-10)) for p, c, dp in zip(self.params, cache, dparams)

 ] + [

(dp, mu*dp – learning_rate*T.grad(cost, p)/T.sqrt(c + 10e-10)) for p, c, dp in zip(self.params, cache, dparams)

 ]

Теперь мы можем определить функцию для обучений нейронной сети.

train_op = theano.function(

inputs=[thX, thY],

updates=updates

 )

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

n_batches = N / batch_sz

costs = []

for i in xrange(epochs):

X, Y = shuffle(X, Y)

for j in xrange(n_batches):

Xbatch = X[j*batch_sz:(j*batch_sz+batch_sz)]

Ybatch = Y[j*batch_sz:(j*batch_sz+batch_sz)]

 train_op(Xbatch, Ybatch)

if j % 20 == 0:

 c, p = cost_predict_op(Xvalid, Yvalid)

 costs.append(c)

 e = error_rate(Yvalid, p)

print(“i:”, i, “j:”, j, “nb:”, n_batches, “cost:”, c, “error rate:”, e)

И после всего этого – рисуем график.

if show_fig:

 plt.plot(costs)

 plt.show()

Нам осталось определить лишь функции forward и predict.

def forward(self, X):

 Z = X

for h in self.hidden_layers:

 Z = h.forward(Z)

 return T.nnet.softmax(Z.dot(self.W) + self.b)

def predict(self, X):

 pY = self.th_forward(X)

 return T.argmax(pY, axis=1)

Всё, можем запускать:

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

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

Share via
Copy link