# DNN实例实现
为什么要在卷积神经网络里加上一节DNN呢?为了以下目的
1. 为了熟悉tensorflow的使用、
2. 为下面实现卷积神经网络的具体实现做铺垫、
**我们先从tensorflow官网的例子入手,来实现一个简单的DNN**。(以目的为导向的学习方式我认为是最有效的,所以以后我们就一边实现具体的实例一边去学习具体的知识点,因为单独去看知识点太枯燥了)
首先我建议首先看一下官网的该例子(是中文的不用害怕,第一遍肯定是蒙的不要灰心,先跟着我的教程敲一遍,回头再看,你就会有点感觉了):https://www.tensorflow.org/get_started/get_started_for_beginners
我现在假设你已经看过一遍该例子了,同时你必须有python的基础知识,如果没有我建议你去看一遍这个教程:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
好了下面我就带领大家一步步实现例子中的代码,虽然没有官网上讲的清楚但是都是你可以理解的:
废话少说我们开始实现:
首先该例子是:**鸢尾花分类问题**
**问题**:我们将仅根据鸢尾花花萼和花瓣的长度和宽度对其分为三类:山鸢尾 维吉尼亚鸢尾 。为了预测看到的鸢尾花究竟属于哪一类。
**条件**:我们已经创建了一个包含 120 株鸢尾花的数据集,数据集前5个条目如下:
| 花萼长度 | 花萼宽度 | 花瓣长度 | 花瓣宽度 | 品种 |
| --- | --- | --- | --- | --- |
| 6.4 | 2.8 | 5.6 | 2.2 | 2 |
| 5.0 | 2.3 | 3.3 | 1.0 | 1 |
| 4.9 | 2.5 |4.5 | 1.7 | 2 |
| 4.9 | 3.1 | 1.5 | 0.1 | 0 |
| 5.7 | 3.8 | 1.7 | 0.3 | 0 |
* 0 代表 setosa(山鸢尾)
* 1 代表 versicolor(变色鸢尾)
* 2 代表 virginica(维吉尼亚鸢尾)
**方法**:我们首先构建DNN(神经网络)然后训练该网络,然后就可以使用训练好的网络进行预测。网络结构类似如下图所示:
:-: ![](https://box.kancloud.cn/3090b771954aef5ec25cf4841e252b00_667x535.png)
知道了具体问题和解决问题的方法我们下一步就要用代码去实现,首先要确定你已经安装好了环境如果没有请参考前面环境搭建一章。
首先打来Anaconda Prompt(一个命令行窗口):
输入以下命令来创建一个新的开发环境,因为我已经有一个tensorflow的开发环境了所以我现在使用tensorflow1同时也为了让大家能很容易的实现该例子:
~~~
conda create --name tensorflow1
~~~
输入下面命令进去该环境:
~~~
conda activate tensorflow1
~~~
然后我们输入以下命令可以看到该环境都安装了那些包,然后我们看到该环境什么都没有:
~~~
conda list
~~~
好了我们开始安装软件包:
先安装python我们选择目前最新的版本,把依赖的也都安装下来选择y(有兴趣可以看看 conda 和 pip 包管理工具的不同,其实主要就一点:是否安装所依赖的包)
~~~
conda install python=3.6.5
~~~
然后输入以下命令安装panda,因为该实例需要用到。(这一次我们用pip安装是为了不让它出现所依赖的包安装提醒)
~~~
pip install pandas
~~~
最后我们安装tensorflow:
~~~
pip install --upgrade --ignore-installed tensorflow
~~~
测试tensorflow是否安装成功:
输入以下代码:
输入以下命令进入python交互环境:
~~~
python
~~~
然后输入以下代码
~~~
# python code
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
~~~
按一下enter键可以看到以下就证明安装成功:
:-: ![](https://box.kancloud.cn/134d927a194a917e58040a0c737aed44_677x458.png)
**好的环境搭建好了我们使用编辑器开始写代码吧**!
打开pycharm
点击file---->project然后输入项目的名字:dnn,选择new environment using
如下图所示:
![](https://box.kancloud.cn/c836027fd1e9b7f810914aa0e37270c8_783x488.png)
然后去选择你刚才新建的环境中的Python3.6.5的解析器(应该在envs\tensorflow1下面)
如下图过程:
![](https://box.kancloud.cn/dda5dbfe9c837b1db965a405f758a1ee_783x488.png)
![](https://box.kancloud.cn/df97efc952b23d63af9915ce671d994f_854x629.png)
![](https://box.kancloud.cn/f7f574db80b1d15603d6e75689798d2b_839x568.png)
然后点击create。
首先我们在dnn下建立一个python包名叫DNNclassfier,如下图
![](https://box.kancloud.cn/6ce1f2632e7c961b0b2c7b40694f17e3_730x613.png)
然后我们在包DNNclassfier下创建名为:premade_estimator.py
然后输入tensorflow项目的架子代码:
~~~
from __future__ import absolute_import #为了解决python版本不一致的问题
from __future__ import division #为了解决python版本不一致的问题
from __future__ import print_function #为了解决python版本不一致的问题
import tensorflow as tf
def main(argv):
#主要代码
if __name__ == '__main__':
tf.logging.set_verbosity(tf.logging.INFO) #设置日志记录类型
tf.app.run(main) #执行代码
~~~
要用120 株鸢尾花的数据集进行网络训练我们首先要把数据读入网络,所以我们单独建立一个模块来操作数据,新建一个iris_data.py文件。
输入以下代码(不解释了注释写的很明白了):
~~~
#导入所依赖的模块
import pandas as pd
import tensorflow as tf
#定义所需要的常量, csv是一种文件格式
TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"
# 定义数据集列的名字
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
#定义三个类别常量
SPECIES = ['Setosa', 'Versicolor', 'Virginica']
~~~
然后接着在iris_data.py文件中输入下面代码:
~~~
# 读取网上文件到本地,Keras 是一个开放源代码机器学习库;tf.keras 是 Keras 的一种 TensorFlow 实现。
def maybe_download():
train_path = tf.keras.utils.get_file(TRAIN_URL.split('/')[-1], TRAIN_URL)
test_path = tf.keras.utils.get_file(TEST_URL.split('/')[-1], TEST_URL)
return train_path, test_path
#测试代码
if __name__ == '__main__':
x, y = maybe_download()
print(x)
print(y)
~~~
然后运行 iris_data.py会出现:
:-: ![](https://box.kancloud.cn/cea90ed5c789fe5f4255eac921c9a826_1182x277.png)
这就是文件下载下来所放的位置。
好了数据集文件下载下来了我们来把它读取到内存。
接着在iris_data.py文件中定义load_data函数代码如下:
~~~
def load_data(y_name = 'Species'):
"""返回数据集如(train_x, train_y), (test_x, test_y)格式"""
#获取下载下来数据集的本地路径
train_path, test_path = maybe_download();
# 以pandas中定义列表数据结构DataFrame表示在内存中
train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
train_x, train_y = train, train.pop(y_name)
test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
test_x, test_y = test, test.pop(y_name)
return (train_x, train_y), (test_x, test_y)
~~~
你可以添加测试代码进行测试看返回的结果是什么(这里我就不截图了因为数据量有点大):
~~~
#测试代码
if __name__ == '__main__':
x, y = load_data()
print(x)
print(y)
~~~
到目前我们已经可以把数据集以DataFrame数据结构形式读入到内存。我们可以开始在premade_estimator.py写主要代码了:
在premade_estimator.py中输入下面代码:
~~~
def main():
#读取数据
(train_x, train_y), (test_x, test_y) = iris_data.load_data()
#下面我们把读入内存的pandas数据格式DataFrame,换成一种模型能理解的格式,也就是所谓的特征列
#可以参考网址去深入了解:https://www.tensorflow.org/get_started/feature_columns
my_feature_columns = []
for key in train_x.keys():
my_feature_columns.append(tf.feature_column.numeric_column(key=key))
~~~
你可以测一下my_feature_columns里面到底是什么东西,添加测试代码,如下
~~~
if __name__ == '__main__':
main()
~~~
然后打断点,然后执行,我的结果是:
:-: ![](https://box.kancloud.cn/bb4f87c3e9f941a5e8d460ac8d220e3a_1891x948.png)
好了,以后不清楚生成的变量是什么都这样去看看。不再赘述。
我们接着写代码,下面数据准备好以后开始搭建DNN网络,所幸的是tensorflow已经为我们写好了DNN实现的estimator,刚开始你不是很清楚estimator是什么其实就是一个tensorflow实现深度学习的一个架子,你可以使用它里面实现好了的estimator也可以自己实现estimator。这一节我们使用tensorflow里面实现好了的,下一届我们实现我们自己是卷积神经网络。
> 注意:Estimator的核心想法就是:把工作网络封装成一个类,训练、评估、预测都是类方法
> 在这种封装里面,首先隐藏了网络结构,对于程序运行者,只需要考虑输入输出。同时,包含了对参数数据的保存、对训练状态的保存,使得训练过程可复现,可追溯。其数据的管理,交给了Dataset,在进一步了解Dataset后,二者的协作会使得编写tensorflow程序变得井井有条。
然后输入下面代码创建DNN:
~~~
# 创建两个都包含10个神经元的隐含层的DNN
classifier = tf.estimator.DNNClassifier(
#指定特层列告诉DNN该如何使用原始数据
feature_columns=my_feature_columns,
#指定隐含层
hidden_units=[10, 10],
#指定该网络分多少种类
n_classes=3
)
~~~
> 注意:我们使用DNNClassifier中默认的参数(说明文档上写的很清楚:https://www.tensorflow.org/api_docs/python/tf/estimator/DNNClassifier ):例如,损失函数是交叉熵函数,激活函数是RELU,优化函数选择AdagradOptimizer(其实是一种梯度下降法的变种)要想更多的了解一下AdagradOptimizer可以参考:https://blog.csdn.net/tsyccnh/article/details/76769232 ::::::但是有一点权值是怎么初始化的我目前还不太清楚。可能官网还看到的遍数少吧。不过不影响我们下面的进行,后期会补上这一缺点。
>
到目前我们既构建好了网络,又把数据集的数据以DataFrame数据结构读入内存了。
但是我们看DNNClassifierAPI会发现,DNNClassifier的train,evaluate,predict的API的输入全部要求是A 'tf.data.Dataset' object或者A tuple。所以我们下面要做的就是给train evaluate,生成这些对象。
首先我们还是打开iris_data.py文件。继续在该文件中添加下面代码:
~~~
def train_input_fn(features, labels, batch_size):
"""为了训练写的输入函数"""
#转变输入的数据为Dataset的对象
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
#随机拖拽,重复和批生成数据。(其实就是搅拌样本使随机化,并随机组合生成一批样本)
dataset = dataset.shuffle(1000).repeat().batch(batch_size)
return dataset
~~~
没每走一步我们测试一下,下面我们测试一下中间生成了什么并返回了什么。
添加测试代码:
~~~
if __name__ == '__main__':
(train_x, train_y), (test_x, test_y) = load_data()
# 我们使用1个批次来测试
z = train_input_fn(train_x, train_y,1)
~~~
然后打断点,点击debug调试,查看情况,看的是不是很蒙,没关系我们只知道现在变成了train可以使用的数据类型就行后期再学习dataset 的用法:
:-: ![](https://box.kancloud.cn/101ea459efbb6cff64467e8175051560_1914x994.png)
然后我们去写用于训练和预测的输入函数:
代码如下:
~~~
def eval_input_fn(features, labels, batch_size)
"""为了评估和预测写的输入函数"""
features = dict(features)
if labels is None:
#证明是预测
inputs = features
else:
inputs = (features, labels)
#转变数据格式
dataset = tf.data.Dataset.from_tensor_slices(inputs)
# assert 和 is 用法自己查资料吧,网上到处都是
assert batch_size is not None, "batch_size must not be None"
dataset = dataset.batch(batch_size)
return dataset
~~~
好的我有了输入数据现在去写train、evaluate、predict函数吧!
打开premade_estimator.py
添加下面代码:
~~~
#训练该模型设置训练1000次,每次100个样本
classifier.train(
input_fn=lambda :iris_data.train_input_fn(train_x, train_y, 100),
steps=1000
)
# 评估该模型
eval_result = classifier.evaluate(
input_fn=lambda :iris_data.eval_input_fn(test_x, test_y,100)
)
#把评估结果打印到控制台
print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))
~~~
目前我们有了训练和评估代码, 但是还记得我们这个网络的目的吗?那就是预测。下面我们开始写预测代码:
接着在premade_estimator.py中写:
~~~
#从训练好的模型生成预测
#首先我们要有所预测的实例,我们先自己随便写一个
expected = ['Setosa', 'Versicolor', 'Virginica']
predict_x = {
'SepalLength': [5.1, 5.9, 6.9],
'SepalWidth': [3.3, 3.0, 3.1],
'PetalLength': [1.7, 4.2, 5.4],
'PetalWidth': [0.5, 1.5, 2.1],
}
#写预测函数
predictions = classifier.predict(
input_fn=lambda: iris_data.eval_input_fn(predict_x,labels=None,batch_size=100)
)
# 创建输出的模板,如果不懂可以参考python的格式化输出一节
template = ('\nPrediction is "{}" ({:.1f}%), expected "{}"')
~~~
现在我们最后写显示到控制台的代码:
~~~
for pred_dict, expec in zip(predictions, expected):
class_id = pred_dict['class_ids'][0]
probability = pred_dict['probabilities'][class_id]
print(template.format(iris_data.SPECIES[class_id],
100 * probability, expec))
~~~
这段代码我就不解释了很容易理解,如果不理解用我教你们的测试方法看看里面的变量都是什么形式的。至此我们就基本上结束了。现在你可以去运行premade_estimator.py了如果能看到下面的界面证明你成功了。
:-: ![](https://box.kancloud.cn/c76a2a5dcfa00e8e5f2d76d9ef7eb2eb_1903x1012.png)
如果你细心的话会发现我们这里有某些地方跟官网不太一样呀,确实我们现在的batch_size和训练步骤都是写死的。
官网上是可以从命令行输入这些参数的。为了与官网保持一致我们也填上以下代码:
~~~
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--batch_size', default=100, type=int, help='batch size')
parser.add_argument('--train_steps', default=1000, type=int,
help='number of training steps')
def main(argv):
args = parser.parse_args(argv[1:])
把里面用到的写死的ize和训练步骤换成args.batch_size和args.train_steps
~~~
到此我们就介绍了。敲完一遍再回头看官网,我想应该会有点感觉了吧。最后我们这里把最终的代码给写出来。
premade_estimator.py
~~~
from __future__ import absolute_import #为了解决python版本不一致的问题
from __future__ import division #为了解决python版本不一致的问题
from __future__ import print_function #为了解决python版本不一致的问题
import argparse
import tensorflow as tf
import iris_data
parser = argparse.ArgumentParser()
parser.add_argument('--batch_size', default=100, type=int, help='batch size')
parser.add_argument('--train_steps', default=1000, type=int,
help='number of training steps')
def main(argv):
args = parser.parse_args(argv[1:])
#读取数据
(train_x, train_y), (test_x, test_y) = iris_data.load_data()
#下面我们把读入内存的pandas数据格式DataFrame,换成一会模型能理解的格式,也就是所谓的特征列
#可以参考网址去深入了解:https://www.tensorflow.org/get_started/feature_columns
my_feature_columns = []
for key in train_x.keys():
my_feature_columns.append(tf.feature_column.numeric_column(key=key))
# 创建两个都包含10个神经元的隐含层的DNN
classifier = tf.estimator.DNNClassifier(
#指定特层列告诉DNN该如何使用原始数据
feature_columns=my_feature_columns,
#指定隐含层
hidden_units=[10, 10],
#指定该网络分多少种类
n_classes=3
)
#训练该模型设置训练1000次,每次100个样本
classifier.train(
input_fn=lambda :iris_data.train_input_fn(train_x, train_y, args.batch_size),
steps=args.train_steps
)
# 评估该模型
eval_result = classifier.evaluate(
input_fn=lambda :iris_data.eval_input_fn(test_x, test_y, args.batch_size)
)
#把评估结果打印到控制台
print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))
#从训练好的模型生成预测
#首先我们要有所预测的实例,我们先自己随便写一个
expected = ['Setosa', 'Versicolor', 'Virginica']
predict_x = {
'SepalLength': [5.1, 5.9, 6.9],
'SepalWidth': [3.3, 3.0, 3.1],
'PetalLength': [1.7, 4.2, 5.4],
'PetalWidth': [0.5, 1.5, 2.1],
}
#写预测函数
predictions = classifier.predict(
input_fn=lambda: iris_data.eval_input_fn(predict_x,labels=None,batch_size=args.batch_size)
)
# 创建输出的模板,如果不懂可以参考python的格式化输出一节
template = ('\nPrediction is "{}" ({:.1f}%), expected "{}"')
for pred_dict, expec in zip(predictions, expected):
class_id = pred_dict['class_ids'][0]
probability = pred_dict['probabilities'][class_id]
print(template.format(iris_data.SPECIES[class_id],
100 * probability, expec))
if __name__ == '__main__':
tf.logging.set_verbosity(tf.logging.INFO) #设置日志记录类型
tf.app.run(main) #执行代码
~~~
iris_data.py
~~~
#导入所依赖的模块
import pandas as pd
import tensorflow as tf
#定义所需要的常量, csv是一种文件格式
TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"
# 定义数据集列名字
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
'PetalLength', 'PetalWidth', 'Species']
#定义三个类别常量
SPECIES = ['Setosa', 'Versicolor', 'Virginica']
# 读取网上文件到本地,Keras 是一个开放源代码机器学习库;tf.keras 是 Keras 的一种 TensorFlow 实现。
def maybe_download():
train_path = tf.keras.utils.get_file(TRAIN_URL.split('/')[-1], TRAIN_URL)
test_path = tf.keras.utils.get_file(TEST_URL.split('/')[-1], TEST_URL)
return train_path, test_path
def load_data(y_name = 'Species'):
"""返回数据集如(train_x, train_y), (test_x, test_y)格式"""
#获取下载下来数据集的本地路径
train_path, test_path = maybe_download();
# 以pandas中定义列表数据结构DataFrame表示在内存中
train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
train_x, train_y = train, train.pop(y_name)
test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
test_x, test_y = test, test.pop(y_name)
return (train_x, train_y), (test_x, test_y)
def train_input_fn(features, labels, batch_size):
"""为了训练写的输入函数"""
#转变输入的数据为Dataset的对象
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
#随机拖拽,重复和批生成数据。(其实就是搅拌样本使随机化,并随机组合生成一批样本)
dataset = dataset.shuffle(1000).repeat().batch(batch_size)
return dataset
def eval_input_fn(features, labels, batch_size):
"""为了评估和预测写的输入函数"""
features = dict(features)
if labels is None:
#证明是预测
inputs = features
else:
inputs = (features, labels)
#转变数据格式
dataset = tf.data.Dataset.from_tensor_slices(inputs)
# assert 和 is 用法自己查资料吧,网上到处都是
assert batch_size is not None, "batch_size must not be None"
dataset = dataset.batch(batch_size)
return dataset
if __name__ == '__main__':
(train_x, train_y), (test_x, test_y) = load_data()
# 我们使用1个批次来测试
z = train_input_fn(train_x, train_y,2)
print("end")
~~~
最后我们给出两个链接是关于梯度下降和正则化的下一节会用到:
梯度下降:https://www.cnblogs.com/maybe2030/p/5089753.html
正则化:https://blog.csdn.net/sinat_29819401/article/details/60885679
softmax和交叉熵:https://blog.csdn.net/allenlzcoder/article/details/78591535
- 序言
- 第一章 机器学习概述
- 第二章 机器学习环境搭建
- 环境搭建
- 第三章 机器学习之基础算法
- 第一节:基础知识
- 第二节:k近邻算法
- 第三节:决策树算法
- 第四节:朴素贝叶斯
- 第五节:逻辑斯蒂回归
- 第六节:支持向量机
- 第四章 机器学习之深度学习算法
- 第一节: CNN
- 4.1.1 CNN介绍
- 4.1.2 CNN反向传播
- 4.1.3 DNN实例
- 4.1.4 CNN实例
- 第五章 机器学习论文与实践
- 第一节: 语义分割
- 5.1 FCN
- 5.1.1 FCN--------实现FCN16S
- 5.1.2 FCN--------优化FCN16S
- 5.2 DeepLab
- 5.2.1 DeepLabv2
- 第六章 机器学习在实际项目中的应用