ИНС на основе классов в 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)

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

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

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

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