標籤: 包裝設計

  • 深入理解JVM(③)ZGC收集器

    深入理解JVM(③)ZGC收集器

    前言

    ZGC是一款在JDK11中新加入的具有實驗性質的低延遲垃圾收集器,目前僅支持Linux/x86-64。ZGC收集器是一款基於Region內存布局的,(暫時)不設分代的,使用了讀屏障、染色指針和內存多重映射等技術來實現可併發的標記-整理算法的,以低延遲為首要目標的一款垃圾收集器。

    ZGC布局

    與Shenandoah和G1一樣,ZGC也採取基於Region的堆內存布局,但與他們不同的是,ZGC的Region具有動態性(動態的創建和銷毀,以及動態的區域容量大小)。
    ZGC的Region可以分為三類:

    • 小型Region:容量固定為2MB,用於放置小於256KB的小對象。
    • 中型Region:容量固定為32MB,用於放置大於等於256KB但小於4MB的對象。
    • 大型Region:容量不固定,可以動態變化,但必須為2MB的整數倍,用於存放4MB或以上的大對象。並且每個大型Region只會存放一個對象。
      ZGC內存布局圖:

    染色指針

    HotSpot的垃圾收集器,有幾種不同的標記實現方案。

    • 把標記直接記錄在對象頭上(Serial 收集器)。
    • 把標記記錄在於對象相互獨立的數據結構上(G1、Shenandoah使用了一種相當於堆內存的1/64大小的,稱為BitMap的結構來記錄標記信息)。
    • ZGC染色指針直接把標記信息記載引用對象的指針上。
      染色指針是一種直接將少量額外的信息存儲在指針上的技術。
      目前Linux下64位指針的高18位不能用來尋址,但剩餘的46位指針所能支持的64TB內存仍然鞥呢夠充分滿足大型服務器的需要。鑒於此,ZGC將其高4位提取出來存儲四個標誌信息。
      通過這些標誌虛擬機就可以直接從指針中看到器引用對象的三色標記狀態(Marked0、Marked1)、是否進入了重分配集(是否被移動過——Remapped)、是否只能通過finalize()方法才能被訪問到(Finalizable)。由於這些標誌位進一步壓縮了原本只有46位的地址空寂,導致ZGC能夠管理的內存不可以超過4TB。
      染色指針示意圖:

    染色指針的優勢

    • 染色指針可以使得一旦某個Region的存活對象被移走之後,這個Region立即就能夠被釋放和重用掉,而不必等待整個堆中所有指令向該Region的引用都被修正後才能清理。
    • 染色指針可以大幅減少在垃圾收集過程中內存屏障的使用數量,設置內存屏障,尤其是在寫屏障的目的通常是為了記錄對象引用的變動情況,如果將這些信息直接維護在指針中,顯然就可以省去一些專門的記錄操作。
    • 染色指針可以作為一種可擴展的存儲結構用來記錄更多與對象標記、重定位過程相關的數據,以便日後進一步提高性能。

    內存多重映射

    Linux/x86-64平台上ZGC使用了多重映射(Multi-Mapping)將多個不同的虛擬內存地址映射到同一物理內存地址上,這是一種多對一映射,意味着ZGC在虛擬內存中看到的地址空寂要比實際的堆內存容量來的更大。把染色指針中的標誌位看作是地址的分段符,那隻要將這些不同的地址段都映射到同一物理內褲空間,經過多重映射轉換后,就可以使用染色指針正常進行尋址了。
    多重映射下的尋址:

    ZGC的運作過程

    ZGC的運作過程大致可劃分為以下四個大的階段。四個階段都是可以併發執行的,僅是兩個階段中間會存在短暫的停頓小階段。
    運作過程如下:

    • 併發標記(Concurrent Mark): 與G1、Shenandoah一樣,併發標記是遍歷對象圖做可達性分析的階段,前後也要經過類似於G1、Shenandoah的初始標記、最終標記的短暫停頓,而且這些停頓階段所做的事情在目標上也是相類似的。
    • 併發預備重分配( Concurrent Prepare for Relocate): 這個階段需要根據特定的查詢條件統計得出本次收集過程要清理哪些Region,將這些Region組成重分配集(Relocation Set)。
    • 併發重分配(Concurrent Relocate): 重分配是ZGC執行過程中的核心階段,這個過程要把重分配集中的存活對象複製到新的Region上,併為重分配集中的每個Region維護一個轉發表(Forward Table),記錄從舊對象到新對象的轉向關係。
    • 併發重映射(Concurrent Remap): 重映射所做的就是修正整個堆中指向重分配集中舊對象的所有引用,ZGC的併發映射並不是以一個必須要“迫切”去完成的任務。ZGC很巧妙地把併發重映射階段要做的工作,合併到下一次垃圾收集循環中的併發標記階段里去完成,反正他們都是要遍歷所有對象的,這樣合併節省了一次遍歷的開銷。

    ZGC的優劣勢

    • 缺點:浮動垃圾
      當ZGC準備要對一個很大的堆做一次完整的併發收集,駕駛其全過程要持續十分鐘以上,由於應用的對象分配速率很高,將創造大量的新對象,這些新對象很難進入當次收集的標記範圍,通常就只能全部作為存活對象來看待(儘管其中絕大部分對象都是朝生夕滅),這就產生了大量的浮動垃圾。
      目前唯一的辦法就是盡可能地去增加堆容量大小,獲取更多喘息的時間。但若要從根本上解決,還是需要引入分代收集,讓新生對象都在一個專門的區域中創建,然後針對這個區域進行更頻繁、更快的收集。
    • 優點:高吞吐量、低延遲
      ZGC是支持“NUMA-Aware”的內存分配。MUMA(Non-Uniform Memory Access,非統一內存訪問架構)是一種多處理器或多核處理器計算機所設計的內存架構。
      現在多CPU插槽的服務器都是Numa架構,比如兩顆CPU插槽(24核),64G內存的服務器,那其中一顆CPU上的12個核,訪問從屬於它的32G本地內存,要比訪問另外32G遠端內存要快得多。
      ZGC默認支持NUMA架構,在創建對象時,根據當前線程在哪個CPU執行,優先在靠近這個CPU的內存進行分配,這樣可以顯著的提高性能,在SPEC JBB 2005 基準測試里獲得40%的提升。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • Tensorflow 中(批量)讀取數據的案列分析及TFRecord文件的打包與讀取

    Tensorflow 中(批量)讀取數據的案列分析及TFRecord文件的打包與讀取

    內容概要:

    單一數據讀取方式:

      第一種:slice_input_producer()

    # 返回值可以直接通過 Session.run([images, labels])查看,且第一個參數必須放在列表中,如[...]
    [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)

      第二種:string_input_producer()

    # 需要定義文件讀取器,然後通過讀取器中的 read()方法來獲取數據(返回值類型 key,value),再通過 Session.run(value)查看
    file_queue = tf.train.string_input_producer(filename, num_epochs=None, shuffle=True)

    reader = tf.WholeFileReader() # 定義文件讀取器
    key, value = reader.read(file_queue)    # key:文件名;value:文件中的內容

      !!!num_epochs=None,不指定迭代次數,這樣文件隊列中元素個數也不限定(None*數據集大小)。

      !!!如果不是None,則此函數創建本地計數器 epochs,需要使用local_variables_initializer()初始化局部變量

      !!!以上兩種方法都可以生成文件名隊列。

    (隨機)批量數據讀取方式:

    batchsize=2  # 每次讀取的樣本數量
    tf.train.batch(tensors, batch_size=batchsize)
    tf.train.shuffle_batch(tensors, batch_size=batchsize, capacity=batchsize*10, min_after_dequeue=batchsize*5) # capacity > min_after_dequeue

      !!!以上所有讀取數據的方法,在Session.run()之前必須開啟文件隊列線程 tf.train.start_queue_runners()

     TFRecord文件的打包與讀取

     

     一、單一數據讀取方式

    第一種:slice_input_producer()

    def slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None)

    案例1:

    import tensorflow as tf
    
    images = ['image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg']
    labels = [1, 2, 3, 4]
    
    # [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)
    
    # 當num_epochs=2時,此時文件隊列中只有 2*4=8個樣本,所有在取第9個樣本時會出錯
    # [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=2, shuffle=True)
    
    data = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)
    print(type(data))   # <class 'list'>
    
    with tf.Session() as sess:
        # sess.run(tf.local_variables_initializer())
        sess.run(tf.local_variables_initializer())
        coord = tf.train.Coordinator()  # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)  # 開始在圖表中收集隊列運行器
    
        for i in range(10):
            print(sess.run(data))
    
        coord.request_stop()
        coord.join(threads)
    
    """
    運行結果:
    [b'image2.jpg', 2]
    [b'image1.jpg', 1]
    [b'image3.jpg', 3]
    [b'image4.jpg', 4]
    [b'image2.jpg', 2]
    [b'image1.jpg', 1]
    [b'image3.jpg', 3]
    [b'image4.jpg', 4]
    [b'image2.jpg', 2]
    [b'image3.jpg', 3]
    """

      !!!slice_input_producer() 中的第一個參數需要放在一個列表中,列表中的每個元素可以是 List 或 Tensor,如 [images,labels],

      !!!num_epochs設置

     

     第二種:string_input_producer()

    def string_input_producer(string_tensor, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None, cancel_op=None)

    文件讀取器

      不同類型的文件對應不同的文件讀取器,我們稱為 reader對象

      該對象的 read 方法自動讀取文件,並創建數據隊列,輸出key/文件名,value/文件內容;

    reader = tf.TextLineReader()      ### 一行一行讀取,適用於所有文本文件

    reader = tf.TFRecordReader() ### A Reader that outputs the records from a TFRecords file
    reader = tf.WholeFileReader() ### 一次讀取整個文件,適用圖片

     案例2:讀取csv文件

    iimport 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=2)   # 生成文件名隊列
    reader = tf.WholeFileReader()           # 定義文件讀取器(一次讀取整個文件)
    # reader = tf.TextLineReader()            # 定義文件讀取器(一行一行的讀)
    key, value = reader.read(file_queue)    # key:文件名;value:文件中的內容
    print(type(file_queue))
    
    init = [tf.global_variables_initializer(), tf.local_variables_initializer()]
    with tf.Session() as sess:
        sess.run(init)
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)
        try:
            while not coord.should_stop():
                for i in range(6):
                    print(sess.run([key, value]))
                break
        except tf.errors.OutOfRangeError:
            print('read done')
        finally:
            coord.request_stop()
        coord.join(threads)
    
    """
    reader = tf.WholeFileReader()           # 定義文件讀取器(一次讀取整個文件)
    運行結果:
    [b'data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
    [b'data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
    [b'data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']
    [b'data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']
    [b'data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
    [b'data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
    """
    """
    reader = tf.TextLineReader()           # 定義文件讀取器(一行一行的讀)
    運行結果:
    [b'data/B.csv:1', b'4.jpg,4']
    [b'data/B.csv:2', b'5.jpg,5']
    [b'data/B.csv:3', b'6.jpg,6']
    [b'data/C.csv:1', b'7.jpg,7']
    [b'data/C.csv:2', b'8.jpg,8']
    [b'data/C.csv:3', b'9.jpg,9']
    """

    案例3:讀取圖片(每次讀取全部圖片內容,不是一行一行)

    import tensorflow as tf
    
    filename = ['1.jpg', '2.jpg']
    filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=1)
    reader = tf.WholeFileReader()              # 文件讀取器
    key, value = reader.read(filename_queue)   # 讀取文件 key:文件名;value:圖片數據,bytes
    
    with tf.Session() as sess:
        tf.local_variables_initializer().run()
        coord = tf.train.Coordinator()      # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)
    
        for i in range(filename.__len__()):
            image_data = sess.run(value)
            with open('img_%d.jpg' % i, 'wb') as f:
                f.write(image_data)
        coord.request_stop()
        coord.join(threads)

     

     二、(隨機)批量數據讀取方式:

      功能:shuffle_batch() 和 batch() 這兩個API都是從文件隊列中批量獲取數據,使用方式類似;

    案例4:slice_input_producer() 與 batch()

    import tensorflow as tf
    import numpy as np
    
    images = np.arange(20).reshape([10, 2])
    label = np.asarray(range(0, 10))
    images = tf.cast(images, tf.float32)  # 可以註釋掉,不影響運行結果
    label = tf.cast(label, tf.int32)     # 可以註釋掉,不影響運行結果
    
    batchsize = 6   # 每次獲取元素的數量
    input_queue = tf.train.slice_input_producer([images, label], num_epochs=None, shuffle=False)
    image_batch, label_batch = tf.train.batch(input_queue, batch_size=batchsize)
    
    # 隨機獲取 batchsize個元素,其中,capacity:隊列容量,這個參數一定要比 min_after_dequeue 大
    # image_batch, label_batch = tf.train.shuffle_batch(input_queue, batch_size=batchsize, capacity=64, min_after_dequeue=10)
    
    with tf.Session() as sess:
        coord = tf.train.Coordinator()      # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)     # 開始在圖表中收集隊列運行器
        for cnt in range(2):
            print("第{}次獲取數據,每次batch={}...".format(cnt+1, batchsize))
            image_batch_v, label_batch_v = sess.run([image_batch, label_batch])
            print(image_batch_v, label_batch_v, label_batch_v.__len__())
    
        coord.request_stop()
        coord.join(threads)
    
    """
    運行結果:
    第1次獲取數據,每次batch=6...
    [[ 0.  1.]
     [ 2.  3.]
     [ 4.  5.]
     [ 6.  7.]
     [ 8.  9.]
     [10. 11.]] [0 1 2 3 4 5] 6
    第2次獲取數據,每次batch=6...
    [[12. 13.]
     [14. 15.]
     [16. 17.]
     [18. 19.]
     [ 0.  1.]
     [ 2.  3.]] [6 7 8 9 0 1] 6
    """

     案例5:從本地批量的讀取圖片 — string_input_producer() 與 batch()

     1 import tensorflow as tf
     2 import glob
     3 import cv2 as cv
     4 
     5 def read_imgs(filename, picture_format, input_image_shape, batch_size=1):
     6     """
     7     從本地批量的讀取圖片
     8     :param filename: 圖片路徑(包括圖片的文件名),[]
     9     :param picture_format: 圖片的格式,如 bmp,jpg,png等; string
    10     :param input_image_shape: 輸入圖像的大小; (h,w,c)或[]
    11     :param batch_size: 每次從文件隊列中加載圖片的數量; int
    12     :return: batch_size張圖片數據, Tensor
    13     """
    14     global new_img
    15     # 創建文件隊列
    16     file_queue = tf.train.string_input_producer(filename, num_epochs=1, shuffle=True)
    17     # 創建文件讀取器
    18     reader = tf.WholeFileReader()
    19     # 讀取文件隊列中的文件
    20     _, img_bytes = reader.read(file_queue)
    21     # print(img_bytes)    # Tensor("ReaderReadV2_19:1", shape=(), dtype=string)
    22     # 對圖片進行解碼
    23     if picture_format == ".bmp":
    24         new_img = tf.image.decode_bmp(img_bytes, channels=1)
    25     elif picture_format == ".jpg":
    26         new_img = tf.image.decode_jpeg(img_bytes, channels=3)
    27     else:
    28         pass
    29     # 重新設置圖片的大小
    30     # new_img = tf.image.resize_images(new_img, input_image_shape)
    31     new_img = tf.reshape(new_img, input_image_shape)
    32     # 設置圖片的數據類型
    33     new_img = tf.image.convert_image_dtype(new_img, tf.uint8)
    34 
    35     # return new_img
    36     return tf.train.batch([new_img], batch_size)
    37 
    38 
    39 def main():
    40     image_path = glob.glob(r'F:\demo\FaceRecognition\人臉庫\ORL\*.bmp')
    41     image_batch = read_imgs(image_path, ".bmp", (112, 92, 1), 5)
    42     print(type(image_batch))
    43     # image_path = glob.glob(r'.\*.jpg')
    44     # image_batch = read_imgs(image_path, ".jpg", (313, 500, 3), 1)
    45 
    46     sess = tf.Session()
    47     sess.run(tf.local_variables_initializer())
    48     tf.train.start_queue_runners(sess=sess)
    49 
    50     image_batch = sess.run(image_batch)
    51     print(type(image_batch))    # <class 'numpy.ndarray'>
    52 
    53     for i in range(image_batch.__len__()):
    54         cv.imshow("win_"+str(i), image_batch[i])
    55     cv.waitKey()
    56     cv.destroyAllWindows()
    57 
    58 def start():
    59     image_path = glob.glob(r'F:\demo\FaceRecognition\人臉庫\ORL\*.bmp')
    60     image_batch = read_imgs(image_path, ".bmp", (112, 92, 1), 5)
    61     print(type(image_batch))    # <class 'tensorflow.python.framework.ops.Tensor'>
    62 
    63 
    64     with tf.Session() as sess:
    65         sess.run(tf.local_variables_initializer())
    66         coord = tf.train.Coordinator()      # 線程的協調器
    67         threads = tf.train.start_queue_runners(sess, coord)     # 開始在圖表中收集隊列運行器
    68         image_batch = sess.run(image_batch)
    69         print(type(image_batch))    # <class 'numpy.ndarray'>
    70 
    71         for i in range(image_batch.__len__()):
    72             cv.imshow("win_"+str(i), image_batch[i])
    73         cv.waitKey()
    74         cv.destroyAllWindows()
    75 
    76         # 若使用 with 方式打開 Session,且沒加如下2行語句,則會出錯
    77         # ERROR:tensorflow:Exception in QueueRunner: Enqueue operation was cancelled;
    78         # 原因:文件隊列線程還處於工作狀態(隊列中還有圖片數據),而加載完batch_size張圖片會話就會自動關閉,同時關閉文件隊列線程
    79         coord.request_stop()
    80         coord.join(threads)
    81 
    82 
    83 if __name__ == "__main__":
    84     # main()
    85     start()

    從本地批量的讀取圖片案例

     

    案列6:TFRecord文件打包與讀取

     1 def write_TFRecord(filename, data, labels, is_shuffler=True):
     2     """
     3     將數據打包成TFRecord格式
     4     :param filename: 打包後路徑名,默認在工程目錄下創建該文件;String
     5     :param data: 需要打包的文件路徑名;list
     6     :param labels: 對應文件的標籤;list
     7     :param is_shuffler:是否隨機初始化打包后的數據,默認:True;Bool
     8     :return: None
     9     """
    10     im_data = list(data)
    11     im_labels = list(labels)
    12 
    13     index = [i for i in range(im_data.__len__())]
    14     if is_shuffler:
    15         np.random.shuffle(index)
    16 
    17     # 創建寫入器,然後使用該對象寫入樣本example
    18     writer = tf.python_io.TFRecordWriter(filename)
    19     for i in range(im_data.__len__()):
    20         im_d = im_data[index[i]]    # im_d:存放着第index[i]張圖片的路徑信息
    21         im_l = im_labels[index[i]]  # im_l:存放着對應圖片的標籤信息
    22 
    23         # # 獲取當前的圖片數據  方式一:
    24         # data = cv2.imread(im_d)
    25         # # 創建樣本
    26         # ex = tf.train.Example(
    27         #     features=tf.train.Features(
    28         #         feature={
    29         #             "image": tf.train.Feature(
    30         #                 bytes_list=tf.train.BytesList(
    31         #                     value=[data.tobytes()])), # 需要打包成bytes類型
    32         #             "label": tf.train.Feature(
    33         #                 int64_list=tf.train.Int64List(
    34         #                     value=[im_l])),
    35         #         }
    36         #     )
    37         # )
    38         # 獲取當前的圖片數據  方式二:相對於方式一,打包文件佔用空間小了一半多
    39         data = tf.gfile.FastGFile(im_d, "rb").read()
    40         ex = tf.train.Example(
    41             features=tf.train.Features(
    42                 feature={
    43                     "image": tf.train.Feature(
    44                         bytes_list=tf.train.BytesList(
    45                             value=[data])), # 此時的data已經是bytes類型
    46                     "label": tf.train.Feature(
    47                         int64_list=tf.train.Int64List(
    48                             value=[im_l])),
    49                 }
    50             )
    51         )
    52 
    53         # 寫入將序列化之後的樣本
    54         writer.write(ex.SerializeToString())
    55     # 關閉寫入器
    56     writer.close()

    TFRecord文件打包案列

     

     1 import tensorflow as tf
     2 import cv2
     3 
     4 def read_TFRecord(file_list, batch_size=10):
     5     """
     6     讀取TFRecord文件
     7     :param file_list: 存放TFRecord的文件名,List
     8     :param batch_size: 每次讀取圖片的數量
     9     :return: 解析後圖片及對應的標籤
    10     """
    11     file_queue = tf.train.string_input_producer(file_list, num_epochs=None, shuffle=True)
    12     reader = tf.TFRecordReader()
    13     _, ex = reader.read(file_queue)
    14     batch = tf.train.shuffle_batch([ex], batch_size, capacity=batch_size * 10, min_after_dequeue=batch_size * 5)
    15 
    16     feature = {
    17         'image': tf.FixedLenFeature([], tf.string),
    18         'label': tf.FixedLenFeature([], tf.int64)
    19     }
    20     example = tf.parse_example(batch, features=feature)
    21 
    22     images = tf.decode_raw(example['image'], tf.uint8)
    23     images = tf.reshape(images, [-1, 32, 32, 3])
    24 
    25     return images, example['label']
    26 
    27 
    28 
    29 def main():
    30     # filelist = ['data/train.tfrecord']
    31     filelist = ['data/test.tfrecord']
    32     images, labels = read_TFRecord(filelist, 2)
    33     with tf.Session() as sess:
    34         sess.run(tf.local_variables_initializer())
    35         coord = tf.train.Coordinator()
    36         threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    37 
    38         try:
    39             while not coord.should_stop():
    40                 for i in range(1):
    41                     image_bth, _ = sess.run([images, labels])
    42                     print(_)
    43 
    44                     cv2.imshow("image_0", image_bth[0])
    45                     cv2.imshow("image_1", image_bth[1])
    46                 break
    47         except tf.errors.OutOfRangeError:
    48             print('read done')
    49         finally:
    50             coord.request_stop()
    51         coord.join(threads)
    52         cv2.waitKey(0)
    53         cv2.destroyAllWindows()
    54 
    55 if __name__ == "__main__":
    56     main()

    TFReord文件的讀取案列

     

    ,

    內容概要:

    單一數據讀取方式:

      第一種:slice_input_producer()

    # 返回值可以直接通過 Session.run([images, labels])查看,且第一個參數必須放在列表中,如[...]
    [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)

      第二種:string_input_producer()

    # 需要定義文件讀取器,然後通過讀取器中的 read()方法來獲取數據(返回值類型 key,value),再通過 Session.run(value)查看
    file_queue = tf.train.string_input_producer(filename, num_epochs=None, shuffle=True)

    reader = tf.WholeFileReader() # 定義文件讀取器
    key, value = reader.read(file_queue)    # key:文件名;value:文件中的內容

      !!!num_epochs=None,不指定迭代次數,這樣文件隊列中元素個數也不限定(None*數據集大小)。

      !!!如果不是None,則此函數創建本地計數器 epochs,需要使用local_variables_initializer()初始化局部變量

      !!!以上兩種方法都可以生成文件名隊列。

    (隨機)批量數據讀取方式:

    batchsize=2  # 每次讀取的樣本數量
    tf.train.batch(tensors, batch_size=batchsize)
    tf.train.shuffle_batch(tensors, batch_size=batchsize, capacity=batchsize*10, min_after_dequeue=batchsize*5) # capacity > min_after_dequeue

      !!!以上所有讀取數據的方法,在Session.run()之前必須開啟文件隊列線程 tf.train.start_queue_runners()

     TFRecord文件的打包與讀取

     

     一、單一數據讀取方式

    第一種:slice_input_producer()

    def slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None)

    案例1:

    import tensorflow as tf
    
    images = ['image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg']
    labels = [1, 2, 3, 4]
    
    # [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)
    
    # 當num_epochs=2時,此時文件隊列中只有 2*4=8個樣本,所有在取第9個樣本時會出錯
    # [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=2, shuffle=True)
    
    data = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True)
    print(type(data))   # <class 'list'>
    
    with tf.Session() as sess:
        # sess.run(tf.local_variables_initializer())
        sess.run(tf.local_variables_initializer())
        coord = tf.train.Coordinator()  # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)  # 開始在圖表中收集隊列運行器
    
        for i in range(10):
            print(sess.run(data))
    
        coord.request_stop()
        coord.join(threads)
    
    """
    運行結果:
    [b'image2.jpg', 2]
    [b'image1.jpg', 1]
    [b'image3.jpg', 3]
    [b'image4.jpg', 4]
    [b'image2.jpg', 2]
    [b'image1.jpg', 1]
    [b'image3.jpg', 3]
    [b'image4.jpg', 4]
    [b'image2.jpg', 2]
    [b'image3.jpg', 3]
    """

      !!!slice_input_producer() 中的第一個參數需要放在一個列表中,列表中的每個元素可以是 List 或 Tensor,如 [images,labels],

      !!!num_epochs設置

     

     第二種:string_input_producer()

    def string_input_producer(string_tensor, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None, cancel_op=None)

    文件讀取器

      不同類型的文件對應不同的文件讀取器,我們稱為 reader對象

      該對象的 read 方法自動讀取文件,並創建數據隊列,輸出key/文件名,value/文件內容;

    reader = tf.TextLineReader()      ### 一行一行讀取,適用於所有文本文件

    reader = tf.TFRecordReader() ### A Reader that outputs the records from a TFRecords file
    reader = tf.WholeFileReader() ### 一次讀取整個文件,適用圖片

     案例2:讀取csv文件

    iimport 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=2)   # 生成文件名隊列
    reader = tf.WholeFileReader()           # 定義文件讀取器(一次讀取整個文件)
    # reader = tf.TextLineReader()            # 定義文件讀取器(一行一行的讀)
    key, value = reader.read(file_queue)    # key:文件名;value:文件中的內容
    print(type(file_queue))
    
    init = [tf.global_variables_initializer(), tf.local_variables_initializer()]
    with tf.Session() as sess:
        sess.run(init)
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)
        try:
            while not coord.should_stop():
                for i in range(6):
                    print(sess.run([key, value]))
                break
        except tf.errors.OutOfRangeError:
            print('read done')
        finally:
            coord.request_stop()
        coord.join(threads)
    
    """
    reader = tf.WholeFileReader()           # 定義文件讀取器(一次讀取整個文件)
    運行結果:
    [b'data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
    [b'data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
    [b'data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']
    [b'data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']
    [b'data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
    [b'data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
    """
    """
    reader = tf.TextLineReader()           # 定義文件讀取器(一行一行的讀)
    運行結果:
    [b'data/B.csv:1', b'4.jpg,4']
    [b'data/B.csv:2', b'5.jpg,5']
    [b'data/B.csv:3', b'6.jpg,6']
    [b'data/C.csv:1', b'7.jpg,7']
    [b'data/C.csv:2', b'8.jpg,8']
    [b'data/C.csv:3', b'9.jpg,9']
    """

    案例3:讀取圖片(每次讀取全部圖片內容,不是一行一行)

    import tensorflow as tf
    
    filename = ['1.jpg', '2.jpg']
    filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=1)
    reader = tf.WholeFileReader()              # 文件讀取器
    key, value = reader.read(filename_queue)   # 讀取文件 key:文件名;value:圖片數據,bytes
    
    with tf.Session() as sess:
        tf.local_variables_initializer().run()
        coord = tf.train.Coordinator()      # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)
    
        for i in range(filename.__len__()):
            image_data = sess.run(value)
            with open('img_%d.jpg' % i, 'wb') as f:
                f.write(image_data)
        coord.request_stop()
        coord.join(threads)

     

     二、(隨機)批量數據讀取方式:

      功能:shuffle_batch() 和 batch() 這兩個API都是從文件隊列中批量獲取數據,使用方式類似;

    案例4:slice_input_producer() 與 batch()

    import tensorflow as tf
    import numpy as np
    
    images = np.arange(20).reshape([10, 2])
    label = np.asarray(range(0, 10))
    images = tf.cast(images, tf.float32)  # 可以註釋掉,不影響運行結果
    label = tf.cast(label, tf.int32)     # 可以註釋掉,不影響運行結果
    
    batchsize = 6   # 每次獲取元素的數量
    input_queue = tf.train.slice_input_producer([images, label], num_epochs=None, shuffle=False)
    image_batch, label_batch = tf.train.batch(input_queue, batch_size=batchsize)
    
    # 隨機獲取 batchsize個元素,其中,capacity:隊列容量,這個參數一定要比 min_after_dequeue 大
    # image_batch, label_batch = tf.train.shuffle_batch(input_queue, batch_size=batchsize, capacity=64, min_after_dequeue=10)
    
    with tf.Session() as sess:
        coord = tf.train.Coordinator()      # 線程的協調器
        threads = tf.train.start_queue_runners(sess, coord)     # 開始在圖表中收集隊列運行器
        for cnt in range(2):
            print("第{}次獲取數據,每次batch={}...".format(cnt+1, batchsize))
            image_batch_v, label_batch_v = sess.run([image_batch, label_batch])
            print(image_batch_v, label_batch_v, label_batch_v.__len__())
    
        coord.request_stop()
        coord.join(threads)
    
    """
    運行結果:
    第1次獲取數據,每次batch=6...
    [[ 0.  1.]
     [ 2.  3.]
     [ 4.  5.]
     [ 6.  7.]
     [ 8.  9.]
     [10. 11.]] [0 1 2 3 4 5] 6
    第2次獲取數據,每次batch=6...
    [[12. 13.]
     [14. 15.]
     [16. 17.]
     [18. 19.]
     [ 0.  1.]
     [ 2.  3.]] [6 7 8 9 0 1] 6
    """

     案例5:從本地批量的讀取圖片 — string_input_producer() 與 batch()

     1 import tensorflow as tf
     2 import glob
     3 import cv2 as cv
     4 
     5 def read_imgs(filename, picture_format, input_image_shape, batch_size=1):
     6     """
     7     從本地批量的讀取圖片
     8     :param filename: 圖片路徑(包括圖片的文件名),[]
     9     :param picture_format: 圖片的格式,如 bmp,jpg,png等; string
    10     :param input_image_shape: 輸入圖像的大小; (h,w,c)或[]
    11     :param batch_size: 每次從文件隊列中加載圖片的數量; int
    12     :return: batch_size張圖片數據, Tensor
    13     """
    14     global new_img
    15     # 創建文件隊列
    16     file_queue = tf.train.string_input_producer(filename, num_epochs=1, shuffle=True)
    17     # 創建文件讀取器
    18     reader = tf.WholeFileReader()
    19     # 讀取文件隊列中的文件
    20     _, img_bytes = reader.read(file_queue)
    21     # print(img_bytes)    # Tensor("ReaderReadV2_19:1", shape=(), dtype=string)
    22     # 對圖片進行解碼
    23     if picture_format == ".bmp":
    24         new_img = tf.image.decode_bmp(img_bytes, channels=1)
    25     elif picture_format == ".jpg":
    26         new_img = tf.image.decode_jpeg(img_bytes, channels=3)
    27     else:
    28         pass
    29     # 重新設置圖片的大小
    30     # new_img = tf.image.resize_images(new_img, input_image_shape)
    31     new_img = tf.reshape(new_img, input_image_shape)
    32     # 設置圖片的數據類型
    33     new_img = tf.image.convert_image_dtype(new_img, tf.uint8)
    34 
    35     # return new_img
    36     return tf.train.batch([new_img], batch_size)
    37 
    38 
    39 def main():
    40     image_path = glob.glob(r'F:\demo\FaceRecognition\人臉庫\ORL\*.bmp')
    41     image_batch = read_imgs(image_path, ".bmp", (112, 92, 1), 5)
    42     print(type(image_batch))
    43     # image_path = glob.glob(r'.\*.jpg')
    44     # image_batch = read_imgs(image_path, ".jpg", (313, 500, 3), 1)
    45 
    46     sess = tf.Session()
    47     sess.run(tf.local_variables_initializer())
    48     tf.train.start_queue_runners(sess=sess)
    49 
    50     image_batch = sess.run(image_batch)
    51     print(type(image_batch))    # <class 'numpy.ndarray'>
    52 
    53     for i in range(image_batch.__len__()):
    54         cv.imshow("win_"+str(i), image_batch[i])
    55     cv.waitKey()
    56     cv.destroyAllWindows()
    57 
    58 def start():
    59     image_path = glob.glob(r'F:\demo\FaceRecognition\人臉庫\ORL\*.bmp')
    60     image_batch = read_imgs(image_path, ".bmp", (112, 92, 1), 5)
    61     print(type(image_batch))    # <class 'tensorflow.python.framework.ops.Tensor'>
    62 
    63 
    64     with tf.Session() as sess:
    65         sess.run(tf.local_variables_initializer())
    66         coord = tf.train.Coordinator()      # 線程的協調器
    67         threads = tf.train.start_queue_runners(sess, coord)     # 開始在圖表中收集隊列運行器
    68         image_batch = sess.run(image_batch)
    69         print(type(image_batch))    # <class 'numpy.ndarray'>
    70 
    71         for i in range(image_batch.__len__()):
    72             cv.imshow("win_"+str(i), image_batch[i])
    73         cv.waitKey()
    74         cv.destroyAllWindows()
    75 
    76         # 若使用 with 方式打開 Session,且沒加如下2行語句,則會出錯
    77         # ERROR:tensorflow:Exception in QueueRunner: Enqueue operation was cancelled;
    78         # 原因:文件隊列線程還處於工作狀態(隊列中還有圖片數據),而加載完batch_size張圖片會話就會自動關閉,同時關閉文件隊列線程
    79         coord.request_stop()
    80         coord.join(threads)
    81 
    82 
    83 if __name__ == "__main__":
    84     # main()
    85     start()

    從本地批量的讀取圖片案例

     

    案列6:TFRecord文件打包與讀取

     1 def write_TFRecord(filename, data, labels, is_shuffler=True):
     2     """
     3     將數據打包成TFRecord格式
     4     :param filename: 打包後路徑名,默認在工程目錄下創建該文件;String
     5     :param data: 需要打包的文件路徑名;list
     6     :param labels: 對應文件的標籤;list
     7     :param is_shuffler:是否隨機初始化打包后的數據,默認:True;Bool
     8     :return: None
     9     """
    10     im_data = list(data)
    11     im_labels = list(labels)
    12 
    13     index = [i for i in range(im_data.__len__())]
    14     if is_shuffler:
    15         np.random.shuffle(index)
    16 
    17     # 創建寫入器,然後使用該對象寫入樣本example
    18     writer = tf.python_io.TFRecordWriter(filename)
    19     for i in range(im_data.__len__()):
    20         im_d = im_data[index[i]]    # im_d:存放着第index[i]張圖片的路徑信息
    21         im_l = im_labels[index[i]]  # im_l:存放着對應圖片的標籤信息
    22 
    23         # # 獲取當前的圖片數據  方式一:
    24         # data = cv2.imread(im_d)
    25         # # 創建樣本
    26         # ex = tf.train.Example(
    27         #     features=tf.train.Features(
    28         #         feature={
    29         #             "image": tf.train.Feature(
    30         #                 bytes_list=tf.train.BytesList(
    31         #                     value=[data.tobytes()])), # 需要打包成bytes類型
    32         #             "label": tf.train.Feature(
    33         #                 int64_list=tf.train.Int64List(
    34         #                     value=[im_l])),
    35         #         }
    36         #     )
    37         # )
    38         # 獲取當前的圖片數據  方式二:相對於方式一,打包文件佔用空間小了一半多
    39         data = tf.gfile.FastGFile(im_d, "rb").read()
    40         ex = tf.train.Example(
    41             features=tf.train.Features(
    42                 feature={
    43                     "image": tf.train.Feature(
    44                         bytes_list=tf.train.BytesList(
    45                             value=[data])), # 此時的data已經是bytes類型
    46                     "label": tf.train.Feature(
    47                         int64_list=tf.train.Int64List(
    48                             value=[im_l])),
    49                 }
    50             )
    51         )
    52 
    53         # 寫入將序列化之後的樣本
    54         writer.write(ex.SerializeToString())
    55     # 關閉寫入器
    56     writer.close()

    TFRecord文件打包案列

     

     1 import tensorflow as tf
     2 import cv2
     3 
     4 def read_TFRecord(file_list, batch_size=10):
     5     """
     6     讀取TFRecord文件
     7     :param file_list: 存放TFRecord的文件名,List
     8     :param batch_size: 每次讀取圖片的數量
     9     :return: 解析後圖片及對應的標籤
    10     """
    11     file_queue = tf.train.string_input_producer(file_list, num_epochs=None, shuffle=True)
    12     reader = tf.TFRecordReader()
    13     _, ex = reader.read(file_queue)
    14     batch = tf.train.shuffle_batch([ex], batch_size, capacity=batch_size * 10, min_after_dequeue=batch_size * 5)
    15 
    16     feature = {
    17         'image': tf.FixedLenFeature([], tf.string),
    18         'label': tf.FixedLenFeature([], tf.int64)
    19     }
    20     example = tf.parse_example(batch, features=feature)
    21 
    22     images = tf.decode_raw(example['image'], tf.uint8)
    23     images = tf.reshape(images, [-1, 32, 32, 3])
    24 
    25     return images, example['label']
    26 
    27 
    28 
    29 def main():
    30     # filelist = ['data/train.tfrecord']
    31     filelist = ['data/test.tfrecord']
    32     images, labels = read_TFRecord(filelist, 2)
    33     with tf.Session() as sess:
    34         sess.run(tf.local_variables_initializer())
    35         coord = tf.train.Coordinator()
    36         threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    37 
    38         try:
    39             while not coord.should_stop():
    40                 for i in range(1):
    41                     image_bth, _ = sess.run([images, labels])
    42                     print(_)
    43 
    44                     cv2.imshow("image_0", image_bth[0])
    45                     cv2.imshow("image_1", image_bth[1])
    46                 break
    47         except tf.errors.OutOfRangeError:
    48             print('read done')
    49         finally:
    50             coord.request_stop()
    51         coord.join(threads)
    52         cv2.waitKey(0)
    53         cv2.destroyAllWindows()
    54 
    55 if __name__ == "__main__":
    56     main()

    TFReord文件的讀取案列

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 特斯拉招募 1,656 人,拚明年第一季轉虧為盈

    特斯拉招募 1,656 人,拚明年第一季轉虧為盈

    電動車與能源儲存設備製造商特斯拉 (Tesla) 要招募 1,656 人,一下子釋出這麼多職缺,讓人好奇這家執行長光環大過一切的公司,到底再找甚麼樣的能人,順便一窺特斯拉的營運布局。 彭博報導,特斯拉在找的人包括一到三年經驗的汽車雷達系統工程師,墨西哥市的客服經理,阿姆斯特丹、米蘭、上海、成都等大城市的產品專員。

    自從 2007 年虧損 18.8 億美元後,特斯拉推出更多車款,打造世界最大的電池工廠,在全球擴張版圖,包括在墨西哥市與愛丁堡開店,所以他們一直在找人,即便投資巨大,但 Elon Musk 仍然誓言明年第一季就要創造正的現金流。   分析師認為,特斯拉在一連串投資之後,2016 年必須對市場展現他們有獲利能力,擺在眼前的就是汽車製造與電池事業兩大任務,他們必須擴大每個部門的人力。   報導指出,自 2010 年底特斯拉上市之後,至今員工人數已經成長十五倍,超過 14,000 人,可媲美市值的增長幅度。五年前,這家公司只賣一款汽車 Roadster,且市場只在美國,現在在世界三大洲賣兩款電動車,以及提供家用、商用、公用固定式電池系統特斯拉能源  (Tesla Energy)。   大量招募是快速成長的公司典型的作風,特斯拉九月發表第一款 Model X SUV 系列車款時表示,第四季預計可賣出 1.7 萬到 1.9 萬台,今年至少可賣出五萬台。   特斯拉於十月發表自動駕駛功能 Autopilot,Musk 當時表示自動化與電子化是兩項最前瞻的創新,去年第四季後出貨的汽車都配有結合照相機、雷達、超聲波傳感器的設備,功能像是巡航控制或自動車道變換。Musk 曾說 Autopilot 軟體團隊有 50 人,硬體方面約 100 人。   上月 Musk 表示他打造了一個專門的團隊來做全自動汽車,同時表示他們在找硬核軟體工程師,不需要有汽車相關經驗,強調 Autopilot 團隊直接向他報告,所以他會親自面試。   報導指出,蘋果開發自動車,Google 在做無駕駛汽車,還有新創公司 Cruise Automation 等等,現在不管何種汽車工程師在矽谷都相當搶手,但特斯拉說他們接到的履歷仍然非常多,有 150 萬份來自世界各地的履歷,其 HR 對媒體表示,「大家都很想來特斯拉工作。」

    (首圖來源: CC By 2.0)

    (本文授權轉載自《》─〈〉)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 聆風全球銷量42700輛 日產高管稱令人感到“失望”

    日產公司近日發佈了2012財年第二季度報告,日產首席運營官賀俊之稱,目前,日產聆風的全球銷量為42700輛。他同時表示,整體銷量不佳令人感到“失望”。

    截至目前為止,日產聆風在日本的銷量為19000輛,約占全球銷量的一半。日產公司此前制定了2012年在美國銷售2萬輛聆風的目標,雖然現狀與之相距甚遠,但賀俊之堅稱,日產將繼續電動汽車的開發,拓展電動汽車市場。

    賀俊之指出,日產聆風上市兩周年將至,兩年的經驗讓日產公司瞭解了阻礙消費者購買電動汽車的原因、消費者的使用和充電習慣等,這些資訊有利於未來日產團隊採取措施應對相關問題。

    值得一提的是,今年10月份,日產聆風共售出1579輛,較9月份的984輛大幅增加,並遠高於8月份685輛的銷量。正如賀俊之所說,作為第一批大規模生產電動汽車的企業,日產將致力於“零排放”工作,希望民眾能理解日產肩負的重任。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 現代汽車巴西工廠竣工將生產混合動力車型

    現代汽車集團首家南美生產基地巴西工廠日前舉行了竣工儀式。該廠年產能達15萬輛。現代汽車計畫在該工廠生產並銷售巴西戰略車型“HB20”。“HB20”是由乙醇汽油混合燃料提供動力的(flex)。在巴西,混合動力車的銷量接近整個汽車銷量的90%。

    據悉,該工廠總占地面積139萬平方米,具備衝壓、車身、塗裝、總裝等整車生產設備及零部件、物流倉庫等配套設施,總投資規模達7億美元。巴西工廠將創造5000多個新工作崗位,將為當地零部件企業的發展和巴西汽車產業的發展做出很大貢獻。

    隨著巴西工廠的建成,現代汽車可以免去巴西政府對進口車徵收的最高35%關稅,從而確保價格競爭力。外界評價說,現代汽車已經在中國、俄羅斯、印度及巴西等金磚四國(BRICs)均建成生產線,以快速應對局部經濟危機。

    巴西已經成為世界第四大汽車市場,2011年的新車銷量達341萬輛。到了2015年,巴西的汽車年銷量將增至500萬輛,有望超越日本成為世界第三大汽車市場。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 中國高新汽車國際峰會

     

    展會名稱:

    中國高新汽車國際峰會與Automechanika Shanghai

    展館地址:

    中國‧上海,浦東嘉里大酒店

    展會日期:

    2012年12月11-13日

    主辦單位:

    法蘭克福展覽有限公司

    網址:

    會議演講主題:

     

    演講主題範圍包括商業模式,技術創新,基礎設施,服務和生態系統等相關的題目:   ‧ 汽車行業可持續發展的新興商業模式和生態系統合作 ‧ 提高能源效率的混合動力,清潔燃料和電動汽車解決方案 ‧ 個人移動服務的創新設計,技術,市場和服務 ‧ 商用車輛和運輸業的綠色商業模式和經營策略 ‧ 連網車輛和遠程信息處理技術,服務和應用所產生的新收益源 ‧ 充電技術,基礎設施和不斷發展的商業模式 ‧ 先進的電池技術和管理系統,以提高經濟負擔能力 ‧ 替代低碳燃料,能源效率和減少廢氣排放 ‧ 最高性能和效率的動力/傳動系統和電子控制系統 ‧ 先進的材料和製造工藝,以提高生產力和降低成本 ‧ 綠色汽車市場的發展,包括以消費者為導向的策略,售後市場的增長和經銷商的機會 ‧ 未來發展和國際化的投資及融資策略

    演講者及參會者

    峰會的來賓將有來自C級管理,戰略規劃等有影響力的高層決策者,產品創新與服務高管,專業技術人員和工程師:   ‧ 客運和商用車原始設備製造商 ‧ 主要供應商和零部件製造商 ‧ 戰略投資者 ‧ 專業技術人員和工程師 ‧ 車隊管理人員和經營者 ‧ 公用事業和能源服務公司 ‧ 替代燃料供應商 ‧ 先進的傳動系統和電池系統開發商 ‧ 服務提供商 ‧ 政府管理部門和市政領導 ‧ 具有影響力的行業研究機構  

     

    連絡資訊

    連絡人:葉家欣小姐

    電話:(852) 2230 9202

    電子郵件:keiann.yip@hongkong.messefrankfurt.com

    官方網站:www.nextgenautosummit-china.com

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 磨皮美顏算法 附完整C代碼

    磨皮美顏算法 附完整C代碼

    前言

    2017年底時候寫了這篇《集 降噪 美顏 虛化 增強 為一體的極速圖像潤色算法 附Demo程序

    這也算是學習過程中比較有成就感的一個算法。

    自2015年做算法開始到今天,還有個把月,就滿五年了。

    歲月匆匆,人生能有多少個五年。

    這五年裡,從音頻圖像到視頻,從傳統算法到深度學習,從2D到3D各種算法幾乎都走了一個遍。

    好在,不論在哪個領域都能有些許建樹,這是博主我自身很欣慰的事情。

    雖然有所間斷但是仍然堅持寫博客,並且堅持完整開源分享。

    目的就是為了幫助那些一開始跟我一樣,想要學習算法的萌新,

    一起踏入算法領域去跟大家“排排坐,吃果果”。

    引子

    在這個特別的時間點,就想做點特別的事情。

    那就是開源當時寫的這個“美顏算法”,開源代碼和當時的版本有些許出入,但是思路是一樣的。

    早些年的時候大家發現採用保邊濾波的思路可以做到降噪,進而衍生出來針對皮膚的降噪,簡稱磨皮或者美顏。

    從此百家爭鳴,而這個課題到今天也還在發展,當然日新月異了。

    故此,想談談針對美顏磨皮的一些算法思路,為後續想學習並改進的萌新提供一些養分。

    概述美顏磨皮方法

    1.基於保邊降噪

    這類算法有很多方法,但不外乎2種基礎思路,

    基於空間和基於頻率,當然再展開的話,還可以細分為紋理和顏色。

    例如通過膚色或紋理區域做針對性的處理。

    這類算法的優點是計算簡單,通用型強,但缺點就是不夠細膩完美。

    2.基於人臉檢測貼圖

    這種嚴格意義上來說,是易容術,就是基於人臉檢測出的關鍵數據。

    例如人臉關鍵點,將人臉皮膚區域提取出來,重新貼上一張事先準備的皮膚圖,進行皮膚貼合融合。

    臉已經被置換了,效果很贊。有點繆修斯之船的味道。

    這類算法優點是效果極其驚艷,但是算法複雜通用性差,一般只能針對少數角度表情的人臉。

    3.結合1和2的深度學習方法

    前兩者的思路早期大行其道,如今到了數據時代,

    基於深度學習的工具方案,可以非常好地結合前兩者的思路,進行訓練,求一個數據解。

    很多人將深度學習等同於AI,這個做法有點激進。

    基於深度學習的做法,仍然存在前兩者一樣的問題,簡單的不夠細膩,細膩的不夠簡單,

    而如果要設計一個優秀的模型,其實跟設計一個傳統算法一樣困難。

    基於數據驅動的算法,驗證成本非常高,可控性比較差,當然在金錢的驅動下確實能產出還不錯的算法模型。

    這類算法的優點,往往能求出很不錯的局部最優解,甚至以假亂真,缺點就是需要大量金錢和數據的驅動。

    總結來說的話,不付出代價,就別想有好的結果,非常的現實。

     

    據我所知目前使用最多的方案是第一種和第三種,第二種可操作性不強,只有少數公司掌握了這方面的核心技術。

    但是不管是哪種方案,無非就是以下幾個步驟。

    1.確定人臉的皮膚區域

    2.定位人臉的雜質(痘痘,斑點,痣,膚色不均等)

    3.根據定位到雜質進行填補修復或濾除

     

    這就是圖像處理經典三部曲

    1.定位 2.檢測 3.處理

    每一個細分展開,都非常宏大且複雜的算法。

     

    以上,僅以磨皮美顏為例子,闡述圖像方面的算法想要或正在解決什麼樣的問題。

    我們在工作中碰到的圖像問題無非以上幾個核心問題,問題都是類似的,只是不同場景和需求下各有難處。

    本次開源的算法思路

    本次開源的算法是基於保邊降噪的思路,

    當然這個思路可以通過改寫,參數化后可以集成到深度學習中,作為一個先驗層輔助訓練。

    算法步驟如下:

    1.  檢測皮膚顏色,確定皮膚占圖像的比率

    2. 根據皮膚比率進行邊緣檢測,產出細節映射圖

    3. 基於細節映射圖和磨皮強度進行保邊降噪

    4. 對降噪好的圖進行再一次膚色檢測,保留膚色區域的降噪,其他區域還原為原圖

    步驟比較簡單,但是要同時兼顧效果性能,是很不容易的。

    當然這個算法膚色檢測那一部分可以採用深度學習“語義分割”方面的思路進而改進效果。

    做得好,將本算法改良到准商用,驚艷的程度是沒有問題的。

    深度學習相關技術就不展開細說了,有能力的朋友,感興趣的話,可以自行實操。

     

    完整源代碼開源地址:

    https://github.com/cpuimage/skin_smoothing

    項目沒有第三方依賴,完整純c代碼。

    有編譯問題的同學自行參考《Windows下C,C++開發環境搭建指南》搭建編譯環境。

    附上算法效果的示例:

     

     

    以上,權當拋磚引玉之用。

    授人以魚不如授人以漁。

     

    2020年,疫情之下,

    願大家都能事業有成,身體健康。

    世界和平,人們皆友愛。

     

    若有其他相關問題或者需求也可以郵件聯繫俺探討。

    郵箱地址是: gaozhihan@vip.qq.com

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • Python 網絡爬蟲實戰:爬取 B站《全職高手》20萬條評論數據

    Python 網絡爬蟲實戰:爬取 B站《全職高手》20萬條評論數據

    本周我們的目標是:B站(嗶哩嗶哩彈幕網 https://www.bilibili.com )視頻評論數據。

    我們都知道,B站有很多號稱“鎮站之寶”的視頻,擁有着數量極其恐怖的評論和彈幕。所以這次我們的目標就是,爬取B站視頻的評論數據,分析其為何會深受大家喜愛。

    首先去調研一下,B站評論數量最多的視頻是哪一個。。。好在已經有大佬已經統計過了,我們來看一哈!

    ​【B站大數據可視化】B站評論數最多的視頻究竟是?來自 <https://www.bilibili.com/video/av34900167/>

     

    嗯?《全職高手》,有點意思,第一集和最後一集分別佔據了評論數量排行榜的第二名和第一名,遠超了其他很多很火的番。那好,就拿它下手吧,看看它到底強在哪兒。

    廢話不多說,先去B站看看這部神劇到底有多好看 https://www.bilibili.com/bangumi/play/ep107656

    額,需要開通大會員才能觀看。。。

    好吧,不看就不看,不過好在雖然視頻看不了,評論卻是可以看的。

    感受到它的恐怖了嗎?63w6條的評論!9千多頁!果然是不同凡響啊。

    接下來,我們就開始編寫爬蟲,爬取這些數據吧。

     

    使用爬蟲爬取網頁一般分為四個階段:分析目標網頁,獲取網頁內容,提取關鍵信息,輸出保存。

    1. 分析目標網頁

    • 首先觀察評論區結構,發現評論區為鼠標點擊翻頁形式,共 9399 頁,每一頁有 20 條評論,每條評論中包含 用戶名、評論內容、評論樓層、時間日期、點贊數等信息展示。

    • 接着我們按 F12 召喚出開發者工具,切換到Network。然後用鼠標點擊評論翻頁,觀察這個過程有什麼變化,並以此來制定我們的爬取策略。

    • 我們不難發現,整個過程中 URL 不變,說明評論區翻頁不是通過 URL 控制。而在每翻一頁的時候,網頁會向服務器發出這樣的請求(請看 Request URL)。

    • 點擊 Preview 欄,可以切換到預覽頁面,也就是說,可以看到這個請求返回的結果是什麼。下面是該請求返回的 json 文件,包含了在 replies 里包含了本頁的評論數據。在這個 json 文件里,我們可以發現,這裏面包含了太多的信息,除了網頁上展示的信息,還有很多沒展示出來的信息也有,簡直是挖到寶了。不過,我們這裏用不到,通通忽略掉,只挑我們關注的部分就好了。

    2. 獲取網頁內容

    網頁內容分析完畢,可以正式寫代碼爬了。

     1 import requests
     2 
     3 def fetchURL(url):
     4     '''
     5     功能:訪問 url 的網頁,獲取網頁內容並返回
     6     參數:
     7         url :目標網頁的 url
     8     返回:目標網頁的 html 內容
     9     '''
    10     headers = {
    11         'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    12         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    13     }
    14     
    15     try:
    16         r = requests.get(url,headers=headers)
    17         r.raise_for_status()
    18         print(r.url)
    19         return r.text
    20     except requests.HTTPError as e:
    21         print(e)
    22         print("HTTPError")
    23     except requests.RequestException as e:
    24         print(e)
    25     except:
    26         print("Unknown Error !")
    27         
    28 
    29 if __name__ == '__main__':
    30     url = 'https://api.bilibili.com/x/v2/reply?callback=jQuery172020326544171595695_1541502273311&jsonp=jsonp&pn=2&type=1&oid=11357166&sort=0&_=1541502312050'
    31     html = fetchURL(url)
    32     print(html)

    不過,在運行過後,你會發現,403 錯誤,服務器拒絕了我們的訪問。

    運行結果:

    403 Client Error: Forbidden for url: https://api.bilibili.com/x/v2/reply?callback=jQuery172020326544171595695_1541502273311&jsonp=jsonp&pn=2&type=1&oid=11357166&sort=0&_=1541502312050
    HTTPError
    None

    同樣的,這個請求放瀏覽器地址欄裏面直接打開,會變403,什麼也訪問不到。

    這是我們本次爬蟲遇到的第一個坑。在瀏覽器中能正常返迴響應,但是直接打開請求鏈接時,卻會被服務器拒絕。(我第一反應是 cookie ,將瀏覽器中的 cookie 放入爬蟲的請求頭中,重新訪問,發現沒用),或許這也算是一個小的反爬蟲機制吧。

    網上查閱資料之後,我找到了解決的方法(雖然不了解原理),原請求的 URL 參數如下:

    callback = jQuery1720913511919053787_1541340948898
    jsonp = jsonp
    pn = 2
    type = 1
    oid = 11357166&sort=0
    _ = 1541341035236

    其中,真正有用的參數只有三個:pn(頁數),type(=1)和oid(視頻id)。刪除其餘不必要的參數之後,用新整理出的url去訪問,成功獲取到評論數據。

    https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=2

    然後,在主函數中,通過寫一個 for 循環,通過改變 pn 的值,獲取每一頁的評論數據。

    1 if __name__ == '__main__':
    2     for page in range(0,9400):
    3         url = 'https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=' + str(page)
    4         html = fetchURL(url)

     

    3. 提取關鍵信息

    通過 json 庫對獲取到的響應內容進行解析,然後提取我們需要的內容:樓層,用戶名,性別,時間,評價,點贊數,回複數。

     1 import json
     2 import time
     3 
     4 def parserHtml(html):
     5     '''
     6     功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容
     7     參數:
     8             html:類似文件的內存 HTML 文本對象
     9     '''
    10     s = json.loads(html)
    11 
    12     for i in range(20):
    13         comment = s['data']['replies'][i]
    14 
    15         # 樓層,用戶名,性別,時間,評價,點贊數,回複數
    16         floor = comment['floor']
    17         username = comment['member']['uname']
    18         sex = comment['member']['sex']
    19         ctime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment['ctime']))
    20         content = comment['content']['message']
    21         likes = comment['like']
    22         rcounts = comment['rcount']
    23 
    24         print('--'+str(floor) + ':' + username + '('+sex+')' + ':'+ctime)
    25         print(content)
    26         print('like : '+ str(likes) + '      ' + 'replies : ' + str(rcounts))
    27         print('  ')
    部分運行結果如下:
    --204187:day可可鈴(保密):2018-11-05 18:16:22
    太太又出本了,這次真的木錢了(´;ω;`)
    like : 1      replies : 0
      
    --204186:長夜未央233(女):2018-11-05 16:24:52
    12區打卡
    like : 2      replies : 0
      
    --204185:果然還是人渣一枚(男):2018-11-05 13:48:09
    貌似忘來了好幾天
    like : 1      replies : 1
      
    --204183:day可可鈴(保密):2018-11-05 13:12:38
    要準備去學校了,萬惡的期中考試( ´_ゝ`)
    like : 2      replies : 0
      
    --204182:拾秋以恭弘=叶 恭弘(保密):2018-11-05 12:04:19
    11月5日打卡( ̄▽ ̄)
    like : 1      replies : 0
      
    --204181:芝米士噠(女):2018-11-05 07:53:43
    這次是真的錯過了一個億[蛆音娘_扶額]
    like : 2      replies : 1
    
    

    4. 保存輸出

    我們把這些數據以 csv 的格式保存於本地,即完成了本次爬蟲的全部任務。下面附上爬蟲的全部代碼。

      1 import requests
      2 import json
      3 import time
      4 
      5 def fetchURL(url):
      6     '''
      7     功能:訪問 url 的網頁,獲取網頁內容並返回
      8     參數:
      9         url :目標網頁的 url
     10     返回:目標網頁的 html 內容
     11     '''
     12     headers = {
     13         'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
     14         'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
     15     }
     16     
     17     try:
     18         r = requests.get(url,headers=headers)
     19         r.raise_for_status()
     20         print(r.url)
     21         return r.text
     22     except requests.HTTPError as e:
     23         print(e)
     24         print("HTTPError")
     25     except requests.RequestException as e:
     26         print(e)
     27     except:
     28         print("Unknown Error !")
     29         
     30 
     31 def parserHtml(html):
     32     '''
     33     功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容
     34     參數:
     35             html:類似文件的內存 HTML 文本對象
     36     '''
     37     try:
     38         s = json.loads(html)
     39     except:
     40         print('error')
     41         
     42     commentlist = []
     43     hlist = []
     44 
     45     hlist.append("序號")
     46     hlist.append("名字")
     47     hlist.append("性別")
     48     hlist.append("時間")
     49     hlist.append("評論")
     50     hlist.append("點贊數")
     51     hlist.append("回複數")
     52 
     53     #commentlist.append(hlist)
     54 
     55     # 樓層,用戶名,性別,時間,評價,點贊數,回複數
     56     for i in range(20):
     57         comment = s['data']['replies'][i]
     58         blist = []
     59 
     60         floor = comment['floor']
     61         username = comment['member']['uname']
     62         sex = comment['member']['sex']
     63         ctime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment['ctime']))
     64         content = comment['content']['message']
     65         likes = comment['like']
     66         rcounts = comment['rcount']
     67 
     68         blist.append(floor)
     69         blist.append(username)
     70         blist.append(sex)
     71         blist.append(ctime)
     72         blist.append(content)
     73         blist.append(likes)
     74         blist.append(rcounts)
     75 
     76         commentlist.append(blist)
     77 
     78     writePage(commentlist)
     79     print('---'*20)
     80 
     81 def writePage(urating):
     82     '''
     83         Function : To write the content of html into a local file
     84         html : The response content
     85         filename : the local filename to be used stored the response
     86     '''
     87     
     88     import pandas as pd
     89     dataframe = pd.DataFrame(urating)
     90     dataframe.to_csv('Bilibili_comment5-1000條.csv', mode='a', index=False, sep=',', header=False)
     91 
     92 
     93 if __name__ == '__main__':
     94     for page in range(0,9400):
     95         url = 'https://api.bilibili.com/x/v2/reply?type=1&oid=11357166&pn=' + str(page)
     96         html = fetchURL(url)
     97         parserHtml(html)
     98 
     99         # 為了降低被封ip的風險,每爬20頁便歇5秒。
    100         if page%20 == 0:
    101             time.sleep(5)

     

    寫在最後

    在爬取過程中,還是遇到了很多的小坑的。

    1. 請求的 url 不能直接用,需要對參數進行篩選整理后才能訪問。

    2. 爬取過程其實並不順利,因為如果爬取期間如果有用戶發表評論,則請求返回的響應會為空導致程序出錯。所以在實際爬取過程中,記錄爬取的位置,以便出錯之後從該位置繼續爬。(並且,挑選深夜一兩點這種發帖人數少的時間段,可以極大程度的減少程序出錯的機率)

    3. 爬取到的數據有多處不一致,其實這個不算是坑,不過這裏還是講一下,免得產生困惑。

            a. 就是評論區樓層只到了20多萬,但是評論數量卻有63萬多條,這個不一致主要是由於B站的評論是可以回復的,回復的評論也會計算到總評論數里。我們這裏只爬樓層的評論,而評論的回復則忽略,只統計回複數即可。

            b. 評論區樓層在20萬條左右,但是我們最後爬取下來的數據只有18萬條左右,反覆檢查爬蟲程序及原網站后發現,這個屬於正常現象,因為有刪評論的情況,評論刪除之後,後面的樓層並不會重新排序,而是就這樣把刪掉的那層空下了。導致樓層數和評論數不一致。

     

     

     如果文章中有哪裡沒有講明白,或者講解有誤的地方,歡迎在評論區批評指正,或者掃描下面的二維碼,加我微信,大家一起學習交流,共同進步。

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 不敵客訴壓力 澳洲超市延後對塑膠袋收費

    摘錄自2018年8月3日蘋果日報澳洲報導

    澳洲一間大型連鎖超市原本要實施塑膠袋需收費政策,希望可推動「減塑」為環保出一分力,不料顧客對此大感不滿,政策推出後已經第2次延長收費期限。

    連鎖超市科爾斯(Coles)自上月1日起停用一次性塑膠袋,改向顧客提供可重複使用、質料更耐用的塑膠袋作過渡,直至本周三(1日)為止。超市原定顧客此後若索取塑膠袋,每個須收取15澳分(約3.4元台幣)。

    然而科爾斯周三發聲明指,自禁用一次性塑膠袋後,有顧客反映需要更多過渡時間,以適應使用可重複使用塑膠袋,集團因此決定在昆士蘭、新南威爾斯、維多利亞及西澳洲等地繼續提供免費塑膠袋至8月29日,而南澳洲、塔斯馬尼亞等地區則仍繼續收費。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 南非減塑大功臣 寶特瓶廢棄塑膠製成磚

    摘錄自2020年2月14日公視報導

    在全球都出現塑膠垃圾問題時,南非開始用寶特瓶跟廢棄塑膠包裝,做成環保磚頭,來蓋托兒所等建築,成功減少塑膠垃圾。

    根據2018年的「南非廢棄物狀況報告」指出,南非在2017年製造的4200萬噸廢物中,只有約11%被回收再利用。而2012年成立的南非當地民間團體「Waste-ED」,主要協助國家解決廢棄物品問題。除了教育學童相關觀念,還接受諮詢,引進這種塑膠瓶環保磚的製作,用來蓋學校或是簡易建築。

    這種塑膠瓶環保磚,起源於菲律賓北部,後來應用在無法解決塑膠垃圾問題的發展中國家,協助當地政府廢物利用。目前開普敦郊區,已經有許多建築,包括托兒中心等建築牆壁,都是用這些環保磚製作。目前開普敦有超過2萬個、塑膠瓶環保磚的收集點,還跟學校合作,帶學童們一起參與製作跟使用環保磚。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!