基于TensorFlow的手写体识别(十种标签识别,五种作者识别)
这是一篇学习笔记,主要用于日后复习,有很多冗余的地方,大部分内容参考了原 ‘tensorflow 猫狗大战’ 的程序
参考的 ‘tensorflow 猫狗大战’ 的链接在最后附上
共有3000张图片,分成2800张训练集和200张测试集
其中200张测试集:
标签(0-9)识别的测试集由10(0-9、10种图片)*20张组成
作者(A-E)识别的测试集由5(A-E、5种图片)*40张组成
数据集
共有3000张与mnist数据集中相同的图片组成
tensorflow实现
训练数据的读取
input_data_image_label
import tensorflow as tf
import os
import numpy as np
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
# -*- coding: utf-8 -*-
# 用get_files()读取图片,根据图片名添加image和label,再将image、label放到数组中,打乱顺序返回
def get_files_image_label(file_dir):
# 遍历文件,按照0-9顺序生成3000张图片地址列表
label_images = []
for label in [str(i) for i in range(0,10)]:
for file in os.listdir(file_dir):
name = file.split(sep='_')
# name
if label in name[0]:
label_images.append(file_dir + '/' + file)
# 10 label_image lists
label_0_images = label_images[:300]
label_1_images = label_images[300:600]
label_2_images = label_images[600:900]
label_3_images = label_images[900:1200]
label_4_images = label_images[1200:1500]
label_5_images = label_images[1500:1800]
label_6_images = label_images[1800:2100]
label_7_images = label_images[2100:2400]
label_8_images = label_images[2400:2700]
label_9_images = label_images[2700:3000]
test_images_list = []
for x in [label_0_images, label_1_images, label_2_images, label_3_images,
label_4_images, label_5_images, label_6_images, label_7_images,
label_8_images, label_9_images]:
for i in range(20):
randIndex = int(np.random.uniform(0, len(x)))
# 生成测试集
test_images_list.append(x[randIndex])
del (x[randIndex])
# 生成10x280张训练图片(2800)
train_images_list = np.hstack((label_0_images, label_1_images, label_2_images, label_3_images,
label_4_images, label_5_images, label_6_images, label_7_images,
label_8_images, label_9_images))
train_label_list = np.hstack(([0]*280, [1]*280, [2]*280, [3]*280, [4]*280,
[5]*280, [6]*280, [7]*280, [8]*280, [9]*280))
test_label_list = np.hstack(([0]*20, [1]*20, [2]*20, [3]*20, [4]*20,
[5]*20, [6]*20, [7]*20, [8]*20, [9]*20))
# 把图像和作者都放倒一个 temp 中 然后打乱顺序,然后取出来
temp = np.array([train_images_list, train_label_list])
temp = temp.transpose()
# 打乱顺序
np.random.shuffle(temp)
# (2800,2)
print(temp.shape)
# 取出第一个元素作为 image 第二个元素作为 label 第三个元素作为 label
train_image_list = list(temp[:, 0])
train_label_list = list(temp[:, 1])
train_label_list = [int(i) for i in train_label_list]
# 把图像和作者都放倒一个 temp 中 然后打乱顺序,然后取出来
temp = np.array([test_images_list, test_label_list])
temp = temp.transpose()
# 打乱顺序
np.random.shuffle(temp)
# (200,2)
print(temp.shape)
# 取出第一个元素作为 image 第二个元素作为 label
test_images_list = list(temp[:, 0])
test_label_list = list(temp[:, 1])
test_label_list = [int(i) for i in test_label_list]
# 换成整形?不然会产生bug,因为append默认float32
return train_image_list, train_label_list, test_images_list, test_label_list
# 测试 get_files_image_label
# train_imgs , train_label, test_imgs,test_label = get_files_image_label('D:\\python_projects\\unitied\\image')
# for i in train_imgs:
# print("img:",i)
#
# for i in train_label:
# print('label:',i)
#
# for i in test_imgs:
# print('label:',i)
#
# for i in test_label:
# print('label:',i)
# 测试 get_files_image_label
#将第一步处理好的image、label的数组,转化为tensorflow能够识别的格式,
# 然后将图片裁剪和补充进行标准化处理,分批次返回,裁剪和补充猫狗大战里做的,这里不需要
# 生成相同大小的批次
# image_W ,image_H 指定图片大小,batch_size 每批读取的个数 ,capacity队列中 最多容纳元素的个数
def get_batch(image, label, image_W, image_H, batch_size, capacity):
# 转换数据为 tf 能识别的格式
image = tf.cast(image, tf.string)
# 32位整数,占4个字节,图像读进来int32
label = tf.cast(label, tf.int32)
# 将image、label放到队列里
input_queue = tf.train.slice_input_producer([image, label])
# 后面run才抽取
# 是一个tensor生成器,作用是按照设定,每次从一个tensor列表中按顺序或者随机抽取出一个tensor放入文件名队列,随机产生一个图片和标签.
# 我的理解是把image和label两个列表放进去形成文件名队列(小朋友手拉手),每次抽取一个tensor,这个tensor就是一对图片和标签
# slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None,
# capacity=32, shared_name=None, name=None)
# tensor_list: 包含一系列tensor的列表,表中tensor的第一维度的值必须相等,即个数必须相等,有多少个图像,就应该有多少个对应的标签。
# num_epochs: 可选参数,是一个整数值,代表迭代的次数,如果设置 num_epochs=None,生成器可以无限次遍历tensor列表,如果设置为 num_epochs=N,生成器只能遍历tensor列表N次。
# shuffle: bool类型,设置是否打乱样本的顺序。一般情况下,如果shuffle=True,生成的样本顺序就被打乱了,在批处理的时候不需要再次打乱样本,使用 tf.train.batch函数就可以了;
# 如果shuffle=False,就需要在批处理时候使用 tf.train.shuffle_batch函数打乱样本。
# seed: 可选的整数,是生成随机数的种子,在第三个参数设置为shuffle=True的情况下才有用。
# capacity: 设置tensor列表的容量。
# shared_name: 可选参数,如果设置一个‘shared_name’,则在不同的上下文环境(Session)中可以通过这个名字共享生成的tensor。
# name: 可选,设置操作的名称。
label = input_queue[1]
# 这里我不知道队列的第二列的形状是什么样的,print出来是 (),因为还没抽取
print(label.shape)
# 读取图片的全部信息,返回从文件中读入的字节数,相应图片的 地址
image_contents = tf.read_file(input_queue[0])
# 把图片解码,channels =3 为彩色图片, r,g ,b 黑白图片为 1 ,也可以理解为图片的厚度
# 图像在存储时并不是直接记录这些矩阵中的数字,而是记录经过压缩编码之后的结果。
# 所以要将一张图象还原成一个三(一)维矩阵。需要解码的过程
image = tf.image.decode_jpeg(image_contents, channels=1)
# 图片集里的照片都是28*28,所以不需要裁剪扩充和缩放
# 将图片以图片中心进行裁剪或者扩充为 指定的image_W,image_H
# image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H)
# 裁剪会受到影响,所以使用resize_images()对图像进行缩放,而不是裁剪,采用NEAREST_NEIGHBOR插值方法
# 把1维矩阵转化成28*28*1的矩阵,也可以reshape吧
image = tf.image.resize_images(image, [image_H, image_W], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
print(image.shape)
# 对数据进行标准化,标准化,就是减去它的均值,除以他的方差
# 标准化处理可以使得不同的特征具有相同的尺度(Scale)。这样,在使用梯度下降法学习参数的时候,不同特征对参数的影响程度就一样了。
# 运算过程是将整幅图片标准化(不是归一化),加速神经网络的训练
# (x - mean) / adjusted_stddev,其中x为图片的RGB三通道像素值,mean分别为三通道像素的均值,
# adjusted_stddev = max(stddev, 1.0/sqrt(image.NumElements()))。
# stddev为三通道像素的标准差,image.NumElements()计算的是三通道各自的像素个数。
image = tf.cast(image, tf.float32)
image = tf.image.per_image_standardization(image)
# 生成批次
# num_threads 有多少个线程根据电脑配置设置,还不清楚
# capacity 队列中 最多容纳图片的个数 tf.train.shuffle_batch 打乱顺序,
# 返回的shape [batch_size, x, y, z]([2,28,28,1])
# 批次数就是图片数
image_batch, label_batch = tf.train.batch([image, label], batch_size=batch_size, num_threads=64, capacity=capacity)
print(label_batch.shape)
# (2,)
# 重新定义下 label_batch的形状
# 把label_betch的形状变成了batch_size行(2行)
label_batch = tf.reshape(label_batch, [batch_size])
# 有什么用,double check(工程上,检查点)
# 转化图片
image_batch = tf.cast(image_batch, tf.float32)
print(image_batch.shape)
#[2,28,28,1]
print(label_batch.shape)
#[2,]
return image_batch, label_batch
# test get_batch
# import matplotlib.pyplot as plt
# BATCH_SIZE = 2
# CAPACITY = 256
# IMG_W = 28
# IMG_H = 28
#
# train_dir = r'D:\python_projects\unitied\image'
#
# image_list, label_list, test, test_list = get_files_image_label(train_dir)
# image_batch, label_batch = get_batch(image_list, label_list, IMG_W, IMG_H, BATCH_SIZE, CAPACITY)
#
#
#
#
# with tf.Session() as sess:
# i = 0
# # Coordinator 和 start_queue_runners 监控 queue 的状态,不停的入队出队
# coord = tf.train.Coordinator()
# # Coordinator类用来管理在Session中的多个线程,可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常,
# # 该线程捕获到这个异常之后就会终止所有线程。使用 tf.train.Coordinator()来创建一个线程管理器(协调器)对象。
#
# threads = tf.train.start_queue_runners(coord=coord)
# # coord.should_stop() 返回 true 时也就是 数据读完了应该调用 coord.request_stop()
# try:
# while not coord.should_stop() and i<1:
# # 测试一个步
# img, label,= sess.run([image_batch, label_batch])
#
# for j in np.arange(BATCH_SIZE):
# # 0 1
# print('label: %d' %label[j])