每次调用returns一批数据的函数
A function that returns a batch of data every time it's called
我正在尝试创建一个函数,每次调用它时 returns 一批数据(列表)。
它应该能够重复任意数量的训练步骤,并在遍历整个数据集(每个时期之后)后从头开始重新开始。
def generate_batch(X, batch_size):
for i in range(0, len(X), batch_size):
batch = X[i:i+batch_size]
yield batch
X = [
[1, 2],
[4, 0],
[5, 1],
[9, 99],
[9, 1],
[1, 1]]
for step in range(num_training_steps):
x_batch = generate_batch(X, batch_size=2)
print(list(x_batch))
当我打印函数的输出时,我发现它获取的是整个数据 (X) 而不是一批数据:
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
问题是什么?这是使用 yield
的正确方法吗?
首先,如果你想在数据结束后从头开始,你需要将生成器函数体包裹在一个无限循环中,像这样:
def generate_batch(X, batch_size):
while 1:
for i in range(0, len(X), batch_size):
batch = X[i:i+batch_size]
yield batch
然后,当你这样做时:
x_batch = generate_batch(X, batch_size=2)
现在x_batch
是一个发电机。您将需要对其进行迭代或对其调用 next()
以一次获取一批数据。如果你只是做 list(x_batch)
它会迭代并将所有批次收集到一个列表中。这不是你想要的。
你想要的是:
gen = generate_batch(X, batch_size=2)
for step in range(num_training_steps):
x_batch = next(gen)
print(x_batch)
或者,如果您需要可调用函数:
gen = generate_batch(X, batch_size=2)
gen = gen.__next__
for step in range(num_training_steps):
x_batch = gen()
print(x_batch)
此外,您可能想为该函数指定一个不同的名称,例如create_batch_generator()
.
好吧,你可以使用 itertools.cycle
。这将像 tf.data.RepeatDataset 那样继续重复列表
您的源代码中有一点调整
from itertools import cycle
def generate_batch(X, batch_size):
dataset = cycle(X)
while True:
batch = list(zip(range(batch_size), dataset))
yield list(map(lambda x: x[1], batch))
就是这样。现在您可以将其插入您的代码
X = [
[1, 2],
[4, 0],
[5, 1],
[9, 99],
[9, 1],
[1, 1]]
for step in range(20):
for batch in generate_batch(X, 2):
print(batch)
会输出如下
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
... and so on
我正在尝试创建一个函数,每次调用它时 returns 一批数据(列表)。
它应该能够重复任意数量的训练步骤,并在遍历整个数据集(每个时期之后)后从头开始重新开始。
def generate_batch(X, batch_size):
for i in range(0, len(X), batch_size):
batch = X[i:i+batch_size]
yield batch
X = [
[1, 2],
[4, 0],
[5, 1],
[9, 99],
[9, 1],
[1, 1]]
for step in range(num_training_steps):
x_batch = generate_batch(X, batch_size=2)
print(list(x_batch))
当我打印函数的输出时,我发现它获取的是整个数据 (X) 而不是一批数据:
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
[[[1, 2], [4, 0]], [[5, 1], [9, 99]], [[9, 1], [1, 1]]]
问题是什么?这是使用 yield
的正确方法吗?
首先,如果你想在数据结束后从头开始,你需要将生成器函数体包裹在一个无限循环中,像这样:
def generate_batch(X, batch_size):
while 1:
for i in range(0, len(X), batch_size):
batch = X[i:i+batch_size]
yield batch
然后,当你这样做时:
x_batch = generate_batch(X, batch_size=2)
现在x_batch
是一个发电机。您将需要对其进行迭代或对其调用 next()
以一次获取一批数据。如果你只是做 list(x_batch)
它会迭代并将所有批次收集到一个列表中。这不是你想要的。
你想要的是:
gen = generate_batch(X, batch_size=2)
for step in range(num_training_steps):
x_batch = next(gen)
print(x_batch)
或者,如果您需要可调用函数:
gen = generate_batch(X, batch_size=2)
gen = gen.__next__
for step in range(num_training_steps):
x_batch = gen()
print(x_batch)
此外,您可能想为该函数指定一个不同的名称,例如create_batch_generator()
.
好吧,你可以使用 itertools.cycle
。这将像 tf.data.RepeatDataset 那样继续重复列表
您的源代码中有一点调整
from itertools import cycle
def generate_batch(X, batch_size):
dataset = cycle(X)
while True:
batch = list(zip(range(batch_size), dataset))
yield list(map(lambda x: x[1], batch))
就是这样。现在您可以将其插入您的代码
X = [
[1, 2],
[4, 0],
[5, 1],
[9, 99],
[9, 1],
[1, 1]]
for step in range(20):
for batch in generate_batch(X, 2):
print(batch)
会输出如下
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
[[1, 2], [4, 0]]
[[9, 99], [9, 1]]
... and so on