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

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

Мы продолжим наш пример описанием проблемы и проектом распознавания выражения лица. В этой лекции мы напишем код для свёрточной нейронной сети в TensorFlow. Перед этим мы писали код для Theano и, надо сказать, тут есть много общего.

Начинаем с импорта основных библиотек; кроме них, используем наш старый код из файла ann_tf для скрытых слоёв. Далее, мы знаем, что нам нужно определить convpool-слои и CNN с размерами convpool и скрытых слоёв. В функции main ничего менять не будем.

import numpy as np

import tensorflow as tf

import matplotlib.pyplot as plt

from sklearn.utils import shuffle

from util import getImageData, error_rate, init_weight_and_bias, y2indicator

from ann_tf import HiddenLayer

class ConvPoolLayer(object):

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

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 main():

    X, Y = getImageData()

    X = X.transpose((0, 2, 3, 1))

    model = CNN(

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

        hidden_layer_sizes=[500, 300],

    )

    model.fit(X, Y)

if __name__ == ‘__main__’:

main()

 

Теперь по поводу некоторых отличий от Theano. Вставим прежнюю функцию init_filter из TensorFlow. Поскольку фильтры в TensorFlow отличаются порядком определениях от таковых в Theano, убедитесь, что вы вставили нужную функцию.

def init_filter(shape, poolsz):

    w = np.random.randn(*shape) / np.sqrt(np.prod(shape[:-1]) + shape[-1]*np.prod(shape[:-2] / np.prod(poolsz)))

    return w.astype(np.float32)

 

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

class ConvPoolLayer(object):

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

        sz = (fw, fh, mi, mo)

        W0 = init_filter(sz, poolsz)

        self.W = tf.Variable(W0)

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

        self.b = tf.Variable(b0)

        self.poolsz = poolsz

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

 

И сразу определим функцию forward для convpool-слоя.

    def forward(self, X):

        conv_out = tf.nn.conv2d(X, self.W, strides=[1, 1, 1, 1], padding=’SAME’)

        conv_out = tf.nn.bias_add(conv_out, self.b)

        pool_out = tf.nn.max_pool(conv_out, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=’SAME’)

        return tf.tanh(pool_out)

 

Теперь вернёмся к классу CNN. Сам класс мы уже определили, но осталась ещё функция fit со всеми параметрами. Ею и займёмся. Все переменные конвертируем во float32.

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

        lr = np.float32(lr)

        mu = np.float32(mu)

        reg = np.float32(reg)

        decay = np.float32(decay)

        eps = np.float32(eps)

        K = len(set(Y))

 

Вновь создадим наш проверочный набор.

        X, Y = shuffle(X, Y)

        X = X.astype(np.float32)

        Y = y2indicator(Y).astype(np.float32)

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

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

        Yvalid_flat = np.argmax(Yvalid, axis=1)

 

Как вы, должно быть, уже хорошо помните, TensorFlow принимает наше X в несколько другой форме, нежели Theano – если в Theano это N, цвет, ширина фильтра, высота фильтра, то в TensorFlow это N, ширина фильтра, высота фильтра, цвет. Проследите, чтобы в функции main это было учтено.

Вернёмся к функции fit. Теперь мы инициируем convpool-слои.

        N, d, d, c = 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 / 2

            outh = outh / 2

            mi = mo

 

И это всё, что касается convpool-слоёв. Переходим теперь к скрытым слоям.

        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 = tf.Variable(W, ‘W_logreg’)

        self.b = tf.Variable(b, ‘b_logreg’)

 

Запишем дополнительные параметры для последующего использования. Всё то же, что и в Theano.

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

        for h in self.convpool_layers:

            self.params += h.params

        for h in self.hidden_layers:

            self.params += h.params

 

Следующий этап – определение функций и переменных TensorFlow.

        tfX = tf.placeholder(tf.float32, shape=(None, d, d, c), name=’X’)

        tfY = tf.placeholder(tf.float32, shape=(None, K), name=’Y’)

        act = self.forward(tfX)

        rcost = reg*sum([tf.nn.l2_loss(p) for p in self.params])

        cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(act, tfY)) + rcost

        prediction = self.predict(tfX)

 

Для функции обучения используем опять же метод адаптивного скользящего среднего градиента (RMSProp).

        train_op = tf.train.RMSPropOptimizer(lr, decay=decay, momentum=mu).minimize(cost)

        n_batches = N / batch_sz

        costs = []

        init = tf. initialize_all_variables()

 

Начинаем сессию и пишем наш основной цикл.

        with tf.Session() as session:

            session.run(init)

            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)]

                    session.run(train_op, feed_dict={tfX: Xbatch, tfY: Ybatch})

 

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

                    if j % 20 == 0:

                        c = session.run(cost, feed_dict={tfX: Xvalid, tfY: Yvalid})

                        costs.append(c)

                        p = session.run(prediction, feed_dict={tfX: Xvalid, tfY: Yvalid})

                        e = error_rate(Yvalid_flat, 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_shape = Z.get_shape().as_list()

        Z = tf.reshape(Z, [-1, np.prod(Z_shape[1:])])

        for h in self.hidden_layers:

            Z = h.forward(Z)

        return tf.matmul(Z, self.W) + self.b

 

Остаётся лишь функция predict. Это совсем просто.

    def predict(self, X):

        pY = self.forward(X)

        return tf.argmax(pY, 1)

 

Готово. Проверим программу.

Спасибо, что уделили время на изучение данного курса.

Увидимся с вами и продолжим на следующих курсах!

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

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