这里主要是参考了github上面一个u-net的程序的结构。链接
在项目中,程序员将整个神经网络分成了网络结构和训练两个类,并定义了一些函数来完成类似混淆矩阵生成这样的操作。
在这里,也是模仿了他的写法,这样会显得清晰一些。
这里使用Keras库,采用的是Functional API
的搭建网络方式:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 15 10:03:52 2017
a simple cnn classifier for mnist data using Functional API
@author: huijian
"""
from __future__ import print_function
import numpy as np
# set the seed for reproducibility
np.random.seed(1234)
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
# the libraries of keras
from keras.datasets import mnist
from keras.models import Sequential, Model
from keras.models import model_from_json
from keras.layers import Input
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering("tf")
"""
for a picture of a form (128,128,3) (img_row, img_col, channels)
th: (3,128,128) (channels,img_row,img_col)
tf: (128,128,3) (img_row, img_col, channels)
"""
def create_conv(img_shape, num_classes):
"""
param:
img_shape: a 1-D tensor, [img_row, img_col, channels]
"""
inputs = Input(shape=(img_shape[0], img_shape[1], img_shape[2]))
conv1 = Conv2D(filters = 30, kernel_size = [5,5],strides=[1,1],
padding = "same", activation = "relu",
kernel_initializer = "glorot_uniform", bias_initializer = "zeros")(inputs)
pool1 = MaxPooling2D(pool_size=[2,2], strides =[2,2])(conv1)
conv2 = Conv2D(filters = 15, kernel_size = [3,3],strides=[1,1],
padding = "same", activation = "relu",
kernel_initializer = "glorot_uniform", bias_initializer = "zeros")(pool1)
pool2 = MaxPooling2D(pool_size=[2,2],strides = [2,2])(conv2)
dropout1 = Dropout(rate=0.5)(pool2)
flat1 = Flatten()(dropout1)
dense1 = Dense(units=128, activation="relu")(flat1)
dense2 = Dense(units=50, activation ="relu")(dense1)
outputs = Dense(num_classes, activation = "softmax")(dense2)
model = Model(outputs = outputs, inputs = inputs)
return model
def get_data():
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# reshape the data
# 0-255
x_train = x_train.reshape(x_train.shape[0],28,28,1).astype(np.float32)
x_train = x_train/255.0
x_test = x_test.reshape(x_test.shape[0],28,28,1).astype(np.float32)
x_test = x_test/255.0
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
return (x_train,y_train),(x_test,y_test)
class CNN(object):
def __init__(self,img_shape, num_classes):
"""
param:
img_shape: a 1-D tensor, [img_row, img_col, channels]
"""
self.img_shape = img_shape
self.num_classes = num_classes
self.inference()
def inference(self):
self.model = create_conv(self.img_shape, self.num_classes)
return
def save(self):
# save the model
json_string = self.model.to_json()
open("my_model_architecture.json","w").write(json_string)
# save the weights
self.model.save_weights("my_model_weights.h5")
return
def restore(self):
# restore the model
self.model = model_from_json(open("my_model_architecture.json").read())
# restore the model
self.model.load_weights("my_model_weights.h5")
def predict(self, x):
# we can use predict, too, which may require a parameter of batch_size
return self.model.predict_on_batch(x)
class Train(object):
def __init__(self, net, loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]):
"""
param:
net: an instance of model, which is not complied
"""
net.model.compile(loss=loss,optimizer=optimizer,metrics=metrics)
self.net = net
def train(self, batch_size, epochs):
# get_data
(x_train,y_train),(x_test,y_test) = get_data()
# here we designate the test data set as the validation set
x_validation = x_test
y_validation = y_test
assert (x_train.shape[0] % batch_size == 0) and (x_test.shape[0] % batch_size == 0)
# training
for step in range(epochs):
for itera in range((x_train.shape[0]/batch_size)):
sta = itera * batch_size
end = (itera+1) * batch_size
# here we can use model.fit if the data can be stored in the raw
info = self.net.model.train_on_batch(x = x_train[sta:end,:,:,:], y = y_train[sta:end,:])
print("It's epoch:{epoch:>2}, loss value:{loss_value:.5f}, accuracy:{accuracy:.5f}".format(
epoch = step, loss_value = info[0], accuracy = info[1]))
# check at every epoch
info = self.net.model.test_on_batch(x = x_validation, y = y_validation)
print("Validate the model:{epoch:>2}, loss value:{loss_value:.5f}, accuracy:{accuracy:.5f}".format(
epoch=step, loss_value=info[0], accuracy=info[1]))
# save the model at every epoch
self.net.save()
# test
values = self.net.model.evaluate(x_test,y_test,batch_size)
return values
def print_confusion_matrix(net):
(x_train, y_train), (x_test, y_test) = get_data()
y_pred = np.argmax(net.model.predict(x_test),axis=1)
y_true = np.argmax(y_test, axis = 1)
cm = confusion_matrix(y_true = y_true, y_pred = y_pred)
plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues)
# make various adjustments to the plot
plt.tight_layout()
plt.colorbar()
tick_marks = np.arange(net.num_classes)
plt.xticks(tick_marks, range(net.num_classes))
plt.yticks(tick_marks, range(net.num_classes))
plt.xlabel("Predicted")
plt.ylabel(("True"))
plt.show()
if __name__=="__main__":
img_shape = [28, 28, 1]
num_classes = 10
cnn = CNN(img_shape, num_classes)
(x_train, y_train), (x_test, y_test) = get_data()
print("Data set information:[1] train data shape and dtype is x:{x_train_shape} y:{y_train_shape} x_dtype:{x_train_dtype} y_dtype:{y_train_dtype}".format(
x_train_shape=x_train.shape, y_train_shape=y_train.shape, x_train_dtype = x_train.dtype, y_train_dtype = y_train.dtype))
print("Data set information:[2] test data shape and dtype is is x:{x_test_shape} y:{y_test_shape} x_dtype:{x_test_dtype} y_dtype:{y_test_dtype}".format(
x_test_shape=x_test.shape, y_test_shape=y_test.shape, x_test_dtype = x_test.dtype, y_test_dtype = y_test.dtype))
# restore
# cnn.restore()
# how to adjust the learning rate or how to initialize the weights?
# train = Train(net = cnn,loss = "categorical_crossentropy",optimizer="adam", metrics=["accuracy"])
# values = cnn.model.evaluate(x_test,y_test,batch_size = 100)
# or train
train = Train(net = cnn,loss = "categorical_crossentropy",optimizer="adam", metrics=["accuracy"])
# print the confusion_matrix before training
print_confusion_matrix(net = train.net)
values = train.train(batch_size = 100, epochs = 1)
print("Test data set: loss value:{loss_value:.5f} accuracy:{accuracy:.5f}".format(
loss_value=values[0], accuracy=values[1]))
# print the confusion_matrix after traininng
print_confusion_matrix(net = train.net)
References:
1. Generic U-Net Tensordflow implementation for segmentation
2. Keras 实现CNN进行手写字符识别
3. Keras Document