(一)数据处理
1.图像增强:
from keras.preprocessing import image
import os
import matplotlib.pyplot as plt
import numpy as np
from imageio import imwrite
"""
数据增强实现
将 1084 张图片扩为 1084*80 张
"""
# 常量
im_h = 46 # 图片高度
im_w = 120 # 图片宽度
im_chan = 3 # 图片通道数目
im_n = 4 # 每张图片分割的子图数目
w = 30 # 分割图片宽度,为im_w的四分之一
def load_img_t(path):
"""
加载完整的一张图片
origin: (43, 120, 3)
target: (1, 43, 120, 3)
:param path: 图片路径
:return:
"""
im = plt.imread(path)
im.resize(im_h, im_w, im_chan) # 压缩成标准尺寸
x = np.zeros((1, im_h, im_w, im_chan))
x[0] = im
return x
def splice_img(arr):
"""
拼接图片
origin: (4, 43, 30, 3)
target: (43, 120, 3)
:param arr: 四张子图片数组
:return:
"""
im = np.zeros((im_h, im_w, im_chan))
for i in range(im_n):
im[:, i*w:(i+1)*w, :] = arr[i]
return im
def load_img(path):
"""
加载某张图片,每张分割成四张图片,返回x数组
origin: (43, 120, 3)
target: (4, 43, 30, 3)
:param path: 图片路径
:return:
"""
im = plt.imread(path)
im.resize(im_h, im_w, im_chan) # 压缩成标准尺寸
x = np.zeros((im_n, im_h, w, im_chan)) # 分割成四张图片
for i in range(im_n):
x[i] = im[:, i*w:(i+1)*w, :]
return x
im_dir = '../../data/images/'
im_aug_dir = '../../data/images_aug/'
files = os.listdir(im_dir)
n = 10
# 1 - 10
# 缩放与旋转
im_gen1 = image.ImageDataGenerator(zoom_range=[2, 1], rotation_range=40)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen1.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1) + '.png', splice_img(im_iter.next()))
# 11 - 20
im_gen2 = image.ImageDataGenerator(samplewise_center=True,
samplewise_std_normalization=True)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen2.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n) + '.png', splice_img(im_iter.next()))
# 21 - 30
im_gen3 = image.ImageDataGenerator(shear_range=0.5)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen3.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*2) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*2) + '.png', splice_img(im_iter.next()))
# 31 - 40
im_gen4 = image.ImageDataGenerator(channel_shift_range=0.2)
for file in files:
im = load_img_t(os.path.join(im_dir, file))
im_iter = im_gen4.flow(im, batch_size=1, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*3) + '.png', im_iter.next()[0])
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*3) + '.png', im_iter.next()[0])
# 41 - 50
im_gen5 = image.ImageDataGenerator(zoom_range=[2, 1])
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen5.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*4) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*4) + '.png', splice_img(im_iter.next()))
# 51 - 60
im_gen6 = image.ImageDataGenerator(rotation_range=40)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen6.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*5) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*5) + '.png', splice_img(im_iter.next()))
# 61 - 70
im_gen7 = image.ImageDataGenerator(zoom_range=[1.5, 1], channel_shift_range=0.1)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen7.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*6) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*6) + '.png', splice_img(im_iter.next()))
# 71 - 80
im_gen8 = image.ImageDataGenerator(rotation_range=30, channel_shift_range=0.1)
for file in files:
im = load_img(os.path.join(im_dir, file))
im_iter = im_gen8.flow(im, batch_size=4, shuffle=False)
for i in range(n):
imwrite(im_aug_dir + file[:-5] + str(i+1+n*7) + '.png', splice_img(im_iter.next()))
# plt.imsave(im_aug_dir + file[:-5] + str(i+1+n*7) + '.png', splice_img(im_iter.next()))
2.图像灰度化
from imageio import imwrite
import matplotlib.pyplot as plt
import os
"""
将所有rgb图片转换成灰度图,放入 /data/images_gray/ 中
"""
def rgb2gray(rgb):
"""
将rgb图转换为灰度图
:param rgb:
:return:
"""
r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
return gray
im_dir = '../../data/images/'
im_aug_dir = '../../data/images_aug/'
im_gray_dir = '../../data/images_gray/'
files = os.listdir(im_dir)
for file in files:
im = plt.imread(os.path.join(im_dir, file))
imwrite(im_gray_dir + file, rgb2gray(im))
files = os.listdir(im_aug_dir)
for file in files:
im = plt.imread(os.path.join(im_aug_dir, file))
imwrite(im_gray_dir + file, rgb2gray(im))
模型训练与预测:
(二)pytorch写法:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import torch
import os
import torch.utils.data as Data
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F
learning_rate = 0.02
batch_size=256
num_epochs = 20
num_classes=1
"""
图片处理与数据加载相关工具方法
"""
# 数字列表
digit_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '']
# 常量
im_h = 46 # 图片高度
im_w = 120 # 图片宽度
im_chan = 3 # 图片通道数目
im_chan_2 = 4 # 图片通道数目
im_n = 4 # 每张图片分割的子图数目
w = 30 # 分割图片宽度,为im_w的四分之一
######################################################################
def load_dir_img(path):
"""加载目录下所有的灰度图片,每张分割成四张图片,返回x数组和y标签数组"""
files = os.listdir(path)
# print('files',files)
#一张训练图片有4张可以分割的图片
x = np.zeros((len(files)*im_n, im_h, w))
#分割的图片是原先训练图片的4倍,产生四倍标签
y = np.zeros(len(files)*im_n)
for i in range(len(files)):
file_path = os.path.join(path, files[i])
im = plt.imread(file_path)
labels = []
for k in files[i][0:im_n]:
if k == '_':
labels.append(10)
else:
labels.append(int(k))
#切割图片然后将1/4的图片赋值给x
for j in range(im_n):
x[i*im_n+j] = im[:, j*w:(j+1)*w]
y[i*im_n+j] = labels[j]
return x, y
def load_data_2(img_dir=r'../../data/images_gray', npz_path='../../data/digits.npz'):
"""加载目录下所有图片,自动分成训练集和测试集"""
x, y = load_dir_img(img_dir)
# print('load images finished')
#将图片分为x_train,y_train,将标签分为y_train,y_test
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.1, random_state=42)
np.savez(npz_path, x_train=x_train, y_train=y_train, x_test=x_test, y_test=y_test)
# print('data saved as ', npz_path)
return (x_train, y_train), (x_test, y_test)
def load_data_3(path='../../data/digits.npz'):
"""加载已保存的数据"""
if os.path.exists(path):
print('load saved data')
with np.load(path) as f:
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
return (x_train, y_train), (x_test, y_test)
else:
print('initial load data')
return load_data_2(npz_path=path)
#多分类标签label 转换为 one-hot
def dense_to_one_hot(labels_dense, num_classes):
"""Convert class labels from scalars to one-hot vectors."""
num_labels = labels_dense.shape[0]
index_offset = np.arange(num_labels) * num_classes
labels_one_hot = np.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset+labels_dense.ravel()] = 1
return labels_one_hot
def setdata():
(x_train, y_train), (x_test, y_test) = load_data_3()
x_train = x_train[:, np.newaxis, :, :]
x_train=torch.from_numpy(x_train)
x_train = x_train.type(torch.FloatTensor) # 转LongTensor
# print(x_train.shape)
y_train = y_train.astype(np.int64)
# y_train = dense_to_one_hot(y_train, 11)
# print(y_train)
# y_train = y_train.astype(np.int64)
y_train=torch.from_numpy(y_train)
# print(y_train.shape)
# print('ay_train', y_train.shape)
x_test = x_test[:, np.newaxis, :, :]
x_test=torch.from_numpy(x_test)
x_test = x_test.type(torch.FloatTensor) # 转LongTensor
y_test = y_test.astype(np.int64)
# y_test = dense_to_one_hot(y_test, num_classes)
# y_test = y_test.astype(np.int64)
y_test=torch.from_numpy(y_test)
# print('y_test', y_test)
train_dataset = Data.TensorDataset(x_train, y_train)
test_dataset = Data.TensorDataset(x_test, y_test)
return train_dataset,test_dataset
####################################################
#########数据集构建#########
train_dataset,test_dataset=setdata()
train_loader=Data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_loader=Data.DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=True)
####################################################
# 将数据处理成Variable, 如果有GPU, 可以转成cuda形式
def get_variable(x):
x = Variable(x)
return x.cuda() if torch.cuda.is_available() else x
def get_test_variable(x):
with torch.no_grad():
x = Variable(x)
return x.cuda() if torch.cuda.is_available() else x
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=5, padding=2),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True)
)
self.layer2 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Dropout(0.25),
)
self.layer3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=5),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True)
)
self.layer4 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Dropout(0.5),
)
self.fc = nn.Sequential(
nn.Linear(2880, 256),
nn.ReLU(inplace=True),
# nn.Dropout(0.5),
nn.Linear(256, 84),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(84, 11),
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
import time
# model = CNN()
model=torch.load("cnn1.pkl")
# model = torch.load('cnn1.pkl')
model.cuda()
##### 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
### 训练模型
print('************************模型训练开始************************')
start = time.process_time()
step = 0 # 步数,可用下面的 i
for i in range(num_epochs):
for data in train_loader:
img, label = data
# img = img.view(img.size(0), -1)
img = Variable(img)
if torch.cuda.is_available():
img = img.cuda()
label = label.cuda()
else:
img = Variable(img)
label = Variable(label)
out = model(img)
loss = criterion(out, label)
print_loss = loss.data.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
step += 1
print('steps: {}, loss: {:.4}'.format(step, print_loss))
print('************************模型训练结束************************')
end = time.process_time() - start
print('模型耗时:{:.2f}/s'.format(end))
# 保存模型
torch.save(model, 'cnn1.pkl')
# 模型评估
# model.eval()
eval_loss = 0
eval_acc = 0
for data in test_loader:
img, label = data
# img = img.view(img.size(0), -1)
img = Variable(img)
if torch.cuda.is_available():
img = img.cuda()
label = label.cuda()
out = model(img)
loss = criterion(out, label)
eval_loss += loss.data.item() * label.size(0)
_, pred = torch.max(out, 1)
num_correct = (pred == label).sum()
eval_acc += num_correct.item()
print('Test Loss: {:.6f}, Acc: {:.6f}'.format(
eval_loss / (len(test_dataset)),
eval_acc / (len(test_dataset))
))
print('预测结果对照显示 (部分) :')
pred_y = torch.max(out.cpu(), 1)[1].data.numpy().squeeze()
label = label.cpu().data.numpy().squeeze()
print(pred_y, ' prediction number')
print(label, ' real number')
模型测试
#keras 预测
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import torch
import os
import torch.utils.data as Data
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F
import utils
"""
测试数字识别
"""
root_path = r'..\..\data\test_images'
im_h = 46
w = 30
# 数字列表
digit_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '']
# 两层卷积两层全连接层
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=5, padding=2),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True)
)
self.layer2 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Dropout(0.25),
)
self.layer3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=5),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True)
)
self.layer4 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Dropout(0.5),
)
self.fc = nn.Sequential(
nn.Linear(2880, 256),
nn.ReLU(inplace=True),
# nn.Dropout(0.5),
nn.Linear(256, 84),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(84, 11),
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
def to_digit(index):
return digit_list[index]
def getPred(pred):
res = ''
for i in range(4):
index = pred[i]
if to_digit(index) == '':
res += '_'
else:
res += digit_list[index]
return res
model=torch.load("cnn1.pkl")
model.cuda()
import cv2
files = os.listdir(root_path)
for file in files:
im_path = os.path.join(root_path, file)
im = utils.load_img(im_path)
im = utils.rgb2gray_2(im)
# im = utils.rgb2gray_2(im)
im = im.reshape(im.shape[0], 1,im_h, w)
# print(im.shape)
im = torch.from_numpy(im) # numpy_data为numpy类型
im = im.type(torch.FloatTensor) # 转LongTensor
im = Variable(im)
if torch.cuda.is_available():
im = im.cuda()
out = model(im)
_, pred = torch.max(out, 1)
pred = pred.cpu().numpy() #tensor_data为tensor张量
pred = list(pred)
pred = getPred(pred)
print('label: ', file[:-4][0:4], ' digits: ', pred)
(三)keras写法:
utils.py
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import keras
import os
"""
图片处理与数据加载相关工具方法
"""
# 数字列表
digit_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '']
# 常量
im_h = 46 # 图片高度
im_w = 120 # 图片宽度
im_chan = 3 # 图片通道数目
im_chan_2 = 4 # 图片通道数目
im_n = 4 # 每张图片分割的子图数目
w = 30 # 分割图片宽度,为im_w的四分之一
def rgb2gray(rgb):
"""
将rgb图转换为灰度图
:param rgb:
:return:
"""
r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
return gray
def rgb2gray_2(arr):
"""
将四张子图组成的rgb图片转换成对应的灰度图组合数组
origin: (4, 46, 30, 3)
target: (4, 46, 30)
:param arr:
:return:
"""
res = np.zeros((im_n, im_h, w))
for i in range(im_n):
res[i] = rgb2gray(arr[i])
return res
def splice_img(arr):
"""
拼接图片
origin: (4, 43, 30, 3)
target: (43, 120, 3)
:param arr: 四张子图片数组
:return:
"""
im = np.zeros((im_h, im_w, im_chan))
for i in range(im_n):
im[:, i*w:(i+1)*w, :] = arr[i]
return im
def load_img(path):
"""
加载某张图片,每张分割成四张图片,返回x数组
origin: (43, 120, 3)
target: (4, 43, 30, 3)
:param path: 图片路径
:return:
"""
im = plt.imread(path)
im.resize(im_h, im_w, im_chan) # 压缩成标准尺寸
x = np.zeros((im_n, im_h, w, im_chan)) # 分割成四张图片
for i in range(im_n):
x[i] = im[:, i*w:(i+1)*w, :]
return x
# def load_img_2(path):
# """
# 加载某张图片,每张分割成四张图片,返回x数组和y标签
# origin: (43, 120, 3)
# target: (4, 43, 30, 3) (4,)
# :param path:
# :return:
# """
# im = plt.imread(path)
# im.resize(im_h, im_w, im_chan) # 压缩成标准尺寸
# x = np.zeros((im_n, im_h, w, im_chan)) # 分割成四张图片
# for i in range(im_n):
# x[i] = im[:, i*w:(i+1)*w, :]
# labels = []
# for k in path[-11:-7]:
# if k == '_':
# labels.append(-1)
# else:
# labels.append(int(k))
# y = np.array(labels)
# return x, y
def load_dir_img(path):
"""
加载目录下所有的灰度图片,每张分割成四张图片,返回x数组和y标签数组
:param path:
:return:
"""
files = os.listdir(path)
# x = np.zeros((len(files)*im_n, im_h, w, im_chan))
x = np.zeros((len(files)*im_n, im_h, w))
y = np.zeros(len(files)*im_n)
for i in range(len(files)):
file_path = os.path.join(path, files[i])
im = plt.imread(file_path)
labels = []
for k in files[i][0:im_n]:
if k == '_':
labels.append(-1)
else:
labels.append(int(k))
for j in range(im_n):
x[i*im_n+j] = im[:, j*w:(j+1)*w]
y[i*im_n+j] = labels[j]
return x, y
# def load_data(train_path='../../data/train/', test_path='../../data/test/'):
# """
# 加载训练集和测试集
# :param train_path:
# :param test_path:
# :return:
# """
# return load_dir_img(train_path), load_dir_img(test_path)
def load_data_2(img_dir='../../data/images_gray/', npz_path='../../data/digits.npz'):
"""
加载目录下所有图片,自动分成训练集和测试集
:param npz_path:
:param img_dir:
:return:
"""
x, y = load_dir_img(img_dir)
print('load images finished')
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.1, random_state=42)
np.savez(npz_path, x_train=x_train, y_train=y_train, x_test=x_test, y_test=y_test)
print('data saved as ', npz_path)
return (x_train, y_train), (x_test, y_test)
def load_data_3(path='../../data/digits.npz'):
"""
加载已保存的数据
:param path:
:return:
"""
if os.path.exists(path):
print('load saved data')
with np.load(path) as f:
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
return (x_train, y_train), (x_test, y_test)
else:
print('initial load data')
return load_data_2(npz_path=path)
def to_digit(cate):
"""
y标签转化为对应的数字
:param cate:
:return:
"""
return digit_list[np.argmax(cate)]
def img_2_digits_mlp(im_path, model_path='model.h5'):
"""
使用mlp模型预测图片中的数字,返回一个对应的数字字符串
:param model_path:
:param im_path:
:return:
"""
im = load_img(im_path)
im = rgb2gray_2(im)
x = im.reshape(im.shape[0], -1) # 拉平矩阵
model = keras.models.load_model(model_path) # 加载训练好的模型
y = model.predict(x) # 预测
res = ''
for i in range(y.shape[0]):
res += to_digit(y[i])
return res
#
#
# def img_2_digits_cnn(im_path, model_path='model_cnn.h5'):
# """
# 使用cnn模型预测图片中的数字,返回一个对应的数字字符串
# :param im_path:
# :param model_path:
# :return:
# """
# im = load_img(im_path)
# im = rgb2gray_2(im)
# x = im.reshape(im.shape[0], im_h, w, 1)
# model = keras.models.load_model(model_path) # 加载训练好的模型
# y = model.predict(x) # 预测
# res = ''
# for i in range(y.shape[0]):
# res += to_digit(y[i])
#
# return res
def img_2_digits(x, model):
"""
使用训练好的模型,预测结果
:param x:
:param model:
:return:
"""
y = model.predict(x)
res = ''
for i in range(y.shape[0]):
if to_digit(y[i])=='':
res += '_'
else:
res += to_digit(y[i])
return res
if __name__ == '__main__':
x, y = load_img_2('../../data/test/728_a_0.png')
print(x)
print(y)
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
# import utils
import torch.utils.data as Data
import keras
from keras.models import Sequential,load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
import utils
"""
数字识别cnn模型
"""
batch_size = 256
num_classes = 11
epochs = 20
# input image dimensions
img_rows, img_cols = 46, 30
(x_train, y_train), (x_test, y_test) = utils.load_data_3()
print(x_train)
print(y_train)
print('origin')
print('x_train.shape: ', x_train.shape, ' y_train.shape: ', y_train.shape)
print('x_test.shape: ', x_test.shape, 'y_test.shape: ', y_test.shape)
# channel last default
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
print('reshape x')
print('x_train',x_train)
print('x_train.shape: ', x_train.shape)
print('x_test.shape: ', x_test.shape)
print('by_train: ', y_train.shape)
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
print('cate y')
print(y_train)
print('ay_train: ', y_train.shape)
print('y_test: ', y_test.shape)
# Test accuracy: 0.9983770855873811
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.summary()
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_split=0.1)
model.save('model_cnn.h5')
print('model saved')
model = load_model('model_cnn.h5')
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
模型测试代码:
#keras 预测
import os
import utils
import keras
"""
测试数字识别
"""
root_path = r'D:\银行卡识别系统\CardIdentify-master1\data\test_images'
im_h = 46
w = 30
model = keras.models.load_model('model_cnn.h5')
model.summary()
files = os.listdir(root_path)
for file in files:
im_path = os.path.join(root_path, file)
im = utils.load_img(im_path)
im = utils.rgb2gray_2(im)
x = im.reshape(im.shape[0], im_h, w, 1)
# x = im.reshape(im.shape[0], -1) # 拉平矩阵
print('label: ', file[:-4], ' digits: ', utils.img_2_digits(x, model))
测试结果: