一:CNN基礎(chǔ)
深度學(xué)習(xí)的熱潮正是由2012年AlexNet的出現(xiàn)而引發(fā)的皿曲,因此摩疑,學(xué)習(xí)AlexNet網(wǎng)絡(luò)的結(jié)構(gòu),對(duì)于CNN的學(xué)習(xí)與理解是不可或缺的鞋怀。
[圖片上傳失敗...(image-8dca66-1536679715804)]
1. 卷積
如果我們使用傳統(tǒng)神經(jīng)網(wǎng)絡(luò)方式双泪,對(duì)一張圖片進(jìn)行分類,那么密似,我們把圖片的每個(gè)像素都連接到隱藏層節(jié)點(diǎn)上焙矛,那么對(duì)于一張1000x1000像素的圖片,如果我們有1M隱藏層單元残腌,那么一共有10^12個(gè)參數(shù)村斟,這顯然是不能接受的。(如下圖所示)
2. 激勵(lì)函數(shù)
Alexnet中使用relu作為激活函數(shù)抛猫,表達(dá)式為max(0, x)蟆盹。在此之前,神經(jīng)網(wǎng)絡(luò)的激活函數(shù)通常是sigmoid或者tanh函數(shù)邑滨,這兩種函數(shù)最大的缺點(diǎn)就是其飽和性日缨,當(dāng)輸入的x過(guò)大或過(guò)小時(shí),函數(shù)的輸出會(huì)非常接近+1與-1掖看,在這里斜率會(huì)非常小匣距,那么在訓(xùn)練時(shí)引用梯度下降時(shí),其飽和性會(huì)使梯度非常小哎壳,嚴(yán)重降低了網(wǎng)絡(luò)的訓(xùn)練速度毅待。
激勵(lì)層的實(shí)踐經(jīng)驗(yàn):
- 不要用sigmoid!不要用sigmoid归榕!不要用sigmoid尸红!
- 首先試RELU,因?yàn)榭欤⌒狞c(diǎn)
- 如果2失效外里,請(qǐng)用Leaky ReLU
- 某些情況下tanh倒是有不錯(cuò)的結(jié)果怎爵,但是很少
3. 池化
池化層是CNN中非常重要的一層,可以起到提取主要特征盅蝗,減少特征圖尺寸的作用鳖链,對(duì)加速CNN計(jì)算非常重要,主要分為最大池化墩莫,均值池化芙委。
- 特征不變性,圖像壓縮時(shí)去掉的信息只是一些無(wú)關(guān)緊要的信息狂秦,而留下的信息則是具有尺度不變性的特征灌侣,是最能表達(dá)圖像的特征。
- 降低計(jì)算裂问,我們知道一幅圖像含有的信息是很大的侧啼,特征也很多,但是有些信息對(duì)于我們做圖像任務(wù)時(shí)沒(méi)有太多用途或者有重復(fù)愕秫,我們可以把這類冗余信息去除慨菱,把最重要的特征抽取出來(lái)焰络,這也是池化操作的一大作用戴甩。
- 在一定程度上防止過(guò)擬合,更方便優(yōu)化闪彼。
4. 全連接
[圖片上傳失敗...(image-51b67-1536679715804)]
在最后一層卷積結(jié)束后甜孤,進(jìn)行了最后一次池化,輸出了20個(gè)1212的圖像畏腕,然后通過(guò)了一個(gè)全連接層變成了1100的向量缴川。
這是怎么做到的呢,其實(shí)就是有20100個(gè)1212的卷積核卷積出來(lái)的描馅,對(duì)于輸入的每一張圖把夸,用了一個(gè)和圖像一樣大小的核卷積,這樣整幅圖就變成了一個(gè)數(shù)了铭污,如果厚度是20就是那20個(gè)核卷積完了之后相加求和恋日。這樣就能把一張圖高度濃縮成一個(gè)數(shù)了。
二:CIFAR-10圖片分類
概述
對(duì)CIFAR-10 數(shù)據(jù)集的分類是機(jī)器學(xué)習(xí)中一個(gè)公開(kāi)的基準(zhǔn)測(cè)試問(wèn)題嘹狞,其任務(wù)是對(duì)一組32x32RGB的圖像進(jìn)行分類岂膳,這些圖像涵蓋了10個(gè)類別:
飛機(jī), 汽車磅网, 鳥谈截, 貓, 鹿, 狗簸喂, 青蛙毙死, 馬, 船以及卡車喻鳄。
模型結(jié)構(gòu)
本教程中的模型是一個(gè)多層架構(gòu)规哲,由卷積層和非線性層(nonlinearities)交替多次排列后構(gòu)成。這些層最終通過(guò)全連通層對(duì)接到softmax分類器上诽表。這一模型除了最頂部的幾層外唉锌,基本跟Alex Krizhevsky提出的模型一致。
在一個(gè)GPU上經(jīng)過(guò)幾個(gè)小時(shí)的訓(xùn)練后竿奏,該模型達(dá)到了最高86%的精度袄简。細(xì)節(jié)請(qǐng)查看下面的描述以及代碼。模型中包含了1,068,298個(gè)學(xué)習(xí)參數(shù)泛啸,分類一副圖像需要大概19.5M個(gè)乘加操作绿语。
[圖片上傳失敗...(image-1609-1536679715804)]
模型包括:
CIFAR-10 網(wǎng)絡(luò)模型部分的代碼位于 cifar10.py. 完整的訓(xùn)練圖中包含約765個(gè)操作。但是我們發(fā)現(xiàn)通過(guò)下面的模塊來(lái)構(gòu)造訓(xùn)練圖可以最大限度的提高代碼復(fù)用率:
- 模型輸入: 包括inputs() 候址、 distorted_inputs()等一些操作吕粹,分別用于讀取CIFAR的圖像并進(jìn)行預(yù)處理,做為后續(xù)評(píng)估和訓(xùn)練的輸入岗仑;
- 模型預(yù)測(cè): 包括inference()等一些操作匹耕,用于進(jìn)行統(tǒng)計(jì)計(jì)算,比如在提供的圖像進(jìn)行分類荠雕; adds operations that perform inference, i.e. classification, on supplied images.
- 模型訓(xùn)練: 包括loss() and train()等一些操作稳其,用于計(jì)算損失、計(jì)算梯度炸卑、進(jìn)行變量更新以及呈現(xiàn)最終結(jié)果既鞠。
# the input
images=tf.placeholder(tf.float32,[None,24,24,3])
# build up the network.
logits = cifar10.network(images)
# Calculate loss.
loss = cifar10.loss(logits, labels)
# Caluculate grad and back propagation
train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
# initialize
sess=tf.Session()
sess.run(tf.global_variables_initializer())
saver=tf.train.Saver()
images = cifar10.distorted_inputs()
# iterate 2000 times
for i in range(2000):
# shuffle the images index
np.random.shuffle(images)
# one epoch
for j in int(np.shape(images)[0]/batch_size):
input_batch=images[j:j+batch_size,:,:,:]
sess.run([loss,train_op],feed_dict={images:input_batch})
saver.save(sess,resutl_dir+'model.ckpt')
def network(images):
"""Build the CIFAR-10 model.
Args:
images: Images returned from distorted_inputs() or inputs().
Returns:
Logits.
"""
# We instantiate all variables using tf.get_variable() instead of
# tf.Variable() in order to share variables across multiple GPU training runs.
# If we only ran this model on a single GPU, we could simplify this function
# by replacing all instances of tf.get_variable() with tf.Variable().
#
# conv1
with tf.variable_scope('conv1') as scope:
kernel = _variable_with_weight_decay('weights',
shape=[5, 5, 3, 64],
stddev=5e-2,
wd=None)
conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
pre_activation = tf.nn.bias_add(conv, biases)
conv1 = tf.nn.relu(pre_activation, name=scope.name)
_activation_summary(conv1)
# pool1
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
padding='SAME', name='pool1')
# norm1 基本不再使用
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
name='norm1')
# conv2
with tf.variable_scope('conv2') as scope:
kernel = _variable_with_weight_decay('weights',
shape=[5, 5, 64, 64],
stddev=5e-2,
wd=None)
conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME')
biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1))
pre_activation = tf.nn.bias_add(conv, biases)
conv2 = tf.nn.relu(pre_activation, name=scope.name)
_activation_summary(conv2)
# norm2
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
name='norm2')
# pool2
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1],
strides=[1, 2, 2, 1], padding='SAME', name='pool2')
# local3
with tf.variable_scope('local3') as scope:
# Move everything into depth so we can perform a single matrix multiply.
reshape = tf.reshape(pool2, [images.get_shape().as_list()[0], -1])
dim = reshape.get_shape()[1].value
weights = _variable_with_weight_decay('weights', shape=[dim, 384],
stddev=0.04, wd=0.004)
biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1))
local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)
_activation_summary(local3)
# local4
with tf.variable_scope('local4') as scope:
weights = _variable_with_weight_decay('weights', shape=[384, 192],
stddev=0.04, wd=0.004)
biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1))
local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)
_activation_summary(local4)
# linear layer(WX + b),
# We don't apply softmax here because
# tf.nn.sparse_softmax_cross_entropy_with_logits accepts the unscaled logits
# and performs the softmax internally for efficiency.
with tf.variable_scope('softmax_linear') as scope:
weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
stddev=1/192.0, wd=None)
biases = _variable_on_cpu('biases', [NUM_CLASSES],
tf.constant_initializer(0.0))
softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)
_activation_summary(softmax_linear)
return softmax_linear
損失曲線