小言_互联网的博客

【专业术语】(计算机 / 深度学习与目标检测 / 轨道交通)

420人阅读  评论(0)

一、 计算机

1 IDE

  集成开发环境,例如:Visual Studio Code;Pycharm等

2 API

  操作系统给应用程序的调用接口

3 CUDA Driver API

  1. 与GPU沟通的驱动级别底层API
  2. CUDA Driver随显卡驱动发布,与cudatoolkit分开看 CUDA
  3. Driver对应于cuda.h和libcuda.so文件
  4. 主要知识点是Context的管理机制,以及CUDA系列接口的开发习惯(错误检查方法),还有内存模型


参考链接:https://www.cnblogs.com/marsggbo/p/11838823.html

3.1 cuInit - 驱动初始化

  • cuInit的意义是,初始化驱动API,如果不执行,则所有API都将返回错误,全局执行一次即可
  • 没有对应的cuDestroy,不需要释放,程序销毁自动释放

3.2 关于context,有两种:

  • 手动管理的context,cuCtxCreate(手动管理,以堆栈方式push/pop)
  • 自动管理的context,cuDevicePrimaryCtxRetain(自动管理,runtime api以此为基础)

3.3 CUcontext

  • context是一种上下文,关联对GPU的所有操作 context与一块显卡关联,一个显卡可以被多个context关联
  • 每个线程都有一个栈结构储存context,栈顶是当前使用的context,对应有push、pop函数操作
  • context的栈,所有api都以当前context为操作目标
  • 试想一下,如果执行任何操作你都需要传递一个device决定送到哪个设备执行,得多麻烦
  • 由于高频操作,是一个线程基本固定访问一个显卡不变,且只使用一个context,很少会用到多context
  • CreateContext、PushCurrent、PopCurrent这种多context管理就显得麻烦,还得再简单
  • 因此推出了cuDevicePrimaryCtxRetain,为设备关联主context,分配、释放、设置、栈都不用你管
  • primaryContext:给我设备id,给你context并设置好,此时一个显卡对应一个primary context
    不同线程,只要设备id一样,primary context就一样。context是线程安全的

4 RuntimeAPI

  • 对于runtimeAPI,与driver最大区别是懒加载
  • 即,第一个runtime API调用时,会进行cuInit初始化,避免驱动api的初始化窘境
  • 即,第一个需要context的API调用时,会进行context关联并创建context和设置当前context,调用cuDevicePrimaryCtxRetain实现
  • 绝大部分api需要context,例如查询当前显卡名称、参数、内存分配、释放等
  • CUDA Runtime是封装了CUDA Driver的高级别更友好的API
  • 使用cuDevicePrimaryCtxRetain为每个设备设置context,不再手工管理context,并且不提供直接管理context的API(可Driver
    API管理,通常不需要)
  • 可以更友好的执行核函数,.cpp可以与.cu文件无缝对接
  • 对应cuda_runtime.h和libcudart.so
  • runtime api随cuda toolkit发布
  • 主要知识点是核函数的使用、线程束布局、内存模型、流的使用
  • 主要实现归约求和、仿射变换、矩阵乘法、模型后处理,就可以解决绝大部分问题

5 Memory

  内存模型是CUDA中很重要的知识点

  • 主要理解pinned memory、global memory、shared memory即可,其他不常用

5.1 关于内存,有两大类:

5.1.1 CPU内存,称之为Host Memory

  • Pageable Memory:可分页内存
  • Page-Locked Memory:页锁定内存

5.1.2 GPU内存,称之为Device Memory

  • Global Memory:全局内存
  • Shared Memory:共享内存
  • …以及其他多种内存

5.2 Pinned Memory



对于整个Host Memory内存条而言,操作系统区分为两个大类(逻辑区分,物理上是同一个东西):

  • Pageable memory,可分页内存
  • Page lock memory,页锁定内存

  你可以理解为Page lock memory是vip房间,锁定给你一个人用。而Pageable memory是普通房间,在酒店房间不够的时候,选择性的把你的房间腾出来给其他人交换用,这就可以容纳更多人了。造成房间很多的假象,代价是性能降低

5.2.1 基于前面的理解,我们总结如下:

  • pinned memory具有锁定特性,是稳定不会被交换的(这很重要,相当于每次去这个房间都一定能找到你)
  • pageable memory没有锁定特性,对于第三方设备(比如GPU),去访问时,因为无法感知内存是否被交换,可能得不到正确的数据(每次去房间找,说不准你的房间被人交换了)
  • pageable memory的性能比pinned memory差,很可能降低你程序的优先级然后把内存交换给别人用
  • pageable memory策略能使用内存假象,实际8GB但是可以使用15GB,提高程序运行数量(不是速度)
  • pinned memory太多,会导致操作系统整体性能降低(程序运行数量减少),8GB就只能用8GB。注意不是你的应用程序性能降低,这一点一般都是废话,不用当回事
  • GPU可以直接访问pinned memory而不能访问pageable memory(因为第二条)

5.2.2 显卡访问Pinned Memory轨迹

5.2.3 内存方面总结

  原则:

  • GPU可以直接访问pinned memory,称之为(DMA Direct Memory Access)
  • 对于GPU访问而言,距离计算单元越近,效率越高,所以PinnedMemory<GlobalMemory<SharedMemory
  • 代码中,由new、malloc分配的,是pageable memory,由cudaMallocHost分配的是PinnedMemory,由cudaMalloc分配的是GlobalMemory
  • 尽量多用PinnedMemory储存host数据,或者显式处理Host到Device时,用PinnedMemory做缓存,都是提高性能的关键

6 stream - 流

  1. 流是一种基于context之上的任务管道抽象,一个context可以创建n个流
  2. 流是异步控制的主要方式
  3. nullptr表示默认流,每个线程都有自己的默认流
  4. 要十分注意,指令发出后,流队列中储存的是指令参数,不能加入队列后立即释放参数指针,这会导致流队列执行该指令时指针失效而出错
  5. 应当在十分肯定流已经不需要这个指针后,才进行修改或者释放,否则会有非预期结果出现
  6. 举个粒子:你给钱让男朋友买西瓜,他刚到店拿好西瓜,你把转的钱撤回去了。此时你无法预知他是否会跟店家闹起来矛盾,还是屁颠的回去。如果想得到预期结果,必须得让卖西瓜结束再处理钱的事情

7 核函数

  1. 核函数是cuda编程的关键
  2. 通过xxx.cu创建一个cudac程序文件,并把cu交给nvcc编译,才能识别cuda语法
  3. __global__表示为核函数,由host调用。__device__表示为设备函数,由device调用
  4. __host__表示为主机函数,由host调用。__shared__表示变量为共享变量
  5. host调用核函数:function<<<gridDim, blockDim, sharedMemorySize,
    stream>>>(args…);
  6. 只有__global__修饰的函数才可以用<<<>>>的方式调用
  7. 调用核函数是传值的,不能传引用,可以传递类、结构体等,核函数可以是模板
  8. 核函数的执行,是异步的,也就是立即返回的
  9. 线程layout主要用到blockDim、gridDim
  10. 核函数内访问线程索引主要用到threadIdx、blockIdx、blockDim、gridDim这些内置变量

核函数里面,把blockDim、gridDim看作shape,把threadIdx、blockIdx看做index
则可以按照维度高低排序看待这个信息:

8 共享内存

  1. 共享内存因为更靠近计算单元,所以访问速度更快
  2. 共享内存通常可以作为访问全局内存的缓存使用
  3. 可以利用共享内存实现线程间的通信
  4. 通常与__syncthreads同时出现,这个函数是同步block内的所有线程,全部执行到这一行才往下走
  5. 使用方式,通常是在线程id为0的时候从global memory取值,然后syncthreads,然后再使用

9 Warpaffine

  主要解决图像的缩放和平移,来处理目标检测中常见的预处理行为

  1. warpaffine是对图像做平移缩放旋转变换进行综合统一描述的方法
  2. 同时也是一个很容易实现cuda并行加速的算法
  3. 在深度学习领域通常需要做预处理,比如CopyMakeBorder,RGB->BGR,减去均值除以标准差,BGRBGRBGR -> BBBGGGRRR
  4. 如果使用cuda进行并行加速实现,那么可以对整个预处理都进行统一,并且性能贼好
  5. 由于warpaffine是标准的矩阵映射坐标,并且可逆,所以逆变换就是其变换矩阵的逆矩阵
  6. 对于缩放和平移的变换矩阵,其有效自由度为3

二、 深度学习与目标检测

1 TTA(test time augmentation)

  测试时数据增强:指的是在推理(预测)阶段,将原始图片进行水平翻转、垂直翻转、对角线翻转、旋转角度等数据增强操作,得到多张图,分别进行推理,再对多个结果进行综合分析,得到最终输出结果。

2 NMS (Non-maximum suppression)

  非极大抑制:经典NMS最初第一次应用到目标检测中是在RCNN算法中,其实现严格按照搜索局部极大值,抑制非极大值元素的思想来实现的,具体的实现步骤如下:

  1. 设定目标框的置信度阈值,常用的阈值是0.5左右
  2. 根据置信度降序排列候选框列表
  3. 选取置信度最高的框A添加到输出列表,并将其从候选框列表中删除
  4. 计算A与候选框列表中的所有框的IoU值,删除大于阈值的候选框
  5. 重复上述过程,直到候选框列表为空,返回输出列表
    当NMS的阈值设为0.2时:

    python实现:
def nms(bounding_boxes, Nt):
    if len(bounding_boxes) == 0:
        return [], []
    bboxes = np.array(bounding_boxes)

    # 计算 n 个候选框的面积大小
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]
    scores = bboxes[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)

    # 对置信度进行排序, 获取排序后的下标序号, argsort 默认从小到大排序
    order = np.argsort(scores)

    picked_boxes = []  # 返回值
    while order.size > 0:
        # 将当前置信度最大的框加入返回值列表中
        index = order[-1]
        picked_boxes.append(bounding_boxes[index])

        # 获取当前置信度最大的候选框与其他任意候选框的相交面积
        x11 = np.maximum(x1[index], x1[order[:-1]])
        y11 = np.maximum(y1[index], y1[order[:-1]])
        x22 = np.minimum(x2[index], x2[order[:-1]])
        y22 = np.minimum(y2[index], y2[order[:-1]])
        w = np.maximum(0.0, x22 - x11 + 1)
        h = np.maximum(0.0, y22 - y11 + 1)
        intersection = w * h

        # 利用相交的面积和两个框自身的面积计算框的交并比, 将交并比大于阈值的框删除
        ious = intersection / (areas[index] + areas[order[:-1]] - intersection)
        left = np.where(ious < Nt)
        order = order[left]
    return picked_boxes

 

3 soft-NMS

  经典NMS算法存在着一些问题:对于重叠物体无法很好的检测。经典NMS算法的做法是直接删除Iou大于阈值的Bounding box;而Soft-NMS则是使用一个基于Iou的衰减函数,降低Iou大于阈值Nt的Bounding box的置信度,IoU越大,衰减程度越大。
python代码

def soft_nms(bboxes, Nt=0.3, sigma2=0.5, score_thresh=0.3, method=2):
    # 在 bboxes 之后添加对于的下标[0, 1, 2...], 最终 bboxes 的 shape 为 [n, 5], 前四个为坐标, 后一个为下标
    res_bboxes = deepcopy(bboxes)
    N = bboxes.shape[0]  # 总的 box 的数量
    indexes = np.array([np.arange(N)])  # 下标: 0, 1, 2, ..., n-1
    bboxes = np.concatenate((bboxes, indexes.T), axis=1)  # concatenate 之后, bboxes 的操作不会对外部变量产生影响
    # 计算每个 box 的面积
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]
    scores = bboxes[:, 4]
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)

    for i in range(N):
        # 找出 i 后面的最大 score 及其下标
        pos = i + 1
        if i != N - 1:
            maxscore = np.max(scores[pos:], axis=0)
            maxpos = np.argmax(scores[pos:], axis=0)
        else:
            maxscore = scores[-1]
            maxpos = 0
        # 如果当前 i 的得分小于后面的最大 score, 则与之交换, 确保 i 上的 score 最大
        if scores[i] < maxscore:
            bboxes[[i, maxpos + i + 1]] = bboxes[[maxpos + i + 1, i]]
            scores[[i, maxpos + i + 1]] = scores[[maxpos + i + 1, i]]
            areas[[i, maxpos + i + 1]] = areas[[maxpos + i + 1, i]]
        # IoU calculate
        xx1 = np.maximum(bboxes[i, 0], bboxes[pos:, 0])
        yy1 = np.maximum(bboxes[i, 1], bboxes[pos:, 1])
        xx2 = np.minimum(bboxes[i, 2], bboxes[pos:, 2])
        yy2 = np.minimum(bboxes[i, 3], bboxes[pos:, 3])
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        intersection = w * h
        iou = intersection / (areas[i] + areas[pos:] - intersection)
        # Three methods: 1.linear 2.gaussian 3.original NMS
        if method == 1:  # linear
            weight = np.ones(iou.shape)
            weight[iou > Nt] = weight[iou > Nt] - iou[iou > Nt]
        elif method == 2:  # gaussian
            weight = np.exp(-(iou * iou) / sigma2)
        else:  # original NMS
            weight = np.ones(iou.shape)
            weight[iou > Nt] = 0
        scores[pos:] = weight * scores[pos:]
    # select the boxes and keep the corresponding indexes
    inds = bboxes[:, 5][scores > score_thresh]
    keep = inds.astype(int)
    return res_bboxes[keep]

 

4 WBF(weighted boxes fusion)

  加权框融合:假设,我们已经绑定了来自N个不同模型的相同图像的框预测。或者,我们对相同图像的原始和增强版本(即垂直/水平反射,数据增强)有相同模型的N个预测)。

  1. 每个模型的每个预测框都添加到List B,并将此列表按置信度得分C降序排列
  2. 建立空List L 和 F(用于融合的)
  3. 循环遍历B,并在F中找到于之匹配的box(同一类别MIOU > 0.55)
  4. 如果 step3 中没有找到匹配的box 就将这个框加到L和F的尾部
  5. 如果 step3 中找到了匹配的box 就将这个框加到L,加入的位置是box在F中匹配框的Index.L中每个位置可能有多个框,需要根据这多个框更新对应F[index]的值。
  6. F[index]更新方法:x,y对应的是坐标值,对坐标值根据置信值进行加权求和如下图:

      NMS/Soft-NMS将只留下一个不准确的框,而WBF将使用所有预测的框来融合它。

三、轨道交通

1 ATC 列车自动控制系统

城市轨道交通信号系统通常由列车自动控制系(Automatic Train Control,简称ATC)组成,ATC 系统包括三个子系统:
(1)列车自动监控系统 (Automatic Train Supervision,简称ATS)
(2)列车自动防护子系统(Automatic Train Protection,简称ATP)
(3)列车自动运行系统 (Automatic Train Operation,简称ATO)
三个子系统通过信息交换网络构成闭环系统,实现地面控制与车上控制结合、现地控制与中央控制结合,构成一个以安全设备为基础,集行车指挥、运行调整以及列车驾驶自动化等功能为一体的列车自动控制系统。

2 ATS 列车自动监控系统

列车自动监控系统 (Automatic Train Supervision,简称ATS)

3 ATP 列车自动防护子系统

列车自动防护子系统(Automatic Train Protection,简称ATP)

4 ATO 列车自动运行系统

列车自动运行系统 (Automatic Train Operation,简称ATO)


转载:https://blog.csdn.net/qq_44703886/article/details/127841571
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场