本文记录用keras的cnn进行图像分类。原始数据为图片
基本流程
- 加载图像数据
- 图像数据预处理
- 训练模型
- 保存模型与模型的可视化
- 训练过程可视化
代码结构
整个过程可以在一个.py文件中完成,思路按照上面的流程
# 导包
#
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
from PIL import Image
# 必须,可视化用得到
import numpy as np
import os
# 1. 读取图片并转成numpy类型函数
def read_image(imageName):
im = Image.open(imageName).convert('L')
data = np.array(im)
return data
# 读取在data里面有几个文件夹
text = os.listdir('./data')
images = []
labels = []
# 把文件夹里面的图片和其对应的故障类型对应
for textPath in text:
for fn in os.listdir(os.path.join('data', textPath)):
if fn.endswith('.png'):
fd = os.path.join('./data', textPath, fn)
images.append(read_image(fd))
labels.append(textPath)
X = np.array(images)
y = np.array(list(map(int, labels)))
# 按三七分把这些数据分为测试集和训练集
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.30, random_state=30)
# 将原始的特征矩阵做数据处理形成模型需要的数据
train_X = train_X.reshape(-1, 64, 64, 1)
train_X = train_X.astype('float32')
train_X /= 255
# 使用keras中的方法对数字的标签分类做One-Hot编码
train_y = to_categorical(train_y, 10)
# 将原始的特征矩阵做数据处理形成模型需要的数据
test_X = test_X.reshape(-1, 64, 64, 1)
test_X = test_X.astype('float32')
test_X /= 255
# 使用keras中的方法对数字的标签分类做One-Hot编码
test_y = to_categorical(test_y, 10)
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dropout, Dense
from keras.losses import categorical_crossentropy
from keras.optimizers import Adadelta
model = Sequential()
model.add(Conv2D(32, (5,5), activation='relu', input_shape=[64, 64, 1]))
model.add(Conv2D(64, (5,5), activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss=categorical_crossentropy,
optimizer=Adadelta(),
metrics=['accuracy'])
batch_size = 8 # 一次训练的样本数
epochs = 16 # 所有样本遍历次数
model.fit(train_X, train_y,
batch_size=batch_size,
epochs=epochs)
loss, accuracy = model.evaluate(test_X, test_y, verbose=1)
print('loss:%.4f accuracy:%.4f' %(loss, accuracy))
保存模型
model.summary()
if not os.path.isdir(save_dir) :
os.makedirs(save_dir)
model_path = os.path.join(save_dir, model_name)
model.save(model_path)
print('Saved trained model at %s' % model_path)
可视化
import matplotlib.pyplot as plt
# 绘制训练 & 验证的准确率值
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.savefig('tradition_cnn_valid_acc.png')
plt.show()
# 绘制训练 & 验证的损失值
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.savefig('tradition_cnn_valid_loss.png')
plt.show()
历史网络结构
04091
model = Sequential()
model.add(Conv2D(32, (5,5), activation='relu', input_shape=[64, 64, 1]))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.5))
model.add(Conv2D(32, (5,5), activation='relu', input_shape=[64, 64, 1]))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
04092
百度的LeCNN,准确度不错了
model.add(Conv2D(32,(5,5),strides=(1,1),input_shape=(64,64,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(5,5),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(128,activation='relu'))
model.add(Dense(10,activation='softmax'))
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 60, 60, 32) 832
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 30, 30, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 26, 26, 64) 51264
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 13, 13, 64) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 10816) 0
_________________________________________________________________
dense_1 (Dense) (None, 128) 1384576
_________________________________________________________________
dense_2 (Dense) (None, 10) 1290
=================================================================
Total params: 1,437,962
Trainable params: 1,437,962
后面
尝试改小图片?
尝试新的结构,比如上面的加入dropout
翻译论文的方法
epoch:18,38
L1 Conv(5×5×32)
L2 Maxpool(2×2)
L3 Conv(3×3×64)
L4 Maxpool(2×2)
L5 Conv(3×3×128)
L6 Maxpool(2×2)
L7 Conv(3×3×256)
L8 Maxpool(2×2)
64*64
model.add(Conv2D(32,(5,5),strides=(1,1),input_shape=(64,64,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(128,(3,3),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(256,(3,3),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(2560,activation='relu'))
model.add(Dense(10,activation='softmax'))
实验效果不佳
32x32新方法
减少了第一个卷积层的维度,32-》16
model = Sequential()
model.add(Conv2D(16,(5,5),strides=(1,1),input_shape=(32,32,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(32,(3,3),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(256,activation='relu'))
model.add(Dense(10,activation='softmax'))