深度学习复习(包括文件读取与解码、卷积神经网络实现mnist分类)

dropout 防止过拟合
relu 激活函数

卷积神经网络的结构:
卷积层、激活层、池化层(pooling layer/subsample)、全连接层
怎么排列他们效果比较好是需要实验的

卷积神经网络隐藏层重要模块

一、卷积层

卷积核kernal/过滤器filter/模型参数/卷积单元
卷积核四要素有:个数、大小、步长、零填充的大小

常用大小:11 33 5*5
卷积核个数 相当于派多人去观察 得到多张观测结果
如何计算输出图像的大小

在这里插入图片描述
输入32321 50个filter 大小为5*5 移动步长为1 填充为1(意思是填充了几0)
H1=32 D1(通道数)=1 k=50 f=5 p=1
故H2=30 D2=k 所以输出为[30,30,50]
(若不能整除,则卷积向下取整,池化向上取整)

卷积网络API

tf.nn.conv2D(input,filter,strides=,padding=,name=None) 五个参数 最后一个修改指令名称不管了

**input:**输入的图像,为四阶张量的形式
[batch,height,width,channel] 类型必须为float32 或者float64

**filter:**指定过滤器的权重 包括weghts和bias 这里主要是权重 bias是后加上去的
模型参数(权重)用变量保存,需要指定初始值
filter的形状为[filter_height,filter_width,in_channels,out_channels]四阶张量的形状
initial_value=random_normal(shape=[filter_height,filter_width,in_channels,out_channels])

initial_value=random_normal(shape=[f,f,输入图片的通道数,输出的通道数(就等于filter个数K)])
f=1,3,5
strides:步长,1,2,一般取1比较多的 其形状也有要求
strides=[1,strides,strides,1] 如果步长为1则直接在strides这里填上1即为[1,1,1,1]
也就是说不管是横着平移竖着平移均为1格

padding:零填充
“SAME”:越过边缘取样,得到的输出的大小(长宽)与输入的大小一致
“VALID”:不越过边缘取样,即不进行零填充

注意,每个过滤器都会带若干权重和一个偏置

二、激活函数(激活层)

Relu 计算速度快 解决了梯度消失 图像没有负的像素值
tensorflow中使用relu

激活层API

tf.nn.relu(features,name=None)
features即为卷积+偏置的结果

三、池化层

降低网络参数,防止过拟合
max_pooling 最大池化
avg_pooling 平均池化
计算方法与卷积一样
D2=64(上一层的通道个数)

池化层API

tf.nn.max_pool(value,ksize=,strides=,padding=,name=None)
**value:**即为上一步的输出,为四维张量的形式,[batch,height,width,channels]
ksize:池化窗口的大小 [1,ksize,ksize,1],如[1,2,2,1]
strides:strides=[1,strides,strides,1] 如果步长为2则直接在strides这里填上1即为[1,2,2,1]
padding:零填充
“SAME”:越过边缘取样,得到的输出的大小(长宽)与输入的大小一致
“VALID”:不越过边缘取样,即不进行零填充


全连接层

充当分类器的作用 复习全连接层分类mnist:
可以直接调接口下载数据集 训练集55000张数据
特征值: 28*28=784个元素
**目标值:**分类 目标值 用独热码(one-hot)表示
0,1,2_,9 一共10种可能
若为1 则用独热码表示为:
0,1,0,_,0
故mnist.train.label=[55000,10] 即一行表示一张图片的label

写形状shape的时候最好使用中括号

补充:数据IO操作

如何将大量的数据加载到内存当中
三种文件读取的方法:
占位符和feed_dict搭配使用的方法
QueueRunner的方式
通用文件读取流程
图片
二进制文件
TFrecords

QueueRunner的方式 通用文件读取流程

多任务 多线程 多进程 如何解决数据传递的问题
用队列
多线程+队列

1.通用文件的读取流程
总共三个阶段:
阶段一:构造文件名队列
阶段二:读取与解码
阶段三:将样本放到批处理队列当中
手动开启线程

阶段一:构造文件名队列

将需要读取的文件的文件名放入文件名队列

tf.train.string_input_producer(string_tensor,shuffle=True)

string_tensor:含有文件名+路径的列表
shuffle=True:默认打乱文件名顺序
num_epochs:过几遍数据,默认无限过数据
return 文件名队列filequeue=tf.train.string_input_producer(string_tensor,shuffle=True)

阶段二:读取与解码

读取不同的文件类型 区别就在这里

图片:
读取:tf.WholeFileReader() 一个文件名对应一张图片 一张图片对应一个样本
解码tf.image.decode_jpeg(contents)
**>**contents是读取的返回的value
**>**将jpeg编码的图像解码为uint8张量
**>**return 张量类型,3-D形状[height,weight,channels]
tf.image.decode_png(contents)
**>**将png编码的图像解码为uint8张量
**>**return 张量类型,3-D形状[height,weight,channels]
二进制文件:
读取tf.FixedLengthRecordReader(recordbytes) 一个固定字节(要告诉他recordbytes是多少) 对应一个样本
解码tf.decode_raw
TFRecords:
读取tf.TFRecordReader()

读取器 有个共同的方法 read方法 会返回一个tensor元组key,value
也就是key,value=读取器.read(file.queue) key:样本所在的文件的文件名 value:一个样本

默认所有解码的类型都是unit8类型,如果要改为其他类型则需要用tf.cast()进行类型转换

阶段三:将样本放到批处理队列当中

有两种方法

tf.train.batch

tf.train.shuffle_batch

tf.train.batch(tensors,batch_size,num_threads,capacity)

tensors:可以是包含张量的列表,批处理的内容放到列表当中
batch_size:从队列中读取的批处理大小,一次性要处理几个样本
num_threads:进入队列的线程数,跟电脑cpu或gpu的核芯数有关,核心越多可以填多一点
capacity:整数,队列中元素的最大数量
return tensors

至此还没完 需要手动开启线程
用到tf.train.QueueRunner对象
在开启会话之后
调用tf.train.start_queue_runners(sess=None,coord=None)
传参有两个,sess:所在的会话
coord:线程协调器——任务完成后回收线程用

此处写一个狗文件读取案例:

(1)构造文件名队列
(2)读取与解码
使得样本形状和类型保持统一
(3)批处理

import tensorflow as tf

#不显示警告日志的方法:
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'


#注意读取操作必须需要import  os


def picture_read(filelist):
    """"
    狗图片读取案例
    """
    #1.构造文件名队列file_queue
    file_queue=tf.train.string_input_producer(filelist)

    #2.读取与解码

    # 读取阶段
    #先构建读取器
    reader=tf.WholeFileReader()
    #key是文件名  value是一个样本也就是此图片的原始编码形式(二进制)
    key,value=reader.read(file_queue)
    #print("key\n",key)
    #print("value\n",value)

    # 解码阶段
    image=tf.image.decode_jpeg(value)
    print("解码后的image的属性\n", image)

    #图像的形状、类型的修改  将图片统一为200×200的像素
    image_resized = tf.image.resize_images(image,[200,200])
    print("image_resized\n",image_resized)

    #静态形状修改    因为知道肯定是3通道
    image_resized.set_shape([200,200,3])
    print("image_resized\n", image_resized)

    #3.批处理
    image_batch = tf.train.batch([image_resized],batch_size=100,num_threads=1,capacity=100)
    print("image_batch\n",image_batch)

    #开启会话
    with tf.Session() as sess:
        #开启线程 因为入队和出队的操作需要开启线程,否则运行会卡死
        #创建线程协调员
        coord=tf.train.Coordinator()
        threads=tf.train.start_queue_runners(sess,coord=coord)

        key_new,value_new,image_resized_new=sess.run([key,value,image_resized])
        #print("key_new:\n",key_new)
        #print("value_new:\n",value_new)
        print("image_resized_new:\n", image_resized_new)
        image_new=sess.run(image)
        print("解码后的image\n",image_new)

        #回收线程
        coord.request_stop()       #请求停止
        coord.join(threads)

    return None

if __name__ == "__main__":
    #构造路径+文件名的列表  用os模块
    filename=os.listdir("./dog")
    #print(filename)
    #拼接路径+文件名
    filelist=[os.path.join("./dog/",file) for file in filename]
    #print(filelist)
    picture_read(filelist)

此处再写一个cifar10二进制文件读取案例:

二进制数据集 每张图片为32323
故每3073个字节为一个样本:一个目标值(标签0~9)+3072个像素(1024字节红色 1024字节绿色 1024字节蓝色)
故读取器这里tf.FixedLengthRecordReader(recordbytes) recordbytes要填3073
依然是三部曲
(1)构造文件名队列
(2)读取与解码

reader=tf.FixedLengthRecordReader(recordbytes) 
key,value= reader.read(file_queue)
decoded=tf.decode_raw(value,uint8)

将数据的标签和图片(tensor)进行分割(切片)得到
label和
一个样本image(3072个字节 = 1024r +1024g +1024b)
[[r[32, 32]],
[g[32,32]],
[b[32,32]]]
shape=[3 , 32 , 32]=[channels,height,width]
故需要转换成tensorflow的图像表示习惯
图片的形状和类型调整完毕后:
(3)批处理

import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'


#用面向对象的方法写
class Cifar(object):

    def __init__(self):
        #初始化操作
        self.height=32
        self.width=32
        self.channels=3

        #字节数
        self.image_bytes=self.height * self.width * self.channels
        self.label_bytes=1
        self.all_bytes=self.image_bytes+self.label_bytes

    def read_and_decode(self,file_list):

        #1. 构造文件名队列
        file_queue = tf.train.string_input_producer(file_list)

        #2. 读取与解码

        #读取阶段
        reader = tf.FixedLengthRecordReader(self.all_bytes)
        #key为文件名  value为一个样本的内容
        key,value = reader.read(file_queue)
        print("key:\n",key)
        print("value:\n",value)

        #解码阶段  结果是一个一维数组  第一个元素是标签值 后面3072为像素值 故需要切片操作
        decoded = tf.decode_raw(value,tf.uint8)
        print("decoded:\n",decoded)

        #将目标值和特征值切开  #第一个【】是切出来的起始元素索引  第二个【】填切片的长度
        label = tf.slice(decoded,[0],[self.label_bytes])
        image = tf.slice(decoded,[1],[self.image_bytes])
        print("label:\n",label)
        print("image:\n",image)

        #调整图片形状  因为是跨阶调整图片形状 不能用静态形状 必须用动态形状
        image_reshape = tf.reshape(image,shape=[self.channels,self.height,self.width])
        print("image_shape:\n",image_reshape)

        #转置,将图片的顺序转为 height,width,channels   原先按0,1,2排列,然后在这里的[]里面放在对应的位置
        image_transposed = tf.transpose(image_reshape,[1,2,0])
        print("image_transposed:\n",image_transposed)

        #调整图像类型 uint8→float32
        image_cast = tf.cast(image_transposed,tf.float32)


        #3. 批处理
        label_batch,image_batch = tf.train.batch([label,image_cast],batch_size=100,num_threads=8,capacity=100)
        print("lable_batch:\n",label_batch)
        print("image_batch:\n", image_batch)



        #开启会话
        with tf.Session() as sess:

            #开启线程
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess=sess,coord=coord)

            key_new,value_new,decoded_new,label_new,image_new,image_reshape_new,image_transposed_new = sess.run([key,value,decoded,label,image,image_reshape,image_transposed])
            label_batch_new,image_batch_new = sess.run([label_batch,image_batch])
            print("key_new:\n",key_new)
            print("value_new:\n", key_new)
            print("decoded_new:\n", decoded_new)
            print("label_new:\n",label_new)
            print("image_new:\n",image_new)
            print("image_shape_new:\n",image_reshape_new)
            print("image_transposed_new:\n", image_transposed_new)
            print("labe_batch_new:\n",label_batch_new)
            print("image_batch_new:\n", image_batch_new)

            #回收线程
            coord.request_stop()
            coord.join(threads)

        return None


if __name__ == "__main__":
    file_name = os.listdir("./cifar-10-batches-bin")
    print("filename:\n",file_name)
    #构造文件名路径列表
    file_list = [os.path.join("./cifar-10-batches-bin/",file) for file in file_name if file[-3:] == "bin"]
    print("filelist:\n",file_list)


    #实例化Cifar
    cifar=Cifar()
    cifar.read_and_decode(file_list)


用CNN识别mnist

网络设计:
需要知道形状的变化
第一个卷积大层:
输入的形状[None,28,28,1]
卷积层:
32个 filter 大小55 步长1 padding ‘SAME’ [ 5 , 5 , 1 , 32 ]
输出的形状[None,28,28,32]
激活:
relu
池化:
输入的形状[None,28,28,32]
大小2
2 步长2 (习惯)
输出的形状需要用公式算[None,14,14,32]
记住 池化就是把长和宽干掉一半

第二个卷积大层:
卷积层:
输入的形状[None,14,14,32]
64个 filter 大小55 步长1 padding= ‘SAME’ [ 5 , 5 , 32 , 64 ]
输出的形状[None,14,14,64]
激活:
relu
池化:
输入的形状[None,14,14,64]
大小2
2 步长2 (习惯)
输出的形状[None,7,7,64]

全连接层
形状:
tf.reshape()
[None,7,7,64]------->[None,7764]
[None,7764][] = [None,10] **所以权重为 [77*64,10]**
y_predict = tf.matmul(pool2,weights)+bias

调参 提高准确率的方法
(1)学习率减小 0.1——>0.001
(2) 随机初始化权重、偏置的值 可以将方差设为stddev=0.01
(3)选择好用的优化器 如AdamOptimizer

看来改变学习率的效果是最显著的

网络的优化与改进方法:
1.模型参数的大小调整
2.改进网络结构
加入 batch_normalization 批归一化(批标准化)
dropout层 使得某些神经元失效

二者都是为了防止过拟合

import tensorflow as tf
import os
#调用端口下载数据集
from tensorflow.examples.tutorials.mnist import input_data

#1、利用数据,在训练的时候实时提供数据
#mnist手写识别数字数据在运行时候实时提供给占位符
tf.app.flags.DEFINE_integer("is_train", 1, "指定是否是训练模型,还是拿数据去预测")
FLAGS = tf.app.flags.FLAGS


#定义权重生成器
def create_weights(shape):
    return tf.Variable(initial_value=tf.random_normal(shape=shape,stddev=0.01))



# 构建卷积神经网络
def create_model(x):

    #1)第一个卷积大层
    with tf.variable_scope("conv1"):
        #卷积层
        #将x[None,784]形状进行修改  跨阶数修改
        input_x = tf.reshape(x,shape=[-1, 28, 28, 1])
        #定义filter和偏置
        conv1_weights = create_weights(shape=[5,5,1,32])
        conv1_bias = create_weights(shape=[32])
        conv1_x = tf.nn.conv2d(input=input_x, filter=conv1_weights,strides=[1,1,1,1],padding="SAME") + conv1_bias

        #激活层
        relu1_x = tf.nn.relu(conv1_x)

        #池化层
        pool1_x = tf.nn.max_pool(value=relu1_x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")


    #2)第二个卷积大层
    with tf.variable_scope("conv2"):
        # 卷积层
        # 定义filter和偏置
        conv2_weights = create_weights(shape=[5, 5, 32, 64])
        conv2_bias = create_weights(shape=[64])
        conv2_x = tf.nn.conv2d(input=pool1_x, filter=conv2_weights, strides=[1, 1, 1, 1], padding="SAME") + conv2_bias

        # 激活层
        relu2_x = tf.nn.relu(conv2_x)

        # 池化层
        pool2_x = tf.nn.max_pool(value=relu2_x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")

    #3)全连接层
    with tf.variable_scope("full_connection"):
        #首先做形状修改
        # [None, 7, 7, 64] - ------>[None, 7 * 7 * 64]
        # [None, 7 * 7 * 64] * [] = [None, 10]   所以权重为[7 * 7 * 64, 10]
        x_fc = tf.reshape(pool2_x,shape=[-1, 7 * 7 * 64])   #注意reshape没有None的用法  需要用-1
        weights_fc = create_weights(shape=[7 * 7 * 64, 10])
        bias_fc = create_weights(shape=[10])
        y_predict = tf.matmul(x_fc, weights_fc) + bias_fc



    return y_predict




def full_connection_completed():

    #1.准备数据
    #1)导入数据集
    mnist = input_data.read_data_sets("./mnist_data", one_hot=True)
    #2)准备真实值feeding
    with tf.variable_scope("mnist_data"):
        x = tf.placeholder(dtype=tf.float32,shape=[None,784])
        y_true = tf.placeholder(dtype=tf.float32,shape=(None,10))

    y_predict = create_model(x)


    #3.softmax回归以及交叉熵损失计算
    with tf.variable_scope("softmax_crossentropy"):
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true,logits=y_predict))

    #4.梯度下降优化损失
    with tf.variable_scope("optimizer"):
        train_op=tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

    #5.准确率计算
    with tf.variable_scope("accuracy"):
        #训练集准确率计算
        #1)比较预测值和真实值最大值所在位置,tf.argmax表示按行返回最大值的索引
        equal_list=tf.equal(tf.arg_max(y_true,1),tf.arg_max(y_predict,1))
        #2)将布尔值转换为浮点数,求平均,即为准确率
        accuracy=tf.reduce_mean(tf.cast(equal_list,tf.float32))


        #测试集准确率计算 创造变量sum
        sum = tf.constant(0)



    #(2)收集要显示的变量
    #先收集损失和准确率
    tf.summary.scalar("losses", loss)
    tf.summary.scalar("accuracy",accuracy)



    #初始化变量
    init_op=tf.global_variables_initializer()

    #(3)合并所有变量op
    merged = tf.summary.merge_all()

    #创建模型保存与加载
    saver = tf.train.Saver()


    #以上只是一个图 因此需要
    #开启会话
    with tf.Session() as sess:
        #把变量传进来
        sess.run(init_op)

        #(1)创建一个events文件实例
        file_writer = tf.summary.FileWriter("./tmp/summary2/",graph=sess.graph)

        #加载模型
        if os.path.exists("./tmp/modelckpt2/checkpoint"):
            saver.restore(sess,"./tmp/modelckpt2/cnn_model")  #注意modelckpt2这个文件夹要自己建立
                                                              #也就是说 模型保存和加载的时候 也就是saver.save或saver.restore的路径需要自己建立 否则会蓝屏
                                                              #但是创建envents实例化的路径可以不用自己建立
        if FLAGS.is_train == 1:

            image,label=mnist.train.next_batch(100)

            print("训练之前,损失为%f" % sess.run(loss,feed_dict={x:image,y_true:label}))

            #开始训练  注意每次sess.run都要feed数据
            for i in range(300):
                _,error,accuracy_value=sess.run([train_op,loss,accuracy],feed_dict={x:image,y_true:label})
                print("第%d次的训练,损失为%f,准确率为%f" % (i+1 , error , accuracy_value))
                #运行合变量op,写入事件文件当中
                summary = sess.run(merged, feed_dict={x:image,y_true:label})
                file_writer.add_summary(summary, i)
                if i % 100 == 0:
                    saver.save(sess,"./tmp/modelckpt2/cnn_model")


        else:
            #如果不是训练,则是用测试集对模型进行测试
            for i in range(100):
                #每次拿一个样本进行预测
                image, label = mnist.test.next_batch(1)
                accuracy_value=sess.run(accuracy,feed_dict={x:image,y_true:label})

                print("第%d个样本的真实值为:%d,预测结果为:%d" % (
                                                        i+1,
                                                        tf.arg_max(sess.run(y_true,feed_dict={x:image,y_true:label}),1).eval(),
                                                        tf.arg_max(sess.run(y_predict,feed_dict={x:image,y_true:label}),1).eval()
                                                        )
                                                        )

                sum = sum + accuracy_value

            print("准确率为 %f" % (sess.run(sum/100)))
        return None

if __name__ == "__main__" :
    full_connection_completed()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值