1. 程式人生 > 其它 >人臉識別智慧小程式 | Tensorflow基礎 | 03

人臉識別智慧小程式 | Tensorflow基礎 | 03

目錄

TensorFlow概念介紹-Graph

TensorFlow:Google開源的基於資料流圖的科學計算庫,適用於機器學習、深度學習等人工智慧領域。

TensorFlow的原始碼是開源的,可以在github上進行下載。

安裝可以直接通過pip直接安裝,也可以把原始碼下載到本地自己進行編譯。

然後TF中提供了很多模型,包括計算機視覺和自然語言處理的,在搭建模型的時候可以直接呼叫這裡面的model。

  • 前端:程式設計模型、構造計算圖、Python、Cpp、Java

網路也被稱為計算圖。

通過構造這樣的一個圖結構,並定好資料流向,來完成整個推理運算。

  • 後端:執行計算圖,C++

前端使用Python搭建網路模型,構造出來的計算圖是不會運算的。前端搭建好計算圖,並給定資料,後端再經過運算,得到輸出。

Graph:描述了整個計算過程。

  • 宣告(單個/多個)

一個圖表示一個網路,如果需要用到多個網路來解決一個任務,那就需要宣告多個圖,也就是多個Graph。

  • 儲存為pb檔案

pb檔案包括了網路的結構和網路的引數。

  • 從pb中恢復Graph

  • Tensorboard視覺化

Graph是在前端來完成的,並且可以通過tf進行視覺化展示。

上圖是一個圖形化的結果。

Session-Tensor-Operation-Feed-Fetch介紹

Session

  • Graph必須在Session的上下文中執行
  • Session將Graph的op分發到諸如CPU或GPU之類的裝置上執行

Graph <=> Session <=> 後端

Session相當於是Graph和後端的一個溝通的橋樑。

注入機制: 實際上就是Session具體完成計算圖的過程,也是在注入機制中完成了前端和後端這個橋樑的作用。

Tensor

  • 在tf中,所有在節點之間傳遞的資料都為Tensor物件
  • N維陣列,影象:\((batch*height*width*channel)\)

上圖是tensor常用的定義方式,重點掌握前三種。

tf.constant() # 常量
tf.Variable() # 變數
tr.placeholder() # 佔位符

Operation(op)

  • tf Graph中的計算節點,輸入輸出均為Tensor
  • 呼叫Session.run(tensor)或者tensor.eval()方可獲取該Tensor的值

上圖中的兩個add,一個maltiply都是op。

具體計算圖的op(操作)在哪裡完成,可以通過Session來指定完成這些op的裝置資源。

Feed:通過feed為計算圖注入值

Feed為Tensor完成具體值的注入,這裡注入的值通常是那些佔位符。

佔位符是在構造計算圖時,那些沒有辦法確定的Tensor。

Fetch: 使用Fetch獲取計算結果

TensorFlow中核心API介面

上面是常用的op操作。

tf.nn 是常用的網路搭建API。

tf.train 定義了很多和優化相關的一些函式。

TFRecord: tf提供了TFRcord的格式來統一儲存資料

TFRecord將影象資料和標籤放在一起的二進位制檔案(protocol buffer),能更好的利用記憶體,實現快速的複製、移動、讀取、儲存。

TensorFlow資料讀取機制與API方法

如果直接從磁碟讀取資料,那麼IO的等待時間會造成計算資源的浪費。

檔名佇列有什麼用呢?這裡就涉及到我們模型訓練的一個概念——Epoch。

訓練樣本是分為一個一個batch的,意思就是每次從訓練樣本中取出一部分樣本,用這個一部分樣本來對網路引數進行調整,進行模型的訓練。

假如訓練樣本有10000個,batch的數量為100,那麼一個Epoch就有100個batch。每取完100個batch(不重複),就叫做跑完了一個Epoch。一個Epoch就意味著全部的樣本都在網路中進行了一遍計算。

通過檔名佇列,可以完成對Epoch更好的管理。比如在檔名佇列中構造出3個Epoch,用A,B,C表示,那麼它們都是包含了所有的檔案列表的,那麼就可以方便進行shuffle。

Cifar10資料解析程式設計案例

接下來以Cifar-10為例,介紹如何使用tf進行資料讀取&資料打包。

Cifar-10也是影象分類任務,在卷積神經網中,我們評價一個模型效果的好壞,可以使用ImageNet資料集對模型進行效能評估,也可以使用Cifar-10或Cifar-100。

按照如下設定,本地連線遠端程式設計環境!

cifar10資料集下載地址

http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz

下載好cifar10資料,解壓後,發現其是二進位制格式存放的,為了更方便的展示讀寫的效果,會對這些二進位制檔案進行解析,將其解析成具體的圖片,並將其存放在data/image/的train/和test/下。

下面的程式碼是對cifar-10圖片進行解碼。

import urllib
import urllib.request
import os
import sys
import tarfile
import glob
import pickle
import numpy as np
import cv2  # pip install opencv-python


def download_and_uncompress_tarball(tarball_url, dataset_dir):
    """
    完成對cifar10資料的下載和解壓
    Downloads the `tarball_url` and uncompresses it locally.
    Args:
      tarball_url: The URL of a tarball file.
      dataset_dir: The directory where the temporary files are stored.

    """
    filename = tarball_url.split('/')[-1]
    filepath = os.path.join(dataset_dir, filename)

    def _progress(count, block_size, total_size):
        sys.stdout.write('\r>> Downloading %s %.1f%%' % (
            filename, float(count * block_size) / float(total_size) * 100.0))
        sys.stdout.flush()

    filepath, _ = urllib.request.urlretrieve(tarball_url, filepath, _progress)
    print()
    statinfo = os.stat(filepath)
    print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
    tarfile.open(filepath, 'r:gz').extractall(dataset_dir)


DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz'  # cifar10資料集
DATA_DIR = 'data'

# cifar10的10個分類
classification = ['airplane',
                  'automobile',
                  'bird',
                  'cat',
                  'deer',
                  'dog',
                  'frog',
                  'horse',
                  'ship',
                  'truck']


def unpickle(file):
    """
    這是cifar10網站給的關於檔案解析的指令碼
    :param file: 二進位制檔案
    :return: 解析好的鍵值對
    """
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict


def to_image(from_file, to_file):
    """
    將cifar10還原成圖片
    儲存至  to_file/train/   to_file/test/
    :param from_file: 圖片二進位制檔案
    :param to_file: 圖片儲存路徑
    :return: 
    """
    # 下面將二進位制檔案解析成圖片
    folders = from_file
    # glob模組的主要方法就是glob,該方法返回所有匹配的檔案路徑列表(list)
    # train_test_file = ["/data_batch*", "/test_batch*"]
    for x in ["train", "test"]:
        if x == "train":
            t_files = glob.glob(folders + "/data_batch*")
        else:
            t_files = glob.glob(folders + "/test_batch*")
        # 定義資料和標籤為一個空格list
        data = []
        labels = []
        # 將每個檔案都進行解碼,得到解碼後的資料
        for file in t_files:
            dt = unpickle(file)
            data += list(dt[b"data"])
            labels += list(dt[b"labels"])

        print(labels)  # 列印標籤 進行檢視

        # 在cifar10是通道優先的
        imgs = np.reshape(data, [-1, 3, 32, 32])

        for i in range(imgs.shape[0]):  # imgs.shape[0] 圖片資料總量
            im_data = imgs[i, ...]  # 獲取第i張圖片
            im_data = np.transpose(im_data, [1, 2, 0])  # 將channel交換到最後一維
            im_data = cv2.cvtColor(im_data, cv2.COLOR_RGB2BGR)  # 將RGB轉換為BGR模式

            f = "{}/{}/{}".format("data/image", x, classification[labels[i]])
            print(f)
            if not os.path.exists(f):
                os.makedirs(f)

            # 命名 編號.jpg
            cv2.imwrite("{}/{}.jpg".format(f, str(i)), im_data)
    print("Finish!")


if __name__ == '__main__':
    # 下載和解壓cifar10資料
    # download_and_uncompress_tarball(DATA_URL, DATA_DIR)
    to_image("data/cifar-10-batches-py", "data/image/")

Tensorflow中TFRecord資料打包程式設計案例

然後需要對解碼好的圖片進行打包,生成TFRecord Writer。

import tensorflow as tf
import cv2
import numpy as np
import glob
import os
import warnings
from tqdm import tqdm
warnings.filterwarnings("ignore")

classification = ['airplane',
                  'automobile',
                  'bird',
                  'cat',
                  'deer',
                  'dog',
                  'frog',
                  'horse',
                  'ship',
                  'truck']


if __name__ == "__main__":
    for x in ["test", "train"]:
        idx = 0
        im_data = []
        im_labels = []
        for path in classification:
            path = "data/image/%s/" % x + path
            im_list = glob.glob(path + "/*")
            im_label = [idx for i in range(im_list.__len__())]
            idx += 1
            im_data += im_list
            im_labels += im_label

        print(im_labels[:10])
        print(im_data[:10])

        tfrecord_file = "data/%s.tfrecord" % x
        with tf.python_io.TFRecordWriter(tfrecord_file) as writer:
            # 使用shuffle進行打亂
            index = [i for i in range(im_data.__len__())]
            np.random.shuffle(index)

            for i in tqdm(range(im_data.__len__())):
                im_d = im_data[index[i]]
                im_l = im_labels[index[i]]
                data = cv2.imread(im_d)  # 使用opencv讀取圖片
                # 下面是另一種圖片讀取方式
                #data = tf.gfile.FastGFile(im_d, "rb").read()

                # 使用tf.train.Example將features編碼資料封裝成特定的PB協議格式
                ex = tf.train.Example(
                    features=tf.train.Features(
                        feature={
                            "image": tf.train.Feature(
                                bytes_list=tf.train.BytesList(
                                    value=[data.tobytes()])),
                            "label": tf.train.Feature(
                                int64_list=tf.train.Int64List(
                                    value=[im_l])),
                        }
                    )
                )
                # 將example資料系列化為字串,並將系列化為字串的example資料寫入協議緩衝區
                writer.write(ex.SerializeToString())

如何使用tf.train.slice_input_producer讀取檔案列表中的樣本

從檔案列表中讀取樣本。

import tensorflow as tf

images = ['image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg']
labels = [1, 2, 3, 4]

"""
tf.train.slice_input_producer是一個tensor生成器,作用是按照設定,每次從一個tensor列表中按順序或者隨機抽取出一個tensor放入檔名佇列。
"""
[images, labels] = tf.train.slice_input_producer([images, labels],num_epochs=None,shuffle=True)

with tf.Session() as sess:
    sess.run(tf.local_variables_initializer())
    tf.train.start_queue_runners(sess=sess)
    for i in range(10):
        print(sess.run([images, labels]))

如何使用tf.train.string_input_producer讀取檔案列表中的樣本

從檔案資料中讀取樣本。

import tensorflow as tf

filename = ['data/A.csv', 'data/B.csv', 'data/C.csv']

file_queue = tf.train.string_input_producer(filename,
                                            shuffle=True,
                                            num_epochs=None)
reader = tf.WholeFileReader()
key, value = reader.read(file_queue)

with tf.Session() as sess:
    sess.run(tf.local_variables_initializer())
    tf.train.start_queue_runners(sess=sess)
    for i in range(10):
        print(sess.run([key, value]))

train.slice_input_producer 和 train.string_input_producer 的差別

主要的區別就是string_input_producer輸出的結果是一個佇列,而slice_input_producer輸出的結果是一個tensor。後者可以直接用sess.run()的方式獲得tensor的值,但是對於string_input_producer 沒有辦法這樣直接獲取。

如何通過TF對已經打包過的資料進行解析

import tensorflow as tf
import cv2
filelist = ['data/train.tfrecord']
file_queue = tf.train.string_input_producer(filelist,
                                            num_epochs=None,
                                            shuffle=True)
reader = tf.TFRecordReader()
_, ex = reader.read(file_queue)  # 解碼得到打包的資料


# 定義好feature
feature = {
    'image': tf.FixedLenFeature([], tf.string),
    'label': tf.FixedLenFeature([], tf.int64)
}

batchsize = 2
batch = tf.train.shuffle_batch([ex], batchsize, capacity=batchsize*10,
                               min_after_dequeue=batchsize*5)

example = tf.parse_example(batch, features=feature)

image = example['image']
label = example['label']

image = tf.decode_raw(image, tf.uint8)
image = tf.reshape(image, [-1, 32, 32, 3])

with tf.Session() as sess:
    sess.run(tf.local_variables_initializer())
    tf.train.start_queue_runners(sess=sess)

    for i in range(1):
        image_bth, _ = sess.run([image, label])
        cv2.imshow("image", image_bth[0, ...])
        cv2.waitKey(0)

上面的示例程式碼完成了對TFRecord資料的讀取,並且每次讀取的時候都是讀取了一個batch_size的資料,也進行了視覺化。

在進行模型訓練的時候,就是這樣,每次讀取一個batch_size的資料,並且將這個batch_size的資料餵給網路訓練。

TF中的高階API介面

之前介紹的是一些tf的基本api介面,如果我們在設計網路的時候,使用這些基本的api介面,這時候就需要寫大量的程式碼。

在tf中,有更加高層的封裝,其中用的最多的就是slim和keras。

TF中的資料增強

資料增強是防止過擬合非常常見的一個手段,在tf中可以通過 tf.image來對影象進行資料增強。

對影象資料進行擾動,進而提高模型對噪聲的魯棒性。

第一幅圖是原圖,後面的都是經過資料增強之後獲取到的影象,這時候就相當於是產生了一些新的樣本,而深度學習是要依賴於大資料的,資料越充分,那麼學到的模型就更加的魯棒。因此在進行模型訓練的時候,資料增強是必須要使用的一種手段。

Tensorboard 除錯技巧

Tensorboard:可以進行網路視覺化/訓練中間結果視覺化。

訓練中間結果採用sess.run()打印出來,或可以新增到tensorboard中,進行視覺化展示。

小結

Tensorflow是什麼?

TensorFlow:Google開源的基於資料流圖的科學計算庫,適用於機器學習、深度學習等人工智慧領域。

TensorFlow的原始碼是開源的,可以在github上進行下載。

安裝可以直接通過pip直接安裝,也可以把原始碼下載到本地自己進行編譯。

**然後TF中提供了很多模型,包括計算機視覺和自然語言處理的,在搭建模型的時候可以直接呼叫這裡面的model。**

TensorFlow的架構

*   前端:程式設計模型、構造計算圖、Python、Cpp、Java

網路也被稱為計算圖。

通過構造這樣的一個圖結構,並定好資料流向,來完成整個推理運算。

*   後端:執行計算圖,C++

前端使用Python搭建網路模型,構造出來的計算圖是不會運算的。前端搭建好計算圖,並給定資料,後端再經過運算,得到輸出。

Graph

Graph:描述了整個計算過程。
*   宣告(單個/多個)

一個圖表示一個網路,如果需要用到多個網路來解決一個任務,那就需要宣告多個圖,也就是多個Graph。
*   儲存為pb檔案

pb檔案包括了網路的結構和網路的引數。
*   從pb中恢復Graph
*   Tensorboard視覺化



Graph是在前端來完成的,並且可以通過tf進行視覺化展示。
上圖是一個圖形化的結果。

Session

Session
*   Graph必須在Session的上下文中執行
*   Session將Graph的op分發到諸如CPU或GPU之類的裝置上執行

Graph <=> Session <=> 後端
Session相當於是Graph和後端的一個溝通的橋樑。


注入機制: 實際上就是Session具體完成計算圖的過程,也是在注入機制中完成了前端和後端這個橋樑的作用。

Tensor

Tensor
*   在tf中,所有在節點之間傳遞的資料都為Tensor物件
*   N維陣列,影象:$(batch*height*width*channel)$

上圖是tensor常用的定義方式,重點掌握前三種。
tf.constant() # 常量
tf.Variable() # 變數
tr.placeholder() # 佔位符

Operation

Operation(op)
*   tf Graph中的**計算節點**,輸入輸出均為Tensor
*   呼叫Session.run(tensor)或者tensor.eval()方可獲取該Tensor的值

上圖中的兩個add,一個maltiply都是op。
具體計算圖的op(操作)在哪裡完成,可以通過Session來指定完成這些op的裝置資源。

Feed & Fetch

Feed:通過feed為計算圖注入值
Feed為Tensor完成具體值的注入,這裡注入的值通常是那些佔位符。
佔位符是在構造計算圖時,那些沒有辦法確定的Tensor。

Fetch: 使用Fetch獲取計算結果

TFRecord

TFRecord: tf提供了TFRcord的格式來統一儲存資料

TFRecord將影象資料和標籤放在一起的二進位制檔案(protocol buffer),能更好的利用記憶體,實現快速的複製、移動、讀取、儲存。

tf的資料讀取機制

輸入資料 -> 檔名佇列 -> 記憶體佇列 -> 計算

檔名佇列有什麼用呢?這裡就涉及到我們模型訓練的一個概念——Epoch。

訓練樣本是分為一個一個batch的,意思就是每次從訓練樣本中取出一部分樣本,用這個一部分樣本來對網路引數進行調整,進行模型的訓練。

假如訓練樣本有10000個,batch的數量為100,那麼一個Epoch就有100個batch。每取完100個batch(不重複),就叫做跑完了一個Epoch。一個Epoch就意味著全部的樣本都在網路中進行了一遍計算。

通過檔名佇列,可以完成對Epoch更好的管理。比如在檔名佇列中構造出3個Epoch,用A,B,C表示,那麼它們都是包含了所有的檔案列表的,那麼就可以方便進行shuffle。

關於TFRecord的Writer和Reader

這是一個模板程式碼的.. 
知道這個東西,然後用的時候在對照著進行修改!

train.slice_input_producer 和 train.string_input_producer 的差別

主要的區別就是string_input_producer輸出的結果是一個佇列,而slice_input_producer輸出的結果是一個tensor。後者可以直接用sess.run()的方式獲得tensor的值,但是對於string_input_producer 沒有辦法這樣直接獲取。

tf的高層介面

之前介紹的是一些tf的基本api介面,如果我們在設計網路的時候,使用這些基本的api介面,這時候就需要寫大量的程式碼。

在tf中,有更加高層的封裝,其中用的最多的就是slim和keras。

資料增強

資料增強是防止過擬合非常常見的一個手段,在tf中可以通過 tf.image來對影象進行資料增強。

對影象資料進行擾動,進而提高模型對噪聲的魯棒性。


第一幅圖是原圖,後面的都是經過資料增強之後獲取到的影象,這時候就相當於是產生了一些新的樣本,而深度學習是要依賴於大資料的,資料越充分,那麼學到的模型就更加的魯棒。**因此在進行模型訓練的時候,資料增強是必須要使用的一種手段。**