2016-07-17 36 views
6

Tôi đã sử dụng feed_dict để cấp dữ liệu trực tiếp placeholder trong khi thực hành viết mã trong các vấn đề nhỏ như MNIST. TensorFlow cũng hỗ trợ dữ liệu cho ăn bằng cách sử dụng queuequeue runner và cần nỗ lực để tìm hiểu.TensorFlow: Nạp dữ liệu với hàng đợi so với nạp trực tiếp với feed_dict

Có ai đã so sánh hai phương pháp này và đo lường hiệu suất không? Có xứng đáng dành thời gian để học cách sử dụng hàng đợi để nạp dữ liệu không?

Tôi đoán sử dụng hàng đợi không chỉ cho hiệu suất, mà còn cho mã sạch hơn, điều đó có nghĩa là gì. Có lẽ mã cho một tập dữ liệu có thể dễ dàng được sử dụng cho một tập dữ liệu khác (khi tôi chuyển đổi dữ liệu thành TFRecord)?

Tuy nhiên, this post dường như nói hàng đợi có thể chậm hơn phương thức feed_dict. Nó vẫn còn đúng không? Tại sao tôi nên sử dụng hàng đợi nếu nó chậm hơn và khó mã hơn?

Cảm ơn bạn đã nhập.

+0

Phần một trong hướng dẫn đó cung cấp thêm một số hướng dẫn về thời điểm sử dụng hàng đợi: https://indico.io/blog/tensorflow-data-inputs-part1-placeholders-protobufs-queues/ –

Trả lời

1

Dưới đây là một điểm chuẩn:

BasicRNNĐược hủy đăng ký thành 20 bước thời gian với 200 đơn vị ẩn. Tôi có 250k ví dụ huấn luyện và chạy 1 thời đại với kích thước lô 20.

feed_dict: 597 giây
đợi: 591 giây

nầy cũng ở với TF v1.0, trên một máy tính xách tay i5 (do đó 4 CPU) w/Ubuntu 16.04.

2

Mô hình NMT của tôi có 2 lớp, 512 đơn vị ẩn. Tôi đào tạo với độ dài câu tối đa = 50, kích thước lô = 32 và xem tốc độ tương tự giữa feed_dict và hàng đợi, khoảng 2400-2500 từ mục tiêu mỗi giây (tôi sử dụng chỉ số này cho tốc độ dựa trên số paper) này.

Tôi tìm thấy feed_dict rất trực quan và dễ sử dụng. Hàng đợi là khó khăn. Sử dụng hàng đợi, bạn phải:

1/Chuyển đổi dữ liệu của bạn thành tfrecords. Tôi thực sự gotta google một chút để hiểu làm thế nào để chuyển đổi dữ liệu seq2seq của tôi để tfrecords bởi vì các tài liệu không phải là rất hữu ích.

2/Giải mã dữ liệu của bạn từ tfrecords. Bạn sẽ tìm thấy các chức năng được sử dụng để tạo ra tfrecords và giải mã nó không trực quan phù hợp. Ví dụ: nếu mỗi ví dụ đào tạo của tôi có 3 chuỗi (chỉ 3 danh sách số nguyên) src_input, trg_input, trg_target và tôi cũng muốn ghi lại độ dài của src_input (một số phần tử của nó có thể là PADDING, vì vậy đừng tính), dưới đây là cách để tạo tfrecord từ mỗi ví dụ:

def _make_example(src_input, src_seq_length, trg_input, trg_seq_length, trg_target, target_weight): 
    context = tf.train.Features(
     feature={ 
      'src_seq_length': int64_feature(src_seq_length) 
     }) 
    feature_lists = tf.train.FeatureLists(
     feature_list={ 
      'src_input': int64_featurelist(src_input), 
      'trg_input': int64_featurelist(trg_input), 
      'trg_target': int64_featurelist(trg_target) 
     }) 

    return tf.train.SequenceExample(context=context, feature_lists=feature_lists) 

Và dưới đây là cách để giải mã nó:

def _read_and_decode(filename_queue): 
    reader = tf.TFRecordReader(options=self.tfrecord_option) 
    _, serialized_ex = reader.read(filename_queue) 

    context_features = { 
     'src_seq_length': tf.FixedLenFeature([], dtype=tf.int64) 
    } 
    sequence_features = { 
     'src_input': tf.FixedLenSequenceFeature([], dtype=tf.int64), 
     'trg_input': tf.FixedLenSequenceFeature([], dtype=tf.int64), 
     'trg_target': tf.FixedLenSequenceFeature([], dtype=tf.int64) 
    } 
    context, sequences = tf.parse_single_sequence_example(
     serialized_ex, 
     context_features=context_features, 
     sequence_features=sequence_features) 

    src_seq_length = tf.cast(context['src_seq_length'], tf.int32) 
    src_input = tf.cast(sequences['src_input'], tf.int32) 
    trg_input = tf.cast(sequences['trg_input'], tf.int32) 
    trg_target = tf.cast(sequences['trg_target'], tf.int32) 

    return src_input, src_seq_length, trg_input, trg_target 

Và để tạo ra mỗi tính năng tfrecord/featurelist:

def int64_feature(value): 
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) 

def int64_featurelist(l): 
    feature = [tf.train.Feature(int64_list=tf.train.Int64List(value=[x])) for x in l] 
    return tf.train.FeatureList(feature=feature) 

http://gph.is/2cg7iKP

3/Thiết lập tàu/dev. Tôi tin rằng đó là một thực tế phổ biến để định kỳ đào tạo mô hình của bạn trong một thời gian, sau đó đánh giá về bộ dev, sau đó lặp lại. Tôi không biết làm thế nào để làm điều này với hàng đợi. Với feed_dict, bạn chỉ cần xây dựng hai biểu đồ có thông số được chia sẻ trong cùng một phiên, một cho đào tạo và một cho dev. Khi bạn đánh giá trên bộ dev, chỉ cần nạp dữ liệu dev vào biểu đồ dev, đó là nó.Nhưng đối với hàng đợi, đầu ra từ hàng đợi là một phần của chính đồ thị. Để chạy hàng đợi, bạn phải bắt đầu hàng đợi, tạo một điều phối viên, sử dụng điều phối viên này để quản lý hàng đợi. Khi nó được thực hiện, hàng đợi là gần !!! Hiện tại, tôi không biết cách viết mã của mình tốt nhất để phù hợp với thiết lập tàu/dev với hàng đợi ngoại trừ việc mở phiên mới, tạo biểu đồ mới cho mỗi lần tôi đánh giá. Cùng một vấn đề được nêu ra here và bạn có thể google cho các câu hỏi tương tự trên Stackoverflow.

Tuy nhiên, nhiều người cho rằng hàng đợi nhanh hơn feed_dict. Đoán của tôi là hàng đợi có lợi nếu bạn đào tạo theo cách phân tán. Nhưng đối với tôi, tôi thường tập luyện chỉ trên 1 GPU và cho tới giờ tôi vẫn không ấn tượng với hàng đợi. Vâng, chỉ là tôi đoán.

2

Tôi nghĩ rằng lợi ích bạn sẽ thấy phụ thuộc nhiều vào vấn đề của bạn. Tôi thấy tốc độ tăng gấp ba lần khi tôi chuyển từ feed_dict sang hàng đợi. Có ít nhất hai lý do khiến nó cải thiện đáng kể trong trường hợp của tôi:

  1. Mã Python tạo ra các vectơ để nạp là khá chậm và không được tối ưu hóa. Đối với mỗi ví dụ đào tạo, đã có rất nhiều bước trung gian (phân bổ một số mảng numpy, tạo một khung dữ liệu Pandas, gọi một loạt các hàm để tính toán/chuyển đổi các tính năng). 25% tổng thời gian đào tạo của tôi đã được chi tiêu để tạo ra dữ liệu nguồn cấp dữ liệu.

  2. Một trong những lý do feed_dict có thể chậm là nó liên quan đến một memcpy của dữ liệu được cấp từ Python đến thời gian chạy TF. Các ví dụ của tôi rất lớn, vì vậy tôi đã có một hit lớn về điều này. (Trong trường hợp của tôi, bởi vì các ví dụ của tôi là seqeuences, và tôi đã đưa chúng vào một độ dài tối đa lớn trước khi cho chúng ăn).

Nếu bạn cho rằng một trong hai tùy chọn này có thể áp dụng cho vấn đề của bạn, bạn nên cân nhắc việc sử dụng hàng đợi.

Các vấn đề liên quan