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:
tracer les données: La Rouge à Verte couleur indique l'heure à laquelle elles se sont produites dans ici
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
)
Si batch_size=1024
et min_queue_examples=40
:
Si batch_size=100
et min_queue_examples=4000
:
Si batch_size=1024
et min_queue_examples=4000
:
Et même si batch_size = 1681 et min_queue_examples=4000
:
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
?
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:
batch_size
: min_after_dequeue + 1
éléments.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:
capacity
.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:
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.
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.
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.
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.
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).
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:
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.
utilisez decode_raw pour lire les données brutes.
float_values = tf.decode_raw(data, tf.float32, little_endian=True)