python-3.x - 是否可以使用自定义生成器来训练带有 keras tensorflow 2.0.0 的多输入架构?
问题描述
使用 TF 2.0.0,我可以训练一个输入的架构,我可以使用自定义生成器训练一个输入的架构,我可以训练一个有两个输入的架构。但是我无法使用自定义生成器训练具有两个输入的架构。
为了保持简约,这里有一个简单的例子,没有生成器,也没有多个输入:
from tensorflow.keras import layers, models, Model, Input, losses
from numpy import random, array, zeros
input1 = Input(shape=2)
dense1 = layers.Dense(5)(input1)
fullModel = Model(inputs=input1, outputs=dense1)
fullModel.summary()
# Generate random examples:
nbSamples = 21
X_train = random.rand(nbSamples, 2)
Y_train = random.rand(nbSamples, 5)
batchSize = 4
fullModel.compile(loss=losses.LogCosh())
fullModel.fit(X_train, Y_train, epochs=10, batch_size=batchSize)
model.fit()
这是一个简单的密集层,它接受大小为 2 的输入向量。随机生成的数据集包含 21 个示例,批量大小为 4。我们也可以在输入中提供自定义生成器,而不是加载所有数据并将它们提供给 。这样做的主要优点(对于 RAM 消耗)是仅批量加载而不是整个数据集。这是一个使用先前架构和自定义生成器的简单示例:
import json
# Save the last dataset in a file:
with open("./dataset1input.txt", 'w') as file:
for i in range(nbSamples):
example = {"x": X_train[i].tolist(), "y": Y_train[i].tolist()}
file.write(json.dumps(example) + "\n")
def generator1input(datasetPath, batch_size, inputSize, outputSize):
X_batch = zeros((batch_size, inputSize))
Y_batch = zeros((batch_size, outputSize))
i=0
while True:
with open(datasetPath, 'r') as file:
for line in file:
example = json.loads(line)
X_batch[i] = array(example["x"])
Y_batch[i] = array(example["y"])
i+=1
if i % batch_size == 0:
yield (X_batch, Y_batch)
i=0
fullModel.compile(loss=losses.LogCosh())
my_generator = generator1input("./dataset1input.txt", batchSize, 2, 5)
fullModel.fit(my_generator, epochs=10, steps_per_epoch=int(nbSamples/batchSize))
在这里,生成器打开数据集文件,但每次调用时只加载 batch_size 示例(不是 nbSamples 示例),并在循环时滑入文件中。
现在,我可以构建一个具有 2 个输入且没有生成器的简单功能架构:
input1 = Input(shape=2)
dense1 = layers.Dense(5)(input1)
subModel1 = Model(inputs=input1, outputs=dense1)
input2 = Input(shape=3)
dense2 = layers.Dense(5)(input2)
subModel2 = Model(inputs=input2, outputs=dense2)
averageLayer = layers.average([subModel1.output, subModel2.output])
fullModel = Model(inputs=[input1, input2], outputs=averageLayer)
fullModel.summary()
# Generate random examples:
nbSamples = 21
X1 = random.rand(nbSamples, 2)
X2 = random.rand(nbSamples, 3)
Y = random.rand(nbSamples, 5)
fullModel.compile(loss=losses.LogCosh())
fullModel.fit([X1, X2], Y, epochs=10, batch_size=batchSize)
直到这里,所有模型都编译并运行,但我无法使用具有最后一个架构及其 2 个输入的生成器......通过尝试以下代码(我认为这在逻辑上应该有效):
# Save data in a file:
with open("./dataset.txt", 'w') as file:
for i in range(nbSamples):
example = {"x1": X1[i].tolist(), "x2": X2[i].tolist(), "y": Y[i].tolist()}
file.write(json.dumps(example) + "\n")
def generator(datasetPath, batch_size, inputSize1, inputSize2, outputSize):
X1_batch = zeros((batch_size, inputSize1))
X2_batch = zeros((batch_size, inputSize2))
Y_batch = zeros((batch_size, outputSize))
i=0
while True:
with open(datasetPath, 'r') as file:
for line in file:
example = json.loads(line)
X1_batch[i] = array(example["x1"])
X2_batch[i] = array(example["x2"])
Y_batch[i] = array(example["y"])
i+=1
if i % batch_size == 0:
yield ([X1_batch, X2_batch], Y_batch)
i=0
fullModel.compile(loss=losses.LogCosh())
my_generator = generator("./dataset.txt", batchSize, 2, 3, 5)
fullModel.fit(my_generator, epochs=10, steps_per_epoch=(nbSamples//batchSize))
我收到以下错误:
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\keras\engine\training.py", line 729, in fit
use_multiprocessing=use_multiprocessing)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\keras\engine\training_v2.py", line 224, in fit
distribution_strategy=strategy)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\keras\engine\training_v2.py", line 547, in _process_training_inputs
use_multiprocessing=use_multiprocessing)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\keras\engine\training_v2.py", line 606, in _process_inputs
use_multiprocessing=use_multiprocessing)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\keras\engine\data_adapter.py", line 566, in __init__
reassemble, nested_dtypes, output_shapes=nested_shape)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\data\ops\dataset_ops.py", line 540, in from_generator
output_types, tensor_shape.as_shape, output_shapes)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\data\util\nest.py", line 471, in map_structure_up_to
results = [func(*tensors) for tensors in zip(*all_flattened_up_to)]
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\data\util\nest.py", line 471, in <listcomp>
results = [func(*tensors) for tensors in zip(*all_flattened_up_to)]
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\framework\tensor_shape.py", line 1216, in as_shape
return TensorShape(shape)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\framework\tensor_shape.py", line 776, in __init__
self._dims = [as_dimension(d) for d in dims_iter]
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\framework\tensor_shape.py", line 776, in <listcomp>
self._dims = [as_dimension(d) for d in dims_iter]
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\framework\tensor_shape.py", line 718, in as_dimension
return Dimension(value)
File "C:\Anaconda\lib\site-packages\tensorflow_core\python\framework\tensor_shape.py", line 193, in __init__
self._value = int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
正如文档中解释的那样,x
参数model.fit()
可以是A generator or keras.utils.Sequence returning (inputs, targets)
和The iterator should return a tuple of length 1, 2, or 3, where the optional second and third elements will be used for y and sample_weight respectively
。因此,我认为它不能接受超过一台发电机的输入。自定义生成器可能无法进行多个输入。请问,你能解释一下吗?一个办法?
(否则,似乎可以tf.data.Dataset.from_generator()
采用不那么定制的方法,但我很难理解output_signature
论点中要指出的内容)
[编辑]感谢您的回复@Francis Tang。事实上,可以使用自定义生成器,但它让我明白我只需要更改行:
yield ([X1_batch, X2_batch], Y_batch)
到:
yield (X1_batch, X2_batch), Y_batch
尽管如此,使用tf.keras.utils.Sequence
. 但我觉得它有点限制。特别是,我在给出的示例(以及我可以找到的大多数示例中Sequence
)中理解,__init__()
它首先用于加载完整的数据集,这违背了生成器的利益。但也许这是一个关于 Sequence() 的特殊示例,没有必要这样使用__init__()
:您可以直接读取文件并将所需的批处理加载到__getitem__()
. 在这种情况下,似乎每次都推送浏览数据文件,否则需要事先为每个批次创建一个文件(不是真正优化的)。
解决方案
from tensorflow.python.keras.utils.data_utils import Sequence
class generator(Sequence):
def __init__(self,filename,batch_size):
data = pickle.load(open(filename,'rb'))
self.X1 = data['X1']
self.X2 = data['X2']
self.y = data['y']
self.bs = batch_size
def __len__(self):
return (len(self.y) - 1) // self.bs + 1
def __getitem__(self,idx):
start, end = idx * self.bs, (idx+1) * self.bs
return (self.X1[start:end], self.X2[start:end]), self.y[start:end]
您需要使用 Sequence 编写一个类:https ://www.tensorflow.org/api_docs/python/tf/keras/utils/Sequence
推荐阅读
- kubernetes - 在 Windows 10 上安装 Kubernetes
- azure - Azure Devops - 使用 docker 和 Azure 容器注册表 (ACR) 发布管道 - 标记问题
- angular - 页面未检测到更改?
- excel-2010 - Excel 删除重复项(如 SELECT ID、max(Monday)、max(Tuesday)
- c# - 在类中使用静态函数返回它初始化
- ios - UICollectionViewCell 快速调整大小
- python - 在python中使用UI手机作为kivy的默认界面
- django-forms - 包含子表单的 django 表单未显示子表单的验证错误
- python - 尽管没有产生错误,但 python 中的 subprocess.call() 没有产生文件
- javascript - 如何阻止其他人发布请求我的 php