Как повысить точность нейронных сетей

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

У меня есть пара изображений продукта под каждым номером продукта, и каждый номер продукта имеет метку (т. Е. Тип продукта) на листе Excel.

Ниже мой код:

from sklearn.preprocessing import LabelEncoder
from sklearn.cross_validation import train_test_split
from keras.models import Sequential
from keras.layers import Activation
from keras.optimizers import SGD
from keras.layers import Dense
from keras.utils import np_utils
from imutils import paths
import numpy as np
import argparse
import cv2
import os
import xlwt
import xlrd
import glob2
import pickle

def image_to_feature_vector(image, size=(32,32)):
    return cv2.resize(image, size).flatten()

def read_data(xls = "/Desktop/num_to_product_type.xlsx"):
    book = xlrd.open_workbook(xls)
    sheet = book.sheet_by_index(0)
    d = {}
    for row_index in xrange(1, sheet.nrows): # skip heading row
        prod_type, prod_num = sheet.row_values(row_index, end_colx=2)
        prod_type = unicode(prod_type).encode('UTF8')
        produ_num = unicode(prod_num).encode('UTF8')

        d[prod_num] = prod_type
    return d

def main():

    try:
        imagePaths=[]
        print("[INFO] describing images...")
        for path, subdirs, files in os.walk(r'/Desktop/data'):
            for filename in files:
                imagePaths.append(os.path.join(path, filename))

        files = glob2.glob('/Desktop/data/**/.DS_Store')
        for i in files:
            imagePaths.remove(i)  
    except:
        pass

    dd = read_data() 
    # initialize the data matrix and labels list
    data = []
    labels1 = []

    for (i, imagePath) in enumerate(imagePaths):
        image = cv2.imread(imagePath)
        #print(image.shape)
        subdir = imagePath.split('/')[-2]
        for k, v in dd.items():
            if k == subdir:
                label = v
                break

        features = image_to_feature_vector(image)
        data.append(features)
        labels1.append(label)


        # show an update every 1,000 images
        if i > 0 and i % 1000 == 0:
            print("[INFO] processed {}/{}".format(i, len(imagePaths)))
    print("String Labels")
    print(labels1)

    # encode the labels, converting them from strings to integers
    le = LabelEncoder()
    labels = le.fit_transform(labels1)
    print(labels) 

    d={}
    d[labels[0]] = labels1[0]

    for i in range(1,len(labels)-1):
        if labels[i-1] != labels[i] and labels[i] == labels[i+1]:
            d[labels[i]]  = labels1[i]

    data = np.array(data) / 255.0
    labels = np_utils.to_categorical(labels, 51)
    print("To_Categorical")
    print(labels) 

    print("[INFO] constructing training/testing split...")
    (trainData, testData, trainLabels, testLabels) = train_test_split(
        data, labels, test_size=0.25, random_state=42)

    model = Sequential()
    model.add(Dense(768, input_dim=3072, init="uniform",
        activation="relu"))
    model.add(Dense(384, init="uniform", activation="relu"))
    model.add(Dense(51))
    model.add(Activation("softmax"))

    print("[INFO] compiling model...")

    sgd = SGD(lr=0.125
              )
    model.compile(loss="categorical_crossentropy", optimizer=sgd,
        metrics=["accuracy"])
    model.fit(trainData, trainLabels, nb_epoch=50, batch_size=750)


#     #Test the model
    #show the accuracy on the testing set
     print("[INFO] evaluating on testing set...")
     (loss, accuracy) = model.evaluate(testData, testLabels,
         batch_size=128, verbose=1)
     print("[INFO] loss={:.4f}, accuracy: {:.4f}%".format(loss,
         accuracy * 100))

if __name__ == '__main__':

    main()

Нейронная сеть представляет собой нейронную сеть с прямой связью 3-2-3-51. Слой 0 содержит 3 входа. Слои 1 и 2 являются скрытыми слоями, содержащими 2 и 3 узла соответственно. Уровень 3 — это выходной уровень, который имеет 51 узел (т. е. для 51 типа категории продуктов). Однако при этом я получаю очень низкую точность, всего около 45-50%.

Что-то не так, что я делаю? Как повысить точность нейронной сети? Я где-то читал, что это можно сделать с помощью "crossvalidation and hyperparameter tuning", но как это сделать? Извините, я новичок в нейронных сетях, просто пробую что-то новое. Спасибо.


person akrama81    schedule 03.08.2017    source источник
comment
Попробуйте использовать хорошо зарекомендовавшую себя сеть, например Alexnet или Googlenet, и переобучите пару последних слоев для своего приложения.   -  person c2huc2hu    schedule 03.08.2017


Ответы (2)


Для создания классификатора изображений в keras я бы предложил попробовать сверточные нейронные сети, поскольку они, как правило, работают намного лучше для изображений. Кроме того, нормализация между слоями может помочь с точностью во время обучения, что должно помочь повысить точность проверки/тестирования. (Та же концепция, что и при нормализации данных перед обучением.)

Для сверточного слоя keras просто вызовите model.add(Conv2D(params)), а для нормализации между слоями вы можете вызвать model.add(BatchNormalization())

Сверточные нейронные сети более продвинуты, но лучше подходят для изображений. Разница в том, что свертка на высоком уровне представляет собой просто «мини» нейронную сеть, сканирующую участки изображения. Это важно, потому что, например, у вас может быть ТОЧНО один и тот же объект на двух изображениях, но если они находятся в разных местах на этом изображении, обычная нейронная сеть будет рассматривать это как два изображения. разные объекты и один и тот же объект в разных местах изображения...

Таким образом, эта «мини-нейронная сеть», которая сканирует изображение фрагментами (часто называемыми размером ядра), более склонна улавливать схожие особенности объектов. Затем характеристики объекта обучаются в сети, поэтому, даже если объект присутствует в разных областях ваших изображений, его можно более точно распознать как одно и то же. Это ключ к тому, почему сверточная нейронная сеть лучше подходит для работы с изображениями.

Вот базовый пример в keras 2 с нормализацией, основанной на архитектуре модели NVIDIA...

        model = Sequential()
        # crop the images to get rid of irrelevant features if needed...
        model.add(Cropping2D(cropping=((0, 0), (0,0)), input_shape=("your_input_shape tuple x,y,rgb_depth")))
        model.add(Lambda(lambda x: (x - 128) / 128)) # normalize all pixels to a mean of 0 +-1
        model.add(Conv2D(24, (2,2), strides=(2,2), padding='valid', activation='elu')) # 1st convolution
        model.add(BatchNormalization()) # normalize between layers
        model.add(Conv2D(36, (2,2), strides=(2,2), padding='valid', activation='elu')) # 2nd convolution
        model.add(BatchNormalization())
        model.add(Conv2D(48, (1,1), strides=(2,2), padding='valid', activation='elu')) # 3rd convolution
        model.add(BatchNormalization())
        # model.add(Conv2D(64, (3,3), strides=(1,1), padding='valid', activation='elu')) # 4th convolution
        # model.add(BatchNormalization())
        # model.add(Conv2D(64, (3,3), strides=(1,1), padding='valid', activation='elu')) # 4th convolution
        # model.add(BatchNormalization())
        model.add(Dropout(0.5))
        model.add(Flatten()) # flatten the dimensions
        model.add(Dense(100, activation='elu')) # 1st fully connected layer
        model.add(BatchNormalization())
        model.add(Dropout(0.5))
        model.add(Dense(51, activation= 'softmax')) # label output as probabilites

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

person Fury    schedule 03.08.2017
comment
Большое спасибо, я попробую использовать нейронную сеть свертки и посмотрю, улучшится ли результат. - person akrama81; 03.08.2017
comment
Я пробовал то, что вы сказали, но получаю сообщение об ошибке: ValueError: Ошибка при проверке ввода: ожидается, что Cropping2d_1_input будет иметь 4 измерения, но получил массив с формой (39, 3072) - person akrama81; 04.08.2017
comment
Таким образом, kerascropping2d ожидает, что вы подадите изображение, изображение имеет значения x, y и rgb .... однако, как ни странно, ошибка в 4 измерениях также относится к размеру пакета. Итак, keras хочет, чтобы вы дали его (batch_size, x, y, rgb). Значение rgb должно быть просто 3, если вы используете цветные изображения. - person Fury; 04.08.2017
comment
Я также хотел сказать, что вы должны подавать изображения напрямую, не сглаживая/изменяя их форму... поэтому массив формы (39, 3072) не может быть правильным или это изображение странной формы. Если вы распечатаете значение trainData.shape, вы должны увидеть размер пакета, x, y, кортеж color_channel. Последние три значения должны соответствовать входному параметру формы в Cropping2D. Надеюсь, это поможет. - person Fury; 04.08.2017
comment
Большое спасибо. Вот это действительно полезная информация! Итак, я удалил начальное сглаживание при выполнении trainData.shape, которое я получил (39,32,32,3), и я также предоставил (32,32,3) для cropping2d. Но это дает мне какую-то странную ошибку: AssertionError: На графике есть отрицательная форма! который я не могу найти нигде в Интернете, а также. - person akrama81; 04.08.2017
comment
Вышеупомянутая ошибка появляется в строке - model.add(Conv2D(64, (3,3), strides=(1,1), padding='valid', активация='elu')) # 4-я свертка - person akrama81; 04.08.2017
comment
Таким образом, еще одна причина, по которой сверточные нейронные сети более продвинуты, заключается в том, что свертки изменяют форму изображения при перемещении по сети. Что происходит, если вы начинаете с изображения (32, 32, 3), в зависимости от размера ядра и шага в каждом слое (шаг - это перекрывающиеся сканы изображения), результат многих сверток изменит размер изображения, чтобы быть меньше с большей глубиной, вы получите (2, 2, 100). Теперь это представляет собой абстракцию исходного изображения, и если вы запустите другое ядро ​​​​5X5, вы получите ошибку отрицательного размера. - person Fury; 04.08.2017
comment
Я отредактировал исходный код, чтобы сократить свертки, поскольку модель была настроена для гораздо больших изображений. Поэкспериментируйте с размерами свертки и немного подвигайтесь, чтобы увидеть, что работает... вам нужно быть менее агрессивным с размером ядра и шагом для изображений 32X32. - person Fury; 04.08.2017
comment
Спасибо. Это очень хорошее объяснение :) У меня очень большое количество изображений (около 35 ГБ), что вы предлагаете, играя, чтобы получить лучший CNN, использовать ли я каждый раз весь набор данных? Потому что прямо сейчас я просто пробовал это примерно на 50 изображениях, что ничто по сравнению с количеством изображений, которые у меня есть в наборе данных. - person akrama81; 04.08.2017
comment
Я бы просто отложил несколько тысяч изображений и поэкспериментировал, чтобы прочувствовать все, пока вы учитесь. Проверьте результаты и скорректируйте их, затем, если вам нужна более надежная модель, попробуйте провести обучение на полном наборе данных. Просто будьте готовы подождать некоторое время, если вы не обрабатываете на графическом процессоре ... - person Fury; 05.08.2017
comment
Кроме того, что вы подразумеваете под менее агрессивным размером ядра и шагом для изображений 32X32? - person akrama81; 05.08.2017
comment
Меньший размер ядра 2x2 против 5x5 или шаг 1 против 5. Ваши изображения имеют размер всего 32x32, поэтому вы не можете использовать большое ядро ​​​​/ шаг, иначе у вас быстро закончится изображение и вы получите ошибки размеров. Нет ничего, что помешало бы свёртке повторяться за краем изображения, когда вы выдаёте ошибки измерения. - person Fury; 06.08.2017

Проверка гиперпараметров

Почему вы выбрали ИНС 3-2-3-2 вместо 3-6-2 или 3-4-4-4-4-2?

Обычно мы не знаем точную топологию (количество слоев, количество нейронов в слое, связи между нейронами), которая нам нужна для достижения точности 80% или что-то еще, что делает нас счастливыми. Здесь в игру вступает обучение гиперпараметрам. С его помощью мы говорим нашей программе попробовать несколько разных топологий, пока она не найдет ту, которая достаточно хороша для нас.

Как вы сообщаете своей программе, какую топологию попробовать? мы делаем это с помощью другой ИНС или эволюционного алгоритма, которые генерируют псевдослучайные топологии, оценивают каждую из них и дают оценку каждой топологии, затем топологии с более высокими оценками объединяются, и вы знаете, как это работает.

Это наверняка поможет вам увеличить общий балл (при условии, что есть хорошее решение для вашей проблемы).

Перекрестная проверка

Как узнать, сколько итераций нужно сделать в вашем алгоритме? каковы ваши критерии остановки?

Существует повторяющаяся проблема с ANN, называемая запоминанием. Если вы запустите свой алгоритм обучения на 1 миллион итераций, вы, как правило, получите лучший результат, чем если бы вы запустили его всего на 10 итераций, но это может быть связано с запоминанием вашего тренировочного набора: ваша ИНС учится только для того, чтобы предсказывать результаты этого обучения. наборы, но плохо справится с попытками предсказать данные, которых он раньше не видел.

Одним из способов решения этой проблемы является перекрестная проверка, что означает, что вы разделите свои данные на 2 группы: train и validation. Затем вы обучаете свою ИНС только с набором train столько итераций, сколько хотите, но параллельно вы будете тестировать свою ИНС с набором validation, чтобы знать, когда остановиться. Если после 10 итераций ваша train точность продолжает расти, а validation точность продолжает снижаться, то вы можете определить, что ваша ИНС запоминает, поэтому вы остановите свой алгоритм обучения и выберете ИНС, какой она была 10 итераций назад.

Конечно, 10 — это просто пример, вы можете попробовать с разными значениями, даже поместите это в свои тренировки с гиперпараметрами, вам не нужно жестко задавать значение.

Я рекомендую вам ознакомиться с материалами этого курса на Coursera, где они объясняют очень ясно такие понятия.

(Кстати: обычно вы делите свой входной набор на 3: train, validate и test. Где test используется, чтобы увидеть, как ваша ИНС будет вести себя с полностью невидимыми данными, вы не используете этот набор test для получения каких-либо решение в вашей тренировке)

person Daniel    schedule 03.08.2017
comment
Рад, что помогает :) - person Daniel; 03.08.2017