深度学习应用于太空「终于解决」

深度学习应用于太空「终于解决」家用电器、汽车、娱乐系统,他们都包含AI功能。麦哲伦太空探测器用于绘制金星表面,使用Unity在地球轨道上模拟。

人工智能无处不在。家用电器、汽车、娱乐系统,他们都包含AI功能。航天工业也不例外。

深度学习应用于太空「终于解决」

麦哲伦太空探测器用于绘制金星表面,使用Unity在地球轨道上模拟。

本文讲解深度学习、神经网络和Tensorflow对卫星对接所发挥的作用。

数据集准备

了解卫星的详细尺寸,目标是创建一种算法,可以准确地预测其姿势和相机的相对距离。该项目的数据集是从安装在机器人手臂上的卫星真实大小的模型中创建的。当摄像机记录视频输入时,手臂模拟各种动作。

深度学习应用于太空「终于解决」

由机器人手臂上的摄像机捕获的卫星模型

我决定集中精力寻找卫星的尖端。如果我能准确找到它,我有信心我可以对模型上的至少两个其他标签做同样的事情。鉴于这3个点和卫星的3D模型,我可以重建卫星的姿态和相对于摄像机的相对位置。

相机记录了14424个未标记的图像,我想用它们来训练和评估神经网络。我担心的一个问题是,我必须花费很多时间在每个图像上手动标记提示。幸运的是,我们可以使用OpenCV优秀的图像标记工具:CVAT。

使用CVAT,你可以批量导入要注释的所有图像,将它们作为电影播放并插入相隔多帧的注释。它还允许工作分散在多个人之间,甚至还有一个漂亮的docker-compose文件,只需点击一下按钮即可运行它。

CVAT节省了大量的时间和工作:只需花费几个小时来注释每个14,424图像上的提示。对于卫星的线性运动,我们只需要注释开始和结束位置,CVAT将插入并添加其间的所有标签。如果你需要视频或图像注释工具,强烈建议使用CVAT,

深度学习应用于太空「终于解决」

使用OpenCV CVAT中的方框注释卫星的尖端。

然而,有一些可改进的地方。例如,CVAT不支持点之间的插值。作为解决方法,必须使用框来代替所有注释的点。此外,任何未注释的帧,即尖端不可见的帧,都不包含在XML输出中。

<?xml version=”1.0″ encoding=”utf-8″?><annotations><meta><!– omitted –></meta><image id=”0″ name=”20180727-OG3_04_45-camL0000.png” width=”528″ height=”406″><box label=”1,” xtl=”331.86″ ytl=”353.18″ xbr=”348.68″ ybr=”369.50″ occluded=”0″ id=”985″></box></image><!– … –><image id=”8443″ name=”Image_IMU_20180914-20180914_152038-camR0090.png” width=”528″ height=”406″><box label=”1,” xtl=”286.40″ ytl=”405.56″ xbr=”308.66″ ybr=”406.00″ occluded=”0″ id=”896″></box></image></annotations>

CVAT的XML输出。

为了使此XML文件适合于训练和评估模型,必须将其后处理为正确的格式。有趣的是:这个看似微不足道的任务,实际上需要相当多的迭代来校对。我经常不得不回去修改标签,添加新标签,更新输出格式等等。

将原始数据和注释转换为适合训练和评估的数据集的代码是代码库的重要组成部分。它不仅仅是一堆模糊的一次性终端命令。你应该重视它,因为它允许你重现你的结果和文档。版本化你的代码,查看它,为你的数据集版本使用语义版本控制,最重要的是,让处理相同问题的其他人通过压缩并提供下载来轻松使用数据集。

数据集构建脚本还允许使用不同版本的数据集进行快速实验:

  • 应用数据增强:旋转,模糊,锐化。
  • 尝试不同的训练和评估分组。
  • 调整数据到适合你模型的表示。
  • 将数据转换并打包成合适的格式。

最后一点值得关注。因为我正在使用Tensorflow,所以我想使用TFRecords数据格式。不仅因为它很好地集成到TF数据集API中,而且主要是因为我假设这种二进制数据格式可以从磁盘中更有效地读取。这是一个关于如何使用Python多处理将图像和标签转换为TFRecords文件的代码摘录。

import multiprocessing as mp

import tensorflow as tf

from skimage.io import imread

CPU_CORES = mp.cpu_count()

def write_tfrecords(labels, file):

with tf.io.TFRecordWriter(file) as tf_writer:

pool = mp.Pool(CPU_CORES)

for label in labels:

pool.apply_async(to_tf_records_example,

args=[label],

callback=lambda example: tf_writer.write(example),

error_callback=lambda exception: print(“error converting to tfrecords example: {}”.format(exception)))

pool.close()

pool.join()

def to_tf_records_example(label):

def _bytes_feature(values):

return tf.train.Feature(bytes_list=tf.train.BytesList(value=values))

def _float_feature(values):

return tf.train.Feature(float_list=tf.train.FloatList(value=values))

def _int64_feature(values):

return tf.train.Feature(int64_list=tf.train.Int64List(value=values))

name, (x, y) = label

img = os.path.join(BUILD_IMG_DIR, name + “.png”)

img = imread(img, as_gray=True)

assert img.shape == (406, 528)

img = img.reshape([-1]) # flatten image into sequence of rows

example = tf.train.Example(features=tf.train.Features(feature={

“label”: _int64_feature([round(float(x)), round(float(y))]),

“image”: _int64_feature(img),

“name”: _bytes_feature([(name + “.png”).encode(“utf-8”)])

}))

return example.SerializeToString()

使用Python中的多处理将图像和标签转换为TFRecords文件。

在创建TFRecords文件之后,创建了这个脚本来进行基准测试并比较从TFRecords文件中读取13,198个训练图像所需的时间,而不是简单地从磁盘读取每个图像并在运行中解码它们。令人惊讶的是,TFRecords数据格式并没有真正提高读取训练数据集的速度。下面的定时输出显示从TFRecords文件顺序读取比从磁盘读取每个图像并在运行中解码它们要慢。差异很小,但我绝对希望TFRecords更快。

如果你真的想要提高数据导入管道的性能,请考虑并行处理和预取数据。通过在解析数据集时简单地设置tf.data.Dataset.map num_parallel_calls参数,从TFRecords文件并行读取这些相同的图像比其顺序读取文件快2倍。从磁盘读取每个图像并在运行中解码它们甚至快3倍。但是,在并行示例中,读取TFRecords文件几乎比在运行中读取图像慢2倍。

最后,结合并行解析和预取允许我在训练期间消除任何CPU瓶颈,并使用nvidia-smi命令测量的平均GPU利用率从75%增加到95%以上。

以下是在我的旧版iMac(2.7 GHz Intel Core i5)上运行时脚本的时序输出:

顺序解析13198图像:

  • TFRecords数据集:50.13s
  • 普通的PNG文件数据集:49.46s

并行解析13198图像:

  • TFRecords数据集:26.78s
  • 普通的PNG文件数据集:15.96s

模型原则

使用YOLO算法对物体检测,如下所示。

深度学习应用于太空「终于解决」

使用YOLO进行物体检测

“YOLO是最有效的物体检测算法之一,涵盖了与物体检测相关的整个计算机视觉文献中的许多最佳创意。”

我将重点关注我如何使用YOLO来解决我的特定本地化问题。

Intermezzo – 对象分割,检测和本地化。

对象分割,检测和本地化之间存在差异。对象分割旨在找到各种形状的片段,其给出要在图像中检测的对象的轮廓的像素方式描述。对象检测是在给定图像中的一个或多个对象周围找到矩形边界框的过程。对象定位是关于找到一个或多个对象的位置。

深度学习应用于太空「终于解决」

深度学习应用于太空「终于解决」

深度学习应用于太空「终于解决」

从左到右的对象分割,检测和定位。

该算法的主要原理很简单:获取输入图像并应用大量的卷积层,每个层都有自己的滤波器组。每组卷积层将减少图像的特征空间或分辨率。请记住,卷积保留了空间局部性,因为每个层都与其相邻层具有局部连接模式。因此,输出层中的每个元素表示输入处原始图像的小区域。每个卷积步骤的滤波器可以在64到1024或甚至4096之间变化。然而,在最终输出层中,滤波器的数量减少到3.换句话说,输出层有3个通道,每个通道都将被训练为为图像中特定区域的不同目的激活:

  • 通道1 – 预测器位:表示在图像的该区域中卫星尖端存在的0和1之间的机会。
  • 通道2 – 相对X位置:尖端的垂直位置(如果可用),相对于该区域的左上角原点。
  • 通道3 – 相对Y位置:与通道2相同,但不同。

看看下面的图片,这是我试图描绘这个概念。

深度学习应用于太空「终于解决」

顶层中的输入图像在尺寸上减小到底部的输出层。输入和输出层之间的灰线显示沿深度维度的每个神经元如何专用于图像的特定区域。每个区域,输出体积预测尖端是否可见,其X和Y坐标是否相对于该区域的原点。在理想情况下,除了尖端可见的突出显示的体积之外,预测将所有元素设置为零。

在我的第一个算法版本中,我没有花很多时间来弄清楚什么是完美的CNN模型架构来解决我的问题。相反,我想专注于代码中允许我训练和评估模型的部分。因此,我只使用原始YOLO论文(下图)实现了与建筑图片相同的模型布局。

深度学习应用于太空「终于解决」

YOLO v1 CNN模型

这就是我的简单思维将这些层解释为代码的方式。

def model(features, labels, mode, params):

is_training = (mode == tf.estimator.ModeKeys.TRAIN)

layer = conv_layer(features, is_training, filter_size=7, num_filters=64, strides=2, dropout_rate=params[“dropout_rate”]) # (?, 200, 261, 64)

layer = tf.layers.max_pooling2d(layer, pool_size=2, strides=2) # (?, 100, 130, 64)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=192, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 100, 130, 192)

layer = tf.layers.max_pooling2d(layer, pool_size=2, strides=2) # (?, 50, 65, 192)

layer = conv_layer(layer, is_training, filter_size=1, num_filters=128, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 50, 65, 192)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=256, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 50, 65, 256)

layer = conv_layer(layer, is_training, filter_size=1, num_filters=256, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 50, 65, 256)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=512, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 50, 65, 512)

layer = tf.layers.max_pooling2d(layer, pool_size=2, strides=2) # (?, 25, 32, 512)

for _ in range(4):

layer = conv_layer(layer, is_training, filter_size=1, num_filters=256, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 25, 32, 256)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=512, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 25, 32, 512)

layer = conv_layer(layer, is_training, filter_size=1, num_filters=512, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 25, 32, 512)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 25, 32, 1024)

layer = tf.layers.max_pooling2d(layer, pool_size=2, strides=2) # (?, 12, 16, 1024)

for _ in range(2):

layer = conv_layer(layer, is_training, filter_size=1, num_filters=512, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 12, 16, 512)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 12, 16, 1024)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 12, 16, 1024)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=2, dropout_rate=params[“dropout_rate”]) # (?, 5, 7, 1024)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 5, 7, 1024)

layer = conv_layer(layer, is_training, filter_size=3, num_filters=1024, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 5, 7, 1024)

layer = conv_layer(layer, is_training, filter_size=1, num_filters=4096, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 5, 7, 4096)

logits = conv_layer(layer, is_training, filter_size=1, num_filters=3, strides=1, dropout_rate=params[“dropout_rate”]) # (?, 5, 7, 3)

def conv_layer(input, is_training, filter_size, num_filters, activation=tf.nn.relu, strides=1, dropout_rate=0.1):

padding = “same” if strides == 1 else “valid”

conv = tf.layers.conv2d(input, num_filters, filter_size, padding=padding, strides=strides, activation=activation) # (?, 32, 32, 32)

norm = tf.layers.batch_normalization(conv, training=is_training)

drop = tf.layers.dropout(norm, rate=dropout_rate, training=is_training) # (?, 32, 32, 32)

return drop

损失函数

为计算损失,我的第一步是将所有标签(基本上是卫星尖端的x,y位置)转换为输出音量,如上图所示。

代码摘录,将给定标签解析为类似于模型输出的体积。

import tensorflow as tf

def parse_label(point, img_w, img_h, out_w, out_h):

block_dims = tf.constant([img_w/out_w, img_h/out_h]) # The width and height of one block in the final output volume.

offset_w, offset_h = tf.unstack(tf.floor(point/block_dims)) # Relative offset of the label in the output image.

point_x, point_y = tf.unstack((point % block_dims)/block_dims) # Get the part after the decimal point as a relative pos within a block.

offset_w, point_x = limit(offset_w, point_x, out_w) # Keep the point x and width within the image boundaries.

offset_h, point_y = limit(offset_h, point_y, out_h) # Keep the point y and height within the image boundaries.

point = tf.concat([[1.0], [point_x, point_y]], axis=0) # Add probability bit with value 1.0.

pixel = tf.reshape(point, [1, 1, 3]) # Reshape to a pixel in the output volume with 3 channels.

# Pad the pixel to the dimensions of the output.

return tf.image.pad_to_bounding_box(pixel, tf.to_int32(offset_h), tf.to_int32(offset_w), out_h, out_w)

def limit(offset, point, max):

return tf.cond(offset >= max, lambda: (max – 1.0, 1.0), lambda: (offset, point))

tf.InteractiveSession()

# For a label with x: 264 and y: 203 in a picture with w: 528 and h: 406, the following label would be produced if the output volume would be w: 7 and h: 5.

r = parse_label([264, 203], 528, 406, 7, 5)

tf.shape(r).eval()

# array([5, 7, 3], dtype=int32)

# All elements in the output are 0 except for this position:

r[2, 3, :].eval()

# array([1. , 0.4999999, 0.5000001], dtype=float32)

下一步是将给定的解析标签与模型的输出进行比较,并设置一个允许梯度下降来优化模型参数的损失函数。我尝试了很多替代方案,摆弄了均方误差和均方对数误差。最后,我决定使用交叉熵损失,因为它对于概率值在0和1之间的分类任务特别有效,就像预测损失一样。

损失函数本身是两部分的加权和:

  • 预测损失:模型预测输出量中每个盒子是否有卫星尖端的程度。我给这个预测损失的权重为5,因为它是正确预测的主要贡献者。
  • XY损失:如果在该框中有一个模型,模型如何预测尖端的位置。如果图中没有可用的提示,则损失函数的这部分应该为零,以便只有预测损失决定最终的损失。我给这个预测损失的权重为1。

看看下面实现这个损失函数的代码。有了这个,我准备使用Adam优化器训练模型。

def get_loss(logits, labels, available):

“””

Calculate the loss from the output of the model and a given set of annotations or labels.

Args:

logits: a batch of model output volumes.

labels: a batch of labels.

available: boolean describing if there is a tip or not per image in a batch.

“””

batch_size = tf.shape(logits)[0]

pred_logits = logits[:, :, :, 0]

pred_labels = labels[:, :, :, 0]

pred_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=pred_labels, logits=pred_logits)

weights = tf.reshape(tf.to_float(available), [batch_size, 1]) # If no points are available, only the probability bits determine the loss

xy_logits = tf.reshape(logits[:, :, :, 1:3], [batch_size, -1])

xy_labels = tf.reshape(labels[:, :, :, 1:3], [batch_size, -1])

xy_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=xy_labels, logits=xy_logits, weights=weights)

return 5 * pred_loss + xy_loss

模型的损失函数。

这种损失特征仍然可以得到很大改善。如果图像中有尖端,则计算输出体积中每个框的XY损耗。这意味着对于没有尖端可见的所有盒子也考虑了XY损失,这不是我想要的。因此,XY损失主要是训练以检测背景而不是卫星尖端。此外,XY损失不是像预测损失那样的分类任务。因此,使用均方误差或类似策略计算它可能更好。

迁移学习

一旦我有了模型和损失特征,正确运行和训练,我想换掉我对YOLO模型的解释,用于经过实战考验和预先训练的版本。由于我只有一个有限的数据集,我认为需要迁移学习来解决问题。

一种选择是简单地从Tensorflow Hub中选择一个模型。然而,TensorFlow使得使用这些模型变得太容易了,我想采取更具挑战性的路线,以便我可以学到更多。我决定使用原作者的最新版YOLO模型,因为它是为Darknet编写的,我想学习如何将该模型导入Tensorflow。

当我开始研究最新的YOLO模型定义时,我很快意识到我需要解析并将该定义文件中的每个部分映射到正确的Tensorflow层。也许我应该更加小心我所希望的,因为这是繁琐而耗时的工作。幸运的是,我发现这个脚本将YOLO模型定义转换为Keras模型,我可以使用Tensorflow加载。

迁移学习是关于重复使用在不同但相似的数据集上预训练的现有模型的部分层权重,并仅重新训练剩余的层。一旦我将所有252个模型层加载起来,我就必须弄清楚我想要保持不变的层(及其相关的权重),我想要重新训练的层以及它们的每个维度。在这个程度上,我写了一个简短的脚本,将Keras模型绘制成图像,并根据给定的图层列表计算尺寸。

使用此脚本,我可以简单地预览完整的模型布局,包括所有图层名称。然后我在模型的正中间手工挑选了一层:”add_19″。在我的实现中,使用layer.trainable属性,前半部分中的所有层的权重保持不变,并且后半部分中的所有层的权重都被重新训练。模型中的最后一层是”conv2d_75″,它有255个通道。我添加了一个额外的卷积层,内核/滤波器大小为3,以减少并使模型输出适合我的目标最终尺寸。

在Keras中加载YOLO模型,启用传输学习并匹配输出层维度以匹配标签和损失函数。

K.set_learning_phase(1)m = load_model(params[“model”], compile=False)m.load_weights(params[“model”], by_name=True)m = Model(m.input, m.get_layer(“conv2d_75”).output) # Skip last layer (?, out_h, out_w, 255)for i, layer in enumerate(m.layers):if i == 152:assert layer.name == “add_19″layer.trainable = (i > 152)m = m(batch[“image”])logits = tf.layers.conv2d(inputs=m, filters=3, kernel_size=1, strides=1, padding=”same”) # (?, out_h, out_w, out_c)loss = get_loss(logits, batch[“label”], batch[“available”])

结果

首先,让我们检查迁移学习如何影响结果。看看下面的图片。重新使用YOLO模型的前半部分并重新训练后半部分会产生巨大的差异。事实上,结果是无法比拟的。没有迁移学习,损失函数停滞在80左右,而通过迁移学习,损失函数立即下降到几乎为零。

深度学习应用于太空「终于解决」

每个训练步骤的模型损失函数输出。深蓝色线显示没有迁移学习的损失或仅仅是随机初始化的模型。浅蓝色线显示模型的一半重用YOLO模型的权重时的损失。

以下图片显示了不使用传输学习时的模型输出。注意模型如何能够过滤掉背景并专注于提示,但永远无法做出准确的预测。

深度学习应用于太空「终于解决」

不使用迁移学习时的模型预测输出。模型的每个输出体积显示为半透明盒子,颜色范围从(非常透明)蓝色(表示该盒子中存在尖端的可能性很小)到绿色然后再变为红色(表示很高的机会) 。

深度学习应用于太空「终于解决」

当不使用迁移学习时,模型预测输出在42个训练时期内针对相同图像可视化。注意模型如何学习如何过滤背景,但从未成功缩小技巧。

这就是整个评估数据集的样子,仍然没有迁移学习。无需迁移学习的评估数据模型预测的视频动画。但是,这是整个评估数据集的样子,启用了传输学习。使用迁移学习对评估数据进行模型预测的视频动画。很明显,迁移学习是对结果产生巨大影响的。因此,本文的其余部分和结果假设启用了迁移学习。

除了损失函数的输出之外,模型的性能还有4种方式:

  1. metrics / dist_mean:对于模型正确预测尖端存在的所有样本,从预测到标签的平均距离(以像素为单位)是多少。
  2. accuracy / point_mean:对于模型正确预测尖端存在的所有样本,这些样本的百分比在距标记的尖端10个像素内。
  3. accuracy / prob_mean:模型能够准确预测尖端的存在。即预测器位必须高于0.5。
  4. accuracy / overall_mean:正确预测样本的百分比。即如果没有尖端,模型也预测相同,如果有尖端,则距离标签10个像素。

以下是在训练模型约8小时后,来自2885个样品的评估数据集的评估结果。

  1. metrics / dist_mean: 1.352px
  2. accuracy/ point_mean: 98.2%
  3. accuracy/ prob_mean: 98.7%
  4. accuracy/ overall_mean: 98.7%

你可以在下面看到Tensorboard中随时间绘制的数字。简单来说,算法平均偏离一个像素。

深度学习应用于太空「终于解决」

深度学习应用于太空「终于解决」

在8小时的训练期间,每个训练时期之后计算四个评估指标和损失函数。

在2885个评估样本中,32张图片的预测已关闭。当我看着它们时,28张是照片,其中检测到的尖端的位置非常准确,但模型根本没有足够的信心说有一个尖端。即预测位不超过0.5,但选择了正确的方框。这是一个例子。

深度学习应用于太空「终于解决」

该模型预测尖端在10px内,但置信水平刚好低于0.5,因此它被标记为错误的预测。它接近于0.5,当舍入预测器位时,它恰好产生0.50。

剩下的四个负面预测更有趣。它们大部分被贴错标签或至少含糊不清。当尖端隐藏在对象后面但仍然容易让人进行本地化时,一些图像被标记为不一致。这正是模型捕获的内容。下面显示了两个示例:尖端隐藏在对象后面,并标记为没有可见的尖端。而模型预测有一个提示和正确的位置。

深度学习应用于太空「终于解决」

深度学习应用于太空「终于解决」

负面预测的示例,其中卫星的尖端隐藏在对象后面。这些图像被标记为没有可见的尖端(因此标记为-1,-1),而模型仍然能够预测正确的位置。

Intermezzo – Tensorflow估算器与手动抽象。

Tensorflow包括估算器,用于保护开发人员免受样板代码的影响,并将代码引导到一个易于扩展到多台机器的结构中。我总是使用估算器,并假设我对他们的忠诚会得到高效率,干净的代码和免费特征。在Tensorflow 1.12中,部分假设是正确的,但我仍然决定创建自己的抽象。下面我解释一下原因。

为了确保一致性,每次调用估算器时,估算器都会从磁盘重新加载模型。{train(),predict(),evaluate()}。(train_and_evaluate方法只是一个用于调用estimator.train和estimator.evaluate的循环。)如果你有一个大型模型并且你想在同一台机器上交错训练和评估,那么重新加载模型真的会慢下来训练过程。

估算器重新加载模型的原因是为了确保分发模型时的一致性。这是他们背后的设计理念的重要组成部分,但正如你可以在这里看到的那样,减速确实会引起挫折。此外,并非所有人都有需要或奢侈地拥有GPU的大军,或者更重要的是,他们需要时间来制作他们的模型,因为这需要仔细设计和努力。Tensorflow确实有一个InMemoryEvaluatorHook来克服这个问题。我试过它并且工作正常,但感觉更像是一种解决方法而不是真正的修复。

此外,当我尝试从估算器模型函数中加载我的Keras模型时,我花了一些时间才意识到必须在每列火车或评估呼叫后手动清除Keras模型。

这些东西并不是真正的显示器,但是随着学习Tensorflow如何工作的冲动,它们足以说服我创建自己的微抽象。

随着Tensorflow 2.0的出现,我相信我所挣扎的大部分内容都将得到解决。Keras将集成到Tensorflow的核心,并成为其主要接口之一。估算器仍然是首选。

经验教训

以下是我学到的一些可能对你有用的总结:

  • 双重,三重和四重检查评估/训练指标的语义,解释和正确性。例如,我的模型从一开始就获得了100%的准确率。这不是因为该模型非常准确,而是因为该度量仅考虑了模型正确预测的那些样本,所以存在提示。如果10000个中只有5个样本检测到正确的尖端,则100%的准确度仍然意味着在10px内仅检测到5个图像。
  • 特别是tf.metrics API骗了我不止一次。明智地使用tf.metrics。它们用于评估,即通过多个批处理操作和整个评估数据集聚合结果。务必在适当的时候重置他们的状态。
  • 如果你在Tensorflow中使用批量规范,请不要忘记在训练期间更新移动均值和方差。这些更新操作自动存储在tf.GraphKeys.UPDATE_OPS集合中,因此不要忘记运行它们。

# Example using tf.control_dependencies:

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)

with tf.control_dependencies(update_ops):

train_op = optimiser.minimize(loss)

# Example using tf.group:

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)

minimize = optimizer.minimize(loss)

train_op = tf.group([minimize, update_ops])

  • 关于在Tensorflow中执行批量规范时如何更新移动均值和方差的两个代码示例。
  • 将单元测试写为完整性检查或至少将快速和脏的测试脚本保存到单独的文件中以供以后参考。彻底测试损失函数尤其有意义。
  • 每次训练模型时,请确保将所有输出指标和其他数据保存到唯一的,带时间标记的目录中。另外,存储git标签(例如heads / master-0-g5936b9e)。这样,无论何时搞砸模型,它都会帮助你恢复到之前的工作版本。

有关如何将git描述写入文件的示例代码。

def write_git_description(dir):

mkdir(dir)

fnull = open(os.devnull, “w”)

cmd = “git describe –all –long > {}/git-description”.format(dir)

subprocess.call(cmd, shell=True, stdout=fnull, stderr=fnull)

view raw

  • 将你的指标写入Tensorboard,用于训练和评估。这是非常值得的,因为可视化可以让你深入了解工作表现。它有一些挑战,但作为回报,你可以更快地迭代和测试你的想法。
  • 跟踪TensorBoard中的所有可训练变量,以帮助你尽早检测爆炸或消失的梯度。以下是关于如何做到这一点的一些灵感。

关于如何可视化模型中每个可训练变量的平均值和直方图以及所有可训练变量的总体直方图的示例代码。

  • 尝试自动并定期暂停训练过程以评估模型。务必将训练曲线和评估曲线渲染到Tensorboard中的相同图形。这样,你可以将模型的性能可视化为在训练过程中从未见过的数据,并在你发现问题时立即停止。请注意,只需重复使用相同的标记,就无法在同一个图中显示多个摘要。Tensorboard将通过在标签名称中添加”_1″来自动使这些摘要唯一,从而强制它们显示在单独的图中。如果要解决此限制,可以自己生成摘要协议缓冲区,然后手动将它们添加到summary.FileWriter()

有关如何在评估期间使用标记”metrics / loss”保存度量标准的示例,同时在训练期间使用具有完全相同标记的度量标准。这允许将训练和评估曲线显示在Tensorboard中的同一图表上。

  • 监控GPU利用率和内存消耗,并尽可能提高GPU利用率。如果你使用NVIDIA显卡,则可以使用nvidia-smi命令来执行此操作。你还可以使用htop监控CPU和内存消耗。

所用硬件列表

· NVIDIA Geforce RTX2080TI(11GB,4352 Cuda核心,600W,INNO3D GAMING OC X3)

· Supermicro X9DRG-QF双CPU主板

· 2x Intel Xeon E5-2630(12核)

· 三星860 EVO SD(500G)

· 128G内存

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11661.html

(0)

相关推荐

  • Redis学习笔记(六) 对象[通俗易懂]

    Redis学习笔记(六) 对象[通俗易懂]前面我们看了Redis用到的主要数据结构,如简单动态字符串(SDS)、双向链表、字典、压缩列表、整数集合等。 但是Redis并没有直接使用这些数据结构来实现键值对,而是基于这些数据结构创建了一个对象系

    2023-02-28
    144
  • 数据库-表结构设计性能优化「建议收藏」

    数据库-表结构设计性能优化「建议收藏」在进行数据库表结构设计时,最优性能设计建议如下:1、客户端IP两种存储方式(不考虑ipv6):1)、int2)、char(10)性能上考虑推荐使用int。2、有些表的电话号码改成varchar(12…

    2023-04-03
    165
  • Python中使用os模块删除文件的正确姿势

    Python中使用os模块删除文件的正确姿势在Python中,删除文件是非常常见的一个操作。但是要确保删除操作的正确性和可靠性,需要使用正确的方式。使用os模块可以帮助我们实现这一点。

    2024-02-01
    111
  • 前端正则表达式语法_正则表达式使用

    前端正则表达式语法_正则表达式使用为什么要学正则表达式. 有位网友这么说: 江湖传说里, 程序员的正则表达式和医生的处方, 道士的鬼符齐名, 曰: 普通人看不懂的三件神器. 这个传说至少向我们透露了两点信息: 一是正则表达式很牛, 能和医生的处方, 道士的鬼符齐名, 并被大家提起, 可见其江湖地位. 二是正则表达式很难, 这也从侧面说明了, 如果你可以熟练的掌握并应用它, 在装逼的路上, 你将如日中天 (别问我中天是谁……) !

    2023-07-15
    117
  • Explain详解与索引优化实践

    Explain详解与索引优化实践为什么要用explain 使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈 如何使用explain 下面是使用 …

    2022-12-16
    130
  • mysql入门以及远程访问

    mysql入门以及远程访问
    MySQL 数据库的使用 一、MySQL 简介 1什么是 MySQL MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 …

    2023-04-05
    145
  • 自学代码(Java)第一i天(2022-2-28)

    自学代码(Java)第一i天(2022-2-28)第一章、Java系统框架Java框架课程表课程表攒代码行数,不妨先给自己定个小目标!

    2022-12-14
    225
  • 【优化技术专题】「温故而知新」基于Quartz系列的任务调度框架的动态化任务实现分析

    【优化技术专题】「温故而知新」基于Quartz系列的任务调度框架的动态化任务实现分析Quartz的动态暂停 恢复 修改和删除任务 当然如果你有需要,可以实现成JDBCJobStore,那样任务信息将会更全面。 比如每天2点执行一个数据导入操作,这个操作执行时间需要5分钟,在这5分钟之

    2023-08-01
    123

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注