目录python
参考书git
《TensorFlow:实战Google深度学习框架》(第2版)github
划重点编程
==从今天开始(20190505-1521),个人博客都用Markdown语法来编写啦,也不知道之后的本身会不会被人所知,会不会有大佬来看过去的我,给我挖坟呢。想一想就有点期待呢!但愿本身还能更加努力!更加优秀吧!==api
目前比较主流的TensorFlow高层封装有4个,分别是TensorFlow-Slim、TFLearn、Keras和Estimator。数组
首先,这里介绍先用TensorFlow-Slim在MNIST数据集上实现LeNet-5模型。浏览器
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: slim_learn.py @time: 2019/4/22 10:53 @desc: 使用TensorFlow-Slim在MNIST数据集上实现LeNet-5模型。 """ import tensorflow as tf import tensorflow.contrib.slim as slim import numpy as np from tensorflow.examples.tutorials.mnist import input_data # 经过TensorFlow-Slim来定义LeNet-5的网络结构 def lenet5(inputs): # 将输入数据转化为一个4维数组。其中第一维表示batch大小,另三维表示一张图片。 inputs = tf.reshape(inputs, [-1, 28, 28, 1]) # 定义第一层卷积层。从下面的代码能够看到经过TensorFlow-Slim定义的网络结构 # 并不须要用户去关心如何声明和初始化变量,而只须要定义网络结构便可。下一行代码中 # 定义了一个卷积层,该卷积层的深度为32,过滤器的大小为5x5,使用全0补充。 net = slim.conv2d(inputs, 32, [5, 5], padding='SAME', scope='layer1-conv') # 定义一个最大池化层,其过滤器大小为2x2,步长为2. net = slim.max_pool2d(net, 2, stride=2, scope='layer2-max-pool') # 相似的定义其余网络层结构 net = slim.conv2d(net, 64, [5, 5], padding='SAME', scope='layer3-conv') net = slim.max_pool2d(net, 2, stride=2, scope='layer4-max-pool') # 直接使用TensorFlow-Slim封装好的flatten函数将4维矩阵转为2维,这样能够 # 方便后面的全链接层的计算。经过封装好的函数,用户再也不须要本身计算经过卷积层以后矩阵的大小。 net = slim.flatten(net, scope='flatten') # 经过TensorFlow-Slim定义全链接层,该全链接层有500个隐藏节点。 net = slim.fully_connected(net, 500, scope="layer5") net = slim.fully_connected(net, 10, scope="output") return net # 经过TensorFlow-Slim定义网络结构,并使用以前章节中给出的方式训练定义好的模型。 def train(mnist): # 定义输入 x = tf.placeholder(tf.float32, [None, 784], name='x-input') y_ = tf.placeholder(tf.float32, [None, 10], name='y-input') # 使用TensorFLow-Slim定义网络结构 y = lenet5(x) # 定义损失函数和训练方法 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1)) # 1 means axis=1 loss = tf.reduce_mean(cross_entropy) train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss) # 训练过程 with tf.Session() as sess: tf.global_variables_initializer().run() for i in range(10000): xs, ys = mnist.train.next_batch(100) _, loss_value = sess.run([train_op, loss], feed_dict={x: xs, y_: ys}) if i % 1000 == 0: print("After %d training step(s), loss on training batch is %g." % (i, loss_value)) def main(argv=None): mnist = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) train(mnist) if __name__ == '__main__': main()
OK!运行吧皮卡丘!网络
第一个例子都报错。。。(ValueError: Rank mismatch: Rank of labels (received 1) should equal rank of logits minus 1 (received 4).)框架
我哭了!找了我半天错误,才发现少写了一句。分布式
net = slim.flatten(net, scope='flatten')
可把我愁坏了,整了半天才弄好。。。
网上都是什么神仙回答,解释的有板有眼的,都说这本书是垃圾,害得我差点马上在我对这本书评价的博客上再加上几句芬芳。
好歹是学到了知识了。对logits和labels加深了印象了。
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
logits:是计算获得的结果
labels:是原来的数据标签。
千万不要记混了!
labels=tf.argmax(y_, 1)
labels输入的是[0, 0, 0, 1, 0, 0, 0, 0, 0, 0](以MNIST为例),
而在tf.nn.sparse_softmax_cross_entropy_with_logits函数中
labels的输入格式须要是[3],也就是说,是类别的编号。
诶!问题来了!
logits=y
logits的格式与labels同样吗?
不同!
logits的格式与labels转换前的同样,也就是
[0.2, 0.3, 0.1, 0.9, 0.1, 0.1, 0.2, 0.2, 0.4, 0.6]
若是不转换labels的话,能够用tf.nn.softmax_cross_entropy_with_logits达到一样的效果。
诶?那为何非要转换一下labels呢?
我也没看懂,非要骚一下吧。。。
好了正确的运行结果出来了:
若是咱们把刚才说的那句代码改成:
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=y, labels=y_)
试试看?
哇哦~正常运行了有没有!!!
因此呢?因此为何这里要非要用有sparse的这个函数呢?
反正我是没看懂(摊手┓( ´∀` )┏)。。。
与TensorFlow-Slim相比,TFLearn是一个更加简洁的高层封装。
由于TFLearn并无集成在TensorFlow中,因此首先是用pip安装。
安装完后,下面是用TFLearn在MNIST数据集上实现LeNet-5模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: tflearn_learn.py @time: 2019/5/5 16:53 @desc: 使用TFLearn在MNIST数据集上实现LeNet-5模型。 """ import tflearn from tflearn.layers.core import input_data, fully_connected from tflearn.layers.conv import conv_2d, max_pool_2d from tflearn.layers.estimator import regression import tflearn.datasets.mnist as mnist # 读取mnist数据 trainX, trainY, testX, testY = mnist.load_data(data_dir="D:/Python3Space/BookStudy/book2/MNIST_data", one_hot=True) # 将图像数据reshape成卷积神经网络输入的格式 trainX = trainX.reshape([-1, 28, 28, 1]) testX = testX.reshape([-1, 28, 28, 1]) # 构建神经网络,这个过程和TensorFlow-Slim比较相似。input_data定义了一个placeholder来接入输入数据。 net = input_data(shape=[None, 28, 28, 1], name='input') # 经过TFLearn封装好的API定义一个深度为5,过滤器为5x5,激活函数为ReLU的卷积层 net = conv_2d(net, 32, 5, activation='relu') # 定义一个过滤器为2x2的最大池化层 net = max_pool_2d(net, 2) # 相似地定义其余的网络结构。 net = conv_2d(net, 64, 5, activation='relu') net = max_pool_2d(net, 2) net = fully_connected(net, 500, activation='relu') net = fully_connected(net, 10, activation='softmax') # 使用TFLearn封装好的函数定义学习任务。指定优化器为sgd,学习率为0.01,损失函数为交叉熵。 net = regression(net, optimizer='sgd', learning_rate=0.01, loss='categorical_crossentropy') # 经过定义的网络结构训练模型,并在指定的验证数据上验证模型的效果。 # TFLearn将模型的训练过程封装到了一个类中,这样能够减小很是多的冗余代码。 model = tflearn.DNN(net, tensorboard_verbose=0) model.fit(trainX, trainY, n_epoch=20, validation_set=([testX, testY]), show_metric=True)
我的感相较于Slim,TFLearn好用太多了吧。。。特别是model.fit真的是给我眼前一亮的感受,这也太帅了吧,瞧这交叉熵小黄字,瞧这epoch,瞧这step。。。封装万岁!!!(对我这种菜鸡而言,不要跟我谈底层,我!不!够!格!)
运行结果:
下面是用原生态的Keras在MNIST数据集上实现LeNet-5模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_learn.py @time: 2019/5/5 17:42 @desc: 使用Keras在MNIST数据集上实现LeNet-5模型。 """ import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D from keras import backend as K num_calsses = 10 img_rows, img_cols = 28, 28 # 经过Keras封装好的API加载MNIST数据。其中trainX就是一个60000x28x28的数组, # trainY是每一张图片对应的数字。 (trainX, trainY), (testX, testY) = mnist.load_data() # 由于不一样的底层(TensorFlow或者MXNet)对输入的要求不同,因此这里须要根据对图像 # 编码的格式要求来设置输入层的格式。 if K.image_data_format() == 'channels_first': trainX = trainX.reshape(trainX.shape[0], 1, img_rows, img_cols) testX = testX.reshape(trainX.shape[0], 1, img_rows, img_cols) # 由于MNIST中的图片是黑白的,因此第一维的取值为1 input_shape = (1, img_rows, img_cols) else: trainX = trainX.reshape(trainX.shape[0], img_rows, img_cols, 1) testX = testX.reshape(testX.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # 将图像像素转化为0到1之间的实数。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 将标准答案转化为须要的格式(One-hot编码)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 使用Keras API定义模型 model = Sequential() # 一层深度为32,过滤器大小为5x5的卷积层 model.add(Conv2D(32, kernel_size=(5, 5), activation='relu', input_shape=input_shape)) # 一层过滤器大小为2x2的最大池化层。 model.add(MaxPooling2D(pool_size=(2, 2))) # 一层深度为64, 过滤器大小为5x5的卷积层。 model.add(Conv2D(64, (5, 5), activation='relu')) # 一层过滤器大小为2x2的最大池化层。 model.add(MaxPooling2D(pool_size=(2, 2))) # 将卷积层的输出拉直后做为下面全链接的输入。 model.add(Flatten()) # 全链接层,有500个节点。 model.add(Dense(500, activation='relu')) # 全链接层,获得最后的输出。 model.add(Dense(num_calsses, activation='softmax')) # 定义损失函数、优化函数和测评的方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 相似TFLearn中的训练过程,给出训练数据,batch大小、训练轮数和验证数据,Keras能够自动完成模型的训练过程。 model.fit(trainX, trainY, batch_size=128, epochs=20, validation_data=(testX, testY)) # 在测评数据上计算准确率 score = model.evaluate(testX, testY) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
运行以后(跑了我一晚上呀我滴妈。。。):
下面是用原生态的Keras实现循环神经网络。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_rnn.py @time: 2019/5/6 12:30 @desc: 用原生态的Keras实现循环神经网络 """ from keras.preprocessing import sequence from keras.models import Sequential from keras.layers import Dense, Embedding, LSTM from keras.datasets import imdb # 最多使用的单词数 max_features = 20000 # 循环神经网络的截断长度。 maxlen = 80 batch_size = 32 # 加载数据并将单词转化为ID,max_features给出了最多使用的单词数。和天然语言模型相似, # 会将出现频率较低的单词替换为统一的的ID。经过Keras封装的API会生成25000条训练数据和 # 25000条测试数据,每一条数据能够被当作一段话,而且每段话都有一个好评或者差评的标签。 (trainX, trianY), (testX, testY) = imdb.load_data(num_words=max_features) print(len(trainX), 'train sequences') print(len(testX), 'test sequences') # 在天然语言中,每一段话的长度是不同的,但循环神经网络的循环长度是固定的,因此这里须要先将 # 全部段落统一成固定长度。对于长度不够的段落,要使用默认值0来填充,对于超过长度的段落 # 则直接忽略掉超过的部分。 trainX = sequence.pad_sequences(trainX, maxlen=maxlen) testX = sequence.pad_sequences(testX, maxlen=maxlen) print('trainX shape', trainX.shape) print('testX shape: ', testX.shape) # 在完成数据预处理以后构建模型 model = Sequential() # 构建embedding层。128表明了embedding层的向量维度。 model.add(Embedding(max_features, 128)) # 构建LSTM层 model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2)) # 构建最后的全链接层。注意在上面构建LSTM层时只会获得最后一个节点的输出, # 若是须要输出每一个时间点的结果,呢么能够将return_sequence参数设为True。 model.add(Dense(1, activation='sigmoid')) # 与MNIST样例相似的指定损失函数、优化函数和测评指标。 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # 在测试数据上评测模型。 score = model.evaluate(testX, testY, batch_size=batch_size) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
睡了个午觉就跑完啦:
面对上面的例子,都是顺序搭建的神经网络模型,相似于Inception这样的模型结构,就须要更加灵活的模型定义方法了。
在这里我真的是忍不住要吐槽一下书上的内容,简直彻底没有讲清楚在说什么鬼。。。没说清楚到底是用的那一部分的数据,是MNIST仍是rnn的数据。。。捣鼓了半天才知道是MNIST。而后这里的意思应该是用全链接的方式,即输入数据为(60000, -1),也就是说样本是60000个,而后把图片的维度拉伸为1维。(这里我也是摸索了很久才知道的),因此在代码中须要对数据进行reshape处理。否则会报错:
ValueError: Error when checking input: expected input_1 to have 2 dimensions, but got array with shape (60000, 28, 28)
参考连接:https://blog.csdn.net/u012193416/article/details/79399679
是真的坑爹,只能说。。。什么也没有说清楚,就特么瞎指挥。。。(然鹅,我是真的菜。。。摊手。。。)
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception.py @time: 2019/5/6 14:29 @desc: 用更加灵活的模型定义方法在MNIST数据集上实现全链接层模型。 """ import keras from keras.layers import Input, Dense from keras.models import Model from keras.datasets import mnist # 使用前面介绍的相似方法生成trainX、trainY、testX、testY,惟一的不一样是这里只用了 # 全链接层,因此不须要将输入整理成三维矩阵。 num_calsses = 10 img_rows, img_cols = 28, 28 # 经过Keras封装好的API加载MNIST数据。其中trainX就是一个60000x28x28的数组, # trainY是每一张图片对应的数字。 (trainX, trainY), (testX, testY) = mnist.load_data() trainX = trainX.reshape(len(trainX), -1) testX = testX.reshape(len(testX), -1) # 将图像像素转化为0到1之间的实数。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 将标准答案转化为须要的格式(One-hot编码)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定义输入,这里指定的维度不用考虑batch大小。 inputs = Input(shape=(784, )) # 定义一层全链接层,该层有500隐藏节点,使用ReLU激活函数。这一层的输入为inputs x = Dense(500, activation='relu')(inputs) # 定义输出层。注意由于keras封装的categorical_crossentropy并无将神经网络的输出 # 再通过一层softmax,因此这里须要指定softmax做为激活函数。 predictions = Dense(10, activation='softmax')(x) # 经过Model类建立模型,和Sequential类不一样的是Model类在初始化的时候须要指定模型的输入和输出 model = Model(inputs=inputs, outputs=predictions) # 使用与前面相似的方法定义损失函数、优化函数和评测方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 使用与前面相似的方法训练模型。 model.fit(trainX, trainY, batch_size=128, epochs=10, validation_data=(testX, testY))
修改以后运行能够获得:
经过这样的方式,Keras就能够实现相似Inception这样的模型结构了。
如今又要说坑爹的部分了,这本书在这里直接照抄的Keras的手册中的例子,来解释用Keras实现Inception-v3的模型结构,因此给出的代码是这样的
from keras.layers import Conv2D, MaxPooling2D, Input # 定义输入图像尺寸 input_img = Input(shape=(256, 256, 3)) # 定义第一个分支。 tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1) # 定义第二个分支。与顺序模型不一样,第二个分支的输入使用的是input_img,而不是第一个分支的输出。 tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2) # 定义第三个分支。相似地,第三个分支的输入也是input_img。 tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img) tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3) # 将三个分支经过concatenate的方式拼凑在一块儿。 output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)
你可能要问“这就完啦?”,我想告诉你的是,对的。关于Inception-v3的部分就这么点。而后我给你看一眼网上官方的代码:
参考连接:https://keras.io/zh/getting-started/functional-api-guide/
是否是有种似曾相识的感受。。。
踏马的根本就没有想着去实现好吗?
我也是醉了的,我就问一句,不是一直在用MNIST数据集做为例子吗!那这个
input_img = Input(shape=(256, 256, 3))
图像尺寸怎么忽然就编程(256, 256, 3)了呢?而不是(28, 28, 1)呢?
==这本书一点都不走心好吗!==
我也是佛了,那么我只能靠本身理解,并本身写例子了。这里面的艰辛我就不说了,不卖惨了,是真的恨,我只但愿每个例子都可以善始善终,都可以有输出有结果,能运行!
下面贴一下我本身想的改的代码吧:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception2.py @time: 2019/5/6 15:43 @desc: 用原生态的Keras实现Inception """ from keras.layers import Conv2D, MaxPooling2D, Input, Dense, Flatten import keras from keras.models import Model from keras.datasets import mnist from keras import backend as K # 使用前面介绍的相似方法生成trainX、trainY、testX、testY,惟一的不一样是这里只用了 # 全链接层,因此不须要将输入整理成三维矩阵。 num_calsses = 10 img_rows, img_cols = 28, 28 # 经过Keras封装好的API加载MNIST数据。其中trainX就是一个60000x28x28的数组, # trainY是每一张图片对应的数字。 (trainX, trainY), (testX, testY) = mnist.load_data() if K.image_data_format() == 'channels_first': trainX = trainX.reshape(trainX.shape[0], 1, img_rows, img_cols) testX = testX.reshape(trainX.shape[0], 1, img_rows, img_cols) # 由于MNIST中的图片是黑白的,因此第一维的取值为1 input_shape = (1, img_rows, img_cols) else: trainX = trainX.reshape(trainX.shape[0], img_rows, img_cols, 1) testX = testX.reshape(testX.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # 将图像像素转化为0到1之间的实数。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 将标准答案转化为须要的格式(One-hot编码)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定义输入图像尺寸 input_img = Input(shape=(28, 28, 1)) # 定义第一个分支。 tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1) # 定义第二个分支。与顺序模型不一样,第二个分支的输入使用的是input_img,而不是第一个分支的输出。 tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img) tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2) # 定义第三个分支。相似地,第三个分支的输入也是input_img。 tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img) tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3) # 将三个分支经过concatenate的方式拼凑在一块儿。 output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1) # 将卷积层的输出拉直后做为下面全链接的输入。 tower_4 = Flatten()(output) # 全链接层,有500个节点。 tower_5 = Dense(500, activation='relu')(tower_4) # 全链接层,获得最后的输出。 predictions = Dense(num_calsses, activation='softmax')(tower_5) # 经过Model类建立模型,和Sequential类不一样的是Model类在初始化的时候须要指定模型的输入和输出 model = Model(inputs=input_img, outputs=predictions) # 使用与前面相似的方法定义损失函数、优化函数和评测方法。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), metrics=['accuracy']) # 使用与前面相似的方法训练模型。 model.fit(trainX, trainY, batch_size=128, epochs=20, validation_data=(testX, testY)) # 在测试数据上评测模型。 score = model.evaluate(testX, testY, batch_size=128) print('Test loss: ', score[0]) print('Test accuracy: ', score[1])
运行结果:
说明,我改了以后是能跑的。。。
对了,若是有杠精问我,人家只是抛砖引玉,让读者触类旁通。。。那我没什么好说的。。。
又花了一夜跑完。。。
用原生态的Keras实现非顺序模型,多输入和多输出模型。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_inception3.py @time: 2019/5/7 14:54 @desc: 用原生态的Keras实现非顺序模型,多输入和多输出模型 """ import keras from tflearn.layers.core import fully_connected from keras.datasets import mnist from keras.layers import Input, Dense from keras.models import Model from keras import backend as K # 相似前面的方式生成trainX、trainY、testX、testY num_calsses = 10 img_rows, img_cols = 28, 28 # 经过Keras封装好的API加载MNIST数据。其中trainX就是一个60000x28x28的数组, # trainY是每一张图片对应的数字。 (trainX, trainY), (testX, testY) = mnist.load_data() trainX = trainX.reshape(len(trainX), -1) testX = testX.reshape(len(testX), -1) # 将图像像素转化为0到1之间的实数。 trainX = trainX.astype('float32') testX = testX.astype('float32') trainX /= 255.0 testX /= 255.0 # 将标准答案转化为须要的格式(One-hot编码)。 trainY = keras.utils.to_categorical(trainY, num_calsses) testY = keras.utils.to_categorical(testY, num_calsses) # 定义两个输入,一个输入为原始的图片信息,另外一个输入为正确答案。 input1 = Input(shape=(784, ), name='input1') input2 = Input(shape=(10, ), name='input2') # 定义一个只有一个隐藏节点的全链接网络。 x = Dense(1, activation='relu')(input1) # 定义只使用了一个隐藏节点的网络结构的输出层。 output1 = Dense(10, activation='softmax', name='output1')(x) # 将一个隐藏节点的输出和正确答案拼接在一块儿,这个将做为第二个输出层的输入。 y = keras.layers.concatenate([x, input2]) # 定义第二个输出层。 output2 = Dense(10, activation='softmax', name='output2')(y) # 定义一个有多个输入和多个输出的模型,这里只须要将全部的输入和输出给出便可。 model = Model(inputs=[input1, input2], outputs=[output1, output2]) # 定义损失函数、优化函数和评测方法。若多个输出的损失函数相同,能够只指定一个损失函数。 # 若是多个输出的损失函数不一样,则能够经过一个列表或一个字典来指定每个输出的损失函数。 # 好比可使用:loss = {'output1': 'binary_crossentropy', 'output2': 'binary_crossentropy'} # 来为不一样的输出指定不一样的损失函数。相似的,Keras也支持为不一样输出产生的损失指定权重, # 这能够经过经过loss_weights参数来完成。在下面的定义中,输出output1的权重为1,output2 # 的权重为0.1。因此这个模型会更加偏向于优化第一个输出。 model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(), loss_weights=[1, 0.1], metrics=['accuracy']) # 模型训练过程。由于有两个输入和输出,因此这里提供的数据也须要有两个输入和两个期待的正确 # 答案输出。经过列表的方式提供数据时,Keras会假设数据给出的顺序和定义Model类时输入输出 # 给出的顺序是对应的。为了不顺序不一致致使的问题,这里更推荐使用字典的形式给出。 model.fit( [trainX, trainY], [trainY, trainY], batch_size=128, epochs=20, validation_data=([testX, testY], [testY, testY]) )
运行结果:
咱们能够看出,因为输出层1只使用了一个一维的隐藏节点,因此正确率很低,输出层2虽然使用了正确答案最为输入,可是损失函数中的权重较低,因此收敛速度较慢,准确率只有0.804。如今咱们把权重设置相同,运行获得:
这样输出二通过了足够的训练,精度就提升了不少。
虽然经过返回值的方式已经能够实现大部分的神经网络模型,然而Keras API还存在两大问题。一是对训练数据的处理流程支持的不太好;二十没法支持分布式训练。为了解决这两个问题,Keras提供了一种与原生态TensorFlow结合得更加紧密的方式。下面的代码是:实现Keras与TensorFlow联合起来解决MNIST问题。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: keras_test4.py @time: 2019/5/7 15:45 @desc: 实现Keras与TensorFlow联合起来解决MNIST问题。 """ import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist_data = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) # 经过TensorFlow中的placeholder定义输入。相似的,Keras封装的网络层结构也能够支持使用 # 前面章节中介绍的输入队列。这样能够有效避免一次性加载全部数据的问题。 x = tf.placeholder(tf.float32, shape=(None, 784)) y_ = tf.placeholder(tf.float32, shape=(None, 10)) # 直接使用TensorFlow中提供的Keras API定义网络结构。 net = tf.keras.layers.Dense(500, activation='relu')(x) y = tf.keras.layers.Dense(10, activation='softmax')(net) # 定义损失函数和优化方法。注意这里能够混用Keras的API和原生态TensorFlow的API loss = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_, y)) train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss) # 定义预测的正确率做为指标。 acc_value = tf.reduce_mean(tf.keras.metrics.categorical_accuracy(y_, y)) # 使用原生态TensorFlow的方式训练模型。这样能够有效地实现分布式。 with tf.Session() as sess: tf.global_variables_initializer().run() for i in range(10000): xs, ys = mnist_data.train.next_batch(100) _, loss_value = sess.run([train_step, loss], feed_dict={x: xs, y_: ys}) if i % 1000 == 0: print("After %d training step(s), loss on training batch is %g." % (i, loss_value)) print(acc_value.eval(feed_dict={x: mnist_data.test.images, y_: mnist_data.test.labels}))
运行结果:
经过和原生态TensorFlow更紧密地结合,可使建模的灵活性进一步提升,可是同时也会损失一部分封装带来的易用性。因此在实际问题中,须要根据需求合理的选择封装的程度。
基于MNIST数据集,经过Estimator实现全链接神经网络。
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test1.py @time: 2019/5/7 16:22 @desc: 基于MNIST数据集,经过Estimator实现全链接神经网络。 """ import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data # 将TensorFlow日志信息输出到屏幕 tf.logging.set_verbosity(tf.logging.INFO) mnist = input_data.read_data_sets('D:/Python3Space/BookStudy/book2/MNIST_data', one_hot=True) # 指定神经网络的输入层,全部这里指定的输入都会拼接在一块儿做为整个神经网络的输入。 feature_columns = [tf.feature_column.numeric_column("image", shape=[784])] # 经过TensorFlow提供的封装好的Estimator定义神经网络模型。feature_columns参数 # 给出了神经网络输入层须要用到的数据,hidden_units列表中给出了每一层 # 隐藏层的节点数。n_classes给出了总共类目的数量,optimizer给出了使用的优化函数。 # Estimator会将模型训练过程当中的loss变化以及一些其余指标保存到model_dir目录下, # 经过TensorFlow能够可视化这些指标的变化过程。并经过TensorBoard可视化监控指标结果。 estimator = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[500], n_classes=10, optimizer=tf.train.AdamOptimizer(), model_dir="./log" ) # 定义数据输入。这里x中须要给出全部的输入数据。由于上面feature_columns只定义了一组 # 输入,因此这里只须要制定一个就好。若是feature_columns中指定了多个,那么这里也须要 # 对每个指定的输入提供数据。y中须要提供每个x对应的正确答案,这里要求分类的结果 # 是一个正整数。num_epochs指定了数据循环使用的轮数。好比在测试时能够将这个参数指定为1. # batch_size指定了一个batch的大小。shuffle指定了是否须要对数据进行随机打乱。 train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.train.images}, y=mnist.train.labels.astype(np.int32), num_epochs=None, batch_size=128, shuffle=True ) # 训练模型。注意这里没有指定损失函数,经过DNNClassifier定义的模型会使用交叉熵做为损失函数。 estimator.train(input_fn=train_input_fn, steps=10000) # 定义测试时的数据输入。指定的形式和训练时的数据输入基本一致。 test_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images}, y=mnist.test.labels.astype(np.int32), num_epochs=1, batch_size=128, shuffle=False ) # 经过evaluate评测训练好的模型的效果。 accuracy_score = estimator.evaluate(input_fn=test_input_fn)["accuracy"] print("\nTest accuracy: %g %%" % (accuracy_score*100))
运行可得:
使用下面的命令开启tensorboard之旅:(我又要喷了,书里根本没说怎么开启tensorboard,我彻底靠自行百度摸索的。。。)
tensorboard --logdir=""
引号里面填本身的log所在的地址。而后运行:
复制最下面的那个地址,在浏览器(我是谷歌浏览器)粘贴并转到。
记住!是粘贴并转到,不是ctrl+v,是右键,粘贴并转到。
别问!问就是吃了好多亏。。。
反正个人电脑是粘贴并转到以后,卡了一下子,就出现了这个界面:
虽然跟书上的图的布局不同,下面折叠的指标,展开也有图就是了。。。
固然GRAPHS也是有的嘿嘿。。。
经过自定义的方式使用卷积神经网络解决MNIST问题:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test2.py @time: 2019/5/9 12:31 @desc: 经过自定义的方式使用卷积神经网络解决MNIST问题 """ import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data tf.logging.set_verbosity(tf.logging.INFO) # 经过tf.layers来定义模型结构。这里可使用原生态TensorFlow API或者任何 # TensorFlow的高层封装。X给出了输入层张量,is_training指明了是否为训练。 # 该函数返回前向传播的结果。 def lenet(x, is_training): # 将输入转化为卷积层须要的形状 x = tf.reshape(x, shape=[-1, 28, 28, 1]) net = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu) net = tf.layers.max_pooling2d(net, 2, 2) net = tf.layers.conv2d(net, 64, 3, activation=tf.nn.relu) net = tf.layers.max_pooling2d(net, 2, 2) net = tf.contrib.layers.flatten(net) net = tf.layers.dense(net, 1024) net = tf.layers.dropout(net, rate=0.4, training=is_training) return tf.layers.dense(net, 10) # 自定义Estimator中使用的模型,定义的函数有4个输入,features给出了在输入函数中 # 会提供的输入层张量。注意这是一个字典,字典里的内容是经过tf.estimator.inputs.numpy_input_fn # 中x参数的内容指定的。labels是正确答案,这个字段的内容是经过numpy_input_fn中y参数给出的。 # mode的取值有3中可能,分别对应Estimator类的train、evaluate和predict这3个函数。经过 # 这个参数能够判断当前会否是训练过程。最后params是一个字典,这个字典中能够给出模型相关的任何超参数 # (hyper-parameter)。好比这里将学习率放在params中。 def model_fn(features, labels, mode, params): # 定义神经网络的结构并经过输入获得前向传播的结果。 predict = lenet(features["image"], mode == tf.estimator.ModeKeys.TRAIN) # 若是在预测模式,那么只须要将结果返回便可。 if mode == tf.estimator.ModeKeys.PREDICT: # 使用EstimatorSpec传递返回值,并经过predictions参数指定返回的结果。 return tf.estimator.EstimatorSpec( mode=mode, predictions={"result": tf.argmax(predict, 1)} ) # 定义损失函数 loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=predict, labels=labels)) # 定义优化函数。 optimizer = tf.train.GradientDescentOptimizer(learning_rate=params["learning_rate"]) # 定义训练过程。 train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step()) # 定义评测标准,在运行evaluate时会计算这里定义的全部评测标准。 eval_metric_ops = { "my_metric": tf.metrics.accuracy(tf.argmax(predict, 1), labels) } # 返回模型训练过程须要使用的损失函数、训练过程和评测方法。 return tf.estimator.EstimatorSpec( mode=mode, loss=loss, train_op=train_op, eval_metric_ops=eval_metric_ops ) mnist = input_data.read_data_sets("D:/Python3Space/BookStudy/book2/MNIST_data", one_hot=False) # 经过自定义的方式生成Estimator类。这里须要提供模型定义的函数并经过params参数指定模型定义时使用的超参数。 model_params = {"learning_rate": 0.01} estimator = tf.estimator.Estimator(model_fn=model_fn, params=model_params) # 和前面的相似,训练和评测模型。 train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.train.images}, y=mnist.train.labels.astype(np.int32), num_epochs=None, batch_size=128, shuffle=True ) estimator.train(input_fn=train_input_fn, steps=30000) test_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images}, y=mnist.test.labels.astype(np.int32), num_epochs=1, batch_size=128, shuffle=False ) test_results = estimator.evaluate(input_fn=test_input_fn) # 这里使用的my_metric中的内容就是model_fn中eval_metric_ops定义的评测指标。 accuracy_score = test_results["my_metric"] print("\nTest accuracy: %g %%" % (accuracy_score*100)) # 使用训练好的模型在新数据上预测结果。 predict_input_fn = tf.estimator.inputs.numpy_input_fn( x={"image": mnist.test.images[:10]}, num_epochs=1, shuffle=False ) predictions = estimator.predict(input_fn=predict_input_fn) for i, p in enumerate(predictions): # 这里result就是tf.estimator.EstimatorSpec的参数predicitons中指定的内容。 # 由于这个内容是一个字典,因此Estimator能够很容易支持多输出。 print("Prediction %s : %s" % (i + 1, p["result"]))
运行以后获得:
预测结果:
#!/usr/bin/env python # -*- coding: UTF-8 -*- # coding=utf-8 """ @author: Li Tian @contact: 694317828@qq.com @software: pycharm @file: estimator_test3.py @time: 2019/5/9 14:13 @desc: 经过Estimator和数据集相结合的方式完成整个数据读取和模型训练的过程。 """ import tensorflow as tf tf.logging.set_verbosity(tf.logging.INFO) # Estimator的自定义输入函数须要每一次被调用时能够获得一个batch的数据(包括全部的 # 输入层数据和期待的正确答案标注),经过数据集能够很天然地实现这个过程。虽然Estimator # 要求的自定义输入函数不能有参数,可是经过python提供的lambda表达式能够快速将下面的 # 函数转化为不带参数的函数。 def my_input_fn(file_path, perform_shuffle=False, repeat_count=1): # 定义解析csv文件中一行的方法。 def decode_csv(line): # 将一行中的数据解析出来。注意iris数据中最后一列为正确答案,前面4列为特征。 parsed_line = tf.decode_csv(line, [[0.], [0.], [0.], [0.], [0]]) # Estimator的输入函数要求特征是一个字典,因此这里返回的也须要是一个字典。 # 字典中key的定义须要和DNNclassifier中feature_columns的定义匹配。 return {"x": parsed_line[:-1]}, parsed_line[-1:] # 使用数据集处理输入数据。数据集的具体使用方法能够参考前面。 dataset = (tf.data.TextLineDataset(file_path).skip(1).map(decode_csv)) if perform_shuffle: dataset = dataset.shuffle(buffer_size=256) dataset = dataset.repeat(repeat_count) dataset = dataset.batch(12) iterator = dataset.make_one_shot_iterator() # 经过定义的数据集获得一个batch的输入数据。这就是整个自定义的输入过程的返回结果。 batch_features, batch_labels = iterator.get_next() # 若是是为预测过程提供输入数据,那么batch_labels能够直接使用None。 return batch_features, batch_labels # 与前面中相似地定义Estimator feature_columns = [tf.feature_column.numeric_column("x", shape=[4])] classifier = tf.estimator.DNNClassifier( feature_columns=feature_columns, hidden_units=[10, 10], n_classes=3 ) # 使用lambda表达式将训练相关的信息传入自定义输入数据处理函数并生成Estimator须要的输入函数 classifier.train(input_fn=lambda: my_input_fn("./iris_data/iris_training (1).csv", True, 10)) # 使用lambda表达式将测试相关的信息传入自定义输入数据处理函数并生成Estimator须要的输入函数。 # 经过lambda表达式的方式能够大大减小冗余代码。 test_results = classifier.evaluate(input_fn=lambda: my_input_fn("./iris_data/iris_test (1).csv", False, 1)) print("\nTest accuracy: %g %%" % (test_results["accuracy"]*100))
运行以后,玄学报错。。。
我佛了,查了一万种方法,也解决不了玄学报错。。。
而后,我换了个机器,macbook。。。就正常运行了。。。
头就很疼。。。
要什么总结,不就是几种常见的TensorFlow高层封装嘛!包括TensorFlow-Slim、TFLearn、Keras和Estimator。反正就是结合起来,反正就是头疼。
个人CSDN:https://blog.csdn.net/qq_21579045
个人博客园:https://www.cnblogs.com/lyjun/
个人Github:https://github.com/TinyHandsome
纸上得来终觉浅,绝知此事要躬行~
欢迎你们过来OB~
by 李英俊小朋友