0

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

我在每个产品编号下都有几个产品图像,每个产品编号在 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”完成,但它是如何完成的?对不起,我对神经网络很陌生,只是尝试一些新的东西。谢谢。

4

2 回答 2

3

超参数验证

你为什么选择3-2-3-2ANN 而不是3-6-2or 3-4-4-4-4-2

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

你如何告诉你的程序尝试哪些拓扑?我们用另一个人工神经网络或进化算法来做,它们生成伪随机拓扑,评估每个拓扑,并给每个拓扑打分,然后组合得分较高的拓扑,好吧,你知道它是如何工作的。

这样做肯定会帮助您提高整体分数(前提是您的问题有一个好的解决方案)

交叉验证

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

ANN 有一个反复出现的问题,称为记忆。如果你运行你的学习算法 100 万次迭代,你通常会比只运行 10 次迭代得到更好的分数,但这可能是由于你的训练集的记忆:你 ANN 只学习预测那些训练的结果集,但在尝试预测它以前从未见过的数据时会做得很差。

解决该问题的一种方法是交叉验证,这意味着您将数据分成 2 组:trainvalidation. 然后,您只使用您的集合训练您的 ANN ,train进行尽可能多的迭代,但同时,您将使用该validation集合测试您的 ANN,以了解何时停止。如果在 10 次迭代之后,你的train准确率继续上升,但你的validation准确率一直在下降,那么你可以确定你的 ANN 正在记忆,所以你将停止你的学习算法并选择 10 次迭代前的 ANN。

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

我建议你看一下Coursera上这门课程的材料,它们非常清楚地解释了这些概念。

(顺便说一句:通常您将输入集拆分为 3:trainvalidatetest用于test查看您的 ANN 将如何处理完全看不见的数据的行为,您不会使用该test集在训练中做出任何决定)

于 2017-08-03T01:57:27.913 回答
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

最后,超参数调整只是调整批量大小、时期、学习率等以获得最佳结果。您所能做的就是进行实验,看看什么效果最好。

于 2017-08-03T02:26:38.717 回答