我正在尝试构建一个简单的神经网络,用于将产品图片分类到不同的标签(产品类型)。例如,给定一张新的产品图片,判断它属于哪个产品类别(书籍、玩具、电子产品等)。
我有每种产品编号下的几张产品图片,每个产品编号在Excel表格中都有一个标签(即产品类型)。
以下是我的代码:
from sklearn.preprocessing import LabelEncoderfrom sklearn.cross_validation import train_test_splitfrom keras.models import Sequentialfrom keras.layers import Activationfrom keras.optimizers import SGDfrom keras.layers import Densefrom keras.utils import np_utilsfrom imutils import pathsimport numpy as npimport argparseimport cv2import osimport xlwtimport xlrdimport glob2import pickledef 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 ddef 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%。
我做错了什么吗?如何提高神经网络的准确性?我在某处读到可以通过“交叉验证和超参数调优”来实现,但具体该怎么做呢?抱歉,我对神经网络很新手,只是尝试一些新东西。谢谢。
回答:
在Keras中创建图像分类器时,我建议尝试使用卷积神经网络,因为它们在处理图像时效果更好。此外,层间归一化可以帮助提高训练过程中的准确性,从而改善验证/测试准确性。(这与训练前数据归一化的概念相同。)
要在Keras中添加卷积层,只需调用model.add(Conv2D(params))
,而要在层间进行归一化,可以调用model.add(BatchNormalization())
卷积神经网络虽然更复杂,但更适合处理图像。它们的不同之处在于,卷积层在高层次上只是一个“迷你”神经网络,扫描图像的各个部分。这很重要,因为例如,你可以在两张图片中拥有完全相同的对象,但如果它们在图像中的位置不同,普通的神经网络会将其视为两个不同的对象,而卷积神经网络则能识别出它们是同一对象,只是出现在图像的不同位置…
因此,这个扫描图像部分(通常称为卷积核大小)的“迷你”神经网络更倾向于捕捉对象的相似特征。这些对象特征随后被训练到网络中,因此即使对象出现在图像的不同区域,也能更准确地识别为相同的东西。这是卷积神经网络在处理图像时表现更好的关键所在。
以下是基于NVIDIA模型架构的Keras 2中的一个基本示例,包括归一化…
model = Sequential() # 如果需要,裁剪图像以去除不相关的特征... 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)) # 将所有像素归一化为0的均值 ±1 model.add(Conv2D(24, (2,2), strides=(2,2), padding='valid', activation='elu')) # 第1次卷积 model.add(BatchNormalization()) # 层间归一化 model.add(Conv2D(36, (2,2), strides=(2,2), padding='valid', activation='elu')) # 第2次卷积 model.add(BatchNormalization()) model.add(Conv2D(48, (1,1), strides=(2,2), padding='valid', activation='elu')) # 第3次卷积 model.add(BatchNormalization()) # model.add(Conv2D(64, (3,3), strides=(1,1), padding='valid', activation='elu')) # 第4次卷积 # model.add(BatchNormalization()) # model.add(Conv2D(64, (3,3), strides=(1,1), padding='valid', activation='elu')) # 第4次卷积 # model.add(BatchNormalization()) model.add(Dropout(0.5)) model.add(Flatten()) # 展平维度 model.add(Dense(100, activation='elu')) # 第1个全连接层 model.add(BatchNormalization()) model.add(Dropout(0.5)) model.add(Dense(51, activation= 'softmax')) # 输出标签的概率
最后,超参数调优只是调整批量大小、训练轮数、学习率等,以达到最佳结果。你所能做的就是实验,看看什么效果最好。