如何提高神经网络的准确性

时间:2017-08-03 01:37:06

标签: python image-processing machine-learning neural-network feed-forward

我正在尝试构建一个简单的神经网络,将产品图像分类为不同的标签(产品类型)。即,给定一个新的产品图像,告诉它属于哪种产品类别(书籍,玩具,电子产品等)。

我在每个产品编号下面都有几个产品图像,每个产品编号在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层和第1层2是隐藏层,包含2& 3节点分别第3层是具有51个节点的输出层(即,对于51个产品类别类型)。然而,有了这个,我的准确度非常低,只有约45-50%。

我有什么不对劲吗?你如何提高神经网络的准确性?我在某个地方看到它可以通过“crossvalidation and hyperparameter tuning”完成,但它是如何完成的?对不起,我是神经网络的新手,只是尝试新的东西。感谢。

2 个答案:

答案 0 :(得分:3)

超参数验证

为什么选择3-2-3-2 ANN代替3-6-23-4-4-4-4-2

通常我们不知道我们需要达到80%准确度的确切拓扑(层数,每层神经元数量,神经元之间的连接)或者让我们满意的任何东西。这是超参数训练发挥作用的地方。有了它,我们告诉我们的程序尝试使用几种不同的拓扑,直到它找到一个对我们来说足够好的拓扑。

您如何告诉您的计划尝试哪种拓扑?我们使用另一个ANN或进化算法来生成伪随机拓扑,对每个拓扑进行评估,并为每个拓扑提供分数,然后将具有更高分数的拓扑结合起来,并且,您知道它是如何工作的。

这样做肯定可以帮助您提高总分(假设您的问题有一个很好的解决方案)

交叉验证

您如何知道算法中要进行多少次迭代?你的停止标准是什么?

ANN有一个反复出现的问题叫做记忆。如果你运行你的学习算法进行100万次迭代,你通常会获得比只运行10次迭代更好的分数,但这可能是因为记忆你的训练集:你只学会预测这些训练的结果虽然设置不好,但会很难预测以前从未见过的数据。

解决该问题的一种方法是交叉验证,这意味着您将数据分为两组:trainvalidation。然后用你的train训练你的ANN 你需要多少次迭代,但同时,你将用validation集来测试你的ANN,知道什么时候停止。如果在10次迭代后你的train精确度不断提高,但你的validation精确度会下降,那么你就可以确定你的ANN正在记忆,所以你将停止你的学习算法并选择人工神经网络。 10次​​迭代前。

当然,10只是一个例子,您可以尝试使用不同的值,甚至将其放入您的超参数训练中,您不需要对该值进行硬编码。

我建议你看看这个course in Coursera的材料,他们会非常清楚地解释这些概念。

(顺便说一下:通常你将你的输入集分成3:trainvalidatetest。其中test用于查看你的ANN将如何完全表现看不见的数据,您不会使用test设置在培训中做出任何决定

答案 1 :(得分:2)

为了在keras中创建图像分类器,我建议尝试卷积神经网络,因为它们往往更适合图像。此外,层之间的标准化有助于在训练期间的准确性,这有助于产生更好的验证/测试准确性。 (与训练前规范化数据的概念相同。)

对于keras卷积层,只需调用model.add(Conv2D(params))并在图层之间进行标准化,即可调用model.add(BatchNormalization())

卷积神经网络更先进,但更适合图像。不同之处在于卷积处于高水平,只是“迷你”神经网络扫描图像的片段。这很重要,因为例如您可以在两个图像中使用 EXACT 相同的对象,但如果它们位于该图像中的不同位置,则普通神经网络会将其视为两个不同的对象与图像中不同位置的同一对象...

所以这个以迷你方式扫描图像的“迷你”神经网络(通常称为内核大小)更倾向于选择对象的类似 特征 。然后将对象特征训练到网络中,因此即使对象存在于图像的不同区域中,也可以更准确地将其识别为相同的东西。这是卷积神经网络为什么更适合处理图像的关键。

以下是基于NVIDIA模型架构的规范化的keras 2中的基本示例...

        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

最后,超参数调整只是调整批量大小,时代,学习率等,以达到最佳效果。你所能做的就是试验,看看哪种方法效果最好。