• [其他] 基于row-wise的方法
    作者丨wanghy@知乎链接丨https://zhuanlan.zhihu.com/p/551743843行分类方法是一种简单的基于输入图像为网格划分的检测方法。对于每一行,只选择一个最可能的一个网格。Ultra Fast Structure-aware Deep Lane Detection: 对一张图在高度H 上划分为h个row-anchors, 在宽度W上划分为w个griding-cells,并将车道线检测问题变成一个分类问题:分类预测一个三维tensor Ch(w+1),P_i,j代表i_th车道线在j_th row-anchor上的概率分布向量。w+1是分类类别,而不是C。基于分割的方法计算量是HW(C+1),每个像素上都要做一次分类,类别数为C+1; 本文方法计算量是Ch(w+1),需要做C*h次分类,类别数为w+1。计算量下降了两个数量级。CondLaneNet: 利用 conditional convolution,实现了更精细的车道线检测,并且引入了 Recurrent instance module 用于解决车道线分叉场景;局限:不能适用于横向车道线;由于每一行选择一个网格,所以需要对每条可能的车道线都要重复操作,这种方法还需要后处理;
  • [其他] 基于关键点的方法
    作者丨wanghy@知乎链接丨https://zhuanlan.zhihu.com/p/551743843RelayChain: 模型预测一个分割图来对前景和背景区域进行分类。对于前景区域中的每个像素点,通过前向分支和后向分支来恢复整个车道。每个分支解码传输图和距离图以产生移动到下一个点的方向,以及逐步预测relay station(下一个点)的步骤。实际上就是预测三种图:分割图、两侧间隔1m距离点的方向图和距离两个端点的距离图。最后通过分割图得到的关键点生成车道线实例,并通过NMS进行处理得到最终的车道线。FOLOLane: 第一次将车道线检测做成局部的几何建模。模型只需要在受限的空间范围内,关注于比较简单的任务,使估计出来的局部曲线非常精确。输入一张图片,经过CNNs提取特征。把图片沿着高度等距离画线,距离为固定值,这样等分线和车道线曲线的交点就是关键点集合的子集。然后逐像素的预测四个map:key points, 关键点与上一个交点关键点在水平上的坐标偏差、关键点与当前交点关键点在水平上的坐标偏差、关键点与下一个交点关键点在水平上的坐标偏差。最后通过后处理连线。PINet: 经过feature extraction layer,由关键点预测里最常用的2个Hourglass block构成,每个block有三个output branch,分别为confidence branch、offset branch、feature branch。最后通过后处理聚类得到实例车道线;关键点检测方法,相比分割网络而言,模型更小,计算开销也更小。A Keypoint-based Global Association Network for Lane Detection: 提出了一个全局关联网络(GANet)来从一个新的角度描述车道检测问题,其中每个关键点直接回归到车道线的起点,而不是逐点扩展。关键点与其所属车道线的关联是通过预测它们在全局范围内与相应车道起点的偏移量来实现的。还提出了一种车道感知特征聚合器(LFA),它自适应地捕获相邻关键点之间的局部相关性。
  • [其他] 基于分割和辅助实例化信息的方法:
    作者丨wanghy@知乎链接丨https://zhuanlan.zhihu.com/p/551743843基于分割和辅助实例化信息的方法:HDMapNet (BEV): 通过MLP得到视觉bev特征,通过Pointpillar得到激光bev特征,concat得到最终bev feature。在bev feature上学习语义分割、实例分割instance embedding和方向预测direction prediction,并通过后处理得到语义要素;后处理得到的线会出现闭环;3D-LaneNet+ (BEV): 将图像划分成格子,每个格子进行二分类(判断是否有线经过),另外,对有线的格子回归线段的横向偏移、角度(N个bins分类+offset微调)、高度偏移和Embedding vector(用于把曲线小片段聚合成车道线曲线)。在特征学习上,沿用了3D-LaneNet,都是两路的path way。只不过相机外参俯仰角、安装高度直接输入而不是模型预测。LaneAF (Affinity fields): 输出binary seg, 横纵向affinity fields,分别表示:在每行中,每个前景像素位于它所属车道线中心的左边还是右边、当前像素相较于上一行的车道线中心,是在左边还是右边。最后通过这三个预测解码得到车道线实例。Spatial CNN: 将车道线检测问题构建为一个多类别语义分割问题,提出spatial cnn方法来建模空间结构信息(信息向下/向上/向右/向左传播),来学习形状先验。该方法对细长的车道线检测很有效;该方法固定数量、需要聚类等处理、多类别分割模型较大,速度慢;RESA: 这篇文章是SCNN的升级,减少计算量。RESA整体思路和SCNN相同,包含四种OPs:”往上“、”往下“、”往左“、”往右“。区别是每个OPs会重复做K次,每次的stride会逐渐增加。LaneNet:利用实例分割instance embedding管道来处理可变数量的线,但它需要推理后聚类来生成线实例。SAD: 提出基于知识蒸馏(Knowledge Distillation)的车道线检测模型SAD,能增强CNN的特征表达能力。由于SAD只参与模型训练,因此不会增加推断时的计算复杂度。ONCE-3DLanes (BEV): 在图像视图中回归车道的三维坐标,而不将特征地图转换为鸟瞰视图(BEV)。该方法还利用分割分支和空间上下文分支分别预测图像层面分割和像素位置偏移。最后通过几何处理得到3D车道线;分割方法局限:需要后处理,速度慢,实例区分有困难;它们还受到分割任务的局部性的影响,因此它们往往在遮挡或极端光照条件下表现更差。
  • [其他] 使用Python+OpenCV+Tensorflow实现图像聚类
    文章来源于深度学习与计算机视觉 ,作者磐怼怼在不想自己收集数据集的情况,我们如何解决这个问题呢?这就是本文的主要内容,即将深度学习直接应用于测试数据(此处为图像),而无需创建训练数据集并在该数据集上训练神经网络。卷积神经网络作为特征提取器首先我们需要讨论为什么需要特征提取器?以及如何使卷积神经网络(CNN)发挥作用。图像数据的特征提取器:假设算法需要像特征一样需要两只眼睛,一只鼻子和一张嘴来将图像分类为面部,但是在不同的图像中,这些特征存在于不同的像素位置,因此简单地将图像扁平化并将其提供给算法是不起作用的。而解决这个问题刚好是CNN的卷积层发挥作用的地方。卷积层作为我们的特征提取器,并将图像分解为越来越精细的细节,我们来看一下下面的例子:这是一只猫的图像,这是Vgg16的第一个卷积层看到它的样子请注意不同的图像,这些是我们的CNN所学习的特征图,一些特征图着重于轮廓,一些特征着重于纹理,而某些特征则涉及更细微的细节(如耳和嘴),下一阶段的卷积层将这些特征分解得更细的细节。上午我们知道了卷积层可以学习图像的特定功能,那么接下来我们将实现编码。实现CNN的卷积层网络:以下代码显示了如何使用预训练的CNN Vgg16获得以上结果: MyModel = tf2.<a onclick="parent.postMessage({'referent':'.tensorflow.keras'}, '*')">keras.applications.VGG16(    include_top=True, weights='imagenet', input_tensor=None, input_shape=None,    pooling=None, classes=1000, classifier_activation='softmax')MyModel.summary() ## lets Define a Function that can show Features learned by CNN's nth convolusion layerdef ShowMeWhatYouLearnt(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..Image'}, '*')">Image, <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..layer'}, '*')">layer, <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..MyModel'}, '*')">MyModel):<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img = img_to_array(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..Image'}, '*')">Image)<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img = np.<a onclick="parent.postMessage({'referent':'.numpy.expand_dims'}, '*')">expand_dims(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img, 0)    ### preprocessing for img for vgg16<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img = tf2.<a onclick="parent.postMessage({'referent':'.tensorflow.keras'}, '*')">keras.applications.vgg16.preprocess_input(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img)    ## Now lets define a model which will help us    ## see what vgg16 sees<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..inputs'}, '*')">inputs = <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..MyModel'}, '*')">MyModel.inputs<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..outputs'}, '*')">outputs = <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..MyModel'}, '*')">MyModel.layers[<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..layer'}, '*')">layer].output<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..model'}, '*')">model = Model(inputs=<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..inputs'}, '*')">inputs, outputs=<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..outputs'}, '*')">outputs)<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..model'}, '*')">model.summary()    ## let make predictions to see what the Cnn sees<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..featureMaps'}, '*')">featureMaps = <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..model'}, '*')">model.predict(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..img'}, '*')">img)    ## Plotting Features    for a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..maps'}, '*')">maps in <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..featureMaps'}, '*')">featureMaps:plt.<a onclick="parent.postMessage({'referent':'.matplotlib.pyplot.figure'}, '*')">figure(figsize=(20,20))<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..pltNum'}, '*')">pltNum = 1        for <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..a'}, '*')">a in range(8):            for <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..b'}, '*')">b in <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..range'}, '*')">range(8):plt.<a onclick="parent.postMessage({'referent':'.matplotlib.pyplot.subplot'}, '*')">subplot(8, 8, <a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..pltNum'}, '*')">pltNum)plt.<a onclick="parent.postMessage({'referent':'.matplotlib.pyplot.imshow'}, '*')">imshow(<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..maps'}, '*')">maps[: ,: ,<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..pltNum'}, '*')">pltNum - 1], cmap='gray')<a onclick="parent.postMessage({'referent':'.kaggle.usercode.12234793.44545592.ShowMeWhatYouLearnt..pltNum'}, '*')">pltNum += 1plt.<a onclick="parent.postMessage({'referent':'.matplotlib.pyplot.show'}, '*')">show()接下来我们将重点介绍如何来创建我们的聚类算法。设计图像聚类算法在本节中,我们使用Kaggle上的 keep-babies-safe 数据集。https://www.kaggle.com/akash14/keep-babies-safe首先,我们创建一个图像聚类模型,来将给定的图像分为两类,即玩具或消费品,以下是来自该数据集的一些图像。以下代码实现我们的聚类算法:##################### Making Essential Imports ############################ import sklearn import os import sys import matplotlib.pyplot as plt import cv2 import pytesseract import numpy as np import pandas as pd import tensorflow as tf conf = r'-- oem 2' ##################################### # Defining a skeleton for our       # # DataFrame                         # ##################################### DataFrame = {     'photo_name' : [],     'flattenPhoto' : [],     'text' : [],     } ####################################################################################### #      The Approach is to apply transfer learning hence using Resnet50 as my          # #      pretrained model                                                               # ####################################################################################### MyModel = tf.keras.models.Sequential() MyModel.add(tf.keras.applications.ResNet50(     include_top = False, weights='imagenet',    pooling='avg', )) # freezing weights for 1st layer MyModel.layers[0].trainable = False ### Now defining dataloading Function def LoadDataAndDoEssentials(path, h, w):     img = cv2.imread(path)     DataFrame['text'].append(pytesseract.image_to_string(img, config = conf))     img = cv2.resize(img, (h, w))     ## Expanding image dims so this represents 1 sample     img = img = np.expand_dims(img, 0)     img = tf.keras.applications.resnet50.preprocess_input(img)     extractedFeatures = MyModel.predict(img)     extractedFeatures = np.array(extractedFeatures)     DataFrame['flattenPhoto'].append(extractedFeatures.flatten()) ### with this all done lets write the iterrrative loop def ReadAndStoreMyImages(path):     list_ = os.listdir(path)     for mem in list_:         DataFrame['photo_name'].append(mem)         imagePath = path + '/' + mem         LoadDataAndDoEssentials(imagePath, 224, 224) ### lets give the address of our Parent directory and start path = 'enter your data's path here' ReadAndStoreMyImages(path) ###################################################### #        lets now do clustering                      # ###################################################### Training_Feature_vector = np.array(DataFrame['flattenPhoto'], dtype = 'float64') from sklearn.cluster import AgglomerativeClustering kmeans = AgglomerativeClustering(n_clusters = 2) kmeans.fit(Training_Feature_vector) A little explanation for the above code:上面的代码使用Resnet50(一种经过预先训练的CNN)进行特征提取,我们只需移除其头部或用于预测类别的神经元的最后一层,然后将图像输入到CNN并获得特征向量作为输出,实际上,这是我们的CNN在Resnet50的倒数第二层学习到的所有特征图的扁平数组。可以将此输出向量提供给进行图像聚类的任何聚类算法。让我向你展示通过这种方法创建的簇。该可视化的代码如下## lets make this a dataFrame import seaborn as sb import matplotlib.pyplot as plt dimReducedDataFrame = pd.DataFrame(Training_Feature_vector) dimReducedDataFrame = dimReducedDataFrame.rename(columns = { 0: 'V1', 1 : 'V2'}) dimReducedDataFrame['Category'] = list (df['Class_of_image']) plt.figure(figsize = (10, 5)) sb.scatterplot(data = dimReducedDataFrame, x = 'V1', y = 'V2',hue = 'Category') plt.grid(True) plt.show()结论本文通过解释如何使用深度学习和聚类将视觉上相似的图像聚在一起形成簇,而无需创建数据集并在其上训练CNN。
  • [其他] 使用YOLOv5模型进行目标检测(4)-- 训练参数解释
     训练参数解释我们打开train.py文件,滑到主函数部分就可以看到需要传入的参数,下面一一介绍一下这些参数:weights:权重文件路径,如果是''则重头训练参数,如果不为空则做迁移学习,----那么权重文件的模型需与cfg参数中的模型对应cfg:存储模型结构的配置文件data:训练、验证数据配置文件hyp:超参数配置文件,其中的参数意义下面会解释epochs:指的就是训练过程中整个数据集将被迭代多少次batch-size:每次梯度更新的批量数,太大会导致显存不足img-size:训练图片的尺寸rect:进行矩形训练resume:恢复最近保存的模型开始训练nosave:仅保存最终checkpointnotest:仅测试最后的epochnoautoanchor:不进行anchors的k-means聚类evolve:进化超参数bucket:gsutil bucketcache-images:缓存图像以加快训练速度image-weights:给图片加上权重进行训练device:cuda device, i.e. 0 or 0,1,2,3 or cpumulti-scale:多尺度训练,img-size +/- 50%single-cls:单类别的训练集adam:使用adam优化器name:重命名results.txt to results_name.txt超参数配置文件./data/hyp.scratch.yaml参数解释:lr0:学习率,可以理解为模型的学习速度lrf:OneCycleLR学习率变化策略的最终学习率系数momentum:动量,梯度下降法中一种常用的加速技术,加快收敛weight_decay:权值衰减,防止过拟合。在损失函数中,weight decay是正则项(regularization)前的一个系数warmup_epochs:预热学习轮数warmup_momentum:预热学习初始动量warmup_bias_lr:预热学习初始偏差学习率giou:GIoU损失收益cls:类别损失收益cls_pw:类别交叉熵损失正类权重obj:是否有物体损失收益obj_pw:是否有物体交叉熵正类权重iou_t:iou阈值anchor_t:多尺度anchor阈值fl_gamma:focal loss gamma系数hsv_h:色调Hue,增强系数hsv_s:饱和度Saturation,增强系数hsv_v:明度Value,增强系数degrees:图片旋转角度translate:图片转换scale:图片缩放shear:图片仿射变换perspec:透视变换mosaic:mosaic数据增强mixup:mixup数据增强由于时间和能力有限,上面的解释没有包含所有参数,读者可以通过阅读源代码进行进一步理解。
  • [其他] 使用YOLOv5模型进行目标检测(3)---训练自己的数据集
    训练自己的数据集3.1 使用labelimg标注图片我们训练模型的第一步就是获取数据集,数据集一般通过拍照、爬虫或直接下载等方式获得,直接下载的数据集如比赛数据集都会有标注,我们可以直接使用所给的数据进行训练,但是通过拍照和爬虫获得的数据需要我们自己进行数据标注。目标检测标注工具有很多,今天主要讲解labelimg的标注步骤(文末附labeling下载地址)。下载并解压完后打开data文件夹中的predefined_classes.txt文件,可以在文件中写入自己要定义的类名,如安全帽检测中有两类:安全帽和人,我们就在predefined_classes.txt文件中的第一行写helmet,第二行写person。标注图片步骤如下:把要标注的数据放在img_whole/datasets文件夹中,打开labelimg.exe,点击“Open Dir”打开img_whole/datasets文件夹,屏幕中就会显示图片,点击“Create RectBox”将需要标注的物体框出来并注明其类别,在标注完所有物体后点击“Save”保存标注文件至img_whole/xml文件夹中,标注文件格式为xml,点击“Next Image”标注下一张图片,然后继续进行步骤3直至标注完全部图片3.2 将xml文件转换为YOLO标注文件我们随便打开一个xml文件,xml文件是DOM树结构,python的xml模块可以解析它。我们需要的信息是图像宽度width、图像高度height、检测框左上角坐标xmin和ymin以及检测框右下角坐标xmax、ymax。我们运行voc_label.py便可在labels文件夹中生成YOLOv5标签文件,标签文件中每一行的数据为class, x, y, w, h,class是该物体的类别,x,y是检测框中心坐标,w,h是检测框的宽和高。voc_label.py代码:import xml.etree.ElementTree as ET import os from os import getcwd from tqdm import tqdm classes = ["helmet", "person"] def convert(size, box):     dw = 1. / size[0]     dh = 1. / size[1]     x = (box[0] + box[1]) / 2.0     y = (box[2] + box[3]) / 2.0     w = box[1] - box[0]     h = box[3] - box[2]     x = x * dw     w = w * dw     y = y * dh     h = h * dh     return (x, y, w, h) def convert_annotation(image_id):     in_file = './xml/%s.xml' % (image_id)     out_file = open('./labels/%s.txt' % (image_id), 'w')     tree = ET.parse(in_file)     root = tree.getroot()     size = root.find('size')     w = int(size.find('width').text)     h = int(size.find('height').text)     for obj in root.iter('object'):         difficult = obj.find('Difficult').text         cls = obj.find('name').text         if cls not in classes or int(difficult) == 1:             continue         cls_id = classes.index(cls)         xmlbox = obj.find('bndbox')         b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),              float(xmlbox.find('ymax').text))         bb = convert((w, h), b)         out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') if __name__ == "__main__":     wd = getcwd()     print(wd)     if not os.path.exists('./labels/'):         os.makedirs('./labels/')     image_ids = os.listdir('./datasets')     for image_id in tqdm(image_ids):         convert_annotation(image_id.split('.')[0])3.3 训练本文的训练数据使用的是开源数据集SHWD,数据已上传开源数据平台Graviti,在文末可下载。当我们数据很多的时候我们可以将数据集划分为训练集、验证集和测试集,比例大致为98:1:1,数据较少划分时比例大概为6:2:2。我们新建一个文件夹datasets,将划分好的图片和标签放入其中,文件夹结构如下:以训练集为例,标签文件名需要与图片对应:然后将datasets文件夹放入yolov5-master中的data文件夹中,数据准备阶段就算完成了。下面需要修改YOLOv5的配置文件,需要修改的配置文件有两个,我们先复制一份data/coco.yaml,这里将其重命名为helmet.yaml,修改图中横线中的参数:在 download前加上一个#注释掉这段代码将train、val、test修改为自己的路径,以train为例   ./data/helmet/images/train将nc修改为数据的类别数,如安全帽检测只检测人和安全帽,故修改为2将names修改自己数据的类名,如['helmet', 'person']修改后的文件如下:下一个需要修改的文件为模型配置文件,在models文件夹中有四个模型的配置文件:yolov5s.yaml、yolov5m.yaml、yolov5l.yaml和yolov5x.yaml,可以根据需要选择相应的模型,这里以yolovx.yaml为例,打开文件,修改文件中的nc为自己的类别数即可。yolov5加入了自动判断是否需要重新k-means聚类anchors的功能,所以该文件中的anchors参数可以不做修改。如果有需要只需将这里anchors修改为自己计算出的即可。在修改完这两个配置文件后就可以开始训练了!我们在cmd中输入(记住在yolov5-master路径下):python train.py --weights weights/yolov5x.pt --cfg models/yolov5x.yaml --data data/helmet.yaml --epoch 50 --batch-size 32如果出现下面界面,说明已经开始训练了:
  • [其他] 使用YOLOv5模型进行目标检测(2)--检测文件参数说明
    检测文件参数说明yolov5的参数是由argparse包传入的,我们可以通过命令行传入参数,也可以直接设置参数默认值。我们打开yolov5-master文件加下的detect.py文件,传参的代码在主函数中,几个关键参数如下:parser.add_argument('--weights', nargs='+', type=str, default='yolov5x.pt', help='model.pt path(s)') parser.add_argument('--source', type=str, default='data/images/happysheep.mp4', help='source') parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')weights参数是我们训练好的权重文件,yolov5共有四种模型:yolov5s、yolov5m、yolov5l、yolov5x,它们的网络主干深度和宽度依次递增,一般情况下检测效果也递增,yolov5x的效果最好,yolov5s最差,但是yolov5s网络参数最少(14MB),yolov5x参数最多(166MB)。官方提供的预训练模型也有四种,大家可以根据需要设置。source参数为检测数据路径。img-size参数为检测时图像大小,最好与训练时相同,默认为640。conf-thres为检测置信度阈值,预测出的置信度高于这个阈值的物体就会显示在图中。iou-thres是NMS的IOU阈值,一般为0.3~0.5。
  • [其他] 使用YOLOv5模型进行目标检测(1)
    文章来源于Datawhale ,作者陈信达目标检测是计算机视觉领域的一大任务,大致分为一阶段目标检测与两阶段目标检测。其中一阶段目标检测模型以YOLO系列为代表。最新的YOLOv5在各个数据集上体现出收敛速度快、模型可定制性强的特点,值得关注。本文主要讲解如何从零训练自己的YOLOv5模型与一些重要参数的含义。本文的训练数据使用的是开源数据集SHWD,已上传开源数据平台Graviti,在文末可下载。在学习或研究目标检测的同学,后台回复“210702”可进群一起交流。一、配置环境1.1 创建虚拟环境俗话说,环境配不对,学习两行泪,首先我们需要安装Anaconda(Anaconda安装非常简单并且百度上有大量资料),然后创建一个专门用来训练YOLOv5的虚拟环境。按win+r打开“运行对话框”,输入“cmd”打开cmd。输入下面代码创建虚拟环境:conda create -n course_yolov5 python==3.8其中“course_yolov5”是虚拟环境的名称,“python==3.8”是虚拟环境的python版本。然后我们需要将Ultralytics开源的YOLOv5代码Clone或下载到本地,可以直接点击Download ZIP进行下载,下载地址:https://github.com/ultralytics/yolov5接下来激活刚刚创建的虚拟环境并解压刚下好的压缩文件,将工作路径切换到解压好的文件夹下:conda activate course_yolov5 cd D:\Study\PyCharm20\PycharmProjects\course_yolov5\yolov5-master d:注意:这里需要将" D:\Study\PyCharm20\PycharmProjects\course_yolov5"替换为自己的路径。1.2 安装模块:在安装模块之前,最好先更换pip源为阿里源或国科大源,然后安装yolov5需要的模块,记住工作路径要在yolov5文件夹下:python -m pip install -r requirements.txt如果没有安装cuda默认安装pytorch-cpu版,如果有gpu可以安装pytorch-gpu版。二、检测2.1 COCO数据集在正确配置好环境后就可以检测自己的图片或视频了。YOLOv5已经在COCO数据集上训练好,COCO数据集一共有80个类别,如果您需要的类别也在其中的话,可以直接用训练好的模型进行检测。这80个类分别是:['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']2.2 用预训练模型进行测试下面我们先演示如何检测图片中的目标。我们一般将要检测的数据放在'./data/images'路径下,其中 '.' 代表当前路径即解压好的yolov5-master文件夹,然后我们在cmd中输入下面代码:python detect.py --source ./data/images/example.jpg --weights weights/yolov5s.pt --conf-thres 0.25如果没有下载预训练模型需要等预训练模型下好,没有报错就说明我们的图像检测成功了!检测好的图片会放在'./runs/detect'下,各个参数的含义下面会有具体的介绍。我们也可以对视频进行检测:python detect.py --source ./data/images/happysheep.mp4 --weights weights/yolov5s.pt --conf-thres 0.25或一个文件夹中的所有图片和视频(图片支持的格式:'bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo',视频支持的格式:'mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'),检测结果同样放在'./runs/detect'下。python detect.py --source ./data/images/ --weights weights/yolov5s.pt --conf-thres 0.25仔细观察图中,我们可以发现,官方训练好的模型虽然能将物体框出来,但是对物体的分类存在问题。一会儿将那只边牧预测为奶牛,一会儿预测为绵羊。
  • [其他] 通用卷积神经网络CCNN(2)-实验结果
    如下表 1-4 所示,CCNN 模型在所有任务中都表现良好。首先是 1D 图像分类 CCNN 在多个连续基准上获得 SOTA,例如 Long Range Arena、语音识别、1D 图像分类,所有这些都在单一架构中实现的。CCNN 通常比其他方法模型更小架构更简单。然后是 2D 图像分类:通过单一架构,CCNN 可以匹配并超越更深的 CNN。对 ND 进行远程依赖建模的重要性。原则上可以将所有任务视为不考虑 2D 结构的序列任务,该研究只需改变进入核生成器网络的坐标维数,就可以在多维空间上轻松定义 CCNN。有趣的是,该研究观察到,通过在 LRA 基准测试中考虑图像和 Pathfinder 任务的 2D 特性,可以获得更好的结果(上表 3)。在具有 2D 图像的 PathFinder 中,最大的 CCNN 获得了 96.00% 的准确率,比之前 SOTA 高出近 10 个点,并在扁平图像上的表现明显优于 CCNN。此外,在原始 2D 数据上训练的模型显示出比它们的序列对应物更快的收敛(图 3)。具有小卷积核的 2D CNN,例如 ResNet-18,由于中间池化层缺乏细粒度的全局上下文建模,无法解决 Pathfinder。
  • [其他] CCNN:在 ND 中建模远程依赖关系
    具有连续核卷积的残差块改进。该研究对 FlexNet 架构进行了修改 ,其残差网络由类似于 S4 网络的块组成。CCNN 架构如下图 2 所示。基于这些观察,该研究构建了 FlexConv 的深度(depth-wise)可分离版本,其中通道(channel-wise)卷积是使用核生成器网络生成的核计算的,之后是从 N_in 到 N_out 进行逐点卷积。这种变化允许构建更广泛的 CCNN—— 从 30 到 110 个隐藏通道,而不会增加网络参数或计算复杂度。正确初始化核生成器网络 G_Kernel。该研究观察到,在以前的研究中核生成器网络没有正确初始化。在初始化前,人们希望卷积层的输入和输出的方差保持相等,以避免梯度爆炸和消失,即 Var (x)=Var (y)。因此,卷积核被初始化为具有方差 Var (K)=gain^2 /(in channels ⋅ kernel size) 的形式,其增益取决于所使用的非线性。然而,神经网络的初始化使输入的 unitary 方差保留在输出。因此,当用作核生成器网络时,标准初始化方法导致核具有 unitary 方差,即 Var (K)=1。结果,使用神经网络作为核生成器网络的 CNN 经历了与通道⋅内核大小成比例的特征表示方差的逐层增长。例如,研究者观察到 CKCNNs 和 FlexNets 在初始化时的 logits 大约为 1e^19。这是不可取的,这可能导致训练不稳定和需要低学习率。为了解决这个问题,该研究要求 G_Kernel 输出方差等于 gain^2 /(in_channels⋅kernel_size)而不是 1。他们通过、重新加权核生成器网络的最后一层。因此,核生成器网络输出的方差遵循传统卷积核的初始化,而 CCNN 的 logits 在初始化时呈现单一方差。
  • [其他] 连续核卷积
    连续核卷积将小型神经网络作为核生成器网络,同时将卷积核参数化为连续函数。该网络将坐标映射到该位置的卷积核值:(图 1a)。通过将 K 个坐标的向量通过 G_Kernel,可以构造一个大小相等的卷积核 K,即。随后,在输入信号和生成的卷积核之间进行卷积运算,以构造输出特征表示,即。任意数据维度的一般操作。通过改变输入坐标 c_i 的维数 D,核生成器网络 G_Kernel 可用于构造任意维数的卷积核。因此可以使用相同的操作来处理序列 D=1、视觉 D=2 和更高维数据 D≥3。不同输入分辨率的等效响应。如果输入信号 x 有分辨率变化,例如最初在 8KHz 观察到的音频现在在 16KHz 观察到,则与离散卷积核进行卷积以产生不同的响应,因为核将在每个分辨率下覆盖不同的输入子集。另一方面,连续核是分辨率无关的,因此无论输入的分辨率如何,它都能够识别输入。当以不同的分辨率(例如更高的分辨率)呈现输入时,通过核生成器网络传递更精细的坐标网格就足够了,以便以相应的分辨率构造相同的核。对于以分辨率 r (1) 和 r (2) 采样的信号 x 和连续卷积核 K,两种分辨率下的卷积大约等于与分辨率变化成比例的因子:
  • [其他] 通用卷积神经网络CCNN(1)
    转载自机器之心在 VGG、U-Net、TCN 网络中... CNN 虽然功能强大,但必须针对特定问题、数据类型、长度和分辨率进行定制,才能发挥其作用。我们不禁会问,可以设计出一个在所有这些网络中都运行良好的单一 CNN 吗?本文中,来自阿姆斯特丹自由大学、阿姆斯特丹大学、斯坦福大学的研究者提出了 CCNN,单个 CNN 就能够在多个数据集(例如 LRA)上实现 SOTA !1998 年 LeCun 等人提出卷积神经网络 (CNN),这是一类广泛用于机器学习的深度学习模型。由于 CNN 具有高性能和高效率等特点,使其在跨序列、视觉和高维数据的多个应用程序中实现 SOTA 性能。然而,CNN(以及一般的神经网络)存在一个严重缺陷,这些架构必须针对特定应用进行定制,以便处理不同的数据长度、分辨率和维度。这反过来又导致大量特定于任务的 CNN 架构出现。数据可以有许多不同的长度,例如图像可以是 32x32 或 1024x1024。标准 CNN 存在的问题是,它们的卷积核是局部的,这需要为每个长度定制一个精心选择的步长和池化层来捕获整个上下文自定义架构。此外,许多数据本质上是连续的,在不同的分辨率下具有相同的语义,例如图像可以在任意分辨率下捕获,并具有相同的语义内容,音频可以在 16kHz 或 44.1kHz 采样,但人耳听起来仍然是相同的。然而,由于卷积核的离散性,传统的 CNN 不能跨分辨率使用。当考虑具有相同 CNN 的不同维度数据时,这两个问题会进一步加剧,例如序列(1D)、视觉(2D)和高维数据(3D、4D),因为不同的维度以不同的特征长度和分辨率运行,例如一秒音频的长度很容易达到 16000,这与基准数据集中的图像大小形成强烈对比。在本文中,研究者提出了迈向通用 CNN 架构。其目标是构建一个单一的 CNN 架构,可以用于任意分辨率、长度和维度的数据。标准 CNN 需要特定于任务的架构,因为其卷积核的离散性将内核绑定到特定的数据分辨率,并且由于构建大型离散卷积核所需的大量参数,它们不适合对全局上下文进行建模。因此,为了构建一个通用的 CNN 架构,关键是开发一个分辨率不可知的卷积层,该卷积层能够以参数有效的方式对远程依赖关系进行建模。该研究入选 ICML 2022 。论文地址:https://arxiv.org/pdf/2206.03398.pdf代码地址:https://github.com/david-knigge/ccnn
  • [互动交流] 数字机器人网页自动化拾取信息无法拾取完全,该咋办
    数字机器人网页拾取数据时好微妙啊,比如网页文件,有些列表只能拾取前10个大概,想选后面的,就没有相似元素。始终无法选到所有的文本。有些python代码都能把元素选出来,用机器人工具就是选不出来。比如:"xpath": [         "//html/body/div/div/div/main/div[6]/div/div/div/div[2]/div/div/div/div/div/div/div/div/div[2]/div/div/span/div/span/span",         "//html/body/div/div/div/main/div[6]/div/div/div/div[2]/div/div/div/div/div/div[3]/div/div/div[2]/div/div/span/div/span/span"这个可以识别。这个就无法识别:/html/body/div[1]/div[1]/div[1]/main/div[6]/div/div/div/div[2]/div/div/div/div/div[5]/div[9]/div/div/div[2]/div[1]/div/span/div/span/span。下面是我自己写的代码,用python执行没问题,但是使用【网页数据拾取】就不行,真不知道改修改拾取规则。/html/body/div[1]/div[1]/div[1]/main/div[6]/div/div/div/div[2]/div/div/div/div/div/div/div/div/div[2]/div[1]/div/span/div/span/span修改成上面的代码,会报错。知道的能回复一下不
  • [互动交流] 递归流程如何编排?
    跑遍历的时候,比如if的时候,如何遍历后,条件符合和条件不符合能归到同一步处理。例:开始→A→if(A是否存在)→(yes)→B(遍历)→D→结束                                  ↘(no)→→C→→→→→↗(D)
  • [技术干货] 关于人工智能错误算法的认识 改正及思考
    经过我今年对深度学习 机器学习的研究发现 其算法是错误的 计算机是一台以指令为单位的机器 它是不会学习的 所以没有学习算法一说 那是没有认清计算机的本质 学习是人才有的行为 机器怎么会学习吗 它只有指令啊 经过研究发现我们常说的人工智能 主要是如下四个函数构成的 下面我以常见的游戏AI为例讲解其实现 由于已有多年未碰编程 这里只给出大致算法 在游戏中 当角色或者NPC看/听到什么的时候 就开始学习过程 如何学习呢 其实所有的学习都是从理解开始的 下面给出Understand()函数 int Understand(string type, string action, string p1, string p2) {     string memory;     switch(type)     {         case 'walk'         memory=Walk(action,p1,p2);  // Walk()函数根据词典定义及参数p1, p2解释action并将相应的字符串写入memory         break;         case 'run'         memory=Run(action,p1,p2);         break;         case 'fight'         memory=Fight(action,p1,p2);         break;         case 'look'         memory=Look(action,p1,p2);  // 比如看这个行为 Understand()函数会把它解释成使视线接触人或事物 并把记忆记在数据库里                                                         // 实际上人在想看东西的时候 检索记忆也是找到上面的解释并做出相应的行为的         break;         ......         各种人的行为的函数  // 这里要注意的是行为的归类一定要仔细不要冗余 比如躺和侧躺是一类不能归为2类 我个人估算25个行为左右已经有很好                                         // 的人工智能70个基本上完美 这个时候Understand才两三百行 对游戏来说是个微不足道的小函数                                         // 要特别指出的是像跳绳 踢毽子等应该归属于一类Playing()玩游戏         break;     }     Remember(action, memory);  // 记忆理解所得的结果即把原始记忆和理解得出的记忆写入数据库 如表hero/NPC} 第二个函数是Study() 人要认识世界就要各种学习 理解了就学习了 所以 bool Study(string action) {     action=Look()/action=Listen();  // 通过看或者听学习     string type=IsAction(action);  // 判断是某种行为 比如走 跑 说话 看等     string p1,p2;     p1=IsParam1(action); p2=IsParam2(action);  // 对行为的一些描述p1 p2     Understand(type, action, p1, p2);  // 对行为进行理解并记忆 } 然后 NPC在空闲的时候还会想事情(就是普通的漫无目的想 假定其函数名为Thinking) 想了之后就做某种事情 第三个函数如下 int Thinking() {     int n=0;  // n是随机数 NPC在空闲的时候想什么事情是个随机事件 它随机性的发生     int type=rand()/2;  // 2可用其它值 处于某种想之中     switch(type)     {         case 1:         n=OnIdle();  // 在空想 函数给n赋予随机值         break;         case 2:         n=Memory();  // 在回忆 函数给n赋予随机值         break;         ......      }     switch(n)     {         case 1:         Walk();  // 某种形式某种目的的行走 与Understand()中那个不同这个是实际的行为 那个是把行走理解成某种行动的字符串数据         break;         case 2:         Talk();   // 某种目的某种内容的谈话         break;         ......         default         break;      } } 最后一个函数 也是最难的一个函数 就是思考(Thought) 对某个问题经过思考得出结果 int Thought(string question) {     if(LookupMemory(question))  // 在记忆中查找看是否找到 实际上是一个查找数据库的表并在表中的数据项查找的函数      {         string law;         law=Haslaw(question);  // 函数中可用IsNum() IsMathChar() IsLaw()等函数判断question里面是否有数字 数学符号 数学/物理法则等         if(law.IsNotNull())  // 看是否包含有法则         {             RunLogic(law);  // 运行相应的逻辑法则         }         else         {                                      // 做其它的事 比如和某个NPC对话         }         return 1;     }     else     {         if(Research(question))  // 研究问题         {             ......    // 成功相应的行为             return 1;         }         else        {            ......    // 失败相应的行为            return 0;        }     } } 通过以上四个函数就可以把理解 学习 想事情 思考问题完整的实现出来 完成人工智能的全部功能 这里根本不需要什么深度学习 机器学习 这就是全部的人工智能函数 下面再写两个跟游戏有关及常用的人工智能函数 第一个自动寻路/自动驾驶 自动寻路要注意的一点就是不能把HitTest()当成"轻重缓急"算法写在判断避让那里 因为自动寻路避让障碍的时候是个轻重缓急行为 不是进行碰撞检测 bool AutoDriving(int Character) {     bool obstacle=Look();  // 看道路上有无障碍     if(obstacle)     {          int distance=OrderofPriority(Character);  // 判断轻重缓急          int direction=GetInput(keyboard);          ChangeDirection(direction, distance);  // 在距离distance处转向     } } 一个可能的轻重缓急算法是 int OrderofPriority(int Character) {     int type=rand()/2;  // 轻和重 缓和急是个随机产生情况 这是客观世界的真实反应 游戏世界也是一样的     switch(type)     {         int min=GetMinimum();  // 测出物体中心到前端的距离的最大值即碰撞距离 不碰撞只要大于它就行了 比如可以略大于它 也可以+1 +2 +5厘米或者加个随机数         int senmin,senmax;         GetDistanceSensitivity(Character,senmin,senmax);  // 得到角色的最小最大距离敏感度 一个查询数据库的函数         case 1:  // 轻/缓         return min+(rand()/0.1~1)+senmax;  //  大于碰撞距离小于等于角色最大距离敏感度并略有出入的随机数 或者其它可自定         break;         case 2:  // 重/急         return min+(rand()/0.1~1)+senmin;  //  大于碰撞距离小于等于角色最小距离敏感度并略有出入的随机数 或者其它可自定         break;     } } 第二个真实打斗 这个函数主要是随机数加上一些三十六计计谋即可 如 int RealFighting() {      int type=rand()/50;  // 计谋中的一种 包括连环计 计中计      switch(type)      {           case 1:           声东击西();           break;           case 2:           围魏救赵();           break;           case 3:           四面楚歌();           火上浇油();           break;           ......      } } 甚至还可以写出复合体及变体 提到游戏中人工智能 很多时候都是个随机数问题 因为自然界中的事都是随机发生的 当然到了虚拟世界里面 各种事情也是个随机性的 恰好有rand()函数能很好的解决这一问题 欢迎转载
总条数:7868 到第 页
上滑加载中