# 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(神經網絡)然后訓練該網絡,然后就可以使用訓練好的網絡進行預測。網絡結構類似如下圖所示:
:-: 
知道了具體問題和解決問題的方法我們下一步就要用代碼去實現,首先要確定你已經安裝好了環境如果沒有請參考前面環境搭建一章。
首先打來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鍵可以看到以下就證明安裝成功:
:-: 
**好的環境搭建好了我們使用編輯器開始寫代碼吧**!
打開pycharm
點擊file---->project然后輸入項目的名字:dnn,選擇new environment using
如下圖所示:

然后去選擇你剛才新建的環境中的Python3.6.5的解析器(應該在envs\tensorflow1下面)
如下圖過程:



然后點擊create。
首先我們在dnn下建立一個python包名叫DNNclassfier,如下圖

然后我們在包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會出現:
:-: 
這就是文件下載下來所放的位置。
好了數據集文件下載下來了我們來把它讀取到內存。
接著在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()
~~~
然后打斷點,然后執行,我的結果是:
:-: 
好了,以后不清楚生成的變量是什么都這樣去看看。不再贅述。
我們接著寫代碼,下面數據準備好以后開始搭建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 的用法:
:-: 
然后我們去寫用于訓練和預測的輸入函數:
代碼如下:
~~~
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了如果能看到下面的界面證明你成功了。
:-: 
如果你細心的話會發現我們這里有某些地方跟官網不太一樣呀,確實我們現在的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
- 第六章 機器學習在實際項目中的應用