注意该文章仅提供思路哈,最好不要使用文章内提供的数据集,另外距离当时写这篇文章的时间也比较久远了,现在最新版的yolo不确定是否有别的break change,请大家以yolo的最新版文档和api为准。
读完这篇文章,你将可以学习到如何在浏览器里进行”目标检测“!”目标检测“看似很难实现、无从下手,但其实也没有你想象的那么遥不可及啦,相反,现有的一些库与工具的出现,让它的实现变得越来越简单。下面我将从“收集图片”开始,通过配图和文字(一些我自己的理解),一步步带你训练出轻量、高准确度的模型文件,最终成功在浏览器里识别出我们自定义的目标。
这篇文章几乎不涉及机器学习原理
,什么神经网络、卷积等,你在这里是看不到的,讲道理自己对这些原理 & 算法是不太了解的,是不敢
发表自己的见解的。
本文主要以实战
为主,自己的一些使用理解
为辅,训练时采用最新的预置模型来训练,更贴合轻量级使用场景。当你走完整个流程之后,再去学习机器学习相关的原理知识,可以更好的帮你理解。
为何写这篇文章
大概在上周,自己为了完成一个效果
,去学习并成功实践了在浏览器端进行目标检测
,通过各方
查阅资料、踩坑,终于趟出了一条明路
,过程中也苦于没有
一篇完整的博客来向没有相关经验的小白
来介绍如何在浏览器中进行目标检测,那为何自己不写一篇呢?所以就有了写这篇文章的动力
。
自己之前想完成的效果是如何在一个大图
中,找到二维码
的位置,然后截取
到对应的二维码图像,进行解析
,最终将解析结果回显
到对应的位置上。
最终的效果图如下:
在此也推荐
一下最终完成的浏览器插件
!!!
下面是介绍它的一篇文章,有兴趣的话可以读读看
!
机器学习 + 浏览器插件 = 东半球最好用的二维(条形)码识别器
先明确一下你即将要做的事情
我们接下来要做的是在浏览器中进行目标检测,注意了,关键词是“浏览器”
、 “目标检测”
。
根据以上关键词,首先便引出了本文的重头戏之一:Tensorflow.js
在浏览器
进行目标检测,是借助tensorflow
库来实现的,它有很多语言版本(python/java/...
),因为我们本次使用浏览器
作为载体,所以我们采用js
版本,以下是它的js
版本的介绍。
使用Tensorflow.js
,你可以做以下事情:
- 在
浏览器环境
中训练你的模型(区别于其他比如python
等)并可视化训练过程。 部署
训练好的模型
,进行后续操作(识别
、预测
)。- ...
在这里,我们就是使用第二种方式:使用其他语言训练好的模型,在浏览器端加载模型并进行识别
。
Q: 为什么使用其他语言进行训练呢?我总结大致有两个原因吧:
1、其他平台比如python
,训练模型的库(算法)更丰富;
2、训练的速度更快一些(相比于在浏览器中)。
使用一个图来总结一下接下来的流程的话,大致如下:
OK,看到这里,如果你觉得真的有兴趣
的话,那就可以继续
看下去了!
后面我们以二维码
识别为例,逐步讲解,相信你也可以跟着流程做出你的第一个浏览器端目标检测程序
!
步骤一:收集图片
这一步,我分享一下我是怎么收集图片
& 整理图片
的 (一些小经验):
1、收集图片
收集图片阶段,我是怎么简单
怎么来的。
打开百度,搜索二维码,点击搜图片,就可以搜到无数个二维码图片了:
因为这一屏的二维码实在是有点多,我的解决的主要场景是一个页面有1-10个二维码就很足够了,那么这么多图其实也没必要,所以就进入每个图的详情页,依次截屏,放到图片文件夹中,就像下图。
最终我整理了2-300
张图片,这个过程很枯燥,大家也要多去多用心
去准备这些图片,要相信付出总有收获的,图片收集的质量越高/场景越多样
,后面训练、识别的效果越好
!
我大概准备了250
张图片:
2、统一命名
在进行下一步标注之前,希望你可以先给你的图片文件们统一命个名
,不然看起来太乱了,就像下面这样,一眼看不懂文件名是什么意思:
你可以通过MacOS
自带的批量操作
功能完成这件事,它在这里:
重新命名后大致是这样,清爽多了:
OK,当你完成该步骤的时候,你就可以进行下一步了,去给你的图片进行标注!
步骤二:图片标注
所谓的图片标注,就是需要你来
手动处理
每一张图片,使用工具标出来
你认为正确
的信息,比如该案例是二维码,就是需要你在每一张图片中标出来哪里是二维码。
标注的意义就是告诉计算机,这个图片中,我圈的这里就是二维码,你在训练的时候要将你预测的结果和我标注的结果进行
比对
,不对的话就要朝着这个方向调整。
1、安装工具
图片标注我采用的工具是:labelImg
,下面是它的github
地址:
按文档中的README
安装好之后,就可以通过命令启动它了!
$ python3 labelImg.py
启动后的界面如下:
首先选择标注结果格式,这里选择PascalVOC
(文件是.xml
格式),个人认为.xml
格式的结果文件便于清晰的看到标注结果,也方便后面使用脚本划分结果集时使用。
下图是同一份标注的.xml
和.txt
的结果对比:
明显看到左侧的信息可以一眼读出来,右边会更抽象,不便于理解,但是便于计算机读取。
2、开始标注
导入图片后你就可以使用快捷键w
愉快的进行标注了,标注后,会提示让你输入类别名称
,这里我们就使用code
作为二维码分类:
全部标注后,你将得到以下密密麻麻的文件。
至此,图片标注结束,下面我们将进行训练集的划分
!
步骤三:划分训练集、验证集
1、将xml格式的结果集转化成txt格式
接下来,我们需要一段脚本
来划分训练集
、验证集
,该脚本主要做了两件事:(1).xml文件转.txt文件 (2)按百分比将图片 + 标注结果划分为训练集、验证集
。
训练集:拿给训练算法的用于训练的集合
验证集:拿给训练算法用于验证训练结果的集合
在这里你可能会有疑问,为什么要将.xml
转成.txt
呢?如果一开始就需要.txt
的话,那么上面我们特意将结果选择为.xml
格式是为了什么?
大概有下面几种考虑吧:
-
后续使用的训练算法
yolo
是使用.txt
格式的标注结果文件的。 -
使用
.xml
格式可以看一下标注过程到底做了什么、结果文件中包含什么,因为.txt
中的信息几乎不可看。 -
网上分享的很多训练集大部分都是
.xml
格式的,后续你在使用其他分享的标注集的时候,完全可以使用以下操作来进行划分。
清楚原因后,下面我们开始划分
吧!
首先,需要整理一下你的目录为以下结构(建议这么做!
),这样你可以不需要大改后续提供的转化脚本,否则你需要改一下下面提供的python
脚本代码(将脚本中的路径换成你的路径,要对齐)。
说明:图片文件(250张)放在
JPEGImages
中,XML文件(250个)放在Annotations
中
执行划分逻辑的python
脚本如下(保存到你的本地,需与VOCdevkit
文件夹平级):
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile
classes = ["code"] // !!! 需要关注这里,这里是你所有标注的class,1个或多个,我们本次只有一个目标就是二维码,所以这里只写code(code就是之前在标注的时候给的名字)
TRAIN_RATIO = 70 // !!! 需要关注这里,这里是划分训练集的百分比(相对于验证集来说),当这里是70的时候,代表训练集是250 * 70%,验证集是250 * 30%(划分你的标注文件)
def clear_hidden_files(path):
dir_list = os.listdir(path)
for i in dir_list:
abspath = os.path.join(os.path.abspath(path), i)
if os.path.isfile(abspath):
if i.startswith("._"):
os.remove(abspath)
else:
clear_hidden_files(abspath)
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)
// 将 xml 转 txt
def convert_annotation(image_id):
in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' %image_id)
out_file = open('VOCdevkit/VOC2007/YOLOLabels/%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')
in_file.close()
out_file.close()
wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_sapce_dir):
os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir) # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0,len(list_imgs)):
path = os.path.join(image_dir,list_imgs[i])
if os.path.isfile(path):
image_path = image_dir + list_imgs[i]
voc_path = list_imgs[i]
(nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
(voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
annotation_name = nameWithoutExtention + '.xml'
annotation_path = os.path.join(annotation_dir, annotation_name)
label_name = nameWithoutExtention + '.txt'
label_path = os.path.join(yolo_labels_dir, label_name)
prob = random.randint(1, 100)
print("Probability: %d" % prob)
if(prob < TRAIN_RATIO): # train dataset
if os.path.exists(annotation_path):
train_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_train_dir + voc_path)
copyfile(label_path, yolov5_labels_train_dir + label_name)
else: # test dataset
if os.path.exists(annotation_path):
test_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_test_dir + voc_path)
copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()
将上面代码保存到你本地,将上面脚本注释中你需要关注的地方改好,并按照结构放置好你的文件之后(如果不按照上面给到的文件夹结构放置你的文件,那么你需要修改脚本中相关涉及到的路径
),执行以下命令:
$ python3 transform-xml2txt.py
有问题解决问题,没问题你将得到如下目录:
在VOCdevkit
目录下生成images
和labels
文件夹,文件夹下分别生成了train
文件夹和val
文件夹,里面分别保存着训练集的照片和txt
格式的标签,还有验证集的照片和txt
格式的标签。images
文件夹和labels
文件夹就是训练yolo
模型所需的训练集和验证集。在VOCdevkit/VOC2007
目录下还生成了一个YOLOLabels
文件夹,里面存放着所有的txt
格式的标签文件。
至此,你的训练集、验证集就划分好了,下面准备打包一下你的训练集吧!
2、小声明
在这里需要感谢”炮哥
“,以上划分训练集、验证集的部分图片、脚本是学习自该同学
视频:www.bilibili.com/video/BV1f4…
文章和视频都很不错
,以示感谢!如果你对本节有疑问,可以仔细阅读该文章。
步骤四:打包训练集
这里的打包不是真正意义上的打包,而是使用一个骚操作来把你的训练集文件快速导入
另一个平台(Colaboratory
)来进行训练。
不卖关子啦,这里使用的骚操作就是将刚才的文件夹初始化为git
仓库,并上传到gitee
、github
等远程库中,最后在Colaboratory
上使用git
拉下来即可,这样一来可以保存你的训练集,二来可以快速更新你的训练集,因为Colaboratory
的文件访问是谷歌云盘,云盘上传下载巨巨巨慢,更别提200+
图片 & 文件了,不使用git
的话,最少得1-2小时
才能上传好。
如何初始化git
并上传到远程仓库,这里就不做展开描述了,如果不会使用git
的话,实属不该哈。
如下图,我已经初始化git
& 上传远程仓库
完毕:
步骤五:选择训练算法
目标检测算法
有很多种(我了解到的):R-CNN
、Fast-RCNN
、Faster_RCNN
、YOLO
...
其实到这一步之前,我们已经交代过了,我们将会采用yolo
来作为我们的训练算法,为什么采用yolo
呢?有两点吧:配置简单
+ 速度够快
。
官网比较低调的介绍自己:由于其速度和准确性,YOLO 算法是最著名的目标检测算法之一
注:其实
没有深度对比
过以上几种算法的优劣,我只使用yolo
来训练过模型,并且效果是非常符合预期的(不需要太多的配置与超参数修改、部署后识别速度都能在瞬间完成),大家有其他更好的推荐,可以评论下方,我可以去尝试下更好
的替代方案。
步骤六:选择训练平台
在这里,你将有两种
方式来训练你的模型:使用你自己的电脑 or 使用云平台。
我没有使用自己电脑来训练,因为使用的是笔记本,没有外接GPU
,所以干脆直接放弃在自己电脑上训练,采取云平台来训练。
这里采用的是谷歌(牛批
)的 Colaboratory
,其提供完善的python
环境 + GPU
,敲重点!免费的!你好像可以
一直免费使用(科学使用,不浪费,不使用的时候需要立马断开链接),我是因为使用姿势有问题,被锁了24小时,就买了它的pro模式,不过平台整体使用感受还是相当不错的。
下面是平台截图:
步骤七:配置训练平台环境
1、配置Colaboratory运行时模式
你需要配置你的运行时为GPU
模式:
2、拉取相关文件到平台
(1)首先你需要先配置好你的git
参数,登录上你的git
!git config --global user.email "your email"
!git config --global user.name "your name"
(2)挂载你的谷歌云盘到 Colaboratory
import os from google.colab
import drive
drive.mount('/content/drive')
path = "/content/drive/My Drive"
os.chdir(path)
os.listdir(path)
(3)创建 & 进入对应目录,我本次使用的目录是新创建的/learn-for-book/
(4)拉取你的图片、标注文件到 Colaboratory
所挂载的云盘上
!git clone https://gitee.com/xicunyang/learn-image.git
(5)拉取yolov5源码
到 Colaboratory
所挂载的云盘上(和图片文件平级即可)
!git clone https://github.com/ultralytics/yolov5.git
(6)安装依赖
!pip install -r requirements.txt
(7)最后检查一下所需的资源是否都
拉下来了
OK,如果你能得到目前的效果,接下来,就可以开始调整超参数
了!
步骤八:调整超参数
在调整超参数前,我们先做一些前置工作:验证环境是否正确、使用
yolo
识别一张图片。
1、验证环境正确
!python -V
import torch
print(torch.cuda.is_available())
print(torch.backends.cudnn.is_available())
2、使用yolo官方示例权重,检测人像
我们再来验证一下你下载的yolo源码是不是可以用,使用
yolo
自带的detect.py
脚本 +预置权重
来检测一张人像图,看看是不是可以正确检测出来。
1、上传一张带人像的图片,到yolov5
目录下
2、在yolov5
目录下,运行检测脚本,--source
的值是我们上传的图片路径
!python detect.py --source pic/person.jpeg
可以看到,检测结果保存在了runs/detect/exp
目录下
我们吧图片下载到本地后,可以看到,相关信息已经被识别出来,并成功
标注到了对应位置
此时,你可能完成了你人生中第一张机器识别的图片,接着,我们再接再厉
,开始准备训练我们自定义
的模型啦!
3、了解什么是预置权重文件
这里先展开讲一下什么是预置权重文件
:
一般为了缩短训练时间,并且可以达到预期的识别精度,我们需要选择预置权重文件
来进行网络的训练。
可以看到,yolo
提供了一些适合不同场景
的预置权重文件,从左往右会越来越复杂,相应训练的时长会更长,最终生成的权重文件也会越来越大,因为我们是一个轻量级的使用场景,当然是越快越好,且二维码的特征也比较清晰,识别难度不会很大,所以在这里我们选择 YOLOv5n
!
是不是没有看到
这个文件,那是因为在2021
年12
月份yolo
才刚刚推出了tag v6
,其中就包含这个v5n(6)
,其比v5s
还要轻便,这次更新,一共带来了两个让人振奋的功能:
(1)提供了更小巧的weights
文件:YOLOV5n
,使得训练出来的权重体积比YOLOV5s
缩小75%
,更适合移动端使用。
(2)提供export
功能,可以直接将yolo
训练后的权重导出成tensorflow.js
所识别的权重文件!
4、选择预置权重文件
经过上面的简单了解,这里我们最终选择yolov5n6.pt
,可以看到以下官方的对比,发现v5n6
在AP(平均准确度)
上是要优于v5n
的。
在权重下载地址 这里下载对应的文件,并上传到对应的目录下 yolov5/weights/
:
5、调整超参数
在这一步上,我们主要是调整yolo
暴露给我们的一些参数,以达到我们训练自定义模型
的目的。
(1)修改 data/VOC.yaml
文件
train
: 训练集路径val
: 验证集路径nc
: 类型数量names
: 类型名称
(2)修改 models/yolov5n.yaml
nc
: 类型数量
(3)修改 train.py
--weights
: 你上传的yolov5n6.pt
路径--cfg
: 刚才修改的yolov5n.yaml
路径--data
: 刚才修改的VOC.yaml
路径
其余的一些参数介绍,你可以根据你自己的情况来动态配置:
opt模型主要参数解析:
--weights:初始化的权重文件的路径地址
--cfg:模型yaml文件的路径地址
--data:数据yaml文件的路径地址
--hyp:超参数文件路径地址
--epochs:训练轮次
--batch-size:喂入批次文件的多少
--img-size:输入图片尺寸
--rect:是否采用矩形训练,默认False
--resume:接着打断训练上次的结果接着训练
--nosave:不保存模型,默认False
--notest:不进行test,默认False
--noautoanchor:不自动调整anchor,默认False
--evolve:是否进行超参数进化,默认False
--bucket:谷歌云盘bucket,一般不会用到
--cache-images:是否提前缓存图片到内存,以加快训练速度,默认False
--image-weights:使用加权图像选择进行训练
--device:训练的设备,cpu;0(表示一个gpu设备cuda:0);0,1,2,3(多个gpu设备)
--multi-scale:是否进行多尺度训练,默认False
--single-cls:数据集是否只有一个类别,默认False
--adam:是否使用adam优化器
--sync-bn:是否使用跨卡同步BN,在DDP模式使用
--local_rank:DDP参数,请勿修改
--workers:最大工作核心数
--project:训练模型的保存位置
--name:模型保存的目录名称
--exist-ok:模型目录是否存在,不存在就创建
————————————————
版权声明:本文为CSDN博主「炮哥带你学」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/didiaopao/article/details/119954291
步骤九:开始训练(炼丹)
以上配置完成后,我们就可以通过下面的命令,来开始我们的训练啦!
我们执行:
!python train.py
不出意外,你将看到以下输出:
恭喜你,你的yolo
已经配置完毕,而且正在全力训练
中!
你可以关注这个R
值,这个是正确率
,1是百分之百的正确率。可以看到,随着训练次数的增多,R
的值也在不断趋近于1
。
你只需要等待训练完成
,就可以得到以下输出:
步骤十:获取训练权重文件
我们去到对应文件夹下,就可以看到训练完成的权重文件
了,我们此时采用yolo
来测试下刚刚训练成功的权重文件是否有效果。
我们找一个测试图片:
上传到pic文件夹下:
修改detect.py
文件,修改weights
文件地址,让其指向我们刚训练好的权重文件上:
执行:
!python detect.py --source pic/code.jpg
看到已经成功识别
!!!
怀着机动的心情,我们down
下来runs/detect/exp3
文件夹下的这张图片:
可以看到,二维码已经被精准
的识别出来了!
此时,如果你计划使用yolo
来检测图形的话,就可以到此结束了。
不过因为我们是准备在浏览器
中使用,所以,还得继续看下去。
步骤十一:导出web格式权重文件
在这一步,我们需要将yolo
可以识别的.pt
文件,转为tensorflow.js
可以识别的文件(json + bin),转化脚本我们可以使用上面提到的tag v6
提供的export.py
来实现,我们执行:
!python3 export.py --weights /content/drive/MyDrive/learn-for-book/yolov5/runs/train/exp3/weights/best.pt --include tfjs
运行结束,你将得到:
还是在同一文件夹下,多出了一个best_web_model
文件夹,文件夹下的所有文件就是我们后续在浏览器中可以使用的权重文件
啦!
你可以将其down
到本地,接着我们就搞一个demo
项目来在本地测试一个权重文件是不是好用。
步骤十二:安装 & 调整
这里我就不一步一步去描述如何搭建一个测试demo
了,github
上刚好有一个测试的demo项目
,我们正好可以使用它!
github地址:github.com/zldrobit/tf…
我们先观察一下这个项目使用的依赖:
bingo!这个就是我们前面说到的tensorflow
的js
版本!
不难看出这是一个react
项目,down
到本地之后,先装一下依赖、再使用yarn start
即可启动,启动后的页面如下:
可以看到,会有一个报错。
别慌,这里报错的原因应该就是模型文件找不到
的报错,我们需要修改
一些代码
:
(1)本地起一个静态服务,把刚才保存的导出的模型文件
丢进去,并开启跨域
,我这里使用的是http-server,代码如下:
http-server ./ --cors
(2)修改demo
文件如下:
(3)重新运行
,可以看到,报错消失了
步骤十三:检测
选择文件后,稍等2-3s
,可以看到,二维码成功
被识别出来了!!!
至此,在浏览器
中通过目标检测算法
进行二维码识别
的流程就到此结束
啦。
步骤十四:说点什么吧
在你看完或者跟着做完以上流程之后,你会发现,机器学习好像也没那么难
哈哈哈,不过呢,我们是踩在巨人
(yolov5)的肩膀上,如果没有这位巨人,我们就得自己去手撕识别算法、卷积模型,那可不是几千字的小文章
可以带你入门的(还是要对其他学科保持敬畏
)。
由于tensorflow.js
的推出,我们可以用熟悉的javascript
来训练模型、预测结果,这很爽。
在浏览器
里加载模型去识别特征(不依赖服务器
),对一些快速识别
、高频度识别
的场景来说,还是很有帮助的(不用频繁调用
API接口)。
最后呢,希望你在看完这篇文章后,可以对这个领域有一些简单的认识
,而不是听到这个就心生畏惧
,假设后面某一天你遇到一些必须要用机器学习
才可以解决的场景的时候,我希望你可以低调
的说,I can do this (all day)
。