web-dev-qa-db-fra.com

Que se passe tf.train.shuffle_batch et `tf.train.batch?

J'utilise Données binaires pour former un DNN.

Mais tf.train.shuffle_batch et tf.train.batch me rendent confus.

Ceci est mon code et je vais faire quelques tests dessus.

Premier Using_Queues_Lib.py:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os

from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

NUM_EXAMPLES_PER_Epoch_FOR_TRAIN = 100
REAL32_BYTES=4


def read_dataset(filename_queue,data_length,label_length):
  class Record(object):
    pass
  result = Record()

  result_data  = data_length*REAL32_BYTES
  result_label = label_length*REAL32_BYTES
  record_bytes = result_data + result_label

  reader = tf.FixedLengthRecordReader(record_bytes=record_bytes)
  result.key, value = reader.read(filename_queue)

  record_bytes = tf.decode_raw(value, tf.float32)
  result.data  = tf.strided_slice(record_bytes, [0],[data_length])#record_bytes: tf.float list
  result.label = tf.strided_slice(record_bytes, [data_length],[data_length+label_length])
  return result


def _generate_data_and_label_batch(data, label, min_queue_examples,batch_size, shuffle):
  num_preprocess_threads = 16   #only speed code
  if shuffle:
    data_batch, label_batch = tf.train.shuffle_batch([data, label],batch_size=batch_size,num_threads=num_preprocess_threads,capacity=min_queue_examples + batch_size,min_after_dequeue=min_queue_examples)
  else:
    data_batch, label_batch = tf.train.batch([data, label],batch_size=batch_size,num_threads=num_preprocess_threads,capacity=min_queue_examples + batch_size)
  return data_batch, label_batch

def inputs(data_dir, batch_size,data_length,label_length):
  filenames = [os.path.join(data_dir, 'test_data_SE.dat')]
  for f in filenames:
    if not tf.gfile.Exists(f):
      raise ValueError('Failed to find file: ' + f)

  filename_queue = tf.train.string_input_producer(filenames)

  read_input = read_dataset(filename_queue,data_length,label_length)

  read_input.data.set_shape([data_length])   #important
  read_input.label.set_shape([label_length]) #important


  min_fraction_of_examples_in_queue = 0.4
  min_queue_examples = int(NUM_EXAMPLES_PER_Epoch_FOR_TRAIN *
                       min_fraction_of_examples_in_queue)
  print ('Filling queue with %d samples before starting to train. '
     'This will take a few minutes.' % min_queue_examples)

  return _generate_data_and_label_batch(read_input.data, read_input.label,
                                     min_queue_examples, batch_size,
                                     shuffle=True)

Second Using_Queues.py:

import Using_Queues_Lib
import tensorflow as tf
import numpy as np
import time


max_steps=10
batch_size=100
data_dir=r'.'
data_length=2
label_length=1

#-----------Save paras-----------
import struct
def WriteArrayFloat(file,data):
  fout=open(file,'wb')        
  fout.write(struct.pack('<'+str(data.flatten().size)+'f',
                                *data.flatten().tolist()))
  fout.close()
#-----------------------------

def add_layer(inputs, in_size, out_size, activation_function=None):
  Weights = tf.Variable(tf.truncated_normal([in_size, out_size]))
  biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
  Wx_plus_b = tf.matmul(inputs, Weights) + biases
  if activation_function is None:
    outputs = Wx_plus_b
  else:
    outputs = activation_function(Wx_plus_b)
  return outputs

data_train,labels_train=Using_Queues_Lib.inputs(data_dir=data_dir,
                      batch_size=batch_size,data_length=data_length,
                                          label_length=label_length)

xs=tf.placeholder(tf.float32,[None,data_length])
ys=tf.placeholder(tf.float32,[None,label_length])

l1 = add_layer(xs, data_length, 5, activation_function=tf.nn.sigmoid)
l2 = add_layer(l1, 5, 5, activation_function=tf.nn.sigmoid)
prediction = add_layer(l2, 5, label_length, activation_function=None)

loss = tf.reduce_mean(tf.square(ys - prediction))
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)

sess=tf.InteractiveSession()
tf.global_variables_initializer().run()

tf.train.start_queue_runners()

for i in range(max_steps):
  start_time=time.time()
  data_batch,label_batch=sess.run([data_train,labels_train])
  sess.run(train_step, feed_dict={xs: data_batch, ys: label_batch})
  duration=time.time()-start_time
  if i % 1 == 0:
    example_per_sec=batch_size/duration
    sec_pec_batch=float(duration)
    WriteArrayFloat(r'./data/'+str(i)+'.bin',
        np.concatenate((data_batch,label_batch),axis=1))
    format_str=('step %d,loss=%.8f(%.1f example/sec;%.3f sec/batch)')
    loss_value=sess.run(loss, feed_dict={xs: data_batch, ys: label_batch})
    print(format_str%(i,loss_value,example_per_sec,sec_pec_batch))

Les données dans ici . Et il a généré par Mathematica.

data = Flatten@Table[{x, y, x*y}, {x, -1, 1, .05}, {y, -1, 1, .05}];
BinaryWrite[file, mydata, "Real32", ByteOrdering -> -1];
Close[file];

Longueur des données: 1681

Les données ressemblent à ceci:

 enter image description here

tracer les données: La Rouge à Verte couleur indique l'heure à laquelle elles se sont produites dans ici

 enter image description here

Exécutez le Using_Queues.py, il produira dix lots et je dessine chaque bach de ce graphique: (batch_size=100 et min_queue_examples=40)  enter image description here

Si batch_size=1024 et min_queue_examples=40:  enter image description here

Si batch_size=100 et min_queue_examples=4000:  enter image description here

Si batch_size=1024 et min_queue_examples=4000:  enter image description here

Et même si batch_size = 1681 et min_queue_examples=4000:  enter image description here

Les régions sont pas remplies de points.

Pourquoi?

Alors pourquoi changer le min_queue_examples faire plus aléatoire? Comment déterminer la valeur min_queue_examples?

Que se passe-t-il dans tf.train.shuffle_batch?

12
partida

La fonction d'échantillonnage utilisée par tf.train.shuffle_batch() (et donc tf.RandomShuffleQueue ) est un peu subtile. L'implémentation utilise tf.RandomShuffleQueue.dequeue_many(batch_size) , dont l'implémentation (simplifiée) est la suivante:

  • Bien que le nombre d'éléments retirés de la file d'attente soit inférieur à batch_size:
    • Attendez que la file d'attente contienne au moins min_after_dequeue + 1 éléments.
    • Sélectionnez un élément de la file d'attente de manière uniforme et aléatoire, supprimez-le de la file d'attente et ajoutez-le au lot de sortie.

L'autre chose à noter est la façon dont les éléments sont ajoutés à la file d'attente, qui utilise un thread en arrière-plan exécutant tf.RandomShuffleQueue.enqueue() sur la même file d'attente: 

  • Attendez que la taille actuelle de la file d'attente soit inférieure à sa capacity.
  • Ajoutez l'élément à la file d'attente.

Par conséquent, les propriétés capacity et min_after_dequeue de la file d'attente (ainsi que la distribution des données d'entrée mises en file d'attente) déterminent la population à partir de laquelle tf.train.shuffle_batch() échantillonnera. Il semble que les données de vos fichiers d’entrée soient classées, vous vous fiez donc entièrement à la fonction tf.train.shuffle_batch() pour obtenir un caractère aléatoire.

Prendre vos visualisations à tour de rôle:

  1. Si capacity et min_after_dequeue sont petits par rapport à l'ensemble de données, le "brassage" sélectionnera des éléments aléatoires dans une petite population ressemblant à une "fenêtre glissante" dans l'ensemble de données. Avec une petite probabilité, vous verrez les anciens éléments dans le lot retiré de la file d'attente.

  2. Si batch_size est grand et min_after_dequeue est petit par rapport à l'ensemble de données, le "brassage" sera à nouveau sélectionné dans une petite "fenêtre glissante" sur l'ensemble de données.

  3. Si min_after_dequeue est grand par rapport à batch_size et à la taille du jeu de données, vous verrez (environ) des échantillons uniformes à partir des données de chaque lot.

  4. Si min_after_dequeue et batch_size sont grands par rapport à la taille du jeu de données, vous verrez (environ) des échantillons uniformes à partir des données de chaque lot.

  5. Dans le cas où min_after_dequeue est 4000 et batch_size est 1681, notez que le nombre attendu de copies de chaque élément de la file d'attente lors de l'échantillonnage est 4000 / 1681 = 2.38; il est donc plus probable que certains éléments soient échantillonnés plus d'une fois (et moins que vous échantillonnerez chaque élément unique exactement une fois).

13
mrry

shuffle_batch n'est rien d'autre qu'une implémentation asynchrone de RandomShuffleQueue. Vous devez d'abord comprendre ce qu'est l'asynchronisme. Ensuite, shuffle_batch devrait être très simple à comprendre, avec un peu d'aide pour les documents officiels ( https://www.tensorflow.org/versions/r1.3/programmers_guide/threading_and_queues ). Imaginons que vous souhaitiez concevoir un système capable de lire et d’écrire des données en même temps. La plupart des gens l'ont conçu comme tel: 

1) créer un thread pour la lecture des données et un thread pour l'écriture Les données. le fil de lecture supprimera un élément de la file d'attente pour la lecture (sortie de file d'attente) et le fil d'écriture ajoutera un élément à la file d'attente comme résultat de l'écriture (mise en file d'attente).

2) utiliser des files d'attente bloquantes pour gérer la synchronisation entre les lectures et écrire des fils, parce que vous ne voulez pas que le fil de lecture soit lire les mêmes données que le fil d'écriture est en train d'écrire, et quand le la file d'attente est vide, le fil de lecture doit être suspendu (bloqué) pour attendre données à écrire (en file d'attente) par le fil d'écriture, et quand la file d'attente est plein, le fil d'écriture doit attendre le fil de lecture extraire des données de la file d'attente (de la file d'attente) . Dans le pipeline d’entrée de tensorflow, les choses ne sont pas différentes. Il existe essentiellement deux ensembles de threads fonctionnant: l’un ajoute des exemples d’entraînement à une file d’attente et l’autre est chargé de prendre des exemples d’entraînement dans la file d’attente. C’est exactement comment sont conçus slice_input_producer, string_input_producer, shuffle_batch. 

Je vous ai écrit un petit programme qui vous permet de comprendre le pipeline d’entrée tensorflow, shuffle_batch et l’effet des paramètres min_after_dequeue et batch_size:

import tensorflow as tf
import numpy as np
test_size = 2000
input_data = tf.range(test_size)

xi = [x for x in range(0, test_size, 50)[1:]]
yi = [int(test_size * x) for x in np.array(range(1, 100, 5)) / 100.0]
zi = np.zeros(shape=(len(yi), len(xi)))
with tf.Session() as sess:
    for idx, batch_size in enumerate(xi):
        for idy, min_after_dequeue in enumerate(yi):
            # synchronization example 1: create a fifo queue, one thread is
            # adding many training examples  at a time to the queue, and the other
            # is taking one example at a time out of the queue.
            # this is similar to what slice_input_producer does.
            fifo_q = tf.FIFOQueue(capacity=test_size, dtypes=tf.int32,
                                  shapes=[[]])
            en_fifo_q = fifo_q.enqueue_many(input_data)
            single_data = fifo_q.dequeue()
            # synchronization example 2: create a random shuffle queue, one thread is
            # adding one training example  at a time to the queue, and the other
            # is taking many examples as a batch at a time out of the queue.
            # this is similar to what shuffle_batch does.
            rf_queue = tf.RandomShuffleQueue(capacity=test_size,
                                             min_after_dequeue=min_after_dequeue,
                                             shapes=single_data._shape, dtypes=single_data._dtype)
            rf_enqueue = rf_queue.enqueue(single_data)
            batch_data = rf_queue.dequeue_many(batch_size)

            # now let's creating threads for enqueue operations(writing thread).
            # enqueue threads have to be started at first, the tf session will
            # take care of your training(reading thread) which will be running when you call sess.run.
            # the tf coordinators are nothing but threads managers that take care of the life cycle
            # for created threads
            qr_fifo = tf.train.QueueRunner(fifo_q, [en_fifo_q] * 8)
            qr_rf = tf.train.QueueRunner(rf_queue, [rf_enqueue] * 4)
            coord = tf.train.Coordinator()
            fifo_queue_threads = qr_fifo.create_threads(sess, coord=coord, start=True)
            rf_queue_threads = qr_rf.create_threads(sess, coord=coord, start=True)
            shuffle_pool = []
            num_steps = int(np.ceil(test_size / float(batch_size)))
            for i in range(num_steps):
                shuffle_data = sess.run([batch_data])
                shuffle_pool.extend(shuffle_data[0].tolist())
            # evaluating unique_rate of each combination of batch_size and min_after_dequeue
            # unique rate 1.0 indicates each example is shuffled uniformly.
            # unique rate < 1.0 means that some examples are shuffled twice.
            unique_rate = len(np.unique(shuffle_pool)) / float(test_size)
            print min_after_dequeue, batch_size, unique_rate
            zi[idy, idx] = unique_rate
            # stop threads.
            coord.request_stop()
            coord.join(rf_queue_threads)
            coord.join(fifo_queue_threads)

print xi, yi, zi
plt.clf()
plt.title('shuffle_batch_example')
plt.ylabel('num_dequeue_ratio')
plt.xlabel('batch_size')
xxi, yyi = np.meshgrid(xi, yi)
plt.pcolormesh(xxi, yyi, zi)
plt.colorbar()
plt.show()

si vous exécutez le code ci-dessus, vous devriez voir le graphique:  shuffle_batch_example

nous pouvons clairement voir que lorsque la taille de lot augmente, le taux unique augmente et lorsque min_after_dequeue devient plus petit, le taux unique devient plus élevé . le taux unique est un indicateur que je calcule pour contrôler le nombre d'échantillons dupliqués générés sur la volée de shuffle_batch sur les mini-lots.

3
weiyixie

utilisez decode_raw pour lire les données brutes.

float_values = tf.decode_raw(data, tf.float32, little_endian=True)
0
Kris Roofe