Свёрточная сеть в Theano

Здравствуйте и вновь добро пожаловать на наши занятия по теме «Свёрточные нейронные сети: глубокое обучение на языке Python, часть 3».

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

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

При загрузке данных нам больше не нужны сглаженные данные, а нужны изображения, поэтому в функции main используем теперь функцию getImageData, которая даст нам корректные данные для свёрточной нейронной сети.

Кроме того, подумаем о параметрах нашей свёрточной сети. Используем объект CNN и сделаем небольшой многослойный персептрон с 500 и 300 скрытыми узлами. Кроме того, нам понадобятся новые входные переменные, представляющие собой свёрточную и агрегационную части. В каждой из них должны быть указаны количество карт признаков, а также ширина и высота фильтров. Установим два convpool-слоя с 20 картами признаков и шириной и высотой фильтров, равными 5. Всё остальное остаётся прежним.

import numpy as np

import theano

import theano.tensor as T

import matplotlib.pyplot as plt

from sklearn.utils import shuffle

from theano.tensor.nnet import conv2d

from theano.tensor.signal.pool import pool_2d

from util import getImageData, error_rate, init_weight_and_bias, init_filter

from ann_theano import HiddenLayer,

def main():

    X, Y = getImageData()

    model = CNN(

        convpool_layer_sizes=[(20, 5, 5), (20, 5, 5)],

        hidden_layer_sizes=[500, 300],

    )

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

if __name__ == ‘__main__’:

main()

 

Как и в простейшей нейронной сети, создадим класс ConvPoolLayer. Не забываем, что Theano работает с определённым порядком параметров: сначала количество исходящих карт признаков, затем количество входных карт признаков, после чего ширина и высота фильтра. Свободные члены устанавливаем равными нулю.

class ConvPoolLayer(object):

    def __init__(self, mi, mo, fw=5, fh=5, poolsz=(2, 2)):

        sz = (mo, mi, fw, fh)

        W0 = init_filter(sz, poolsz)

        self.W = theano.shared(W0)

        b0 = np.zeros(mo, dtype=np.float32)

        self.b = theano.shared(b0)

        self.poolsz = poolsz

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

 

Далее функция forward с гиперболическим тангенсом в качестве функции активации.

    def forward(self, X):

        conv_out = conv2d(input=X, filters=self.W)

        pooled_out = downsample.max_pool_2d(

            input=conv_out,

            ds=self.poolsz,

            ignore_border=True,

        )

        return T.tanh(pooled_out + self.b.dimshuffle(‘x’, 0, ‘x’, ‘x’))

 

Это всё, что касается convpool-слоя.

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

class CNN(object):

    def __init__(self, convpool_layer_sizes, hidden_layer_sizes):

        self.convpool_layer_sizes = convpool_layer_sizes

        self.hidden_layer_sizes = hidden_layer_sizes

    def fit(self, X, Y, lr=10e-5, mu=0.99, reg=10e-7, decay=0.99999, eps=10e-3, batch_sz=30, epochs=100, show_fig=True):

        lr = np.float32(lr)

        mu = np.float32(mu)

        reg = np.float32(reg)

        decay = np.float32(decay)

        eps = np.float32(eps)

 

И, как и прежде, установим проверочный набор, включающий 1 000 образцов.

        X, Y = shuffle(X, Y)

        X = X.astype(np.float32)

        Y = Y.astype(np.int32)

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

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

 

Теперь инициируем convpool-слои.

        N, c, d, dt = X.shape

        mi = c

        outw = d

        outh = d

        self.convpool_layers = []

        for mo, fw, fh in self.convpool_layer_sizes:

            layer = ConvPoolLayer(mi, mo, fw, fh)

            self.convpool_layers.append(layer)

            outw = (outw – fw + 1) / 2

            outh = (outh – fh + 1) / 2

            mi = mo

 

Далее инициируем слои персептрона.

        K = len(set(Y))

        self.hidden_layers = []

        M1 = self.convpool_layer_sizes[-1][0]*outw*outh

        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 c in self.convpool_layers:

            self.params += c.params

        for h in self.hidden_layers:

            self.params += h.params

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

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

 

Следующим идёт определение переменных Theano. Не забывайте, что теперь входные данные представлены четырёхмерным тензором.

        thX = T.tensor4(‘X’, dtype=’float32′)

        thY = T.ivector(‘Y’)

        pY = self.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 = [

            (p, p + mu*dp – lr*T.grad(cost, p)) for p, dp in zip(self.params, dparams)

        ] + [

            (dp, mu*dp – lr*T.grad(cost, p)) for p, dp in zip(self.params, dparams))

        train_op = theano.function(

            inputs=[thX, thY],

            updates=updates

        )

 

И теперь главный цикл.

        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 c in self.convpool_layers:

            Z = c.forward(Z)

        Z = Z.flatten(ndim=2)

        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.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: :???: :?: :!: