Распознавание выражения лица

Распознавание выражения лица. Двоичная сигмоида

Здравствуйте и вновь добро пожаловать на наши занятия по глубокому обучению.

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

Итак, начало очень похоже на предыдущий файл. Если вы не хотите писать код самостоятельно, зайдите на репозитарий GitHub и найдите файл ann_sigmoid.py.

Из файла util.py импортируем функции getBinaryData, sigmoid, sigmoid_cost, error_rate, relu – новой здесь является только функция relu.

import numpy as np

import matplotlib.pyplot as plt

from sklearn.utils import shuffle

from util import getBinaryData, sigmoid, sigmoid_cost, error_rate, relu

Вновь определяем класс ANN. Количество скрытых единиц сохраним как свойство класса.

class ANN(object):

    def __init__(self, M):

        self.M = M

В классе ANN определим функцию fit, установив коэффициент обучения равным 5*10-7, регуляризацию равной единице, а количество циклов равным 10 000 – намного меньше, чем мы устанавливали ранее. Начало также похоже на то, что мы делали раньше – перемешиваем наши X и Y и делим их на учебный и проверочный наборы. Последние 1 000 примеров будут проверочными.

    def fit(self, X, Y, learning_rate=5*10e-7, reg=1.0, epochs=10000, show_fig=False):

        X, Y = shuffle(X, Y)

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

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

После этого инициируем весовые коэффициенты, начав с прямого распространения.

        N, D = X.shape

        self.W1 = np.random.randn(D, self.M) / np.sqrt(D + self.M)

        self.b1 = np.zeros(self.M)

        self.W2 = np.random.randn(self.M) / np.sqrt(self.M)

        self.b2 = 0

И пишем цикл.

        costs = []

        best_validation_error = 1

        for i in xrange(epochs):

            pY, Z = self.forward(X)

            pY_Y = pY – Y

            self.W2 -= learning_rate*(Z.T.dot(pY_Y) + reg*self.W2)

            self.b2 -= learning_rate*((pY_Y).sum() + reg*self.b2)

Следующее – алгоритм обратного распространения ошибок на входе скрытых весовых коэффициентов.

            dZ = np.outer(pY_Y, self.W2) * (Z > 0)

            self.W1 -= learning_rate*(X.T.dot(dZ) + reg*self.W1)

            self.b1 -= learning_rate*(np.sum(dZ, axis=0) + reg*self.b1)

Через каждые 20 прогонов будем выводить ошибку проверки.

            if i % 20 == 0:

                pYvalid, _ = self.forward(Xvalid)

                c = sigmoid_cost(Yvalid, pYvalid)

                costs.append(c)

                e = error_rate(Yvalid, np.round(pYvalid))

                print(“i:”, i, “cost:”, c, “error:”, e)

             

   if e < best_validation_error:

                    best_validation_error = e

        print(“best_validation_error:”, best_validation_error)

        if show_fig:

            plt.plot(costs)

            plt.show()

Теперь осталось определить функции forward, predict и score – всё как в логистической регрессии.

    def forward(self, X):

        Z = relu(X.dot(self.W1) + self.b1)

        return sigmoid(Z.dot(self.W2) + self.b2), Z

    def predict(self, X):

        pY, _ = self.forward(X)

        return np.round(pY)

    def score(self, X, Y):

        prediction = self.predict(X)

        return 1 – error_rate(Y, prediction)

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

def main():

    X, Y = getBinaryData()

    X0 = X[Y==0, :]

    X1 = X[Y==1, :]

    X1 = np.repeat(X1, 9, axis=0)

    X = np.vstack([X0, X1])

    Y = np.array([0]*len(X0) + [1]*len(X1))

   

    model = ANN(100)

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

if __name__ == ‘__main__’:

main()

В случае, если вы захотите использовать в качестве функции активации гиперболический тангенс, вы должны сделать следующее. Строку

            dZ = np.outer(pY_Y, self.W2) * (Z > 0)

надо заменить на строку

            dZ = np.outer(pY_Y, self.W2) * (1 – Z*Z)

А строку

        Z = relu(X.dot(self.W1) + self.b1)

заменить на строку

        Z = np.tanh(X.dot(self.W1) + self.b1).

Распознавание выражения лица. Логистическая регрессия и софтмакс

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

Итак, как обычно импортируем библиотеки Numpy и Matplotlib. Из файле util импортируем функции getData (причём не забывайте, что мы теперь рассматриваем не сугубо двоичные данные, а все), softmax, cost, y2indicator (данная функция преобразует список меток от 0 до 6 в матрицу размерности Nx7, состоящую из нулей и единиц), а также error_rate. Из sklearn.utils импортируем функцию shuffle, который перемешает наши данные.

import numpy as np

import matplotlib.pyplot as plt

from util import getData, softmax, cost, y2indicator, error_rate

from sklearn.utils import shuffle

И вновь создаём новый класс, который назовём LogisticModel.

class LogisticModel(object):

    def __init__(self):

        pass

Теперь определим нашу функцию fit. Установим значение коэффициента обучения равным 10-8, регуляризацию равной 10-12, и количество циклов, равным 10 000. Первая часть опять очень похожа на то, что мы делали ранее, – перемешиваем наши данные, установив последние 1 000 примеров в качестве проверочного набора. Поскольку у нас логистическая регрессия, то будет лишь один весовой коэффициент и один свободный член.

    def fit(self, X, Y, learning_rate=10e-8, reg=10e-12, epochs=10000, show_fig=False):

        X, Y = shuffle(X, Y)

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

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

        N, D = X.shape

        K = len(set(Y))

        T = y2indicator(Y)

        self.W = np.random.randn(D, K) / np.sqrt(D + K)

        self.b = np.zeros(K)

Далее тоже как обычно. Сначала запускаем прямое распространение, а затем – градиентный спуск.

        costs = []

        best_validation_error = 1

        for i in xrange(epochs):

            pY = self.forward(X)

            self.W -= learning_rate*(X.T.dot(pY – T) + reg*self.W)

            self.b -= learning_rate*((pY – T).sum(axis=0) + reg*self.b)

Через каждые 10 раз будем вычислять значение функции затрат.

            if i % 10 == 0:

                pYvalid = self.forward(Xvalid)

                c = cost(Tvalid, pYvalid)

                costs.append(c)

                e = error_rate(Yvalid, np.argmax(pYvalid, axis=1))

                print(“i:”, i, “cost:”, c, “error:”, e)

               

if e < best_validation_error:

                    best_validation_error = e

        print(“best_validation_error:”, best_validation_error)

        if show_fig:

            plt.plot(costs)

            plt.show()

Теперь определим остальные необходимые нам функции forward, predict и score.

    def forward(self, X):

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

    def predict(self, X):

        pY = self.forward(X)

        return np.argmax(pY, axis=1)

    def score(self, X, Y):

        prediction = self.predict(X)

        return 1 – error_rate(Y, prediction)

Теперь мы готовы определить функцию main.

def main():

    X, Y = getData()

   

    model = LogisticModel()

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

    print(model.score(X, Y))

if __name__ == ‘__main__’:

main()

Запустим программу и посмотрим, что получится.

Распознавание выражения лица. ИНН и софтмакс

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

Поскольку код похож, скопируем часть его из предыдущего файла, с тем лишь отличием, что теперь импортируем вместо функции cost функцию cost2. Как вы помните, обе они делают то же самое, но cost2 несколько эффективнее. Мы также импортируем функцию relu.

import numpy as np

import matplotlib.pyplot as plt

from util import getData, softmax, cost2, y2indicator, error_rate, relu

from sklearn.utils import shuffle

Функция main также очень похожа, разве что класс у нас теперь будет называться ANN.

def main():

    X, Y = getData()

   

    model = ANN()

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

    print(model.score(X, Y))

if __name__ == ‘__main__’:

main()

Итак, давайте определим наш класс ANN.

class ANN(object):

    def __init__(self, M):

        self.M = M

Далее определим функцию fit. Коэффициент обучения равен 10-6, регуляризация равна 10-1, количество циклов равно 10 000. Как и прежде, перемешиваем наши данные, оставляя последние 1 000 примеров в качестве проверочного набора.

    def fit(self, X, Y, learning_rate=10e-7, reg=10e-7, epochs=10000, show_fig=False):

        X, Y = shuffle(X, Y)

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

        # Tvalid = y2indicator(Yvalid)

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

        N, D = X.shape

        K = len(set(Y))

        T = y2indicator(Y)

Инициируем наши весовые коэффициенты.

        self.W1 = np.random.randn(D, self.M) / np.sqrt(D + self.M)

        self.b1 = np.zeros(self.M)

        self.W2 = np.random.randn(self.M, K) / np.sqrt(self.M + K)

        self.b2 = np.zeros(K)

Далее как обычно. Сначала прямое распространение, после чего идёт градиентный спуск. В качестве функции активации давайте используем гиперболический тангенс.

        costs = []

        best_validation_error = 1

        for i in xrange(epochs):

            pY, Z = self.forward(X)

            pY_T = pY – T

            self.W2 -= learning_rate*(Z.T.dot(pY_T) + reg*self.W2)

            self.b2 -= learning_rate*(pY_T.sum(axis=0) + reg*self.b2)

            dZ = pY_T.dot(self.W2.T) * (1 – Z*Z)

            self.W1 -= learning_rate*(X.T.dot(dZ) + reg*self.W1)

            self.b1 -= learning_rate*(dZ.sum(axis=0) + reg*self.b1)

И выводим текущий результат через каждые 10 циклов.

            if i % 10 == 0:

                pYvalid, _ = self.forward(Xvalid)

                c = cost2(Yvalid, pYvalid)

                costs.append(c)

                e = error_rate(Yvalid, np.argmax(pYvalid, axis=1))

                print(“i:”, i, “cost:”, c, “error:”, e)

               

       if e < best_validation_error:

                    best_validation_error = e

        print(“best_validation_error:”, best_validation_error)

 

        if show_fig:

            plt.plot(costs)

            plt.show()

В случае, если в качестве функции активации вы захотите использовать функцию relu, строку

            dZ = pY_T.dot(self.W2.T) * (1 – Z*Z)

необходимо заменить на

            dZ = pY_T.dot(self.W2.T) * (Z > 0)

Теперь определим остальные функции.

    def forward(self, X):

        Z = np.tanh(X.dot(self.W1) + self.b1)

        return softmax(Z.dot(self.W2) + self.b2), Z

В случае использования функции relu вторую строку надо заменить на:

        Z = relu(X.dot(self.W1) + self.b1)

Итак, далее.

    def predict(self, X):

        pY, _ = self.forward(X)

        return np.argmax(pY, axis=1)

    def score(self, X, Y):

        prediction = self.predict(X)

        return 1 – error_rate(Y, prediction)

Теперь можно запускать программу.

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

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