1. 程式人生 > >全連線神經網路實現MNIST手寫資料集識別

全連線神經網路實現MNIST手寫資料集識別

有目錄,內容大部分從官方教程copy,黑體加粗為對官方教程的補充

TensorFlow,pytorch,cuda,cudnn,anaconda安裝

版本對應關係

Version Python version Compiler Build tools cuDNN CUDA
tensorflow_gpu-1.12.0 3.5-3.6 MSVC 2015 update 3 Bazel 0.15.0 7 9
tensorflow_gpu-1.11.0 3.5-3.6 MSVC 2015 update 3 Bazel 0.15.0 7 9
tensorflow_gpu-1.10.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.9.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.8.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.7.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.6.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.5.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 7 9
tensorflow_gpu-1.4.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 6 8
tensorflow_gpu-1.3.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 6 8
tensorflow_gpu-1.2.0 3.5-3.6 MSVC 2015 update 3 Cmake v3.6.3 5.1 8
tensorflow_gpu-1.1.0 3.5 MSVC 2015 update 3 Cmake v3.6.3 5.1 8
tensorflow_gpu-1.0.0 3.5 MSVC 2015 update 3 Cmake v3.6.3 5.1 8

這一步沒做

5. Include cudnn.lib in your Visual Studio project.
a) Open the Visual Studio project and right-click on the project name.
​ b) Click Linker > Input > Additional Dependencies.
​ c) Add cudnn.lib and click OK.

安裝過程與經驗,最終安裝版本

反覆試,Windows10/Ubuntu+anaconda/Python+cuda9.0/cuda10.0組合了遍,以及坑後補坑、越補越大、錯誤的道路上越走越遠

最終安裝:cuda9.0+cudnn7.05+anaconda3.5.3+python3.6.7

經驗:以後只找官方教程,博主坑爹

anaconda下建立了虛擬環境 venv

source activate venv
source deactivate

安裝pytorch

torchvision 0.2.1

pytorch 0.4.1 py36_cuda90_cudnn7he774522_1

MNIST入門

MNIST資料集

每一個MNIST資料單元有兩部分組成:一張包含手寫數字的圖片和一個對應的標籤。我們把這些圖片設為“xs”,把這些標籤設為“ys”。訓練資料集和測試資料集都包含xs和ys,比如訓練資料集的圖片是 mnist.train.images ,訓練資料集的標籤是 mnist.train.labels

在MNIST訓練資料集中,mnist.train.images 是一個形狀為 [60000, 784] 的張量,第一個維度數字用來索引圖片,第二個維度數字用來索引每張圖片中的畫素點。在此張量裡的每一個元素,都表示某張圖片裡的某個畫素的強度值,值介於0和1之間

相對應的MNIST資料集的標籤是介於0到9的數字,用來描述給定圖片裡表示的數字。為了用於這個教程,我們使標籤資料是"one-hot vectors"。 一個one-hot向量除了某一位的數字是1以外其餘各維度數字都是0。所以在此教程中,數字n將表示成一個只有在第n維度(從0開始)數字為1的10維向量。比如,標籤0將表示成([1,0,0,0,0,0,0,0,0,0,0])。因此, mnist.train.labels 是一個 [60000, 10] 的數字矩陣。

Softmax迴歸介紹

我們知道MNIST的每一張圖片都表示一個數字,從0到9。我們希望得到給定圖片代表每個數字的概率

softmax模型可以用來給不同的物件分配概率。

為了得到一張給定圖片屬於某個特定數字類的證據(evidence),我們對圖片畫素值進行加權求和。如果這個畫素具有很強的證據說明這張圖片不屬於該類,那麼相應的權值為負數,相反如果這個畫素擁有有利的證據支援這張圖片屬於這個類,那麼權值是正數。

img

這裡的softmax可以看成是一個激勵(activation)函式或者連結(link)函式,把我們定義的線性函式的輸出轉換成我們想要的格式,也就是關於10個數字類的概率分佈。

img

img

img

但是更多的時候把softmax模型函式定義為前一種形式:把輸入值當成冪指數求值,再正則化這些結果值。這個冪運算表示,更大的證據對應更大的假設模型(hypothesis)裡面的乘數權重值。反之,擁有更少的證據意味著在假設模型裡面擁有更小的乘數係數。假設模型裡的權值不可以是0值或者負值。Softmax然後會正則化這些權重值,使它們的總和等於1,以此構造一個有效的概率分佈。

實現迴歸模型

TensorFlow也把複雜的計算放在python之外完成,但是為了避免前面說的那些開銷,它做了進一步完善。Tensorflow不單獨地執行單一的複雜計算,而是讓我們可以先用圖描述一系列可互動的計算操作,然後全部一起在Python之外執行。

我們通過操作符號變數來描述這些可互動的操作單元,可以用下面的方式建立一個:

x = tf.placeholder("float", [None, 784])

x不是一個特定的值,而是一個佔位符placeholder,我們在TensorFlow執行計算時輸入這個值。我們希望能夠輸入任意數量的MNIST影象,每一張圖展平成784維的向量。我們用2維的浮點數張量來表示這些圖,這個張量的形狀是[None,784 ]。(這裡的None表示此張量的第一個維度可以是任何長度的。)

img

我們的模型也需要權重值和偏置量,當然我們可以把它們當做是另外的輸入(使用佔位符),但TensorFlow有一個更好的方法來表示它們:Variable 。 一個Variable代表一個可修改的張量,存在在TensorFlow的用於描述互動性操作的圖中。它們可以用於計算輸入值,也可以在計算中被修改。對於各種機器學習應用,一般都會有模型引數,可以用Variable表示。

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

我們賦予tf.Variable不同的初值來建立不同的Variable:在這裡,我們都用全為零的張量來初始化Wb。因為我們要學習Wb的值,它們的初值可以隨意設定。

注意,W的維度是[784,10],因為我們想要用784維的圖片向量乘以它以得到一個10維的證據值向量,每一位對應不同數字類。b的形狀是[10],所以我們可以直接把它加到輸出上面。

現在,我們可以實現我們的模型啦。只需要一行程式碼!

y = tf.nn.softmax(tf.matmul(x,W) + b)

首先,我們用tf.matmul(X,W)表示x乘以W,對應之前等式裡面的img,這裡x是一個2維張量擁有多個輸入。然後再加上b,把和輸入到tf.nn.softmax函式裡面。

訓練模型

為了訓練我們的模型,我們首先需要定義一個指標來評估這個模型是好的。其實,在機器學習,我們通常定義指標來表示一個模型是壞的,這個指標稱為成本(cost)或損失(loss),然後儘量最小化這個指標。但是,這兩種方式是相同的。

一個非常常見的,非常漂亮的成本函式是“交叉熵”(cross-entropy)。交叉熵產生於資訊理論裡面的資訊壓縮編碼技術,但是它後來演變成為從博弈論到機器學習等其他領域裡的重要技術手段。它的定義如下:

img

我的理解,表示在正確結果為y’i的條件下對預測結果為yi 的驚訝程度,交叉熵表示對預測正確的平均驚訝程度,值越小越好

y 是我們預測的概率分佈, y’ 是實際的分佈(我們輸入的one-hot vector)。

為了計算交叉熵,我們首先需要新增一個新的佔位符用於輸入正確值:

y_ = tf.placeholder("float", [None,10])

然後我們可以用 img 計算交叉熵:

cross_entropy = -tf.reduce_sum(y_*tf.log(y))

首先,用 tf.log 計算 y 的每個元素的對數。接下來,我們把 y_ 的每一個元素和 tf.log(y_) 的對應元素相乘。最後,用 tf.reduce_sum 計算張量的所有元素的總和。(注意,這裡的交叉熵不僅僅用來衡量單一的一對預測和真實值,而是所有100幅圖片的交叉熵的總和。對於100個數據點的預測表現比單一資料點的表現能更好地描述我們的模型的效能。

現在我們知道我們需要我們的模型做什麼啦,用TensorFlow來訓練它是非常容易的。因為TensorFlow擁有一張描述你各個計算單元的圖,它可以自動地使用反向傳播演算法(backpropagation algorithm)來有效地確定你的變數是如何影響你想要最小化的那個成本值的。然後,TensorFlow會用你選擇的優化演算法來不斷地修改變數以降低成本。

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

學習速率

1541825932833

學習速率是這裡面的α,表示權值關於結果梯度的調整速率

在這裡,我們要求TensorFlow用梯度下降演算法(gradient descent algorithm)以0.01的學習速率最小化交叉熵。梯度下降演算法(gradient descent algorithm)是一個簡單的學習過程,TensorFlow只需將每個變數一點點地往使成本不斷降低的方向移動。

TensorFlow在這裡實際上所做的是,它會在後臺給描述你的計算的那張圖裡面增加一系列新的計算操作單元用於實現反向傳播演算法和梯度下降演算法。然後,它返回給你的只是一個單一的操作,當執行這個操作時,它用梯度下降演算法訓練你的模型,微調你的變數,不斷減少成本。

現在,我們已經設定好了我們的模型。在執行計算之前,我們需要新增一個操作來初始化我們建立的變數:

init = tf.initialize_all_variables()

現在我們可以在一個Session裡面啟動我們的模型,並且初始化變數:

sess = tf.Session()
sess.run(init)

執行 session.run() 可以獲得你要得知的運算結果, 或者是你所要運算的部分.

然後開始訓練模型,這裡我們讓模型迴圈訓練1000次!

for i in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

在這裡,需要再次說明:我們此時只是定義好了圖,並沒有變數並沒有初始化。

init = tf.initialize_all_variables()

此處用於初始化變數。但是這句話仍然不會立即執行。需要通過sess來將資料流動起來 。

切記:所有的運算都應在在session中進行:

with tf.Session() as sess:

此處自動開啟一個session

sess.run(init)

\1. TensorFlow與我們正常的程式設計思維略有不同:TensorFlow中的語句不會立即執行;而是等到開啟會話session的時候,才會執行session.run()中的語句。如果run中涉及到其他的節點,也會執行到。

\2. Tesorflow模型中的所有的節點都是可以視為運算操作op或tensor

該迴圈的每個步驟中,我們都會隨機抓取訓練資料中的100個批處理資料點,然後我們用這些資料點作為引數替換之前的佔位符來執行train_step

使用一小部分的隨機資料來進行訓練被稱為隨機訓練(stochastic training)- 在這裡更確切的說是隨機梯度下降訓練。每一次訓練我們可以使用不同的資料子集,這樣做既可以減少計算開銷,又可以最大化地學習到資料集的總體特性。

評估我們的模型

那麼我們的模型效能如何呢?

首先讓我們找出那些預測正確的標籤。tf.argmax 是一個非常有用的函式,它能給出某個tensor物件在某一維上的其資料最大值所在的索引值。由於標籤向量是由0,1組成,因此最大值1所在的索引位置就是類別標籤,比如tf.argmax(y,1)返回的是模型對於任一輸入x預測到的標籤值,而 tf.argmax(y_,1) 代表正確的標籤,我們可以用 tf.equal 來檢測我們的預測是否真實標籤匹配(索引位置一樣表示匹配)。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

tf.argmax(vector, 1):返回的是vector中的最大值的索引號,如果vector是一個向量,那就返回一個值,如果是一個矩陣,那就返回一個向量,這個向量的每一個維度都是相對應矩陣行的最大值元素的索引號。

這行程式碼會給我們一組布林值。為了確定正確預測項的比例,我們可以把布林值轉換成浮點數,然後取平均值。例如,[True, False, True, True] 會變成 [1,0,1,1] ,取平均值後得到 0.75.

accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

tf.reduce_mean(input_tensor, axis=None, keep_dims=False, name=None, reduction_indices=None)

根據給出的axis在input_tensor上求平均值。除非keep_dims為真,axis中的每個的張量秩會減少1。如果keep_dims為真,求平均值的維度的長度都會保持為1.如果不設定axis,所有維度上的元素都會被求平均值,並且只會返回一個只有一個元素的張量。

最後,我們計算所學習到的模型在測試資料集上面的正確率。

print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})

這個最終結果值應該大約是91%。

程式碼

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 10 14:04:49 2018

@author: HP
"""
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("G:\Desktop\進行時\點團隊\培訓會\MNIST_DATA", one_hot=True)

x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x,W) + b)

y_ = tf.placeholder("float", [None,10])

cross_entropy = -tf.reduce_sum(y_*tf.log(y))

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)//節點值初始化

for i in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
  
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))//此處才真正開始執行圖

執行結果

runfile(‘C:/Users/HP/AppData/Roaming/SPB_16.6/MNIST_low.py’, wdir=‘C:/Users/HP/AppData/Roaming/SPB_16.6’)
Extracting G:\Desktop\進行時\點團隊\培訓會\MNIST_DATA\train-images-idx3-ubyte.gz
Extracting G:\Desktop\進行時\點團隊\培訓會\MNIST_DATA\train-labels-idx1-ubyte.gz
Extracting G:\Desktop\進行時\點團隊\培訓會\MNIST_DATA\t10k-images-idx3-ubyte.gz
Extracting G:\Desktop\進行時\點團隊\培訓會\MNIST_DATA\t10k-labels-idx1-ubyte.gz
WARNING:tensorflow:From C:\Users\HP\Anaconda3\envs\venv\lib\site-packages\tensorflow\python\util\tf_should_use.py:118: initialize_all_variables (from tensorflow.python.ops.variables) is deprecated and will be removed after 2017-03-02.
Instructions for updating:
Use tf.global_variables_initializer instead.
0.9094

TensorFlow基本使用

使用 TensorFlow, 你必須明白 TensorFlow:

  • 使用圖 (graph) 來表示計算任務.
  • 在被稱之為 會話 (Session) 的上下文 (context) 中執行圖.
  • 使用 tensor 表示資料.
  • 通過 變數 (Variable) 維護狀態.
  • 使用 feed 和 fetch 可以為任意的操作(arbitrary operation) 賦值或者從其中獲取資料.

綜述

TensorFlow 是一個程式設計系統, 使用圖來表示計算任務. 圖中的節點被稱之為 op (operation 的縮寫). 一個 op 獲得 0 個或多個 Tensor, 執行計算, 產生 0 個或多個 Tensor. 每個 Tensor 是一個型別化的多維陣列. 例如, 你可以將一小組影象集表示為一個四維浮點數陣列, 這四個維度分別是 [batch, height, width, channels].

一個 TensorFlow 圖描述了計算的過程. 為了進行計算, 圖必須在 會話 裡被啟動. 會話 將圖的 op 分發到諸如 CPU 或 GPU 之類的 裝置 上, 同時提供執行 op 的方法. 這些方法執行後, 將產生的 tensor 返回. 在 Python 語言中, 返回的 tensor 是 numpy ndarray 物件

計算圖

TensorFlow 程式通常被組織成一個構建階段和一個執行階段. 在構建階段, op 的執行步驟 被描述成一個圖. 在執行階段, 使用會話執行執行圖中的 op.

例如, 通常在構建階段建立一個圖來表示和訓練神經網路, 然後在執行階段反覆執行圖中的訓練 op.

構建圖

構建圖的第一步, 是建立源 op (source op). 源 op 不需要任何輸入, 例如 常量 (Constant). 源 op 的輸出被傳遞給其它 op 做運算.

Python 庫中, op 構造器的返回值代表被構造出的 op 的輸出, 這些返回值可以傳遞給其它 op 構造器作為輸入.

TensorFlow Python 庫有一個預設圖 (default graph), op 構造器可以為其增加節點. 這個預設圖對 許多程式來說已經足夠用了

一個TensorFlow程式是預設建立一個圖的,除了系統自動建圖以外,還可以手動建立,並做一些其他的操作。

在預設圖上的操作相當於在圖上新增、修改、減少,圖中的節點、邊

在一個會話中啟動圖

構造階段完成後, 才能啟動圖. 啟動圖的第一步是建立一個 Session 物件, 如果無任何建立引數, 會話構造器將啟動預設圖.

Session 物件在使用完後需要關閉以釋放資源. 除了顯式呼叫 close 外, 也可以使用 “with” 程式碼塊 來自動完成關閉動作.

互動式使用

文件中的 Python 示例使用一個會話 Session 來 啟動圖, 並呼叫 Session.run() 方法執行操作.

變數

程式碼中 assign() 操作是圖所描繪的表示式的一部分, 正如 add() 操作一樣. 所以在呼叫 run() 執行表示式之前, 它並不會真正執行賦值操作.

通常會將一個統計模型中的引數表示為一組變數. 例如, 你可以將一個神經網路的權重作為某個變數儲存在一個 tensor 中. 在訓練過程中, 通過重複執行訓練圖, 更新這個 tensor.

Fetch

為了取回操作的輸出內容, 可以在使用 Session 物件的 run() 呼叫 執行圖時, 傳入一些 tensor, 這些 tensor 會幫助你取回結果.

Feed

上述示例在計算圖中引入了 tensor, 以常量或變數的形式儲存. TensorFlow 還提供了 feed 機制, 該機制 可以臨時替代圖中的任意操作中的 tensor 可以對圖中任何操作提交補丁, 直接插入一個 tensor.

feed 使用一個 tensor 值臨時替換一個操作的輸出結果. 你可以提供 feed 資料作為 run() 呼叫的引數. feed 只在呼叫它的方法內有效, 方法結束, feed 就會消失. 最常見的用例是將某些特殊的操作指定為 “feed” 操作, 標記的方法是使用 tf.placeholder() 為這些操作建立佔位符.

input1 = tf.placeholder(tf.types.float32)
input2 = tf.placeholder(tf.types.float32)
output = tf.mul(input1, input2)

with tf.Session() as sess:
  print sess.run([output], feed_dict={input1:[7.], input2:[2.]})

# 輸出:
# [array([ 14.], dtype=float32)]

MNIST進階

載入MNIST資料

mnist是一個輕量級的類。它以Numpy陣列的形式儲存著訓練、校驗和測試資料集。同時提供了一個函式,用於在迭代中獲得minibatch

執行TensorFlow的InteractiveSession

這裡,我們使用更加方便的InteractiveSession類。通過它,你可以更加靈活地構建你的程式碼。它能讓你在執行圖的時候,插入一些計算圖,這些計算圖是由某些操作(operations)構成的。這對於工作在互動式環境中的人們來說非常便利,比如使用IPython。如果你沒有使用InteractiveSession,那麼你需要在啟動session之前構建整個計算圖,然後啟動該計算圖

計算圖

因此Python程式碼的目的是用來構建這個可以在外部執行的計算圖,以及安排計算圖的哪一部分應該被執行。

構建Softmax 迴歸模型

佔位符

x = tf.placeholder("float", shape=[None, 784])

這裡的x並不是特定的值,相反,他們都只是一個佔位符,可以在TensorFlow執行某一計算時根據該佔位符輸入具體的值。

輸入圖片x是一個2維的浮點數張量。這裡,分配給它的shape[None, 784],其中784是一張展平的MNIST圖片的維度。None表示其值大小不定,在這裡作為第一個維度值,用以指代batch的大小,意即x的數量不定。

雖然placeholdershape引數是可選的,但有了它,TensorFlow能夠自動捕捉因資料維度不一致導致的錯誤。

變數

我們現在為模型定義權重W和偏置b。可以將它們當作額外的輸入量,但是TensorFlow有一個更好的處理方式:變數。一個變數代表著TensorFlow計算圖中的一個值,能夠在計算過程中使用,甚至進行修改。在機器學習的應用過程中,模型引數一般用Variable來表示。

我們在呼叫tf.Variable的時候傳入初始值。

變數需要通過seesion初始化後,才能在session中使用。這一初始化步驟為,為初始值指定具體值(本例當中是全為零),並將其分配給每個變數,可以一次性為所有變數完成此操作。

類別預測與損失函式

tf.reduce_sum把minibatch裡的每張圖片的交叉熵值都加起來了。我們計算的交叉熵是指整個minibatch的。

訓練模型

我們已經定義好模型和訓練用的損失函式,那麼用TensorFlow進行訓練就很簡單了。因為TensorFlow知道整個計算圖,它可以使用自動微分法找到對於各個變數的損失的梯度值。TensorFlow有大量內建的優化演算法 這個例子中,我們用最速下降法讓交叉熵下降,步長為0.01.

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

這一行程式碼實際上是用來往計算圖上新增一個新操作,其中包括計算梯度,計算每個引數的步長變化,並且計算出新的引數值。

返回的train_step操作物件,在執行時會使用梯度下降來更新引數。因此,整個模型的訓練可以通過反覆地執行train_step來完成。

注意,在計算圖中,你可以用feed_dict來替代任何張量,並不僅限於替換佔位符

構建一個多層卷積網路

權重初始化

為了建立這個模型,我們需要建立大量的權重和偏置項。這個模型中的權重在初始化時應該加入少量的噪聲來打破對稱性以及避免0梯度。由於我們使用的是ReLU神經元,因此比較好的做法是用一個較小的正數來初始化偏置項,以避免神經元節點輸出恆為0的問題(dead neurons)。

def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1)
  return tf.Variable(initial)

def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)

tf.truncated_normal(shape, mean, stddev) :shape表示生成張量的維度,mean是均值,stddev是標準差。這個函式產生正太分佈,均值和標準差自己設定。這是一個截斷的產生正太分佈的函式,就是說產生正太分佈的值如果與均值的差值大於兩倍的標準差,那就重新生成。和一般的正太分佈的產生隨機資料比起來,這個函式產生的隨機數與均值的差距不會超過兩倍的標準

卷積和池化

TensorFlow在卷積和池化上有很強的靈活性。我們怎麼處理邊界?步長應該設多大?在這個例項裡,我們會一直使用vanilla版本。我們的卷積使用1步長(stride size),0邊距(padding size)的模板,保證輸出和輸入是同一個大小。我們的池化用簡單傳統的2x2大小的模板做max pooling。

def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')

關於何為卷積?何為池化?

參見https://blog.csdn.net/huahuazhu/article/details/73469491

  • Pooling的結果可以使得特徵減少,引數減少。 常見的池化方式有如下三種:

    1. mean-pooling,即對鄰域內特徵點只求平均,對背景保留更好;

    2. max-pooling,即對鄰域內特徵點取最大,對紋理提取更好;

    3. Stochastic-pooling,介於兩者之間,通過對畫素點按照數值大小賦予概率,再按照概率進行亞取樣;

  • 卷積神經網路(CNN)由輸入層、卷積層、啟用函式、池化層、全連線層組成,即INPUT-CONV-RELU-POOL-FC。

  • 卷積分單通道單卷積核、多通道多卷積核,看連結看圖易懂

第一層卷積