不铺垫啥了,最近看深度学习和神经网络有一点启发,想写个文章算是做个记录,直接开始吧。我看的是b站李宏毅老师的机器学习视频。
我比较懒,了解完原理,写完一遍代码之后,就想写一个一劳永逸的代码,想着以后有不同的应用场景需要,直接改几个参数然后调用就行了,所以这也是我特别喜欢写注释的原因。写注释是就为了一劳永逸。
当然,做图片分类,大概分为三个过程。
第一,收集你的数据,把它做成数据集(后面我是把数据集做出.npy格式),然后对数据预处理一下。具体就是把你的数据按类分好(丢到不同类名称的文件夹里),然后用代码把整体数据分成训练集、验证集、测试集和生成对应的训练集label、验证集_label、测试集_label。
第二、搭建卷积神经网络,把训练好的模型保存为.h5文件。搭建神经网络主要是要确定你处理数据的卷积层结构是什么,比如一张图片进去,要经过的卷积层的filter什么样,池化层什么样,打算设计几个,最后把得到的数据flatten拉直成一个向量,把这个向量丢到一个全连接层去跑(这整个第二步就叫卷积 神经网络,卷积就是数据去全连接层训练前的一种处理方式,没有卷积处理层只有全连接层的神经网络就叫DNN深度神经网络)。
第三、调用保存的模型对某一张图片预测它的类别,输出预测结果。
贴代码:
接下来以给花分类为例子,给出详细的代码。
注:花的数据集和.npy文件的创建代码是参考了这篇博文,后面附上博文的转载版权声明(版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接: https:// blog.csdn.net/umbrellal alalala/article/details/86516928 )
第一、收集数据,放到数据文件夹里面去分好类,一个类一个文件夹(如图),然后做成.npy文件,生成的.npy为6维数组,分别是训练集,训练集标签,验证集,验证集标签,测试集,测试集标签。其中训练集的数据是随机打乱了的,标签对应也是;而训练集、验证集和测试集的数据都是来自于数据文件夹,按比例确定的,比如随机拿出10%做验证集,10%测试集,剩下的当作数据集。注:文件名不能有中文
文件夹名就是类别名,里面是同一类的图片# -*- coding: utf-8 -*-
第二、搭建卷积神经网络,保存模型为.h5文件。
代码如下:
# -*- coding:utf-8 -*-
import numpy as np
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D, Flatten, Conv2D
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import SGD, Adam
from keras.utils import np_utils
from keras.datasets import mnist
# categorical_crossentropy
def load_mnist_data(number):
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train[0:number]
y_train = y_train[0:number]
x_train = x_train.reshape(number, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
# convert class vectors to binary class matrices
y_train = np_utils.to_categorical(y_train, 10)
y_test = np_utils.to_categorical(y_test, 10)
print(x_test.shape)
x_train = x_train / 255
x_test = x_test / 255
return (x_train, y_train), (x_test, y_test)
if __name__ == '__main__':
(x_train, y_train), (x_test, y_test) = load_mnist_data(10000) # 测试集里面只有10000张照片
print(x_test.shape)
# do CNN
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
model2 = Sequential()
model2.add(Conv2D(25, (3, 3), input_shape=(
28, 28, 1), data_format='channels_last'))
model2.add(MaxPooling2D((2, 2)))
model2.add(Conv2D(50, (3, 3)))
model2.add(MaxPooling2D((2, 2)))
model2.add(Flatten())
model2.add(Dense(units=100, activation='relu'))
# 最后要分成十类,所以要用10个单元
model2.add(Dense(units=10, activation='softmax'))
model2.summary()
model2.compile(loss='categorical_crossentropy',
optimizer='adam', metrics=['accuracy'])
model2.fit(x_train, y_train, batch_size=100, epochs=20)
# 打印在训练集上的训练结果
result_train = model2.evaluate(x_train, y_train)
print('nTrain CNN Acc:n', result_train[1])
# 打印在测试集上的测试结果
result_test = model2.evaluate(x_test, y_test)
print('nTest CNN Acc:n', result_test[1])
# 保存模型为.h5,方便下次预测
model2.save('E:projectsmanchine_learningcnnhandwirte.h5')
第三、调用保存的模型对某一张图片预测它的类别,输出预测结果。
# -*- coding:utf-8 -*-
import PIL
import keras
import matplotlib
import os
import numpy as np
from PIL import Image
import cv2
# 读取模型
model = keras.models.load_model('E:projectsmanchine_learningcnnflowerrecong.h5')
# 要预测的图片保存在下面这个文件夹内
sub_dirs = 'C:UserswildpigDesktoptest'
# 定义一个列表来存储类别名称
classcatalogue = ['雏菊', '蒲公英', '玫瑰', '向日葵', '郁金香']
# 下面的2表示返回所有文件名,0表示代表目录的路径,1表示子目录名字,没有就是[]
sub_dir = [x[2] for x in os.walk(sub_dirs)]
# 遍历每一个文件名,代入模型预测
for sub in sub_dir[0]:
image = cv2.imread(sub_dirs + '' + sub)
img = cv2.resize(image, (299, 299)) / 255 # 调整像素保存和训练模型中的像素一致
# 需要用reshape定义出例子的个数,图片的 通道数,图片的长与宽。具体的参加keras文档
img = (img.reshape(1, 299, 299, 3)).astype('float32')
predict = np.argmax(model.predict(img), axis=-1)
# predict = model.predict_classes(img)
# 输出预测结果,格式为 ‘图片名称’+‘识别为:’+‘类别’
print(sub, '识别为:', classcatalogue[int(predict)])
# 如果预测的图片不多,还可以打开照片看下
# cv2.imshow("Image1", img)
# cv2.waitKey(0)
下面瞎扯点皮:
深度学习,从属于机器学习里的一类操作。本质上是让计算机帮助我们去处理复杂的回归问题,有点像大学数学实验课程里的拟合一个函数的练习。而神经网络则是处理回归问题的一种方法,往往是在数据量特别大的时候用神经网络去算回归的函数的参数。如果数据量不多,参数自然也不会太多,这时候可以直接用回归方法去跑,比如一些基于梯度的下降算法,手写代码还更清晰方便调试。
CNN/DNN,就是卷积神经网络和深度神经网络,是针对回归问题中数据量特别大的分类问题的处理模式。而回归问题,就是根据一些已知的数据,去预测一件事情会有怎样的结果,这个结果往往会受到一些相关因素的影响,这些因素可以根据问题相应的理论来确定,也可以人为经验来设定。就比如空气中PM2.5的值,我们可以说它和前8个小时的空气成分的含量有关,我也可以单独认为它和前一个礼拜的PM2.5含量有关。类似的,我们数据建立模型,用机器学习去把目标函数的参数迭代出来之后,我们不进可以对目标进行预测,也可以根据预测结果去对目标进行分类。
比如说:我有一些点(xdata, ydata),我可以去找一个函数去拟合这些数据,当然,我们假设出这些点的关系可能是某一个函数关系时,会带有一些参数(如y=kx+b,k,b就是未知参数),那么最好的函数就要满足所有的
本文的卷积神经网络就是处理分类问题的。
先说做卷积神经网络的目的是什么?/问题是什么?
问题/目的就是:给你一些大量的数据,比如很多手写的数字图片,比如很多种花的图片,要你训练一个模型/函数,能够让我下次丢一张图片(手写数字图片/花的图片)进去,函数可以把图片的类比输出出来(0-9/花的名字)。
几点思考:
1、深度学习做的就是找函数的事情,只不过这个函数的输出是类别,不像一般的机器学习输出的是数值。不过都没关系啦,类别都是自己定的,比如识别花的种类里面,我可以让函数值是1的时候表示玫瑰花,然后输出玫瑰。
2、找函数,本质是回归,就是自己假设可能是一个什么函数,比如线性函数还是非线性函数,是一次函数还是二次函数,等等。然后假设出来了,就是跑优化算法去求解函数里的参数了,找到最好的那个参数,作为你的最终模型。所以我们很容易明白,不同的人、不同的初试数据、甚至人品,都会导致每个人找的函数都是不一样的。就算是同一个模型,放到不同电脑上去跑,得到的具体参数都有可能不同,不过函数/模型的框架是不变的。就比如y=kx+b,每个人的k,b可能都不太一样,但是形式是一样的,用同一个数据集,同样的条件下,训练出来的模型,参数也不会相差太大。
3、神经网络就是应对数据集很大的时候的一种回归方法。假如说就几个子数据,比如100个数据点,让你去拟合一个函数,那不就直接假设函数表达式(比如y=kx+b),然后求loss function的微分,用梯度下降就可以求得最好的k,b了。但是当数据集很大时,比如说数据集是很多图片,去预测图片的种类。这时,我们假设每一张图片都是
哪些问题:
1、图片的数据量太大了(对于优化来说,并不是图片说占的存储空间大,现在固态多便宜啊),导致input很多,使得模型的参数要很多(起码input有多少维就该先有多少参数吧),计算量很大,耗时长。
2、光看input维度是不够的,因为有的图片分辨率不一样,维度也会变。所以先定下模型,相当于定死了图片的分辨率,不具有一般性,无法利用到图像的结构特征,模型根本没有学习到不同种类的花的特征。
这个时候神经网络就出现了。
神经网络,用多个neuron去拟合数据的每一个维度,它就好比是
而且神经网络也有许多优势,暂时写两个比较喜欢的:一个是对数据量比较大是,用多层的hidden layer会比直接手写代码算拟合函数,在求解最优参数的速度上会更快。另一个是神经网络这种传递模型,在更新计算时,每一个neuron的完整输入输出可以看作一个矩阵乘法