網(wǎng)上有很多關(guān)于衛(wèi)星pos機(jī),深度學(xué)習(xí)應(yīng)用于太空衛(wèi)星對(duì)接的知識(shí),也有很多人為大家解答關(guān)于衛(wèi)星pos機(jī)的問(wèn)題,今天pos機(jī)之家(m.afbey.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!
本文目錄一覽:
衛(wèi)星pos機(jī)
人工智能無(wú)處不在。家用電器、汽車、娛樂(lè)系統(tǒng),他們都包含AI功能。航天工業(yè)也不例外。
麥哲倫太空探測(cè)器用于繪制金星表面,使用Unity在地球軌道上模擬。
本文講解深度學(xué)習(xí)、神經(jīng)網(wǎng)絡(luò)和TensorFlow對(duì)衛(wèi)星對(duì)接所發(fā)揮的作用。
數(shù)據(jù)集準(zhǔn)備了解衛(wèi)星的詳細(xì)尺寸,目標(biāo)是創(chuàng)建一種算法,可以準(zhǔn)確地預(yù)測(cè)其姿勢(shì)和相機(jī)的相對(duì)距離。該項(xiàng)目的數(shù)據(jù)集是從安裝在機(jī)器人手臂上的衛(wèi)星真實(shí)大小的模型中創(chuàng)建的。當(dāng)攝像機(jī)記錄視頻輸入時(shí),手臂模擬各種動(dòng)作。
由機(jī)器人手臂上的攝像機(jī)捕獲的衛(wèi)星模型
我決定集中精力尋找衛(wèi)星的尖端。如果我能準(zhǔn)確找到它,我有信心我可以對(duì)模型上的至少兩個(gè)其他標(biāo)簽做同樣的事情。鑒于這3個(gè)點(diǎn)和衛(wèi)星的3D模型,我可以重建衛(wèi)星的姿態(tài)和相對(duì)于攝像機(jī)的相對(duì)位置。
相機(jī)記錄了14424個(gè)未標(biāo)記的圖像,我想用它們來(lái)訓(xùn)練和評(píng)估神經(jīng)網(wǎng)絡(luò)。我擔(dān)心的一個(gè)問(wèn)題是,我必須花費(fèi)很多時(shí)間在每個(gè)圖像上手動(dòng)標(biāo)記提示。幸運(yùn)的是,我們可以使用OpenCV優(yōu)秀的圖像標(biāo)記工具:CVAT。
使用CVAT,你可以批量導(dǎo)入要注釋的所有圖像,將它們作為電影播放并插入相隔多幀的注釋。它還允許工作分散在多個(gè)人之間,甚至還有一個(gè)漂亮的docker-compose文件,只需點(diǎn)擊一下按鈕即可運(yùn)行它。
CVAT節(jié)省了大量的時(shí)間和工作:只需花費(fèi)幾個(gè)小時(shí)來(lái)注釋每個(gè)14,424圖像上的提示。對(duì)于衛(wèi)星的線性運(yùn)動(dòng),我們只需要注釋開(kāi)始和結(jié)束位置,CVAT將插入并添加其間的所有標(biāo)簽。如果你需要視頻或圖像注釋工具,強(qiáng)烈建議使用CVAT,
使用OpenCV CVAT中的方框注釋衛(wèi)星的尖端。
然而,有一些可改進(jìn)的地方。例如,CVAT不支持點(diǎn)之間的插值。作為解決方法,必須使用框來(lái)代替所有注釋的點(diǎn)。此外,任何未注釋的幀,即尖端不可見(jiàn)的幀,都不包含在XML輸出中。
<?xml version="1.0" encoding="utf-8"?><annotations><meta><!-- omitted --></meta><image id="0" name="20180727-OG3_04_45-camL0000.png" width="360px",height="auto" />CVAT的XML輸出。為了使此XML文件適合于訓(xùn)練和評(píng)估模型,必須將其后處理為正確的格式。有趣的是:這個(gè)看似微不足道的任務(wù),實(shí)際上需要相當(dāng)多的迭代來(lái)校對(duì)。我經(jīng)常不得不回去修改標(biāo)簽,添加新標(biāo)簽,更新輸出格式等等。
將原始數(shù)據(jù)和注釋轉(zhuǎn)換為適合訓(xùn)練和評(píng)估的數(shù)據(jù)集的代碼是代碼庫(kù)的重要組成部分。它不僅僅是一堆模糊的一次性終端命令。你應(yīng)該重視它,因?yàn)樗试S你重現(xiàn)你的結(jié)果和文檔。版本化你的代碼,查看它,為你的數(shù)據(jù)集版本使用語(yǔ)義版本控制,最重要的是,讓處理相同問(wèn)題的其他人通過(guò)壓縮并提供下載來(lái)輕松使用數(shù)據(jù)集。
數(shù)據(jù)集構(gòu)建腳本還允許使用不同版本的數(shù)據(jù)集進(jìn)行快速實(shí)驗(yàn):
應(yīng)用數(shù)據(jù)增強(qiáng):旋轉(zhuǎn),模糊,銳化。嘗試不同的訓(xùn)練和評(píng)估分組。調(diào)整數(shù)據(jù)到適合你模型的表示。將數(shù)據(jù)轉(zhuǎn)換并打包成合適的格式。最后一點(diǎn)值得關(guān)注。因?yàn)槲艺谑褂肨ensorflow,所以我想使用TFRecords數(shù)據(jù)格式。不僅因?yàn)樗芎玫丶傻絋F數(shù)據(jù)集API中,而且主要是因?yàn)槲壹僭O(shè)這種二進(jìn)制數(shù)據(jù)格式可以從磁盤中更有效地讀取。這是一個(gè)關(guān)于如何使用Python多處理將圖像和標(biāo)簽轉(zhuǎn)換為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中的多處理將圖像和標(biāo)簽轉(zhuǎn)換為TFRecords文件。在創(chuàng)建TFRecords文件之后,創(chuàng)建了這個(gè)腳本來(lái)進(jìn)行基準(zhǔn)測(cè)試并比較從TFRecords文件中讀取13,198個(gè)訓(xùn)練圖像所需的時(shí)間,而不是簡(jiǎn)單地從磁盤讀取每個(gè)圖像并在運(yùn)行中解碼它們。令人驚訝的是,TFRecords數(shù)據(jù)格式并沒(méi)有真正提高讀取訓(xùn)練數(shù)據(jù)集的速度。下面的定時(shí)輸出顯示從TFRecords文件順序讀取比從磁盤讀取每個(gè)圖像并在運(yùn)行中解碼它們要慢。差異很小,但我絕對(duì)希望TFRecords更快。
如果你真的想要提高數(shù)據(jù)導(dǎo)入管道的性能,請(qǐng)考慮并行處理和預(yù)取數(shù)據(jù)。通過(guò)在解析數(shù)據(jù)集時(shí)簡(jiǎn)單地設(shè)置tf.data.Dataset.map num_parallel_calls參數(shù),從TFRecords文件并行讀取這些相同的圖像比其順序讀取文件快2倍。從磁盤讀取每個(gè)圖像并在運(yùn)行中解碼它們甚至快3倍。但是,在并行示例中,讀取TFRecords文件幾乎比在運(yùn)行中讀取圖像慢2倍。
最后,結(jié)合并行解析和預(yù)取允許我在訓(xùn)練期間消除任何CPU瓶頸,并使用nvidia-smi命令測(cè)量的平均GPU利用率從75%增加到95%以上。
以下是在我的舊版iMac(2.7 GHz Intel Core i5)上運(yùn)行時(shí)腳本的時(shí)序輸出:
順序解析13198圖像:TFRecords數(shù)據(jù)集:50.13s普通的PNG文件數(shù)據(jù)集:49.46s并行解析13198圖像:TFRecords數(shù)據(jù)集:26.78s普通的PNG文件數(shù)據(jù)集:15.96s模型原則使用YOLO算法對(duì)物體檢測(cè),如下所示。
使用YOLO進(jìn)行物體檢測(cè)
"YOLO是最有效的物體檢測(cè)算法之一,涵蓋了與物體檢測(cè)相關(guān)的整個(gè)計(jì)算機(jī)視覺(jué)文獻(xiàn)中的許多最佳創(chuàng)意。"
我將重點(diǎn)關(guān)注我如何使用YOLO來(lái)解決我的特定本地化問(wèn)題。
Intermezzo - 對(duì)象分割,檢測(cè)和本地化。對(duì)象分割,檢測(cè)和本地化之間存在差異。對(duì)象分割旨在找到各種形狀的片段,其給出要在圖像中檢測(cè)的對(duì)象的輪廓的像素方式描述。對(duì)象檢測(cè)是在給定圖像中的一個(gè)或多個(gè)對(duì)象周圍找到矩形邊界框的過(guò)程。對(duì)象定位是關(guān)于找到一個(gè)或多個(gè)對(duì)象的位置。
從左到右的對(duì)象分割,檢測(cè)和定位。
該算法的主要原理很簡(jiǎn)單:獲取輸入圖像并應(yīng)用大量的卷積層,每個(gè)層都有自己的濾波器組。每組卷積層將減少圖像的特征空間或分辨率。請(qǐng)記住,卷積保留了空間局部性,因?yàn)槊總€(gè)層都與其相鄰層具有局部連接模式。因此,輸出層中的每個(gè)元素表示輸入處原始圖像的小區(qū)域。每個(gè)卷積步驟的濾波器可以在64到1024或甚至4096之間變化。然而,在最終輸出層中,濾波器的數(shù)量減少到3.換句話說(shuō),輸出層有3個(gè)通道,每個(gè)通道都將被訓(xùn)練為為圖像中特定區(qū)域的不同目的激活:
通道1 - 預(yù)測(cè)器位:表示在圖像的該區(qū)域中衛(wèi)星尖端存在的0和1之間的機(jī)會(huì)。通道2 - 相對(duì)X位置:尖端的垂直位置(如果可用),相對(duì)于該區(qū)域的左上角原點(diǎn)。通道3 - 相對(duì)Y位置:與通道2相同,但不同。看看下面的圖片,這是我試圖描繪這個(gè)概念。
頂層中的輸入圖像在尺寸上減小到底部的輸出層。輸入和輸出層之間的灰線顯示沿深度維度的每個(gè)神經(jīng)元如何專用于圖像的特定區(qū)域。每個(gè)區(qū)域,輸出體積預(yù)測(cè)尖端是否可見(jiàn),其X和Y坐標(biāo)是否相對(duì)于該區(qū)域的原點(diǎn)。在理想情況下,除了尖端可見(jiàn)的突出顯示的體積之外,預(yù)測(cè)將所有元素設(shè)置為零。
在我的第一個(gè)算法版本中,我沒(méi)有花很多時(shí)間來(lái)弄清楚什么是完美的CNN模型架構(gòu)來(lái)解決我的問(wèn)題。相反,我想專注于代碼中允許我訓(xùn)練和評(píng)估模型的部分。因此,我只使用原始YOLO論文(下圖)實(shí)現(xiàn)了與建筑圖片相同的模型布局。
YOLO v1 CNN模型
這就是我的簡(jiǎn)單思維將這些層解釋為代碼的方式。
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
損失函數(shù)為計(jì)算損失,我的第一步是將所有標(biāo)簽(基本上是衛(wèi)星尖端的x,y位置)轉(zhuǎn)換為輸出音量,如上圖所示。
代碼摘錄,將給定標(biāo)簽解析為類似于模型輸出的體積。
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="360px",height="auto" />
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="360px",height="auto" />
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)
下一步是將給定的解析標(biāo)簽與模型的輸出進(jìn)行比較,并設(shè)置一個(gè)允許梯度下降來(lái)優(yōu)化模型參數(shù)的損失函數(shù)。我嘗試了很多替代方案,擺弄了均方誤差和均方對(duì)數(shù)誤差。最后,我決定使用交叉熵?fù)p失,因?yàn)樗鼘?duì)于概率值在0和1之間的分類任務(wù)特別有效,就像預(yù)測(cè)損失一樣。
損失函數(shù)本身是兩部分的加權(quán)和:
預(yù)測(cè)損失:模型預(yù)測(cè)輸出量中每個(gè)盒子是否有衛(wèi)星尖端的程度。我給這個(gè)預(yù)測(cè)損失的權(quán)重為5,因?yàn)樗钦_預(yù)測(cè)的主要貢獻(xiàn)者。XY損失:如果在該框中有一個(gè)模型,模型如何預(yù)測(cè)尖端的位置。如果圖中沒(méi)有可用的提示,則損失函數(shù)的這部分應(yīng)該為零,以便只有預(yù)測(cè)損失決定最終的損失。我給這個(gè)預(yù)測(cè)損失的權(quán)重為1。看看下面實(shí)現(xiàn)這個(gè)損失函數(shù)的代碼。有了這個(gè),我準(zhǔn)備使用Adam優(yōu)化器訓(xùn)練模型。
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
模型的損失函數(shù)。
這種損失特征仍然可以得到很大改善。如果圖像中有尖端,則計(jì)算輸出體積中每個(gè)框的XY損耗。這意味著對(duì)于沒(méi)有尖端可見(jiàn)的所有盒子也考慮了XY損失,這不是我想要的。因此,XY損失主要是訓(xùn)練以檢測(cè)背景而不是衛(wèi)星尖端。此外,XY損失不是像預(yù)測(cè)損失那樣的分類任務(wù)。因此,使用均方誤差或類似策略計(jì)算它可能更好。
遷移學(xué)習(xí)一旦我有了模型和損失特征,正確運(yùn)行和訓(xùn)練,我想換掉我對(duì)YOLO模型的解釋,用于經(jīng)過(guò)實(shí)戰(zhàn)考驗(yàn)和預(yù)先訓(xùn)練的版本。由于我只有一個(gè)有限的數(shù)據(jù)集,我認(rèn)為需要遷移學(xué)習(xí)來(lái)解決問(wèn)題。
一種選擇是簡(jiǎn)單地從Tensorflow Hub中選擇一個(gè)模型。然而,TensorFlow使得使用這些模型變得太容易了,我想采取更具挑戰(zhàn)性的路線,以便我可以學(xué)到更多。我決定使用原作者的最新版YOLO模型,因?yàn)樗菫镈arknet編寫的,我想學(xué)習(xí)如何將該模型導(dǎo)入Tensorflow。
當(dāng)我開(kāi)始研究最新的YOLO模型定義時(shí),我很快意識(shí)到我需要解析并將該定義文件中的每個(gè)部分映射到正確的Tensorflow層。也許我應(yīng)該更加小心我所希望的,因?yàn)檫@是繁瑣而耗時(shí)的工作。幸運(yùn)的是,我發(fā)現(xiàn)這個(gè)腳本將YOLO模型定義轉(zhuǎn)換為Keras模型,我可以使用Tensorflow加載。
遷移學(xué)習(xí)是關(guān)于重復(fù)使用在不同但相似的數(shù)據(jù)集上預(yù)訓(xùn)練的現(xiàn)有模型的部分層權(quán)重,并僅重新訓(xùn)練剩余的層。一旦我將所有252個(gè)模型層加載起來(lái),我就必須弄清楚我想要保持不變的層(及其相關(guān)的權(quán)重),我想要重新訓(xùn)練的層以及它們的每個(gè)維度。在這個(gè)程度上,我寫了一個(gè)簡(jiǎn)短的腳本,將Keras模型繪制成圖像,并根據(jù)給定的圖層列表計(jì)算尺寸。
使用此腳本,我可以簡(jiǎn)單地預(yù)覽完整的模型布局,包括所有圖層名稱。然后我在模型的正中間手工挑選了一層:"add_19"。在我的實(shí)現(xiàn)中,使用layer.trainable屬性,前半部分中的所有層的權(quán)重保持不變,并且后半部分中的所有層的權(quán)重都被重新訓(xùn)練。模型中的最后一層是"conv2d_75",它有255個(gè)通道。我添加了一個(gè)額外的卷積層,內(nèi)核/濾波器大小為3,以減少并使模型輸出適合我的目標(biāo)最終尺寸。
在Keras中加載YOLO模型,啟用傳輸學(xué)習(xí)并匹配輸出層維度以匹配標(biāo)簽和損失函數(shù)。
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"])結(jié)果首先,讓我們檢查遷移學(xué)習(xí)如何影響結(jié)果。看看下面的圖片。重新使用YOLO模型的前半部分并重新訓(xùn)練后半部分會(huì)產(chǎn)生巨大的差異。事實(shí)上,結(jié)果是無(wú)法比擬的。沒(méi)有遷移學(xué)習(xí),損失函數(shù)停滯在80左右,而通過(guò)遷移學(xué)習(xí),損失函數(shù)立即下降到幾乎為零。
每個(gè)訓(xùn)練步驟的模型損失函數(shù)輸出。深藍(lán)色線顯示沒(méi)有遷移學(xué)習(xí)的損失或僅僅是隨機(jī)初始化的模型。淺藍(lán)色線顯示模型的一半重用YOLO模型的權(quán)重時(shí)的損失。
以下圖片顯示了不使用傳輸學(xué)習(xí)時(shí)的模型輸出。注意模型如何能夠過(guò)濾掉背景并專注于提示,但永遠(yuǎn)無(wú)法做出準(zhǔn)確的預(yù)測(cè)。
不使用遷移學(xué)習(xí)時(shí)的模型預(yù)測(cè)輸出。模型的每個(gè)輸出體積顯示為半透明盒子,顏色范圍從(非常透明)藍(lán)色(表示該盒子中存在尖端的可能性很小)到綠色然后再變?yōu)榧t色(表示很高的機(jī)會(huì)) 。
當(dāng)不使用遷移學(xué)習(xí)時(shí),模型預(yù)測(cè)輸出在42個(gè)訓(xùn)練時(shí)期內(nèi)針對(duì)相同圖像可視化。注意模型如何學(xué)習(xí)如何過(guò)濾背景,但從未成功縮小技巧。
這就是整個(gè)評(píng)估數(shù)據(jù)集的樣子,仍然沒(méi)有遷移學(xué)習(xí)。無(wú)需遷移學(xué)習(xí)的評(píng)估數(shù)據(jù)模型預(yù)測(cè)的視頻動(dòng)畫。但是,這是整個(gè)評(píng)估數(shù)據(jù)集的樣子,啟用了傳輸學(xué)習(xí)。使用遷移學(xué)習(xí)對(duì)評(píng)估數(shù)據(jù)進(jìn)行模型預(yù)測(cè)的視頻動(dòng)畫。很明顯,遷移學(xué)習(xí)是對(duì)結(jié)果產(chǎn)生巨大影響的。因此,本文的其余部分和結(jié)果假設(shè)啟用了遷移學(xué)習(xí)。
除了損失函數(shù)的輸出之外,模型的性能還有4種方式:
metrics / dist_mean:對(duì)于模型正確預(yù)測(cè)尖端存在的所有樣本,從預(yù)測(cè)到標(biāo)簽的平均距離(以像素為單位)是多少。accuracy / point_mean:對(duì)于模型正確預(yù)測(cè)尖端存在的所有樣本,這些樣本的百分比在距標(biāo)記的尖端10個(gè)像素內(nèi)。accuracy / prob_mean:模型能夠準(zhǔn)確預(yù)測(cè)尖端的存在。即預(yù)測(cè)器位必須高于0.5。accuracy / overall_mean:正確預(yù)測(cè)樣本的百分比。即如果沒(méi)有尖端,模型也預(yù)測(cè)相同,如果有尖端,則距離標(biāo)簽10個(gè)像素。以下是在訓(xùn)練模型約8小時(shí)后,來(lái)自2885個(gè)樣品的評(píng)估數(shù)據(jù)集的評(píng)估結(jié)果。
metrics / dist_mean: 1.352pxaccuracy/ point_mean: 98.2%accuracy/ prob_mean: 98.7%accuracy/ overall_mean: 98.7%你可以在下面看到Tensorboard中隨時(shí)間繪制的數(shù)字。簡(jiǎn)單來(lái)說(shuō),算法平均偏離一個(gè)像素。
在8小時(shí)的訓(xùn)練期間,每個(gè)訓(xùn)練時(shí)期之后計(jì)算四個(gè)評(píng)估指標(biāo)和損失函數(shù)。
在2885個(gè)評(píng)估樣本中,32張圖片的預(yù)測(cè)已關(guān)閉。當(dāng)我看著它們時(shí),28張是照片,其中檢測(cè)到的尖端的位置非常準(zhǔn)確,但模型根本沒(méi)有足夠的信心說(shuō)有一個(gè)尖端。即預(yù)測(cè)位不超過(guò)0.5,但選擇了正確的方框。這是一個(gè)例子。
該模型預(yù)測(cè)尖端在10px內(nèi),但置信水平剛好低于0.5,因此它被標(biāo)記為錯(cuò)誤的預(yù)測(cè)。它接近于0.5,當(dāng)舍入預(yù)測(cè)器位時(shí),它恰好產(chǎn)生0.50。
剩下的四個(gè)負(fù)面預(yù)測(cè)更有趣。它們大部分被貼錯(cuò)標(biāo)簽或至少含糊不清。當(dāng)尖端隱藏在對(duì)象后面但仍然容易讓人進(jìn)行本地化時(shí),一些圖像被標(biāo)記為不一致。這正是模型捕獲的內(nèi)容。下面顯示了兩個(gè)示例:尖端隱藏在對(duì)象后面,并標(biāo)記為沒(méi)有可見(jiàn)的尖端。而模型預(yù)測(cè)有一個(gè)提示和正確的位置。
負(fù)面預(yù)測(cè)的示例,其中衛(wèi)星的尖端隱藏在對(duì)象后面。這些圖像被標(biāo)記為沒(méi)有可見(jiàn)的尖端(因此標(biāo)記為-1,-1),而模型仍然能夠預(yù)測(cè)正確的位置。
Intermezzo - Tensorflow估算器與手動(dòng)抽象。Tensorflow包括估算器,用于保護(hù)開(kāi)發(fā)人員免受樣板代碼的影響,并將代碼引導(dǎo)到一個(gè)易于擴(kuò)展到多臺(tái)機(jī)器的結(jié)構(gòu)中。我總是使用估算器,并假設(shè)我對(duì)他們的忠誠(chéng)會(huì)得到高效率,干凈的代碼和免費(fèi)特征。在Tensorflow 1.12中,部分假設(shè)是正確的,但我仍然決定創(chuàng)建自己的抽象。下面我解釋一下原因。
為了確保一致性,每次調(diào)用估算器時(shí),估算器都會(huì)從磁盤重新加載模型。{train(),predict(),evaluate()}。(train_and_evaluate方法只是一個(gè)用于調(diào)用estimator.train和estimator.evaluate的循環(huán)。)如果你有一個(gè)大型模型并且你想在同一臺(tái)機(jī)器上交錯(cuò)訓(xùn)練和評(píng)估,那么重新加載模型真的會(huì)慢下來(lái)訓(xùn)練過(guò)程。
估算器重新加載模型的原因是為了確保分發(fā)模型時(shí)的一致性。這是他們背后的設(shè)計(jì)理念的重要組成部分,但正如你可以在這里看到的那樣,減速確實(shí)會(huì)引起挫折。此外,并非所有人都有需要或奢侈地?fù)碛蠫PU的大軍,或者更重要的是,他們需要時(shí)間來(lái)制作他們的模型,因?yàn)檫@需要仔細(xì)設(shè)計(jì)和努力。Tensorflow確實(shí)有一個(gè)InMemoryEvaluatorHook來(lái)克服這個(gè)問(wèn)題。我試過(guò)它并且工作正常,但感覺(jué)更像是一種解決方法而不是真正的修復(fù)。
此外,當(dāng)我嘗試從估算器模型函數(shù)中加載我的Keras模型時(shí),我花了一些時(shí)間才意識(shí)到必須在每列火車或評(píng)估呼叫后手動(dòng)清除Keras模型。
這些東西并不是真正的顯示器,但是隨著學(xué)習(xí)Tensorflow如何工作的沖動(dòng),它們足以說(shuō)服我創(chuàng)建自己的微抽象。
隨著Tensorflow 2.0的出現(xiàn),我相信我所掙扎的大部分內(nèi)容都將得到解決。Keras將集成到Tensorflow的核心,并成為其主要接口之一。估算器仍然是首選。
經(jīng)驗(yàn)教訓(xùn)以下是我學(xué)到的一些可能對(duì)你有用的總結(jié):
雙重,三重和四重檢查評(píng)估/訓(xùn)練指標(biāo)的語(yǔ)義,解釋和正確性。例如,我的模型從一開(kāi)始就獲得了100%的準(zhǔn)確率。這不是因?yàn)樵撃P头浅?zhǔn)確,而是因?yàn)樵摱攘績(jī)H考慮了模型正確預(yù)測(cè)的那些樣本,所以存在提示。如果10000個(gè)中只有5個(gè)樣本檢測(cè)到正確的尖端,則100%的準(zhǔn)確度仍然意味著在10px內(nèi)僅檢測(cè)到5個(gè)圖像。特別是tf.metrics API騙了我不止一次。明智地使用tf.metrics。它們用于評(píng)估,即通過(guò)多個(gè)批處理操作和整個(gè)評(píng)估數(shù)據(jù)集聚合結(jié)果。務(wù)必在適當(dāng)?shù)臅r(shí)候重置他們的狀態(tài)。如果你在Tensorflow中使用批量規(guī)范,請(qǐng)不要忘記在訓(xùn)練期間更新移動(dòng)均值和方差。這些更新操作自動(dòng)存儲(chǔ)在tf.GraphKeys.UPDATE_OPS集合中,因此不要忘記運(yùn)行它們。# 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])
關(guān)于在Tensorflow中執(zhí)行批量規(guī)范時(shí)如何更新移動(dòng)均值和方差的兩個(gè)代碼示例。將單元測(cè)試寫為完整性檢查或至少將快速和臟的測(cè)試腳本保存到單獨(dú)的文件中以供以后參考。徹底測(cè)試損失函數(shù)尤其有意義。每次訓(xùn)練模型時(shí),請(qǐng)確保將所有輸出指標(biāo)和其他數(shù)據(jù)保存到唯一的,帶時(shí)間標(biāo)記的目錄中。另外,存儲(chǔ)git標(biāo)簽(例如heads / master-0-g5936b9e)。這樣,無(wú)論何時(shí)搞砸模型,它都會(huì)幫助你恢復(fù)到之前的工作版本。有關(guān)如何將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
將你的指標(biāo)寫入Tensorboard,用于訓(xùn)練和評(píng)估。這是非常值得的,因?yàn)榭梢暬梢宰屇闵钊肓私夤ぷ鞅憩F(xiàn)。它有一些挑戰(zhàn),但作為回報(bào),你可以更快地迭代和測(cè)試你的想法。跟蹤TensorBoard中的所有可訓(xùn)練變量,以幫助你盡早檢測(cè)爆炸或消失的梯度。以下是關(guān)于如何做到這一點(diǎn)的一些靈感。關(guān)于如何可視化模型中每個(gè)可訓(xùn)練變量的平均值和直方圖以及所有可訓(xùn)練變量的總體直方圖的示例代碼。
嘗試自動(dòng)并定期暫停訓(xùn)練過(guò)程以評(píng)估模型。務(wù)必將訓(xùn)練曲線和評(píng)估曲線渲染到Tensorboard中的相同圖形。這樣,你可以將模型的性能可視化為在訓(xùn)練過(guò)程中從未見(jiàn)過(guò)的數(shù)據(jù),并在你發(fā)現(xiàn)問(wèn)題時(shí)立即停止。請(qǐng)注意,只需重復(fù)使用相同的標(biāo)記,就無(wú)法在同一個(gè)圖中顯示多個(gè)摘要。Tensorboard將通過(guò)在標(biāo)簽名稱中添加"_1"來(lái)自動(dòng)使這些摘要唯一,從而強(qiáng)制它們顯示在單獨(dú)的圖中。如果要解決此限制,可以自己生成摘要協(xié)議緩沖區(qū),然后手動(dòng)將它們添加到summary.FileWriter()有關(guān)如何在評(píng)估期間使用標(biāo)記"metrics / loss"保存度量標(biāo)準(zhǔn)的示例,同時(shí)在訓(xùn)練期間使用具有完全相同標(biāo)記的度量標(biāo)準(zhǔn)。這允許將訓(xùn)練和評(píng)估曲線顯示在Tensorboard中的同一圖表上。
監(jiān)控GPU利用率和內(nèi)存消耗,并盡可能提高GPU利用率。如果你使用NVIDIA顯卡,則可以使用nvidia-smi命令來(lái)執(zhí)行此操作。你還可以使用htop監(jiān)控CPU和內(nèi)存消耗。所用硬件列表· 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內(nèi)存
pos數(shù)據(jù)全稱?
POS數(shù)據(jù)是定位定姿系統(tǒng),是IMU/DGPS組合的高精度位置與姿態(tài)測(cè)量系統(tǒng)(position and orientation system,POS)。利用裝在飛機(jī)上的GPS接收機(jī)和設(shè)在地面上的一個(gè)或多個(gè)基站上的GPS接收機(jī)同步而連續(xù)地觀測(cè)GPS衛(wèi)星信號(hào)。
精密定位主要采用差分GPS定位(DGPS)技術(shù),而姿態(tài)測(cè)量主要是利用慣性測(cè)量裝置(IMU)來(lái)感測(cè)飛機(jī)或其他載體的加速度,經(jīng)過(guò)積分運(yùn)算,獲取載體的速度和姿態(tài)等信息
以上就是關(guān)于衛(wèi)星pos機(jī),深度學(xué)習(xí)應(yīng)用于太空衛(wèi)星對(duì)接的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于衛(wèi)星pos機(jī)的知識(shí),希望能夠幫助到大家!
