深度學(xué)習(xí)之Tensorflow 入門實(shí)踐

跟其他很多想學(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ù)的這些模型

Model TF-Slim File Checkpoint Top-1 Accuracy Top-5 Accuracy
Inception V1 Code inception_v1_2016_08_28.tar.gz 69.8 89.6
Inception V2 Code inception_v2_2016_08_28.tar.gz 73.9 91.8
Inception V3 Code inception_v3_2016_08_28.tar.gz 78.0 93.9
Inception V4 Code inception_v4_2016_09_09.tar.gz 80.2 95.2
Inception-ResNet-v2 Code inception_resnet_v2_2016_08_30.tar.gz 80.4 95.3
ResNet V1 50 Code resnet_v1_50_2016_08_28.tar.gz 75.2 92.2
ResNet V1 101 Code resnet_v1_101_2016_08_28.tar.gz 76.4 92.9
ResNet V1 152 Code resnet_v1_152_2016_08_28.tar.gz 76.8 93.2
ResNet V2 50^ Code resnet_v2_50_2017_04_14.tar.gz 75.6 92.8
ResNet V2 101^ Code resnet_v2_101_2017_04_14.tar.gz 77.0 93.7
ResNet V2 152^ Code resnet_v2_152_2017_04_14.tar.gz 77.8 94.1
ResNet V2 200 Code TBA 79.9* 95.2*
VGG 16 Code vgg_16_2016_08_28.tar.gz 71.5 89.8
VGG 19 Code vgg_19_2016_08_28.tar.gz 71.1 89.8
MobileNet_v1_1.0_224 Code mobilenet_v1_1.0_224.tgz 70.9 89.9
MobileNet_v1_0.50_160 Code mobilenet_v1_0.50_160.tgz 59.1 81.9
MobileNet_v1_0.25_128 Code mobilenet_v1_0.25_128.tgz 41.5 66.3
MobileNet_v2_1.4_224^* Code mobilenet_v2_1.4_224.tgz 74.9 92.5
MobileNet_v2_1.0_224^* Code mobilenet_v2_1.0_224.tgz 71.9 91.0
NASNet-A_Mobile_224# Code nasnet-a_mobile_04_10_2017.tar.gz 74.0 91.6
NASNet-A_Large_331# Code nasnet-a_large_04_10_2017.tar.gz 82.7 96.2
PNASNet-5_Large_331 Code pnasnet-5_large_2017_12_13.tar.gz 82.9 96.2

壓縮包下載下來只有.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ǔ),差不多就這樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容