python - “无效参数:索引 [0,0,0,0] = 30 不在 [0, 30) 中
问题描述
错误:
InvalidArgumentError: indices[0,0,0,0] = 30 is not in [0, 30)
[[{{node GatherV2}}]] [Op:IteratorGetNext]
历史:
基于此示例,我有一个tf.keras
用于语义分割的基于 U-Net的自定义数据加载器。它是这样写的:
def parse_image(img_path: str) -> dict:
# read image
image = tf.io.read_file(img_path)
#image = tfio.experimental.image.decode_tiff(image)
if xf == "png":
image = tf.image.decode_png(image, channels = 3)
else:
image = tf.image.decode_jpeg(image, channels = 3)
image = tf.image.convert_image_dtype(image, tf.uint8)
#image = image[:, :, :-1]
# read mask
mask_path = tf.strings.regex_replace(img_path, "X", "y")
mask_path = tf.strings.regex_replace(mask_path, "X." + xf, "y." + yf)
mask = tf.io.read_file(mask_path)
#mask = tfio.experimental.image.decode_tiff(mask)
mask = tf.image.decode_png(mask, channels = 1)
#mask = mask[:, :, :-1]
mask = tf.where(mask == 255, np.dtype("uint8").type(NoDataValue), mask)
return {"image": image, "segmentation_mask": mask}
train_dataset = tf.data.Dataset.list_files(
dir_tls(myear = year, dset = "X") + "/*." + xf, seed = zeed)
train_dataset = train_dataset.map(parse_image)
val_dataset = tf.data.Dataset.list_files(
dir_tls(myear = year, dset = "X_val") + "/*." + xf, seed = zeed)
val_dataset = val_dataset.map(parse_image)
## data transformations--------------------------------------------------------
@tf.function
def normalise(input_image: tf.Tensor, input_mask: tf.Tensor) -> tuple:
input_image = tf.cast(input_image, tf.float32) / 255.0
return input_image, input_mask
@tf.function
def load_image_train(datapoint: dict) -> tuple:
input_image = tf.image.resize(datapoint["image"], (imgr, imgc))
input_mask = tf.image.resize(datapoint["segmentation_mask"], (imgr, imgc))
if tf.random.uniform(()) > 0.5:
input_image = tf.image.flip_left_right(input_image)
input_mask = tf.image.flip_left_right(input_mask)
input_image, input_mask = normalise(input_image, input_mask)
return input_image, input_mask
@tf.function
def load_image_test(datapoint: dict) -> tuple:
input_image = tf.image.resize(datapoint["image"], (imgr, imgc))
input_mask = tf.image.resize(datapoint["segmentation_mask"], (imgr, imgc))
input_image, input_mask = normalise(input_image, input_mask)
return input_image, input_mask
## create datasets-------------------------------------------------------------
buff_size = 1000
dataset = {"train": train_dataset, "val": val_dataset}
# -- Train Dataset --#
dataset["train"] = dataset["train"]\
.map(load_image_train, num_parallel_calls = tf.data.experimental.AUTOTUNE)
dataset["train"] = dataset["train"].shuffle(buffer_size = buff_size,
seed = zeed)
dataset["train"] = dataset["train"].repeat()
dataset["train"] = dataset["train"].batch(bs)
dataset["train"] = dataset["train"].prefetch(buffer_size = AUTOTUNE)
#-- Validation Dataset --#
dataset["val"] = dataset["val"].map(load_image_test)
dataset["val"] = dataset["val"].repeat()
dataset["val"] = dataset["val"].batch(bs)
dataset["val"] = dataset["val"].prefetch(buffer_size = AUTOTUNE)
print(dataset["train"])
print(dataset["val"])
现在我想为我的模型使用加权版本,tf.keras.losses.SparseCategoricalCrossentropy
我找到了这个教程,它与上面的示例非常相似。但是,他们还提供了损失的加权版本,使用:
def add_sample_weights(image, label):
# The weights for each class, with the constraint that:
# sum(class_weights) == 1.0
class_weights = tf.constant([2.0, 2.0, 1.0])
class_weights = class_weights/tf.reduce_sum(class_weights)
# Create an image of `sample_weights` by using the label at each pixel as an
# index into the `class weights` .
sample_weights = tf.gather(class_weights, indices=tf.cast(label, tf.int32))
return image, label, sample_weights
和
weighted_model.fit(
train_dataset.map(add_sample_weights),
epochs=1,
steps_per_epoch=10)
我结合了这些方法,因为后一个教程使用以前加载的数据,而我想从磁盘中绘制图像(没有足够的 RAM 来一次加载全部)。
产生第一个示例中的代码(上面的长代码块),然后是
def add_sample_weights(image, segmentation_mask):
class_weights = tf.constant(inv_weights, dtype = tf.float32)
class_weights = class_weights/tf.reduce_sum(class_weights)
sample_weights = tf.gather(class_weights,
indices = tf.cast(segmentation_mask, tf.int32))
return image, segmentation_mask, sample_weights
(inv_weights
是我的权重,一个包含 30 个 float64 值的数组)和
model.fit(dataset["train"].map(add_sample_weights),
epochs = 45, steps_per_epoch = np.ceil(N_img/bs),
validation_data = dataset["val"],
validation_steps = np.ceil(N_val/bs),
callbacks = cllbs)
当我
dataset["train"].map(add_sample_weights).element_spec
在第二个示例中运行时,我得到一个对我来说看起来合理的输出(类似于示例中的输出):
Out[58]:
(TensorSpec(shape=(None, 512, 512, 3), dtype=tf.float32, name=None),
TensorSpec(shape=(None, 512, 512, 1), dtype=tf.float32, name=None),
TensorSpec(shape=(None, 512, 512, 1), dtype=tf.float32, name=None))
但是,当我尝试拟合模型或运行类似
a, b, c = dataset["train"].map(add_sample_weights).take(1)
我将收到上述错误。
到目前为止,我发现了很多关于这个错误的问题(例如,a、b、c、d),但是,它们都在谈论“嵌入层”和我不知道使用的东西。
这个错误来自哪里,我该如何解决?
解决方案
图片tf.gather
作为一种奇特的方式来做索引。您得到的错误类似于 python 中的以下示例:
>>> my_list = [1,2,3]
>>> my_list[3]
IndexError: list index out of range
如果你想使用tf.gather
,那么你的值的范围indices
不应该大于你愿意索引的张量的维度大小。
在您的情况下,在 calltf.gather(class_weights,indices = tf.cast(segmentation_mask, tf.int32))
中,class_weights
作为维度的张量,(30,)
值的范围segmentation_mask
应该在 0 到 29 之间。据我从您的数据管道中可以看出,segmentation_mask
值的范围在 0 到 255 之间。修复将取决于问题。
推荐阅读
- matlab - 如何在不使用 for 循环的情况下计算图像中像素强度的出现次数?
- jenkins - Jenkins Permission Denied on shell 执行
- ios - 显示名称/描述 - 应用内购买已退回
- sql-server - 根据数据库中保存的经度和纬度显示附近的地方。angular6 + sql服务器
- php - 随机选择记录,与先前选择的记录不同
- kubernetes - io.k8s.api.core.v1.PersistentVolumeClaim 中的未知字段“存储”
- configuration - 是否可以为 bitbucket 管道中的不同更改文件触发不同的任务?
- c# - Xamarin.Forms jamesmontemagno 设置插件
- c# - 检查字符串是否仅包含字符 > 或 < 或 -
- javascript - 如何从相关文档中获取工作流的状态?, 关于Alfresco的文件夹规则脚本