本例为3层神经网,包括一个输入层,两个隐层,一个输出层。
输入数据大小:28*28dpi的手写图片,即(28*28)的二维数组,展平后为长度784的数组。
直接上代码,代码后面有解析:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets
import os
import cv2
# 利用Tensorflow2中的接口加载mnist数据集
(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()
# 对数据进行预处理
def preprocess(x, y):
x = tf.cast(x, dtype=tf.float32) / 255.
y = tf.cast(y, dtype=tf.int32)
return x,y
# 构建dataset对象,方便对数据的打乱,批处理等超操作
train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).shuffle(1000).batch(128)
train_db = train_db.map(preprocess) # 使用map操作,对单值调用preprocess方法
test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(128)
test_db = test_db.map(preprocess) # 使用map操作,对单值调用preprocess方法
#导入一张测试图片(28*28dpi的手写数字)请修改自己的图片路径
check_x = cv2.imread("D:\\tensorflow\\mnist_0_001.png", cv2.IMREAD_GRAYSCALE)
check_y = 0
check_x,check_y = preprocess(check_x,check_y)
check_x = tf.reshape(check_x, [-1, 28*28])
# 构建模型中会用到的权重,3层有3组w和b
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))
# 学习率
lr = 0.01
# epoch表示整个训练集循环的次数 这里循环10次,次数越多学习时间越长,准确率越高
for epoch in range(10):
# step表示当前训练到了第几个Batch
for step, (x, y) in enumerate(train_db): #enumerate() --以索引-值对的形式迭代序列
# 把训练集进行打平操作
x = tf.reshape(x, [-1, 28*28])
# 构建模型并计算梯度
with tf.GradientTape() as tape: # tf.Variable
# 三层非线性模型搭建
h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])
h1 = tf.nn.relu(h1)
h2 = h1@w2 + b2
h2 = tf.nn.relu(h2)
out = h2@w3 + b3
# 把y转化成one_hot编码,当depth=10,y=3时,y变换为[0,0,0,1,0,0,0,0,0,0]
y_onehot = tf.one_hot(y, depth=10)
# 计算MSE
loss = tf.square(y_onehot - out)
loss = tf.reduce_mean(loss)
# 计算梯度
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
# w = w - lr * w_grad
# 利用上述公式进行权重的更新
w1.assign_sub(lr * grads[0]) #tf.assign_sub(ref, value, use_locking=None, name=None),变量 ref 减去 value值,即 ref = ref - value
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
w3.assign_sub(lr * grads[4])
b3.assign_sub(lr * grads[5])
# 每训练100个Batch 打印一下当前的loss
if step % 100 == 0:
print(epoch, step, 'loss:', float(loss))
# 每训练完一次数据集 测试一下准确率
total_correct, total_num = 0, 0
for step, (x,y) in enumerate(test_db):
x = tf.reshape(x, [-1, 28*28])
h1 = tf.nn.relu(x@w1 + b1)
h2 = tf.nn.relu(h1@w2 + b2)
out = h2@w3 +b3
# 把输出值映射到[0~1]之间
prob = tf.nn.softmax(out, axis=1)
# 获取概率最大值得索引位置
pred = tf.argmax(prob, axis=1) #根据axis取值的不同返回每行(0)或者每列(1)最大值的索引
pred = tf.cast(pred, dtype=tf.int32) #tf.cast()函数的作用是执行tensorflow中张量数据类型转换
correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
correct = tf.reduce_sum(correct)
# 获取每一个batch中的正确率和batch大小
total_correct += int(correct)
total_num += x.shape[0]
# 计算总的正确率
acc = total_correct / total_num
print("y:",y, "predict:",pred)
# predict check_x,利用获得的权重w和偏置b对手写数字图片数据进行预测
h1 = tf.nn.relu(check_x@w1 + b1)
h2 = tf.nn.relu(h1@w2 + b2)
out = h2@w3 +b3
# 把输出值映射到[0~1]之间
prob = tf.nn.softmax(out, axis=1)
# 获取概率最大值得索引位置
pred_check = tf.argmax(prob, axis=1)
pred_check = tf.cast(pred_check, dtype=tf.int32)
print('test acc:', acc,"pred=",pred_check,"acc=",tf.equal(check_y ,pred_check))
这里利用tensorflow 的Keras.model 类创建模型,练习模型,评估模型,预测模型。
本例创建了2层神经网络,其中隐层有512个神经元,输出层为10。模型完成学习后,将通过model.save_weights()保存训练好的权重和偏置参数,之后就可以通过model.load_weights()导出已存的权重和偏置,然后就可以用学习好的模型进行预测了。
训练数据的保存还有一种方法:model.save()和model.load()。具体可以在网上找到,这里不再演示。
模型创建/训练/评估代码如下:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
# step1 加载训练集和测试集合
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
# step2 创建模型
def create_model():
return tf.keras.models.Sequential([ #堆叠式创建层
tf.keras.layers.Flatten(input_shape=(28, 28)), #将28*28的输入数组展平为784的一维数据
tf.keras.layers.Dense(512, activation='relu'), #512个神经元,激活函数:relu
tf.keras.layers.Dropout(0.2), #设定20%的随机扔掉,为避免过拟合
tf.keras.layers.Dense(10, activation='softmax') #输出层为10,激活函数:softmax
])
model = create_model()
# step3 编译模型 主要是确定优化方法,损失函数等
model.compile(optimizer='adam', #优化器:'adam',损失函数:'sparse_categorical_crossentropy'
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# step4 模型训练 训练1个epochs ,batch_size=256(可以为None),可以自己修改数字,看看运行结果及耗时情况
model.fit(x=x_train,
y=y_train,
epochs=1,
batch_size=256
)
# step5 用model.evaluate进行模型测试
loss, acc = model.evaluate(x_test, y_test) #model.evaluate输入数据(data)和金标准(label),然后将预测结果与金标准相比较,得到两者误差并输出.
print("train model, accuracy:{:5.2f}%".format(100 * acc))
# step6 保存模型的权重和偏置
model.save_weights('./save_weights/my_save_weights')
# step7 删除模型
del model
# step8 重新创建模型
model = create_model()
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# step9 恢复权重
model.load_weights('./save_weights/my_save_weights')
# step10 测试模型
loss, acc = model.evaluate(x_test, y_test)
print("Restored model, accuracy:{:5.2f}%".format(100 * acc))
以下代码为检测图片,输入图片文件名,输出预测结果。注意:输入的手写体如果与MNIST的图片类似识别率还是很高的,如果是自己用画图软件做的手写数字则识别成功率很低。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
import cv2
# step1 重新创建模型
def create_model():
return tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
model = create_model()
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# step2 恢复权重
model.load_weights('./save_weights/my_save_weights')
imgDir = "D:\\tensorflow\\"
imgFile = input("请输入待检测的文件名:")
while imgFile != "q": #输入q则退出程序
#导入测试图片
check_x = cv2.imread(imgDir+imgFile, cv2.IMREAD_GRAYSCALE)
check_x = check_x / 255.0
check_x = tf.reshape(check_x, [1, 28, 28])
#用model.predict对一个手写图片进行预测,显示预测结果
prob = model.predict(check_x, batch_size=None) #model.predict输入数据(data),输出预测结果
pred_check = tf.argmax(prob, axis=1)
pred_check = tf.cast(pred_check, dtype=tf.int32)
print(imgFile,"预测结果:",pred_check)
imgFile = input("请输入待检测的文件名:")