跟其他很多想學(xué)這門技術(shù)的同學(xué)一樣,剛開始也是很懵逼,不知如何開始下手;于是網(wǎng)上搜索各種學(xué)習(xí)路線,其中Andrew Ng的機(jī)器學(xué)習(xí)課在很多地方被推薦。于是乎——雖然是英語的,但也圖文并茂,基本能理解。從這里了解到神經(jīng)網(wǎng)絡(luò)原來就是擬合數(shù)據(jù)的方程矩陣,揭開了神秘面紗;也知道了過擬合欠擬合等基本概念。
機(jī)器學(xué)習(xí)-Andrew Ng
后來看到第8周,感覺有點(diǎn)無聊。然后去網(wǎng)上搜索到這篇博客零基礎(chǔ)入門深度學(xué)習(xí)(3) - 神經(jīng)網(wǎng)絡(luò)和反向傳播算法,里面的內(nèi)容基本上也是之前Nadrew Ng視頻里面講過的內(nèi)容,但是這篇作文更偏向?qū)崙?zhàn)。照著他的樣子推導(dǎo)了一下反向傳播的公式;實(shí)例代碼是手寫數(shù)字識(shí)別,代碼很繁雜,向前傳播與反向傳播都是for循環(huán)實(shí)現(xiàn)的,不容易看明白;然后我用numpy矩陣乘法重新實(shí)現(xiàn)了一下,發(fā)現(xiàn)真的可以識(shí)別,太驚喜了。之前看Andrew Ng視頻看得打瞌睡,現(xiàn)在突然來了精神。
for x, y in zip(inputs, labels):
# 計(jì)算輸出值
z2 = w12.dot(x)
a2 = sigmoid(z2)
z3 = w23.dot(a2)
a3 = softmax(z3)
# print('output:',a3)
# 反向傳播
#######################
label = np.zeros(10)
label[y] = 1
# print('lable:',label)
# print('output:',get_result(a3),'label:',y)
delta3 = a3 - label
# print('delta3:',delta3)
# 更新w23
w23 = w23 + μ * delta3.reshape(len(delta3), 1).dot(a2.reshape(1, len(a2)))
# 計(jì)算a2節(jié)點(diǎn)誤差delta2
delta2 = a2 * (1 - a2) * w23.T.dot(delta3)
# 更新w12
# print(x.shape,w12.shape,delta2.shape)
w12 = w12 + μ * delta2.reshape(len(delta2), 1).dot(x.reshape(1, len(x)))
#計(jì)算代價(jià)函數(shù)值:
J=0.5*np.sum(np.array(list(map(lambda x,y:np.square(x-y),a3,label))))
print(J)
同系列的文章,這篇說卷積網(wǎng)絡(luò)的也說的很詳細(xì):零基礎(chǔ)入門深度學(xué)習(xí)(4) - 卷積神經(jīng)網(wǎng)絡(luò);卷積的公式推導(dǎo)就直接放棄了(看著頭大);為了獲得卷積的客觀認(rèn)識(shí),專門生成了一個(gè)高斯濾波來卷積了一張圖片matplotlib.ipynb
有了這樣的背景常識(shí)后,開始了Tensorflow的學(xué)習(xí)
當(dāng)然這個(gè)時(shí)候都是圍繞手寫數(shù)字識(shí)別進(jìn)行的
手寫數(shù)字中文Tensorflow文檔
MNIST機(jī)器學(xué)習(xí)入門.ipynb
MNIST機(jī)器學(xué)習(xí)入門-優(yōu)化.ipynb
卷積神經(jīng)網(wǎng)絡(luò)-CNN.ipynb
這樣的學(xué)習(xí)感覺還是有點(diǎn)零散,然后買了本《Tensorflow:實(shí)戰(zhàn)Google深度學(xué)習(xí)框架》第2版 鄭澤宇 梁博文 顧思宇 著,把里面大部分代碼過了一遍。
《Tensorflow:實(shí)戰(zhàn)Google深度學(xué)習(xí)框架》第2版 代碼
因?yàn)閠ensorflow用的是1.4.0,版本不一致容易出錯(cuò),所以運(yùn)行代碼還是推薦用docker。
docker run -d -v /Users/yetongxue/Desktop/jupyter_notebook/notebooks:/notebooks --restart=always -p 8889:8888 -p 6007:6006 tensorflow/tensorflow:1.4.0
這里面比較有用的幾個(gè)點(diǎn)如下:
1、模型的保存與恢復(fù)
tensorflow_5.4_model_saver.ipynb
保存一般有兩種方式,一是保存為.ckpt
#模型保存
import tensorflow as tf
v1_=tf.Variable(tf.constant(1.0,shape=[1]),name='v1_')
v2_=tf.Variable(tf.constant(2.0,shape=[1]),name='v2_')
result=v1_+v2_
saver=tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.save(sess,'./tmp/model_saver/model.ckpt')
另一種是保存為.pd
#存儲(chǔ)
import tensorflow as tf
from tensorflow.python.framework import graph_util
v1=tf.Variable(tf.constant(1.0,shape=[1]),name='v1')
v2=tf.Variable(tf.constant(2.0,shape=[1]),name='v2')
result=v1+v2
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
graph_def=tf.get_default_graph().as_graph_def()
out_graph_def=graph_util.convert_variables_to_constants(
sess,
graph_def,
['add']
)
with tf.gfile.GFile('./tmp/convert_vtoc/model.pd','wb') as f:
f.write(out_graph_def.SerializeToString())
這兩種保存方式的恢復(fù)也是不同的
#讀取模型(jupyter kernel should restart!)
import tensorflow as tf
saver=tf.train.import_meta_graph('./tmp/model_saver/model.ckpt.meta')
with tf.Session() as sess:
saver.restore(sess,'./tmp/model_saver/model.ckpt')
#通過張量名稱來獲取張量
print sess.run(tf.get_default_graph().get_tensor_by_name('v1_:0'))
但是平常開發(fā),我們更多的時(shí)候會(huì)使用到別人預(yù)訓(xùn)練好的模型,比如:Tensorflow官方維護(hù)的這些模型
壓縮包下載下來只有.ckpt文件(模型中每個(gè)變量的取值),沒有ckpt.meta(整個(gè)計(jì)算圖的結(jié)構(gòu))
這個(gè)時(shí)候,我們就需要從Code來獲取計(jì)算圖結(jié)構(gòu),這里以恢復(fù)VGG16模型舉例,代碼如下:
import vgg
import tensorflow as tf
IMAGE_SIZE = vgg.vgg_16.default_image_size
VGG16_CKPT = 'tmp/vgg_16.ckpt'
TMP_DIR = 'tmp'
def get_vgg_16_graph(path=VGG16_CKPT):
"""獲取 vgg16 計(jì)算圖 """
x = tf.placeholder(tf.float32, [None, IMAGE_SIZE, IMAGE_SIZE, 3])
vgg.vgg_16(x)
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess, path)
writer = tf.summary.FileWriter(TMP_DIR, sess.graph)
writer.close()
執(zhí)行tensorboard --logdir=TMP_DIR,訪問localhost:6006便可查看vgg16的計(jì)算圖
另外一種從.pd文件恢復(fù)模型:
def get_pool_3_reshape_values(sess, images):
"""
:param images 圖片路徑數(shù)組
通過inception-v3,將圖片處理成pool_3_reshape數(shù)據(jù),以供自定義全連接網(wǎng)絡(luò)訓(xùn)練使用
"""
with tf.gfile.FastGFile(INCEPTION_V3_PD, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
decode_jpeg_contents_tensor, pool_3_reshape_tensor = tf.import_graph_def(
graph_def,
return_elements=[DECODE_JPEG_CONTENTS, POOL_3_RESHAPE_NAME]
)
print decode_jpeg_contents_tensor, pool_3_reshape_tensor
images_2048 = []
for path in images:
img = get_pool_3_reshape_sigal_image_values(sess, pool_3_reshape_tensor, path)
images_2048.append(img)
return images_2048
完整代碼——這份代碼是使用inception-v3做遷移學(xué)習(xí)的時(shí)候,將訓(xùn)練圖片用訓(xùn)練好的inception-v3提取特征之后作為自定義分類網(wǎng)絡(luò)的輸入 的數(shù)據(jù)準(zhǔn)備代碼
2、TFRecord的使用
TFRecord是Tensorflow官方推薦的高效數(shù)據(jù)讀取方式。使用tfrecord的優(yōu)勢(shì)在于:Tensorflow有和tfrecord配套的一些函數(shù),可以加快數(shù)據(jù)的處理。實(shí)際讀取tfrecord數(shù)據(jù)時(shí),先以相應(yīng)的tfrecord文件為參數(shù),創(chuàng)建一個(gè)輸入隊(duì)列,這個(gè)隊(duì)列有一定的容量(視具體硬件限制,用戶可以設(shè)置不同的值),在一部分?jǐn)?shù)據(jù)出隊(duì)列時(shí),tfrecord中的其他數(shù)據(jù)就可以通過預(yù)取進(jìn)入隊(duì)列,并且這個(gè)過程和網(wǎng)絡(luò)的計(jì)算是獨(dú)立進(jìn)行的。也就是說,網(wǎng)絡(luò)每一個(gè)iteration的訓(xùn)練不必等待數(shù)據(jù)隊(duì)列準(zhǔn)備好再開始,隊(duì)列中的數(shù)據(jù)始終是充足的,而往隊(duì)列中填充數(shù)據(jù)時(shí),也可以使用多線程加速。
讀取原始數(shù)據(jù)轉(zhuǎn)成TFRecord文件存儲(chǔ)
def int64_feature(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def to_tfexample(image, label):
return tf.train.Example(features=tf.train.Features(feature={
'image': bytes_feature(image),
'label': int64_feature(label)
}))
def generate_tfrecord(writer):
sub_dirs = [_[0] for _ in os.walk(FLOWER_PHOTOS)][1:]
for index, dirname in enumerate(sub_dirs):
print 'label:%d, flower name: %s' % (index, os.path.basename(dirname))
# 拼接glob匹配的文件名
re = os.path.join(dirname, '*.jpg')
files = glob.glob(re)[:10] if IS_TEST else glob.glob(re)
for path in files:
image = Image.open(path)
resized = image.resize((IMAGE_SIZE, IMAGE_SIZE))
image_bytes = resized.tobytes()
example = to_tfexample(image_bytes, index)
writer.write(example.SerializeToString())
# 執(zhí)行數(shù)據(jù)轉(zhuǎn)換
def test_write():
with tf.python_io.TFRecordWriter(OUTPUT) as writer:
generate_tfrecord(writer)
讀取TFRecord文件
# 讀取TFRecord文件
def read_and_decode(filename_queue):
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
# 解析example
features = tf.parse_single_example(serialized_example, features={
'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)
})
single_image = tf.decode_raw(features['image'], tf.uint8)
single_image = tf.reshape(single_image, [IMAGE_SIZE, IMAGE_SIZE, 3])
single_label = tf.cast(features['label'], tf.int32)
return single_image, single_label
def get_batch():
filename_queue = tf.train.string_input_producer([OUTPUT])
single_image, single_label = read_and_decode(filename_queue)
image_batch, label_batch = tf.train.shuffle_batch(
[single_image, single_label],
batch_size=BATCH_SIZE,
num_threads=4,
capacity=50000,
min_after_dequeue=10000
)
return image_batch,label_batch
def test_read():
image_batch, label_batch = get_batch()
with tf.Session() as sess:
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
# 獲取10批次數(shù)據(jù)
for _ in range(10):
_image_batch, _label_batch = sess.run([image_batch,label_batch])
print _image_batch.shape,_label_batch
coord.request_stop()
coord.join(threads)
完整代碼
tensorflow_6_5_transfer_learning_datasets.ipynb(含flower_photos數(shù)據(jù)集下載鏈接)
3、Tensorflow-image
與圖像有關(guān)基本操作,比如隨機(jī)剪切、翻轉(zhuǎn)、標(biāo)注等API;對(duì)數(shù)據(jù)集進(jìn)行剪切翻轉(zhuǎn)旋轉(zhuǎn),一來可以增加數(shù)據(jù)集數(shù)量,二來還可以增加訓(xùn)練出來的模型的泛化能力,所以也是比較有用的。
tensorflow_7_2_image.ipynb

4、Tensorflow-slim
另外,Tensorflow官方維護(hù)的模型基本上都用slim封裝了,使得定義模型的代碼超級(jí)簡(jiǎn)潔,所以slim也是應(yīng)該了解的。
tensorflow_10_1_tensorflow_slim.ipynb
貼一個(gè)別人寫的:Tensorflow學(xué)習(xí): Slim tutorial,他也是翻譯別人的,沒翻譯完。
寫在后面
進(jìn)行到這里基本上對(duì)深度學(xué)習(xí)-Tensorflow有了客觀的認(rèn)識(shí);其實(shí)很多與深度學(xué)習(xí)有關(guān)的項(xiàng)目,也恰恰是利用了深度學(xué)習(xí),特別是卷積神經(jīng)網(wǎng)絡(luò)強(qiáng)大的特征提取能力,拿到這些特征我們便可以開開心心做一些其他想做事情;去找?guī)讉€(gè)開源項(xiàng)目學(xué)習(xí)下,一來看看人家是如何一步一步實(shí)現(xiàn)的,鞏固下代碼技能;二來就是感受下深度學(xué)習(xí)項(xiàng)目的套路,看能不能有所啟發(fā)。遇到懵逼的數(shù)學(xué)概念、公式,統(tǒng)計(jì)方面的知識(shí)也補(bǔ)一補(bǔ),差不多就這樣。