一. 理解keras的配置+图片转换为矩阵
在搭建自己的网络之前,我们首先看一下keras.json 这一个文件。
1. 理解keras.json 文件
当你导入keras库的时候,keras会产生一个keras.json 文件,打开它(如果找不到就在安装keras库里面搜索)
打开之后是这样的:
{
"epsilon": 1e-07,
"floatx": "float32",
"image_data_format": "channels_last",
"backend": "tensorflow"
}
在里面,你可以看到四个重要的参数,我们一一说一下它的作用。
(1) epsilon: 防止作除法时,分母为0
(2)float32:定义精度
(3) backend:keras库使用tensorflow作为后端,你也可以使用theano作为后端,将其改为theano
(4) image_data_format: 这个非常重要,这个值有两个类型:channels_last 和channels_first
在opencv中,我们知道也是(rows,columns,channels), 即channels_last类型。
但是在theano的设定中是channel_first的设定。
2. 导入图片, 并将图片转换为矩阵处理(有很多程序,不过一劳永逸,保存为package)
将一个project保存为这样的形式,我们一步一步往里面加东西
|--- pyimagesearch
| |--- __init__.py
| |--- datasets
| | |--- __init__.py
| | |--- SimpleDatasetLoader.py #根据类名大写
| |--- preprocessing
| | |--- __init__.py
| | |--- ImageToArrayPreprocessor.py #根据类名大写
| | |--- SimplePreprocessor.py
关于init文件,都是空的,不过必须要建立起作用。
第一步,打开preprocessing文件夹里面的
ImageToArrayPreprocessor.py
添加程序如下,这一步主要是将图片转换成矩阵的形式:
from keras.preprocessing.image import img_to_array
class ImageToArrayPreprocessor:
def __init__(self,dataFormat=None):
self.dataFormat=dataFormat
def preprocess(self,image):
return img_to_array(image,data_format=self.dataFormat)
第二步,打开preprocessing文件夹里面的
SimplePreprocessor.py
添加程序如下,这一步主要是可以rezise图片到你自己想要的大小
# -*- coding: utf-8 -*-
import cv2
class
SimplePreprocessor:
def
__init__(
self,
width,
height,
inter=cv2.INTER_AREA):
self.width=width
self.height=height
self.inter=inter
def
preprocess(
self,
image):
return cv2.resize(image,(
self.width,
self.height),
interpolation=
self.inter)
第三步,打开datasets里面的
SimpleDatasetLoader.py
添加程序如下,这一步骤主要作用为导入你需要的图片
# -*- coding: utf-8 -*-
import numpy
as np
import cv2
import os
class
SimpleDatasetLoader:
def
__init__(
self,
preprocessors=
None):
self.preprocessors = preprocessors
if
self.preprocessors is
None:
self.preprocessors=[]
def
load(
self,
imagePaths,
verbose=-
1):
data=[]
labels=[]
for (i, imagePath) in
enumerate (imagePaths):
image =cv2.imread(imagePath)
label=imagePath.split(os.path.sep)[-
2] #这个非常重要,文件夹建立名称为类名,为label
if
self.preprocessors is not
None:
for p in
self.preprocessors:
image=p.preprocess(image)
data.append(image)
labels.append(label)
if verbose >
0 and i>
0 and (i+
1)%verbose==
0:
print(
'[INFO] processed {}/{}'.format(i+
1,
len(imagePaths)))
return (np.array(data),np.array(labels))
完成了以上三个步骤,基本的图片输入和转换需要的程序就已经写好了,我们可以看一下主要的步骤
1. 导入图片
2. 改变图片大小
3. 选择通道维度
4. 输出矩阵
二. 建立一个简单的卷积网络 ShallowNet
第四步,先从简单的网络开始建立,我们建立我们的package如图所示,该conv文件集里面的shallownet为我们要做的网络:
--- pyimagesearch
| |--- __init__.py
| |--- datasets
| |--- nn
| | |--- __init__.py
...
| | |--- conv
| | | |--- __init__.py
| | | |--- ShallowNet.py
| |--- preprocessing
打开其文件,输入程序如下所示,为一个简单的卷积网络,后面我们会讲更加复杂的,不过现在来一点自己建立网络的满足感:
from keras.models
import Sequential
from keras.layers.convolutional
import Conv2D
from keras.layers.core
import Activation
from keras.layers.core
import Dense
from keras.layers.core
import Flatten
from keras
import backend
as K
class
ShallowNet:
def
build(
width,
height,
depth,
classes):
model=Sequential()
inputShape=(height,width,depth)
if K.image_data_format()==
'channel_first':
inputShape=(depth,height,width) #我们之前讲的通道点
model.add(Conv2D(
32,(
3,
3),
padding=
'same',
input_shape=inputShape,
activation=
'relu'))
model.add(Flatten())
model.add(Dense(classes,
activation=
'softmax')) #根据自己的类别修改,类似于二分类为sigmoid
return model
最后一步,建立一个新的文件导入我们的图片以及开始训练
取名可以叫做shallownet_animals.py
程序如下:
from sklearn.preprocessing
import LabelBinarizer
from sklearn.model_selection
import train_test_split
from sklearn.metrics
import classification_report
from pyimagesearch.preprocessing
import ImageToArrayPreprocessor
from pyimagesearch.preprocessing
import SimplePreprocessor
from pyimagesearch.datasets
import SimpleDatasetLoader
from pyimagesearch.nn.conv
import ShallowNet
from keras.optimizers
import SGD
from imutils
import paths
import matplotlib.pyplot
as plt
import numpy
as np
import argparse
ap=argparse.ArgumentParser()
ap.add_argument(
'-d',
'--dataset',
required=
True,
help=
'path to the input dataset')
args=
vars(ap.parse_args())
print(
'[INFO] loading images...')
imagePaths=
list(paths.list_images(args[
'dataset']))
sp=SimplePreprocessor.SimplePreprocessor(
32,
32)
iap=ImageToArrayPreprocessor.ImageToArrayPreprocessor()
sdl=SimpleDatasetLoader.SimpleDatasetLoader(
preprocessors=[sp,iap])
(data,labels)=sdl.load(imagePaths,
verbose=
500)
data=data.astype(
'float')/
255.0
(train_x,test_x,train_y,test_y)=train_test_split(data,labels,
test_size=
0.25,
random_state=
42)
train_y=LabelBinarizer().fit_transform(train_y)
test_y=LabelBinarizer().fit_transform(test_y)
#print(train_x.shape)
#print(train_y)
print(
'[INFO] compiling models...')
opt=SGD(
lr=
0.005)
model=ShallowNet.ShallowNet.build(
width=
32,
height=
32,
depth=
3,
classes=
1)
model.compile(
loss=
'binary_crossentropy',
optimizer=opt,
metrics=[
'accuracy']) #多分类的话为categorical_crossentropy
print(
'[INFO] training network...')
H=model.fit(train_x,train_y,
validation_data=(test_x,test_y),
batch_size=
32,
epochs=
100,
verbose=
1)
print(
'[INFO] evaliatiing model...')
predictions=model.predict(test_x,
batch_size=
32)
print(classification_report(test_y.argmax(
axis=
1),predictions.argmax(
axis=
1),
target_names=[
'cat',
'dog']))
plt.style.use(
"ggplot")
plt.figure()
plt.plot(np.arange(
0,
100), H.history[
"loss"],
label=
"train_loss")
plt.plot(np.arange(
0,
100), H.history[
"val_loss"],
label=
"val_loss")
plt.plot(np.arange(
0,
100), H.history[
"acc"],
label=
"train_acc")
plt.plot(np.arange(
0,
100), H.history[
"val_acc"],
label=
"val_acc")
plt.title(
"Training Loss and Accuracy")
plt.xlabel(
"Epoch #")
plt.ylabel(
"Loss/Accuracy")
plt.legend()
plt.show()
这里我使用的数据库为网络上出名的dogs vs cats的数据库,我分别取了2000个狗和猫的图片进行分类。
注意这里非常重要的就是之前讲的分类图片文件夹的建立,
我这里的文件夹名称为 C:\animals
在这个文件夹下面有C:\animals\cats和C:\animals\dogs,里面分别存图片。
在command windows里面输入以下的程序,就可以开始训练啦:
$ python shallownet_animals.py --dataset C:/animals
三. 总结
谢谢大家的学习,这个是我学习机器学习几个月来第一次写文来分享,如果有任何问题可以留言。
现在就可以开始训练自己的网络啦,后续我也会继续介绍其他的更加复杂的网络。
参考文献:
Howse J, Minichino J. Learning OpenCV 3 Computer Vision with Python[J]. 2015.