Tensorflow读取与训练Emnist数据集 复现AlexNet

这次是老师的作业,作为mnist数据集的扩展emnist的读取与训练。
就作为一次知识与实例的结合更好的理解CNN。后续会学习LSTM和GAN。

附上链接,这个是我最近看的一个讲解CNN如何工作的视频,结合这次的实例来理解下
https://www.bilibili.com/video/av66125212
这是师兄写的笔记,非常好理解:https://blog.csdn.net/kane7csdn/article/details/83617086
数据集是CSV格式的emnist-balanced,共有47类包括0-9的数字,A-Z和a-z的字母,这里会有一个问题,为什么不是26+26+10 = 62类?注意到大小写的c等字母外形是一样的,那么就是47类了。
附上CSV格式数据集链接:https://pan.baidu.com/s/1Fi1ksu-QR8R59ee_G3vJQA

图像为28*28的尺寸
CSV文件下训练集共28x28+1=785列,第1列为标签,第1列到785为数据,共112800行。
CSV文件下测试集共28x28+1=785列,第1列为标签,第1列到785为数据,共18800行。
也就是将每张图像铺成[1,28x28]

附上代码:
先用pandas读取csv格式的数据集,无头文件,注意路径,服务器下选择相对路径,PC则随意

#用pandas读取csv格式的训练集和测试集#
emnist_train = pd.read_csv('emnist-csv/emnist-balanced-train.csv', header=None)
emnist_test = pd.read_csv('emnist-csv/emnist-balanced-test.csv', header=None)
#用pandas读取csv格式的训练集和测试集#

用pd.iloc切割数据集,iloc是按照行列索引数组
具体用法参考:https://blog.csdn.net/qq_35290785/article/details/89283860
切除第一列作为标签,存放在label_train数组中
剩下的为数据,存放在nd1数组中
pd.get_dummies可以将标签进行one-hot编码,有利于算法运用
参考官方文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.get_dummies.html

#切割训练集#
nd1 = emnist_train.iloc[:,1:] #切出除第一列以外的数据
label_train = emnist_train.iloc[:,0] #切出第一列数据作为标签
print("训练集标签的形状:", label_train.shape,'\n'
      "训练集标签的总数:", label_train.size,'\n'
      "训练集标签的维度:", label_train.ndim,'\n') #用于查看标签信息

label_train = pd.get_dummies(label_train) #将测试集标签进行one-hot编码
print("训练集的形状:",label_train.shape) #查看one-hot处理后标签的形状
assert label_train.shape[0] == label_train.shape[0] #确认训练集和训练集标签第一列是否同形状
label_train = label_train.values #将训练集放入数组存储
x_train = nd1.values #将训练集标签放入数组存储
#切割训练集#

print('这里分割训练集和测试集')

#切割测试集#
nd2 = emnist_test.iloc[:,1:] #切出除第一列以外的数据
label_test = emnist_test.iloc[:,0] #切出第一列数据作为标签
print("测试集标签的形状:",label_test.shape,'\n'
      "测试集标签的总数:",label_test.size,'\n'
      "测试集标签的维度:",label_test.ndim,'\n') #用于查看标签信息

label_test = pd.get_dummies(label_test) #将测试集标签进行one-hot编码
print("测试集的形状:",label_test.shape) #查看one-hot处理后标签的形状
assert label_test.shape[0] == label_test.shape[0] #确认测试集和测试集标签第一列是否同形状
label_test = label_test.values #将测试集放入数组存储
x_test = nd2.values  #将测试集标签放入数组存储
#切割测试集#

网络结构:

#训练网络
conv1 = tf.layers.conv2d(inputs=xs_cut,
                         filters=32,
                         kernel_size=(3, 3),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='same') #?*28*28*32
pool1 = tf.layers.max_pooling2d(inputs=conv1,
                                pool_size=(2, 2),
                                strides=2,
                                padding='same') #?*14*14*32
conv2 = tf.layers.conv2d(inputs=pool1,
                         filters=64,
                         kernel_size=(2, 2),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='same') #?*14*14*64
conv3 = tf.layers.conv2d(inputs=conv2,
                         filters=128,
                         kernel_size=(2, 2),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='valid') #?*13*13*128
pool2 = tf.layers.max_pooling2d(inputs=conv3,
                                pool_size=(2,2),
                                strides=2,
                                padding='same') #?*7*7*128
re1 = tf.reshape(pool2,[-1,7*7*128]) #将pool2的数组rehape为[?,7*7*128]
flat1 = tf.layers.dense(inputs=re1,
                        units=1024,
                        activation=tf.nn.relu)
# flat2 = tf.layers.batch_normalization(flat1)
flat3 = tf.layers.dense(inputs=flat1,
                        units=47)
out = tf.nn.softmax(flat3)

1.卷积层
卷积层就是通过一个小矩阵遍历整个输入图像,通过卷积运算提取局部特征,比如输入一张图像,卷积层有3个卷积核(filter),则会输出三张图像,图片便变高了,以此类推。
我自己的理解就是,卷积核和小块的图像在训练中无限趋近,就比如输入一辆车,输出每个卷积核则是车灯车窗或者车轮,提取了局部特征,卷积核中的权重(weight)由python自己生成,目标则是降低loss。

2.池化层
我的理解是一张图片中有很多无用的信息,池化层便是提取最有用的信息,缩小图片尺寸,减少参数,可以有效的防止过拟合
关于过拟合和欠拟合:https://blog.csdn.net/qq_18254385/article/details/78428887
这是今天我看见计算输出尺寸更加简单的方法,卷积和池化输出尺寸都可以用。
在这里插入图片描述
3.归一化
这里使用了relu作为激活函数,保留大于零的,小于零的部分变为零,这个部分我存在很多疑惑,参考了下似乎是可以解决梯度消失问题,似乎也可以提高效率?

4.全连接层
我对于全连接层的理解便是一个投票的过程,比如判别猫和狗,百分之九十投票是狗,百分之十投票是猫,则最终对应到狗的标签。emnist的例子中,size的变化为(7x7,128)→ (1,7x7x128)→ (1,47)

5.BN层
这里存疑,不知道作用到底怎么用,也不知道加在哪里。

这里附上完整代码:

import tensorflow as tf
import pandas as pd
import numpy as np
import os

#选择硬件设备#
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
#选择硬件设备#

#用pandas读取csv格式的训练集和测试集#
emnist_train = pd.read_csv('emnist-csv/emnist-balanced-train.csv', header=None)
emnist_test = pd.read_csv('emnist-csv/emnist-balanced-test.csv', header=None)
#用pandas读取csv格式的训练集和测试集#

#切割训练集#
nd1 = emnist_train.iloc[:,1:] #切出除第一列以外的数据
label_train = emnist_train.iloc[:,0] #切出第一列数据作为标签
print("训练集标签的形状:", label_train.shape,'\n'
      "训练集标签的总数:", label_train.size,'\n'
      "训练集标签的维度:", label_train.ndim,'\n') #用于查看标签信息

label_train = pd.get_dummies(label_train) #将测试集标签进行one-hot编码
print("训练集的形状:",label_train.shape) #查看one-hot处理后标签的形状
assert label_train.shape[0] == label_train.shape[0] #确认训练集和训练集标签第一列是否同形状
label_train = label_train.values #将训练集放入数组存储
x_train = nd1.values #将训练集标签放入数组存储
#切割训练集#

print('这里分割训练集和测试集')

#切割测试集#
nd2 = emnist_test.iloc[:,1:] #切出除第一列以外的数据
label_test = emnist_test.iloc[:,0] #切出第一列数据作为标签
print("测试集标签的形状:",label_test.shape,'\n'
      "测试集标签的总数:",label_test.size,'\n'
      "测试集标签的维度:",label_test.ndim,'\n') #用于查看标签信息

label_test = pd.get_dummies(label_test) #将测试集标签进行one-hot编码
print("测试集的形状:",label_test.shape) #查看one-hot处理后标签的形状
assert label_test.shape[0] == label_test.shape[0] #确认测试集和测试集标签第一列是否同形状
label_test = label_test.values #将测试集放入数组存储
x_test = nd2.values  #将测试集标签放入数组存储
#切割测试集#

# np.save('E:/Project/HandwritingRead/NumpyData/label',label_train)
# np.save('E:/Project/HandwritingRead/NumpyData/sample',x_train_reshape)
# np.save('E:/Project/HandwritingRead/NumpyData/label_test',label_test)
# np.save('E:/Project/HandwritingRead/NumpyData/sample_test',x_test_reshape)

# x_v = np.load('NumpyData/sample.npy')
# y_v = np.load('NumpyData/label.npy')
# x_w = np.load('NumpyData/sample_test.npy')
# y_w = np.load('NumpyData/label_test.npy')

xs = tf.placeholder(tf.float32, [None, 784]) #取出一块?*(28*28)的区域用于存放数据
ys = tf.placeholder(tf.float32, [None, 47]) #取出一块?*47的区域用于存放标签


xs_cut = tf.reshape(xs, [-1, 28, 28, 1]) #将xs形状改变为四维数组,第一维自动计算
# xc_cut = tf.reshape(xc, [-1, 28, 28, 1])
#训练网络
conv1 = tf.layers.conv2d(inputs=xs_cut,
                         filters=32,
                         kernel_size=(3, 3),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='same') #?*28*28*32
pool1 = tf.layers.max_pooling2d(inputs=conv1,
                                pool_size=(2, 2),
                                strides=2,
                                padding='same') #?*14*14*32
conv2 = tf.layers.conv2d(inputs=pool1,
                         filters=64,
                         kernel_size=(2, 2),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='same') #?*14*14*64
conv3 = tf.layers.conv2d(inputs=conv2,
                         filters=128,
                         kernel_size=(2, 2),
                         strides=1,
                         activation=tf.nn.relu,
                         padding='valid') #?*13*13*128
pool2 = tf.layers.max_pooling2d(inputs=conv3,
                                pool_size=(2,2),
                                strides=2,
                                padding='same') #?*7*7*128
re1 = tf.reshape(pool2,[-1,7*7*128]) #将pool2的数组rehape为[?,7*7*128]
flat1 = tf.layers.dense(inputs=re1,
                        units=1024,
                        activation=tf.nn.relu)
# flat2 = tf.layers.batch_normalization(flat1)
flat3 = tf.layers.dense(inputs=flat1,
                        units=47)
out = tf.nn.softmax(flat3)
# conv4 = tf.layers.conv2d(inputs=pool2,
#                          filters=384,
#                          kernel_size=(3, 3),
#                          strides=1,
#                          activation=tf.nn.relu,
#                          padding='same')
# conv5 = tf.layers.conv2d(inputs=conv4,
#                          filters=256,
#                          kernel_size=(3, 3),
#                          strides=1,
#                          activation=tf.nn.relu,
#                          padding='same')
# pool3 = tf.layers.max_pooling2d(inputs=conv5,
#                                 pool_size=(3, 3),
#                                 strides=2,
#                                 padding='same')
# fc1 = tf.layers.dense(inputs=pool3,
#                       units=4096)
# dp1 = tf.layers.dropout(inputs=fc1,
#                         rate=0.1)
# fc2 = tf.layers.dense(inputs=dp1,
#                       units=4096)
# dp2 = tf.layers.dropout(inputs=fc2,
#                         rate=0.1)
# fc3 = tf.layers.dense(inputs=dp2,
#                       units=1024)
# flat = tf.layers.dense(fc3,47)
# out = tf.nn.softmax(fc3)
#训练网络#
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels = ys,logits=flat3)) #使用交叉熵设置损失函数
train = tf.train.MomentumOptimizer(1e-3,momentum=0.5).minimize(cross_entropy) #降低损失函数
# dataset = tf.data.Dataset.from_tensor_slices((x_v, y_v))
# print(dataset.output_shapes)
# dataset = dataset.shuffle(1).batch(128).repeat()
# iterator = dataset.make_initializable_iterator()
# data_element = iterator.get_next()
#
# dataset_test = tf.data.Dataset.from_tensor_slices((x_w,y_w))
# print(dataset_test.output_shapes)
# dataset_test = dataset_test.shuffle(1).batch(128).repeat()
# iterator_test = dataset_test.make_one_shot_iterator()
# dataset_test_element = iterator_test.get_next()

# def compute_accuracy(v_xs, v_ys):
#     y_pre = sess.run(flat3, feed_dict={xs: v_xs})
#     correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.argmax(v_ys, 1))
#     accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#     result = sess.run(accuracy, feed_dict={xs: v_xs, ys: v_ys})
#     return result

correct = tf.equal(tf.argmax(flat3, 1), tf.argmax(ys, 1))
compute_accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))


sess_config = tf.ConfigProto()
sess_config.gpu_options.per_process_gpu_memory_fraction = 0.70
with tf.Session(config=sess_config) as sess:
    # #sess.run([tf.global_variables_initializer(), iterator.initializer], feed_dict={xs: x_v, ys: y_v})
    # xs_batch,ys_batch = data_element
    # xs_batch_np = np.array(xs_batch,dtype = tf.int64)
    # ys_batch_np = np.array(ys_batch,dtype = tf.int64)
    # print(xs_batch_np.shape)
    # print(ys_batch_np.shape)
    # xs_batch_reshape = xs_batch_np.reshape([None,28,28])
    # ys_batch_reshape = ys_batch_np.reshape([None,1])
    # print(xs_batch_np.dtype)
    # print(ys_batch_np.dtype)
    # sess.run([tf.global_variables_initializer(), iterator.initializer], feed_dict={xs: xs_batch_np, ys: ys_batch_np})
    # for i in range(1000):
    #         x_w_batch, y_w_batch = sess.run(dataset_test_element)
    #         if i % 50 == 0:
    #             print(compute_accuracy(x_w_batch, y_w_batch))
    sess.run(tf.global_variables_initializer()) #初始化变量
    for e in range(100):
        for i in range(1000):
            x_train_b = x_train[i*100:(i+1)*100]  #每次取训练集数据100个
            y_train_b = label_train[i*100:(i+1)*100] #每次取训练集标签100个
            sess.run(train,feed_dict={xs: x_train_b,ys: y_train_b}) #将100个数据和100个标签分别送入xs和ys

            if e%20 == 0:
                accuracy = sess.run(compute_accuracy,feed_dict = {xs:x_test,ys:label_test}) #计算精度
                # accuracy = sess.run(compute_accuracy(x_test,label_test))
                print('当前测试精度:',accuracy)
saver = tf.train.Saver()
save_path=saver.save(sess,'E:/Project/Model/emnist/emnist_save_net.ckpt')
print('存储路径:',save_path)

确认各数据集的形状:
在这里插入图片描述
运行结果:
在这里插入图片描述
最终测试精度大概为80%,还有很多技巧没有学会,步长可以调节,PC似乎训练次数太多会出现内存溢出,服务器后期我会继续学习一些技巧提高精度和数据处理办法,比如dataset还有tfrecords形式读取,再或者用VGG来训练,后期会再写一篇。

环境:win10 Pycharm2019 Python3.6.8
硬件:PC为i7-9750H RTX2070 服务器为i9-9900K RTX2080ti X GTX1080ti
环境硬件经供参考

这次有很多不足,存疑很多,希望未来能学到更多,还请多指正。😃

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值