1.项目介绍
在此项目中,我们要构建语义分割网络,对其进行培训,验证并将其部署在Follow Me项目中,使用自己的神经网络跟踪单个目标!
项目步骤:
1.设置本地环境。
2.有关模拟器如何工作及其基本控件的简要概述。
3.从模拟器收集数据以训练网络。
4.建立神经网络。
5.相关程序编写。
6.训练网络。
7.使用Follow Me!模拟器测试模型。
2. 环境设置
安装依赖项
OS X和Linux(Ubuntu)
source activate RoboND
pip install tensorflow==1.2.1
pip install socketIO-client
pip install transforms3d
pip install PyQt5
pip install pyqtgraph
windows
source activate RoboND
# if the above throws an error, you can run "activate RoboND" instead
pip install tensorflow==1.2.1
pip install socketIO-client
pip install transforms3d
pip install PyQt5
pip install pyqtgraph
克隆存储库
$ git clone https://github.com/udacity/RoboND-DeepLearning-Project.git
下载QuadSim
要将神经网络与QuadSim模拟器连接,必须使用针对该项目量身定制的QuadSim版本。
模拟器文件可以在这里下载。
获取数据
将以下三个文件保存到克隆存储库的data文件夹中。
3.模拟器介绍
启动模拟器:
模拟器提供两个选择:(1)DL Training 和(2)Follow Me!
DLTraining 用于收集培训数据-稍后会详细介绍。
Follow Me! 选项是评估受过训练的网络的质量。
在模拟器中处于活动状态时,可以使用以下键盘控件:
L:打开和关闭带有控制信息的图例
H:启用和禁用四边形的本地控制
WSAD /箭头:启用本地控制后,四边形会移动
E / Q:分别将四边形顺时针和逆时针旋转
Space / C:在启用本地控制时增大和减小四边形的推力
滚轮:放大和缩小相机
鼠标右键(拖动):围绕四边形旋转相机
鼠标右键(单击):重置相机
鼠标中键:切换巡逻和跟随模式
G:重置四边形方向
F5:循环质量设置
/:路径显示开/关
ESC:退出主菜单
Crtl-Q:退出
4.数据收集
在这个项目的存储库中提供了一个简单的培训数据集。如果你对提高你的分数感兴趣,则需要收集额外的训练数据。要做到这一点,请参阅以下步骤。
数据目录组织如下:
data/runs - contains the results of prediction runs
data/train/images - contains images for the training set
data/train/masks - contains masked (labeled) images for the training set
data/validation/images - contains images for the validation set
data/validation/masks - contains masked (labeled) images for the validation set
data/weights - contains trained TensorFlow models
data/raw_sim_data/train/run1
data/raw_sim_data/validation/run1
data/runs - 包含预测运行的结果
data/train/images - 包含训练集的图像
data/train/masks - 包含训练集的掩码(标记)图像
data/validation/images - 包含验证集的图像
data/validation/masks - 包含用于验证集的屏蔽(标记)图像
data/weights - 包含经过训练的TensorFlow模型
data/raw_sim_data/train/run1
data/raw_sim_data/validation/run1
训练集
- 运行QuadSim
- 点击
DL Training
按钮 - 设置patrol points, path points,,spawn points ,具体步骤见下收集指南
- 模拟器运行后,按“r”开始记录。
- 在文件选择菜单中,记录到
data/raw_sim_data/train/run1
目录 - 可选:按“9”键可加快数据采集速度(1-9键会减慢采集速度)
- 收集完数据后,按“r”停止记录。
- 要重置模拟器,点击“”
- 要收集多次运行,请创建目录
data/raw_sim_data/train/run2
、data/raw_sim_data/train/run3
并重复上述步骤。
验证集
要收集验证集,使用目录data/raw_sim_data/validation
,重复上述两组步骤。
图像预处理
在对网络进行训练之前,首先需要对图像进行预处理。预处理步骤将深度掩码从sim转换为适合训练神经网络的二进制掩码。它还将图像从.png转换为.jpeg,以创建缩小大小的数据集。
进行预处理:
python preprocess_ims.py
注意:如果数据是按照上面的步骤存储的,那么这个脚本应该没有错误地运行。
以上为课程提示,但是我在实际使用过程中,因为版本问题,还是报了如下错误:
TypeError: numpy boolean subtract, the-
operator, is deprecated, use the bitwise_xor, the^
operator, or the logical_xor function instead.
按照程序提示所作更改后,将程序内容使用bitwise_xor
替换掉,错误解决。
重要提示1:
运行preprocess_ims.py
不会删除processed_data文件夹中的文件。这意味着,如果将图像留在处理过的数据中,并收集一个新的数据集,processed_data中的一些数据将被覆盖,而另一些则保持原样。建议在使用一组新收集的数据运行preprocess_ims.py
之前,删除processed_data(或整个文件夹)中的train和validation文件夹。
重要提示2:
notebook和代码假设用于培训/验证的数据在data/train
中和data/validation
中。在运行preprocess_ims.py
之后,processed_ims
中可能会有新的培训和验证文件夹。
重命名或移动data/train
和data/validation
,然后将data/processed_ims/train
移动到data/
中,将data/processed_ims/validationalso
移动到data/
中
重要提示3:
合并多个train或validation可能比较困难,建议根据在raw_sim_data/train/run1
中包含的内容来决定数据选择,在目录中可能有许多不同的运行。可以在data/中创建临时文件夹,并存储当前不想使用的原始运行数据,但这可能对以后有用。选择要在raw_sim_data/train
和raw_sim_data/validation
中包含哪些run_x文件夹,然后从code/
目录中运行preprocess_ams .py
来生成新的培训和验证集。
5. 收据收集指南
打开quad sim,在Spawn crowd处打勾,然后点击DL training
本地控制模式
该四边形将以巡逻模式开始,但是由于我们尚未添加任何航点,因此它无处可去。要添加航点,您必须先通过H
键切换到本地控制。
查看和导航
- 要缩小四轴飞行器,可以使用mouse wheel。
- 要在训练过程中随时更改观看角度,请right click在屏幕上移动鼠标。
- 使用WASD键向前,向左,向后和向右移动四边形
- 使用和C推力上下
- 使用QE键将四边形向左或向右旋转
- 按G将其重置为起始姿势。
- 要查找这些命令和其他命令,请按L图例键
管理数据收集
可以控制数据收集过程的3个主要方面,以便确定收集的数据类型。这些如下:
- 四边形在巡逻时将采用的路径。
- 跟踪对象走的路。课程中称跟踪对象为’Hero’ 。
- 干扰行人生成的位置。
设置巡逻点
按下P键设置巡逻点。绿色的巡逻点将出现在无人机的位置上。
移动到另一个位置,然后再次按P在附近的某个地方添加一个巡逻点。
现在,可以通过按H将Quad置于巡检模式。要切换回本地控制,请再次按H。
要删除所有已设置的巡逻点,请按 L。
设置跟踪对象路径点
要设置跟踪对象路径点,请在本地控制模式下按O。跟踪对象路径点与巡逻点非常相似,除了它们总是放在地面上。按下C键来降低四轴飞行器的高度,以便更好地观察你正在设置的点。与巡逻点类似,所有的跟踪对象路径点都可以通过按k删除。跟踪对象将从创建的第一个点开始,并在路径上行走。当到达终点时,跟踪对象会在重新出现在道路的起点。
设置生成点hh
模拟器中除跟踪对象外的所有角色将在30-50秒后在其中一个生成点重新生成。您可以通过放置的生成点的数量和位置来控制给定区域中的人数。可以通过按键I在当前的四边形x,y位置设置生成点。蓝色标记将出现在生成位置。可以通过按J删除所有生成点
设置数据收集运行
对于设置生成和跟踪对象路径点,旋转摄像机很有帮助,因此您可以从上方直接查看四边形。
首先,让我们创建一个小型收集实验。通常情况下,需要运行多个收集数据,并让每个运行针对特定的数据类l型。还需要拥有包含跟踪对象的大量数据样本。如果创建了很大的巡逻路径和跟踪对象路径,那么收集包含跟踪对象的图像的可能性就很小。
开始收集运行
当你对巡逻路径,跟踪对象路径和生成点的放置方式感到满意时,请按M让行人们开始生成。
要开始记录数据,请R按键。保存到“ raw_sim_data/train/target
。我们使用目标目录,因为我们选择让跟踪对象出现在这个集合运行中。或者,随机选择的人可以扮演跟踪对象的角色。在这种情况下,为了正确地准备数据,应该选择non_target
文件夹。
另一个导入说明。在尝试设置另一个数据收集运行之前,最好重新启动模拟器(非常推荐)
target/non_target
文件夹内可以有任意数量的run文件夹。多次使用同一运行文件夹将导致第一次运行的数据被删除,并被第二次运行的数据替换。按下select按钮,屏幕顶部的指示器应变为绿色,这表示正在收集数据。
按下H以使Quad进入巡逻模式。要加快数据收集过程,请9按键。该运行中的数据将存储在所选择的文件夹中。
数据收集完毕后,可以再次按R停止记录。尽管不建议在运行数据收集时添加/删除跟踪对象路径/生成点,但是可以删除巡逻路径并根据需要进行修改。
要重置模拟器,请按 <Esc>
数据收集最佳实践
在记录此项目的数据时,让我们花一些时间介绍最佳做法。
从应该收集的数据开始:
- 通过在非常密集的人群中追踪对象来收集数据。
- 在巡逻期间,数据在追踪对象上方直接之字形巡逻。
- 在四轴飞行器进行标准巡逻时收集的数据。
(1)用data collectionrun收集数据:
收集额外数据的最简单方法是简单地进行DL训练,然后按开始生成。然后开始记录,即使添加很多图像也不会对得分有太大的改善。
(2)以关注模式收集数据
三分之一的评分数据基于跟随目标人员时的质心准确度。
为了收集将为神经网络做好准备的数据,我们创建了两个自定义数据收集运行。
要开始运行模拟器并选择DL训练模式。然后按“ j”,“ k”,然后按“ l”以清除任务航路点。
(3)尝试使用巡逻获取跟踪对象的所有角度:
为此,我们将有两个巡逻点。然后直接在巡逻路径下,
为跟踪对象创建锯齿形路径。由于万向摄像机的角度,将巡逻路径移到跟踪对象路径的边界之外很有帮助。
(4)从完整路径收集数据:
在保存数据的同时,我还将开始从完整的巡逻路径收集一些数据。
此数据中将没有跟踪对象,但这一点很重要,因此网络可以学习解释看起来像跟踪对象的对象。
(5)将跟踪对象数据的收集集中在人群中
之后使用python preprocess_ims.py
命令来处理所收集到的数据,将之转换成训练神经网络所需的数据。将之拷入/train文件夹中
6.建立分割网络
import os
import glob
import sys
import tensorflow as tf
from scipy import misc
import numpy as np
from tensorflow.contrib.keras.python import keras
from tensorflow.contrib.keras.python.keras import layers, models
from tensorflow import image
from utils import scoring_utils
from utils.separable_conv2d import SeparableConv2DKeras, BilinearUpSampling2D
from utils import data_iterator
from utils import plotting_tools
from utils import model_tools
def separable_conv2d_batchnorm(input_layer, filters, strides=1):
output_layer = SeparableConv2DKeras(filters=filters, kernel_size=3, strides=strides,
padding='same', activation='relu')(input_layer)
output_layer = layers.BatchNormalization()(output_layer)
return output_layer
def conv2d_batchnorm(input_layer, filters, kernel_size=3, strides=1):
output_layer = layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides,
padding='same', activation='relu')(input_layer)
output_layer = layers.BatchNormalization()(output_layer)
return output_layer
def bilinear_upsample(input_layer):
output_layer = BilinearUpSampling2D((2,2))(input_layer)
return output_layer
# # 建立模型
# 使用separable_conv2d_batchnorm()函数创建一个可分离的卷积层。
# 该filters参数定义输出层的大小或深度。例如32或64。
def encoder_block(input_layer, filters, strides):
# TODO Create a separable convolution layer using the separable_conv2d_batchnorm() function.
output_layer = separable_conv2d_batchnorm(input_layer, filters, strides)
return output_layer
# 解码器模块
def decoder_block(small_ip_layer, large_ip_layer, filters):
# TODO Upsample the small input layer using the bilinear_upsample() function.
upsampled = bilinear_upsample(small_ip_layer)
print('upsampled_shape:', upsampled.shape)
print('large_input_shape:', large_ip_layer.shape)
# TODO Concatenate the upsampled and large input layers using layers.concatenate
concat_layer = layers.concatenate([upsampled, large_ip_layer])
print('concat_layer_shape:', concat_layer.shape)
# TODO Add some number of separable convolution layers
output_layer = separable_conv2d_batchnorm(concat_layer, filters)
return output_layer
# 构建FCN模型
def fcn_model(inputs, num_classes):
# TODO 添加编码器模块。
# 请记住,对于每个编码器层,模型的深度(过滤器的数量)都会增加。
mid_layer_1 = encoder_block(inputs, filters=32, strides=2)
mid_layer_2 = encoder_block(mid_layer_1, filters=32, strides=2)
print('mid_layer_2:',mid_layer_2)
# TODO 使用conv2d_batchnorm()添加1x1卷积层。
mid_layer_3 = conv2d_batchnorm(mid_layer_2, 32, 3, 1)
print('mid_layer_1:',mid_layer_1)
# TODO: 添加与编码器块数量相同的解码器块数量
mid_layer_4 = decoder_block(mid_layer_3, mid_layer_1, 32)
mid_layer_5 = decoder_block(mid_layer_4, inputs, 32)
# 该函数返回模型的输出层。“x”是从最后一个decoder_block()中获得的最后一层
return layers.Conv2D(num_classes, 3, activation='softmax', padding='same')(mid_layer_5)
image_hw = 160
image_shape = (image_hw, image_hw, 3)
inputs = layers.Input(image_shape)
num_classes = 3
# Call fcn_model()
output_layer = fcn_model(inputs, num_classes)
learning_rate = 0.001
batch_size = 32
num_epochs = 5
steps_per_epoch = 200
validation_steps = 50
workers = 10
# Define the Keras model and compile it for training
model = models.Model(inputs=inputs, outputs=output_layer)
model.compile(optimizer=keras.optimizers.Adam(learning_rate), loss='categorical_crossentropy')
# Data iterators for loading the training and validation data
train_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,
data_folder=os.path.join('..', 'data', 'train'),
image_shape=image_shape,
shift_aug=True)
val_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,
data_folder=os.path.join('..', 'data', 'validation'),
image_shape=image_shape)
logger_cb = plotting_tools.LoggerPlotter()
callbacks = [logger_cb]
model.fit_generator(train_iter,
steps_per_epoch = steps_per_epoch, # the number of batches per epoch,
epochs = num_epochs, # the number of epochs to train for,
validation_data = val_iter, # validation iterator
validation_steps = validation_steps, # the number of batches to validate on
callbacks=callbacks,
workers = workers)
weight_file_name = 'model_weights'
model_tools.save_network(model, weight_file_name)
run_num = 'run_1'
val_with_targ, pred_with_targ = model_tools.write_predictions_grade_set(model,
run_num,'patrol_with_targ', 'sample_evaluation_data')
val_no_targ, pred_no_targ = model_tools.write_predictions_grade_set(model,
run_num,'patrol_non_targ', 'sample_evaluation_data')
val_following, pred_following = model_tools.write_predictions_grade_set(model,
run_num,'following_images', 'sample_evaluation_data')
# images while following the target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data','following_images', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
# images while following the target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data','following_images', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
# images while at patrol with target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data', 'patrol_with_targ', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
# Scores for while the quad is following behind the target.
true_pos1, false_pos1, false_neg1, iou1 = scoring_utils.score_run_iou(val_following, pred_following)
# Scores for images while the quad is on patrol and the target is not visable
true_pos2, false_pos2, false_neg2, iou2 = scoring_utils.score_run_iou(val_no_targ, pred_no_targ)
# This score measures how well the neural network can detect the target from far away
true_pos3, false_pos3, false_neg3, iou3 = scoring_utils.score_run_iou(val_with_targ, pred_with_targ)
# Sum all the true positives, etc from the three datasets to get a weight for the score `-+
true_pos = true_pos1 + true_pos2 + true_pos3
false_pos = false_pos1 + false_pos2 + false_pos3
false_neg = false_neg1 + false_neg2 + false_neg3
weight = true_pos/(true_pos+false_neg+false_pos)
print(weight)
# The IoU for the dataset that never includes the hero is excluded from grading
final_IoU = (iou1 + iou3)/2
print(final_IoU)
# And the final grade score is
final_score = final_IoU * weight
print(final_score)
以上程序比上一个笔记中多增加了一个调制器和解调器,训练速度会有所下降。
程序注解:
fit_generator(self, generator, steps_per_epoch, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_q_size=10, workers=1, pickle_safe=False, initial_epoch=0)
model.fit_generator(train_iter,
steps_per_epoch = steps_per_epoch, # the number of batches per epoch,
epochs = num_epochs, # the number of epochs to train for,
validation_data = val_iter, # validation iterator
validation_steps = validation_steps, # the number of batches to validate on
callbacks=callbacks,
workers = workers)
函数的参数是:
generator:生成器函数,生成器的输出应该为:
-
一个形如(inputs,targets)的tuple
-
一个形如(inputs, targets,sample_weight)的tuple。所有的返回值都应该包含相同数目的样本。生成器将无限在数据集上循环。每个epoch以经过模型的样本数达到samples_per_epoch时,记一个epoch结束
steps_per_epoch:整数,当生成器返回steps_per_epoch次数据时计一个epoch结束,执行下一个epoch
epochs:整数,数据迭代的轮数
verbose:日志显示,0为不在标准输出流输出日志信息,1为输出进度条记录,2为每个epoch输出一行记录
validation_data:具有以下三种形式之一
-
生成验证集的生成器
-
一个形如(inputs,targets)的tuple
-
一个形如(inputs,targets,sample_weights)的tuple
validation_steps: 当validation_data为生成器时,本参数指定验证集的生成器返回次数
class_weight:规定类别权重的字典,将类别映射为权重,常用于处理样本不均衡问题。
sample_weight:权值的numpy array,用于在训练时调整损失函数(仅用于训练)。可以传递一个1D的与样本等长的向量用于对样本进行1对1的加权,或者在面对时序数据时,传递一个的形式为(samples,sequence_length)的矩阵来为每个时间步上的样本赋不同的权。这种情况下请确定在编译模型时添加了sample_weight_mode=‘temporal’。
workers:最大进程数
max_q_size:生成器队列的最大容量
pickle_safe: 若为真,则使用基于进程的线程。由于该实现依赖多进程,不能传递non picklable(无法被pickle序列化)的参数到生成器中,因为无法轻易将它们传入子进程中。
initial_epoch: 从该参数指定的epoch开始训练,在继续之前的训练时有用。
函数返回一个History对象
7.其它程序
follower.py程序
import eventlet.wsgi
import socketio
import time
from flask import Flask
from threading import Thread
# Needs to be sorted through
import argparse
import base64
import math
import numpy as np
import os
import tensorflow as tf
from PIL import Image
from io import BytesIO
from scipy import misc
from transforms3d.euler import euler2mat, mat2euler
from tensorflow.contrib.keras.python import keras
from utils import separable_conv2d
from utils import data_iterator
from utils import visualization
from utils import scoring_utils
from utils import sio_msgs
from utils import model_tools
import time
import signal
import sys
# 创建socketio服务器和Flask应用程序
sio = socketio.Server()
app = Flask(__name__)
def to_radians(deg_ang):
return deg_ang * (math.pi / 180)
# 功能为2D->3D变换
def get_depth_image(data):
pimg = Image.open(BytesIO(base64.b64decode(data)))
img_array = np.array(pimg)
return img_array
def get_xyz_from_image(u, v, depth, im_hw):
cx = im_hw//2
cy = im_hw//2
fx = im_hw
fy = im_hw
x = (u-cx)*depth/fx
y = (v-cy)*depth/fy
return [depth,-x,y]
def get_ros_pose(data):
s_pose = data.split(",")
ros_pose = [float(i) for i in s_pose]
for i in range(3,6):
if ros_pose[i]<-180: ros_pose[i] = 360 + ros_pose[i]
return ros_pose
def get_unity_pose_from_ros(data):
unity_point = [-data[1],data[2],data[0]]
return unity_point
class Follower(object):
def __init__(self, image_hw, model, pred_viz_enabled = False, queue=None):
self.queue = queue
self.model = model
self.image_hw = image_hw
self.last_time_saved = time.time()
self.num_no_see = 0
self.pred_viz_enabled = pred_viz_enabled
self.target_found = False
def on_sensor_frame(self, data):
rgb_image = Image.open(BytesIO(base64.b64decode(data['rgb_image'])))
rgb_image = np.asarray(rgb_image)
if rgb_image.shape != (256, 256, 3):
print('image shape not 256, 256, 3')
return None
if rgb_image.shape[0] != self.image_hw:
rgb_image = misc.imresize(rgb_image, (self.image_hw, self.image_hw, 3))
rgb_image = data_iterator.preprocess_input(rgb_image)
pred = np.squeeze(model.predict(np.expand_dims(rgb_image, 0)))
if self.pred_viz_enabled:
self.queue.put([rgb_image, pred])
target_mask = pred[:, :, 2] > 0.5
# 通过要求更多的像素被识别为包含目标,从而减少误报的数量
if target_mask.sum() > 10:
centroid = scoring_utils.get_centroid_largest_blob(target_mask)
# 将质心从nn图像大小缩放到原始图像大小
centroid = centroid.astype(np.int).tolist()
# 从质心像素获取三维世界点
depth_img = get_depth_image(data['depth_image'])
# 获取特定像素的XYZ坐标
pixel_depth = depth_img[centroid[0]][centroid[1]][0]*50/255.0
point_3d = get_xyz_from_image(centroid[0], centroid[1], pixel_depth, self.image_hw)
point_3d.append(1)
# 从sensor_frame获取cam_pose (ROS约定)
cam_pose = get_ros_pose(data['gimbal_pose'])
# 计算像素对应点的xyz世界坐标
# 变换矩阵
R = euler2mat(math.radians(cam_pose[3]), math.radians(cam_pose[4]), math.radians(cam_pose[5]))
T = np.c_[R, cam_pose[:3]]
T = np.vstack([T, [0,0,0,1]]) # 从world到四轴的变换矩阵
# ROS坐标中的3D点
ros_point = np.dot(T, point_3d)
sio.emit('object_detected', {'coords': [ros_point[0], ros_point[1], ros_point[2]]})
if not self.target_found:
print('Target found!')
self.target_found = True
self.num_no_see = 0
# 发布跟踪对象标记
marker_pos = [ros_point[0], ros_point[1], ros_point[2]] + [0, 0, 0]
marker_msg = sio_msgs.create_box_marker_msg(np.random.randint(99999), marker_pos)
sio.emit('create_box_marker', marker_msg)
elif self.target_found:
self.num_no_see += 1
# print(self.num_no_see)
if self.target_found and self.num_no_see > 6:
print('Target lost!')
sio.emit('object_lost', {'data': ''})
self.target_found = False
self.num_no_see = 0
######################
# SocketIO Callbacks
######################
@sio.on('sensor_frame')
def sensor_frame(sid, data):
# global graph
# with graph.as_default():
follower.on_sensor_frame(data)
def sio_server():
# 部署为一个eventlet WSGI服务器
eventlet.wsgi.server(eventlet.listen(('', 4567)), app)
if __name__ == '__main__':
# 用socketio的中间件包装Flask应用程序
app = socketio.Middleware(sio, app)
# argparse是一个Python模块:命令行选项、参数和子命令解析器。
# 创建解析器
parser = argparse.ArgumentParser()
# 添加参数
parser.add_argument('weight_file',
help='The model file to use for inference')
parser.add_argument('--pred_viz',
action='store_true',
help='display live overlay visualization with prediction regions')
# 解析参数
args = parser.parse_args()
model = model_tools.load_network(args.weight_file)
image_hw = model.layers[0].output_shape[1]
if args.pred_viz:
overlay_plot = visualization.SideBySidePlot('Segmentation Overlay', image_hw)
queue = overlay_plot.start()
else:
queue = None
follower = Follower(image_hw, model, args.pred_viz, queue)
# start eventlet server
sio_server()
8.训练模型
(1)训练
使用GPU加速运算,由于我环境搭建出了一点问题,目前只是用CPU进行运算。我之前使用的tensorflow 1.13.0GPU环境已经搭好了,但是换到1.2.1版本后,可能会存在两个CUDA版本的冲突,尝试几次之后就放弃了。更改程序也是很麻烦,很多函数都进行了不仅仅是位置上的更改,所以在1.2.1版本还是只使用CPU版本。
训练模型
- 培训数据在data目录中
- 验证数据在data目录中
- 文件夹data/train/images/,data/train/masks/,data/validation/images/,和data/validation/masks/应该存在并包含相应的数据
在model_training中完成TODO的训练。然后用ipynb笔记本运行训练单元,选择合适的超参数。
训练运行完成后,模型将作为HDF5文件和configuration_weights
文件存储在data/weights目录中。
以上是我训练完成后的/data文件夹,sample_evalution_data
目录包含专为测试在跟踪转换任务的网络性能数据。sample_evaluation数据中有三个目录,每个目录使用不同的采样方法生成。这些目录的结构与validation和train提供的数据集完全相同。例如patrol_with_targ包含images和masks子目录。
(2)计分
为了在FollowMe任务中对网络进行评分,测量了两种类型的错误。首先,对目标信道计算像素分类的联合上的交集。
此外,我们还确定网络是否检测到目标人员。如果超过3个像素的人成为目标的概率大于0.5,那么这就意味着网络猜测目标在图像中。
我们通过标签掩模中是否有超过3个像素来确定目标是否在图像中。
利用上述方法对检测的真阳性、假阳性、假阴性数进行统计。
最后的分数是像素方面的与sample_evaulation_data中提供的数据相似的数据:
average_IoU*(n_true_positive/(n_true_positive+n_false_positive+n_false_negative))
8.结果
训练模型结束后,程序输出如下:
训练完成之后,运行跟随脚本
python follower.py model_weights
启动模拟器,选择“ Spawn People”,然后单击“Follow Me!”按钮。
四轴就会进入巡航状态并检索目标了,在检索到目标之后,就会进行目标的跟随。