CNN

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("C:/PythonWork/Datasets/MNIST",one_hot=True)
batch_size = 100
n_batch = mnist.train.num_examples // batch_size 
x = tf.placeholder(tf.float32,[None,784])
#上面这个x是feed进来的,每张图的数据都被拉成了一个行向量
#是没有空间特征的,这里是将其还原为图片原来的28*28的大小,然后再去做卷积
#这个x_image第二个参数数组的每位的含意是在后面的conv2d函数中定义了的(这个x_image是要传给conv2d函数做卷积,
#所以reshape的格式要符合conv2d给出的要求)
#第一位为图片的张数,-1代表任意张数(具体多少张,要看前面feed给x的数据是多少行的),中间两位为图片的长和宽,最后一位为通道数
x_image = tf.reshape(x,[-1,28,28,1])
#第一层卷积层
#定义并初始化这层的卷积核,同样,卷积核大小的定义格式也是在con2d中规定了的,因为这个w_conv1也是要传给这个函数的,
#前三个值分别为卷积核的长、宽和通道数,第四个数为卷积核的个数,有32个卷积核(即卷积后得到通道数为32(厚度为32)的数据)
w_conv1 = tf.Variable(tf.truncated_normal([5,5,1,32],stddev=0.1))
#定义卷积核的偏置值,每个卷积核对应一个偏置,每个卷积核扫描整张图时,生成的每个点都会加上这个偏置
b_conv1 = tf.Variable(tf.zeros([32])+0.1)
#进行卷积操作,conv2d函数会根据你给的输入x_image和卷积核w_conv1对图片进行卷积,卷积的步长在strides参数数组中定义,
#第1、4个值固定为1,中间两个值分别时横向移动的步长和纵向移动的步长,padding可以是SAME和VALID,SAME即它会自动帮你填充0,
#使得卷积后的大小不变,VALID则不进行填充
#x_image是许多张28*28的图片,并不是一张,且传进来的w_conv1也是32个卷积核,而不是一个,所以这个函数会同时对多张图片
#用多个卷积核进行卷积,然后分别和相应的偏置相加
o_conv1 = tf.add(tf.nn.conv2d(x_image,w_conv1,strides=[1,1,1,1],padding='SAME'),b_conv1)
#relu激活
activate_conv1 = tf.nn.relu(o_conv1)
#第一个池化层
#ksize参数是定义池化的窗口大小,池化也很类似卷积,也是有个东西在数据上移动,但不同的是,池化移动的只是个窗口,对窗口内的数据进行取样
#比如这里是最大池化,每次取窗口框住的数据中最大的那个数据,窗口时没有厚度的,而卷积核虽然也是在数据上移动,
#但是卷积核是和数据做点积操作,且卷积核的厚度是和数据一样的(这样才能一一对应做点积)
#ksize参数数组中,第1、4个值固定为1,中间两个值分别为窗口的长宽
#strides参数格式和上面讲strides格式一样。padding可以是SAME和VALID,但其意义不同于conv2d函数中的SAME和VALID
#假如窗口一次向右移动2格,此时数据右边只剩下一格了,只能移动一格,不然窗口就出去了
#若是VALID,因为没办法移动两格,所以干脆就不移动了,即后面多出来的一格就不采了,而SAME则会在旁边补零后,然后移动两格再采样
#注!!!池化的输入和输出深度都是一样的,池化是对每个通道分别去取最大值或平均值,不同于卷积,一个卷积核输出深度就一定为1,把通道融合了。
o_poo11 = tf.nn.max_pool(activate_conv1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#第二层卷积层
#上面经过了一个卷积层和一个池化层,因为卷积时padding是SAME,卷积核个数为32,所以卷积后多个28*28*1的图片变成了多个28*28*32的数据
#池化后的数据,长为(N-F)/S+1=(28-2)/2+1=14,因为数据的长宽一样,窗口的长宽一样,然后横向和纵向移动的步长也一样,所以宽也是14,
#所以经过上面的卷积和池化后,现在得到的是多个14*14*32的数据传进这层
#这层的卷积核依旧是5*5,厚度要和传进来的数据一样,所以是32,并且这层用64个卷积核
w_conv2 = tf.Variable(tf.truncated_normal([5,5,32,64],stddev=0.1))
b_conv2 = tf.Variable(tf.zeros([64])+0.1)
o_conv2 = tf.add(tf.nn.conv2d(o_poo11,w_conv2,strides=[1,1,1,1],padding='SAME'),b_conv2)
activate_conv2 = tf.nn.relu(o_conv2)
o_poo12 = tf.nn.max_pool(activate_conv2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#第一层全连接层
#同理,多个14*14*32的数据经过上面的卷积层后,变为了多个14*14*64的数据。池化后变为多个7*7*64的数据传进这层。
#首先进行全连接前,要将前面拥有空间特征的数据又拉回一个行向量,所以将其reshape为行数为任意行,列数为7*7*64的行向量
#相当于又还原回了之前每行代表一张图的数据
o_pool2_flat = tf.reshape(o_poo12,[-1,7*7*64])
#将其分为1024类
w_fc1 = tf.Variable(tf.truncated_normal([7*7*64,1024],stddev=0.1))
b_fc1 = tf.Variable(tf.zeros([1024])+0.1)
o_fc1 = tf.add(tf.matmul(o_pool2_flat,w_fc1),b_fc1)
activate_fc1 = tf.nn.relu(o_fc1)
drop_out_rate = tf.placeholder(tf.float32)
tf.nn.dropout(activate_fc1,drop_out_rate)
#第二层全连接层
#将前面的1024类归为10类
w_fc2 = tf.Variable(tf.truncated_normal([1024,10],stddev=0.1))
b_fc2 = tf.Variable(tf.zeros([10])+0.1)
logits = tf.add(tf.matmul(activate_fc1,w_fc2),b_fc2)
#将最后的得分用softmax转为概率
prediction = tf.nn.softmax(logits)
#这是正确的分类标签(one-hot形式)
labels = tf.placeholder(tf.float32,[None,10])
#注!!!softmax_cross_entropy_with_logits函数是包含了计算softmax过程的,所以直接将logits交给他就行了,
#不用自己计算softmax
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits))
optimizer = tf.train.AdamOptimizer(1e-4)
train = optimizer.minimize(loss)
accuracy_rate = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(prediction,1),tf.argmax(labels,1)),tf.float32))
with tf.Session() as session:
    session.run(tf.global_variables_initializer())
    for i in range(21):
        for j in range(n_batch):
            batch_x,batch_labels = mnist.train.next_batch(batch_size)
            session.run(train,feed_dict={x:batch_x,labels:batch_labels,drop_out_rate:0.7})
        test_acc,l = session.run([accuracy_rate,loss],feed_dict={x:mnist.test.images,labels:mnist.test.labels,drop_out_rate:1.0})
        print("Train " + str(i) + " Times: Testing Accuracy Rate = " + str(test_acc) + ' loss:' + str(l))
######################################################################################################################################
#上面是是用tensorflow的低级API构建CNN网络,这里用tensorflow的高级API(Estimator、Dataset、tf.layers)构建CNN网络
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
#首先需要写输入函数,具体请看pre-proccess
#这里是训练时的输入函数,负责提供训练时的数据输入
def train_input_fn(batch_size,mnist):
    images = mnist.train.images
    images = tf.reshape(images,[-1,28,28,1])
    labels = mnist.train.labels
    #这里用Dataset的from_tensor_slices方法将images和labels这个数字矩阵封装为Dataset
    images_ds = tf.data.Dataset.from_tensor_slices(images)
    labels_ds = tf.data.Dataset.from_tensor_slices(labels)
    images_ds = images_ds.repeat()
    labels_ds = labels_ds.repeat()  
    images_ds = images_ds.batch(batch_size)
    labels_ds = labels_ds.batch(batch_size)
    images_it = images_ds.make_one_shot_iterator()
    labels_it = labels_ds.make_one_shot_iterator()
    images = images_it.get_next()
    labels = labels_it.get_next()
    return {'images':images},labels

#验证时的输入函数
def test_input_fn(batch_size,mnist):
    images = mnist.test.images
    images = tf.reshape(images,[-1,28,28,1])
    labels = mnist.test.labels
    
    images_ds = tf.data.Dataset.from_tensor_slices(images)
    labels_ds = tf.data.Dataset.from_tensor_slices(labels)
    images_ds = images_ds.repeat()  
    labels_ds = labels_ds.repeat()  
    images_ds = images_ds.batch(batch_size)
    labels_ds = labels_ds.batch(batch_size)
    images_it = images_ds.make_one_shot_iterator()
    labels_it = labels_ds.make_one_shot_iterator()
    images = images_it.get_next()
    labels = labels_it.get_next()
    return {'images':images},labels

#预测时的输入函数只给了一个样本
def predict_input_fn(batch_size,mnist):
    images = mnist.test.images[0]
    images = tf.reshape(images,[-1,28,28,1])
    labels = mnist.test.labels[0]
     
    images_ds = tf.data.Dataset.from_tensor_slices(images)
    labels_ds = tf.data.Dataset.from_tensor_slices(labels)
    images_ds = images_ds.batch(batch_size)
    labels_ds = labels_ds.batch(batch_size)
    images_it = images_ds.make_one_shot_iterator()
    labels_it = labels_ds.make_one_shot_iterator()
    images = images_it.get_next()
    labels = labels_it.get_next()
    return {'images':images},labels
#model_fn的作用:1、搭建网络结构;2、训练、验证、预测的op,
#model_fn函数接收的参数是规定的,因为这个函数是要传给estimator去调用的,所以要符合它的规定
#features和labels是input_fn的输出,mode是根据你调用estimator.train还是estimator.evaluate还是estimator.predict,由tensorflow传进来的
#分别是tf.estimator.ModeKeys.TRAIN/EVAL/PREDICT
#params是在构建Estimator时,传给Estimator的params参数,tensorflow会将其转交到这儿来
def model_fn(features,labels,mode,params):
    #用tf.layers构建网络结构
    def create_model(features,is_training):
    #将input_fn返回的'images'特征列作为输入层
        net = features['images']
        #进行卷积+激活,不用再自己去写w和b还要初始化什么的了,全部在这一个函数中搞定,可以类比下前面低级API实现的 #第一层卷积层 部分
        net = tf.layers.conv2d(inputs=net,filters=32,kernel_size=[5,5],strides=(1, 1),padding='same',activation=tf.nn.relu,
                              kernel_initializer=tf.truncated_normal_initializer(stddev=0.1),
                               bias_initializer=tf.constant_initializer(value=0.1),
                               trainable=is_training)
        #第一个池化层
        net = tf.layers.max_pooling2d(inputs=net, pool_size=[2,2],strides=[2,2],padding='same')
        #第二层卷积层
        net = tf.layers.conv2d(inputs=net,filters=64,kernel_size=[5,5],strides=(1, 1),padding='same',activation=tf.nn.relu,
                              kernel_initializer=tf.truncated_normal_initializer(stddev=0.1),
                               bias_initializer=tf.constant_initializer(value=0.1),
                               trainable=is_training)
        #第二个池化层
        net = tf.layers.max_pooling2d(inputs=net, pool_size=[2,2],strides=[2,2],padding='same')
        #第一层全连接层
        net = tf.layers.flatten(inputs=net)
        net = tf.layers.dense(inputs=net,units=1024,activation=tf.nn.relu,
                              kernel_initializer=tf.truncated_normal_initializer(stddev=0.1),
                               bias_initializer=tf.constant_initializer(value=0.1),
                               trainable=is_training)
        net = tf.layers.dropout(inputs=net,rate=0.7,training=is_training)
        #第二层全连接层
        logits = tf.layers.dense(inputs=net,units=10,
                              kernel_initializer=tf.truncated_normal_initializer(stddev=0.1),
                               bias_initializer=tf.constant_initializer(value=0.1),
                               trainable=is_training)

        #返回最后得出得分值logit的那个tensor,返回的是tensor,是网络结构的最后一层
        return logits

    #调用create_model函数搭建网络结构,接收返回的网络最后一层tensor
    logits = create_model(features,mode==tf.estimator.ModeKeys.TRAIN)
    
    #这里写3个if分别用来处理在训练、评估、预测时要做的操作
    #上面create_model只是搭建了网络,而要进行训练还需要进行反向传播学习的操作,
    #像前面低级API实现中,要有loss函数、optimizer和train_op这些,用来训练
    #还要有accuracy_rate函数用来计算精确度,用于评估,
    #所以这些if里面就是用来定义这些的
    #每个if都要返回一个EstimatorSpec类交由tensorflow来维护,你只要把相应的loss、optimizer、train_op、accuracy_rate定义好传过去就行
    #!!!所以在整个model_fn中,其实都是在定义空壳,创建计算图,仅当返回了EstimatorSpec后,是tensorflow根据你的EstimatorSpec
    #去启动seesion去run!!!
    
    #mode为train时返回的EstimatorSpec中一定要有loss和train_op参数(废话,不然人家怎么给你训练)
    #在train的过程中tensorflow会自动记录loss曲线进tensorboard
    #这里的tf.identity是用来将某个tensor拉出来,给它一个身份标识,
    #可以用在当你想要在训练过程中看到某个tensor的输出时,你可以把这个tensor拉出来毙了,呸,是拉出来给个identity
    #然后在训练时传hook参数,用来跟踪这个tensor的输出,具体后面讲
    if mode == tf.estimator.ModeKeys.TRAIN:
        loss = tf.losses.softmax_cross_entropy(onehot_labels=labels,logits=logits)
        tf.identity(loss,name='loss')
        optimizer = tf.train.AdamOptimizer(1e-4)
        train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)
    #mode为eval时EstimatorSpec一定要有loss参数,除此之外还可以传eval_metric_ops参数,将你要作为评估的其他参照标准放进去,
    #比如这里还有个accuracy,用来计算精确度,可以传过去,然后tensorboard会自动记录loss的曲线,但是因为一般验证时都是
    #一批数据只是从头到尾走一遍网络,所以生成的loss只是一个点,除非你也可以每训练多少次就运行一次验证函数,这样就会有整个loss曲线
    #而accuracy是你自己加的评估参数,所以要自己写summary.scalar去记录它的曲线
    if mode == tf.estimator.ModeKeys.EVAL:
        loss = tf.losses.softmax_cross_entropy(onehot_labels=labels,logits=logits)
        accuracy = tf.metrics.accuracy(labels=tf.argmax(labels,1),predictions=tf.argmax(logits,1),name='acc_op')
        metrics = {'accuracy':accuracy}
        tf.summary.scalar('accuracy', accuracy)
        return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics)
    #mode为predict时EstimatorSpec一定要有prediction参数,predictions是一个字典,里面存着你在训练好这个网络后,用这个网络去预测
    #未知的东西时,你要输出的参数,比如这里就是说,给你一个或多个手写数字,你要告诉我这是数字几(class_ids),告诉我这个手写数字
    #是各个数字的可能性各为多大(probabilities),告诉我这个手写数字是各个数字的得分是多少(logits)
    if mode == tf.estimator.ModeKeys.PREDICT:
        predictions = {  
            'logits': logits,
            'probabilities': tf.nn.softmax(logits),
            'class_ids': tf.argmax(logits,1)
        }
        return tf.estimator.EstimatorSpec(mode, predictions=predictions)
#这里其实并没有去调用model_fn和构建网络,这里只是将这些需要的东西都存起来了,构建了个estimator实例,
#在调用estimator的train、evaluate、predict方法时才真正去执行model_fn
#所有一切的输出,比如ckpt文件、tensorboard文件等都输出在model_dir路径下
#这里配置每训练1000步保存一次ckpt,只保存一份ckpt,具体见Note
#这里的params参数相当于传给model_fn的params参数
classifier = tf.estimator.Estimator(
        model_fn=model_fn,
        model_dir='C:/Users/VCC/work/CNN_output',
        config=tf.estimator.RunConfig(save_checkpoints_steps=1000,keep_checkpoint_max = 1),
        params={}
        )
mnist = input_data.read_data_sets("C:/PythonWork/Datasets/MNIST",one_hot=True)
#显示INFO级别的log
tf.logging.set_verbosity(tf.logging.INFO)
#这里配置hook用于跟踪某个tensor的输出,每300步log输出一次tensors_to_log这个字典中所有的tensor,
#tensors_to_log字典的键为输出的名字,值为tensor的名字,也就是我在上面拉出来identity的那个loss
tensors_to_log = {"loss":'loss'}
logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=300)
#开始训练,调用该函数后,tensorflow首先会调用model_fn函数去构建网络,然后查看model_dir目录下是否有ckpt,
#有的话会选择最新的那个ckpt,将ckpt中存的参数复原回模型的各Variable中继续训练,
#如果没有ckpt则初始化各个Variable从头训练
#每次传进去100个样本,正反向传播学习一次,为一个step,然后又取下一组batch传进网络,这样来回11000次
#因为在训练时要跟踪某个tensor的输出,所以将前面的logging_hook传进去
#传进去的input_fn,tensorflow会自动将input_fn的输出传给model_fn作为model_fn函数的features和labels参数
classifier.train(input_fn=lambda:train_input_fn(100,mnist),steps=11000,hooks=[logging_hook])
#在evaluate时,tensorflow首先也会调用model_fn构建网络,然后读取model_dir下最新的ckpt进来,将训练好的权重值复原
#若model_dir下没有相应的ckpt,则报错
#evaluate时input相应的验证数据,跑一遍网络,得出accuracy和loss等相关评估(就是你在model_fn中if eval下设定的那些评估)
evaluation = classifier.evaluate(input_fn=lambda:test_input_fn(10000,mnist),steps=1)
print(evaluation)
#这里predict返回一个字典,里面存的就是你在model_fn中if predict下设定的predictions字典中配置的那些
predictions = classifier.predict(input_fn=lambda:predict_input_fn(1,mnist))
for p in predictions:
    print(p)
    print(p['class_ids'])
    print(p['probabilities'][p['class_ids']])
    print(p['logits'][p['class_ids']])
a = [0:3]
print(a)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值