1. 程式人生 > >tensorflow之GPU加速的理解

tensorflow之GPU加速的理解

最近在整理模型加速的問題,使用到了GPU,但是有時候發現GPU的速度盡然比CPU還低,後來查詢一些相關的資料後發現可能是由於兩方面原因造成的:1. GPU的計算能力不行(畢竟對於筆記本自帶的GPU而言其效能並不一定比CPU強);2. GPU和CPU之間存在通訊問題,即資料的讀取要在CPU中進行,讀取後的資料再送入GPU中進行處理。

針對第2個問題,考慮以佇列的方式來解決,具體原因為:當資料在佇列中傳入的時候可以採用並行的方式進行,即當圖在處理第一張圖片的時候,第二張圖片已經傳進去了,這樣在處理第二張的時候就不用考慮CPU傳入GPU的時間限制。

具體涉及的程式碼如下:

filename = os.listdir(args.input)
    filelist = [os.path.join(args.input, file) for file in filename]
    # 構建檔名佇列
    file_q = tf.train.string_input_producer(filelist, shuffle=False)
    # 構建讀取器
    reader = tf.WholeFileReader()
    # 讀取內容
    key, value = reader.read(file_q)
    # 構建解碼器
    image = tf.image.decode_jpeg(value)
    # print(image)
    # 統一圖片大小   設定長寬
    resize_image = tf.image.resize_images(image, [height, width], method=1)
    # 圖片進行歸一化
    float_image = tf.image.per_image_standardization(resize_image)
    # 指定通道大小
    float_image.set_shape([height, width, 3])
    #float_image = tf.cast(float_image, tf.float32)
    # 構建批量處理管道
    image_batch, key_batch = tf.train.batch([float_image, key], batch_size=1, num_threads=1, capacity=100,
                                            enqueue_many=False)
    with tf.Session() as sess:
        pnet, rnet, onet = detect_face.create_mtcnn(sess, None)
        # 構建執行緒協調器
        coord = tf.train.Coordinator()
        # 開啟執行緒
        threads = tf.train.start_queue_runners(sess, coord=coord)

        image_batch, key_batch = sess.run([image_batch, key_batch])

        print(sess.run(image).shape)
        print(sess.run(tf.image.extract_jpeg_shape(value)))
        for i in range(image_batch.shape[0]):
            # print(key_batch[i])
            image = image_batch[i, :, :, :]
            print(image.shape)
            print(image.dtype)
            start = time.time()
            bounding_boxes = detect_face.detect_face(image, minsize, pnet, rnet, onet, threshold, factor)
            end = time.time()
            nrof_faces = bounding_boxes.shape[0]
            print(end-start)
            print('Total %d face(s) detected' % nrof_faces)
        coord.request_stop()
        coord.join(threads)

其中涉及到以幾個函式:

1.tf.train.string_input_producer: 該函式預設的是輸入一個string的列表,然後該string列表將會產生一個佇列。預設的情況是亂序產生的,當設定shuffle=False時,會以正常順序讀取資料。

2.  tf.image.decode_jpeg:將圖片解碼成一個張量。通過sess.run可以輸出該張量的值

3. tf.train.batch:對資料進行分批處理,其中第一個引數表示需要分批的張量,可以是一個張量的列表,表示對每個張量都需要進行分批處理,產生對應的批資料個數。

4. image_batch, key_batch = sess.run([image_batch, key_batch]): 該指令尤為重要,因為分批處理後的資料只是張量的形式,如果沒有sess.run無法執行。所以該指令是把資料變為可以在後續程式中使用的具體的陣列。另外使用key和value的目的是為了可以知道自己處理的是哪張圖片,此時key和value是一一對應的。

 注意:如果分開則情況不一樣,例如:image_batch = sess.run(image_batch)

                                                           key_batch = sess.run(key_batch)

此時得出的key和value並不對應。主要是因為第一次執行sess.run時對佇列進行了一遍處理,當在執行一次時,佇列的指標指在第一次處理後的位置繼續進行。所以不對應。(key,value都是在佇列中產生的)