打造自己的视频会议系统 GGMeeting(附送源码,PC+手机,支持Linux、国产OS、银河麒麟、统信UOS) - C#开源即时通讯GGTalk - 博客园

mikel阅读(1018)

来源: 打造自己的视频会议系统 GGMeeting(附送源码,PC+手机,支持Linux、国产OS、银河麒麟、统信UOS) – C#开源即时通讯GGTalk – 博客园

自从在博客园发布开源即时通信系统GG(QQ高仿版)以来,结识了很多做IM的朋友,然后我和我的伙伴们也接到了很多与IM相关的项目。相比在发布GG之前难以接到项目的状况相比,现在简直太幸福了,虽然做项目很辛苦,但毕竟有钱赚,那辛苦也值了。

饮水思源,这里要感谢博客园提供了这么好的一个平台,让我们能展现自己的实力,提升我们的知名度,然后才能接到了更多项目。所以,我强烈建议那些希望接项目、接私单的朋友,都来博客园写博客吧,写出自己的知名度后,真是好处多多!

言归正传,前段时间做了个在线教育培训的项目,与视频会议比较类似,所以了,我打算像GGTalk开源即时通讯系统一样,搞一个开源视频会议系统并把实现的原理和源码都分享出来,让有兴趣的朋友可以参考下。继承GG的名称,我把这个开源视频会议系统命名为GGMeeting,目前版本为1.0,后续功能会不断增强。

目前,GGMeeting 服务端支持 Windows、Linux,客户端支持 Windows、Android、iOS、Linux、国产OS(银河麒麟、统信UOS)。

一般而言,视频会议的主要核心功能是:多人语音聊天、多人视频聊天、公共电子白板、会议房间管理。本文我们将介绍视频会议系统的主要功能及其实现原理,后面有空在介绍详细每个功能的详细实现细节。

想要直接下载体验的朋友请点击:“源码下载中心”         

GGMeeting 支持两种视窗布局风格:大视窗自动显示主持人或当前发言人的视频;或 1×1,2×2,3×3 分屏显示。

下图是布局风格1:大视窗自动显示主持人或当前发言人的视频。

      

下图是布局风格2:1×1,2×2,3×3 分屏显示。

以下是手机版截图:

一.语音通话

1.基础模型

在视频会议中,网络语音通话通常多对多的的,但就模型层面来说,我们讨论一个方向的通道就可以了。一方说话,另一方则听到声音。看似简单而迅捷,但是其背后的流程却是相当复杂的。我们将其经过的各个主要环节简化成下图所示的概念模型:

这是一个最基础的模型,由五个重要的环节构成:采集、编码、传送、解码、播放。

语音采集指的是从麦克风采集音频数据,即声音样本转换成数字信号。其涉及到几个重要的参数:采样频率、采样位数、声道数。

假设我们将采集到的音频帧不经过编码,而直接发送,那么我们可以计算其所需要的带宽要求,仍以上例:320*100 =32KBytes/s,如果换算为bits/s,则为256kb/s。这是个很大的带宽占用。而通过网络流量监控工具,我们可以发现采用类似QQ等IM软件进行语音通话时,流量为3-5KB/s,这比原始流量小了一个数量级。而这主要得益于音频编码技术。 所以,在实际的语音通话应用中,编码这个环节是不可缺少的。目前有很多常用的语音编码技术,像G.729、iLBC、AAC、SPEEX等等。

当一个音频帧完成编码后,即可通过网络发送给通话的对方。对于语音对话这样Realtime应用,低延迟和平稳是非常重要的,这就要求我们的网络传送非常顺畅。

当对方接收到编码帧后,会对其进行解码,以恢复成为可供声卡直接播放的数据。

完成解码后,即可将得到的音频帧提交给声卡进行播放。

2.高级功能

如果仅仅依靠上述的技术就能实现一个效果良好的应用于广域网上的语音对话系统,那就太easy了。正是由于很多现实的因素为上述的概念模型引入了众多挑战,使得网络语音系统的实现不是那么简单,其涉及到很多专业技术。一个“效果良好”的语音对话系统应该达到如下几点:低延迟,背景噪音小,声音流畅、没有卡、停顿的感觉,没有回音。

对于低延迟,只有在低延迟的情况下,才能让通话的双方有很强的Realtime的感觉。当然,这个主要取决于网络的速度和通话双方的物理位置的距离,就单纯软件的角度,优化的可能性很小。

(1)回音消除

现在大家几乎都已经都习惯了在语音聊天时,直接用PC或笔记本的声音外放功能。当使用外放功能时,扬声器播放的声音会被麦克风再次采集,传回给对方,这样对方就听到了自己的回音。

回音消除的原理简单地来说就是,回音消除模块依据刚播放的音频帧,在采集的音频帧中做一些类似抵消的运算,从而将回声从采集帧中清除掉。这个过程是相当复杂的,因为它还与你聊天时所处的房间的大小、以及你在房间中的位置有关,因为这些信息决定了声波反射的时长。 智能的回音消除模块,能动态调整内部参数,以最佳适应当前的环境。

(2)噪声抑制

噪声抑制又称为降噪处理,是根据语音数据的特点,将属于背景噪音的部分识别出来,并从音频帧中过滤掉。有很多编码器都内置了该功能。

(3)抖动缓冲区

抖动缓冲区(JitterBuffer)用于解决网络抖动的问题。所谓网络抖动,就是网络延迟一会大一会小,在这种情况下,即使发送方是定时发送数据包的(比如每100ms发送一个包),而接收方的接收就无法同样定时了,有时一个周期内一个包都接收不到,有时一个周期内接收到好几个包。如此,导致接收方听到的声音就是一卡一卡的。

JitterBuffer工作于解码器之后,语音播放之前的环节。即语音解码完成后,将解码帧放入JitterBuffer,声卡的播放回调到来时,从JitterBuffer中取出最老的一帧进行播放。

JitterBuffer的缓冲深度取决于网络抖动的程度,网络抖动越大,缓冲深度越大,播放音频的延迟就越大。所以,JitterBuffer是利用了较高的延迟来换取声音的流畅播放的,因为相比声音一卡一卡来说,稍大一点的延迟但更流畅的效果,其主观体验要更好。

当然,JitterBuffer的缓冲深度不是一直不变的,而是根据网络抖动程度的变化而动态调整的。当网络恢复到非常平稳通畅时,缓冲深度会非常小,这样因为JitterBuffer而增加的播放延迟就可以忽略不计了。

(4)静音检测

在语音对话中,要是当一方没有说话时,就不会产生流量就好了。静音检测就是用于这个目的的。静音检测通常也集成在编码模块中。静音检测算法结合前面的噪声抑制算法,可以识别出当前是否有语音输入,如果没有语音输入,就可以编码输出一个特殊的的编码帧(比如长度为0)。特别是在多人视频会议中,通常只有一个人在发言,这种情况下,利用静音检测技术而节省带宽还是非常可观的。

(5)混音

在视频会议中,多人同时发言时,我们需要同时播放来自于多个人的语音数据,而声卡播放的缓冲区只有一个,所以,需要将多路语音混合成一路,这就是混音算法要做的事情。

二.视频通话

1.基础模型

视频通话的概念模型与语音完全一致:

摄像头采集指的是从捕捉摄像头采集到的每一帧视频图像。在windows系统上,通常使用VFW技术或DirectShow技术来实现。采集视频的两个关键参数是帧频(fps)和分辨率。

一般而言,一个摄像头可以支持多种不同的采集分辨率和采集帧频,而不同的摄像头支持的分辨率的集合不一样。比如现在有很多高清摄像头可以支持30fps的1920*1080的图像采集。

编码用于压缩视频图像,同时也决定了图像的清晰度。视频编码常用的技术是H.263、H.264、MPEG-4、XVID等。

当对方接收到编码的视频帧后,会对其进行解码,以恢复成一帧图像,然后在UI的界面上绘制出来。

2.高级功能

相比于语音,视频的相关处理要简单一些。

(1)动态调整视频的清晰度

在Internet上,网络速度是实时动态变化的,所以,在视频会议中,为了优先保证语音的通话质量,需要实时调整视频的相关参数,其最主要的就是调整编码的清晰度,因为清晰度越高,对带宽要求越高,反之亦然。

比如,当检测网络繁忙时,就自动降低编码的清晰度,以降低对带宽的占用。

(2)自动丢弃视频帧

同样网络繁忙时,还有一个方法,就是发送方是主动丢弃要发送的视频帧,这样在接收方看来,就是帧频fps降低了。

三.电子白板

在视频会议中,电子白板的功能是很重要的。通常会议的主持人会在白板上画图进行讲解,然后其它的人能同步观看和操作电子白板的内容。

通常的电子白板都支持如下功能:线段、箭头线、双箭头线,水平肘型连接符、垂直肘型连接符,矩形、三角形、椭圆(圆),文本,自由曲线,插入图片,激光笔。

在实现上,电子白板主要是使用GDI+技术。

对于电子白板的同步,其原理是这样的:比如,当操作者在白板上绘制一个图像时,这个操作会被封装成一个Command对象(命令模式),然后,通过网络广播发送给会议中的其它人。当其他人接收到这个Command对象时,就将其转换成一个白板操作来执行,这样各个白板的内容就自动同步了。

四.会议房间管理

对于那些动态创建视频会议室,在用完之后就动态将其销毁的通常的视频会议应用场景来说,使用动态组来表示会议房间,是非常恰当的。

所谓“动态组”,就是在服务器内存中动态创建的组,不需要序列化存储到比如数据库或磁盘中,需要的时候就创建一个,然后加入多个成员进行组内沟通,当不再使用的时候,就直接从内存中销毁了。

基于Socket技术,我们可以在服务端实现DynamicGroupManager类来对动态组进行管理。

虽然,动态组仅仅存在于内存之中,但是,在项目需要时,我们仍然可以将其某些重要的信息持久化到数据库中存储。然后,在服务器重启时,可以从DB中加载重要的房间信息。

五.GGMeeting开源视频会议系统下载

请转到 GGTalk与GGMeeting 源码统一下载中心 进行下载。

广告:如果您有类似视频会议系统、在线培训系统、IM系统需要定制开发的,可以联系我们哦:)  QQ:2027224508

部署说明:

(1)将GGMeeting.Server部署到服务器上,并运行起来。

(2)修改Client配置文件GGMeeting.exe.config中的ServerIP的值。

(3)运行第一个Client实例,以随机帐号进入测试房间。

(4)在别的机器上继续运行Client,以随机帐号进入测试房间,大家即可在测试房间中进行视频会议。

注意:语音视频数据都是实时采集、实时播放的数据,所以测试时,服务器的带宽要求最好是独享带宽,共享带宽一般无法满足实时语音视频的要求。

________________________________________________________________________

欢迎和我探讨关于 GG 开源即时通讯系统和 GGMeeting开源视频会议系统 的一切,我的QQ:2027224508,多多交流!

大家有什么问题和建议,可以留言,也可以发送email到我邮箱:2027224508@qq.com。

如果你觉得还不错,请粉我,顺便再顶一下啊

源码下载中心 - C#开源即时通讯GGTalk - 博客园

mikel阅读(751)

来源: 源码下载中心 – C#开源即时通讯GGTalk – 博客园

GGTalk(简称GG)是可在广域网部署运行的QQ高仿版 ,2013.08.07发布V1.0版本,至今最新是8.0版本,关于GG更详细的介绍,可以查看 可在广域网部署运行的QQ高仿版 — GGTalk总览。

GGMeeting是可在广域网部署运行的视频会议系统Demo,2015.05.11发布V1.0版本,至今最新是3.2版本,关于GGMeeting更详细的介绍,可以查看 打造自己的视频会议系统 GGMeeting

ScreenMonitor 是屏幕监控系统,支持在PC和安卓手机上监控PC桌面、安卓屏幕。

1.GGTalk 即时通信系统源码

最新版本:V8.0  (详细介绍) 。 GGTalk 源码剖析系列:数据库设计、 服务端全局缓存虚拟数据库

最后更新:2023.04.14

源码下载:

(1)Windows 服务端、客户端 + Linux  服务端、客户端(支持国产OS):GGTalk_V8.0.zip(提取码: 1234)

(2)Android 端:GGTalk_V8.0_Android.rar (提取码: 1234)  备用下载地址:GGTalk_V8.0_Android.rar

(3)iOS 端:GGTalk_V8.0_iOS.zip (提取码: 1234)

(4)可直接部署运行:GGTalk_V8.0_Deploy.zip (提取码: 1234)

部署说明:

下面我们说明一下如何部署GGTalk_V8.0_Deploy.rar压缩包中的可直接运行的各个端。

(1)服务端默认配置是使用内存虚拟数据库,不需要真实数据库,这样方便测试。

(2)Windows 服务端:将GGTalk.Server文件夹拷贝到服务器上,运行 GGTalk.Server.exe。

(3)Linux 服务端:将GGTalk.Server.Linux文件夹拷贝到CentOS服务器上,进入该文件夹,打开终端,执行命令:dotnet GGTalk.Server.NetCore.dll。

注:GGTalk Windows服务端或Linux服务端只要启动一个就可以的,所有类型客户端都可以连到这个启动的服务端。

(4)Windows 客户端:修改GGTalk目录下的客户端配置文件GGTalk.exe.config中ServerIP配置项的值为服务器的IP,双击GGTalk.exe运行客户端,注册帐号登录试用。。

(5)Linux  客户端:将GGTalk.Linux文件夹拷贝到国产Linux系统(Ubuntu也可以)上,进入该文件夹,打开终端,执行命令:dotnet GGTalk.Linux.dll。

注:如果Linux电脑的CPU不是x86/x64架构的,则需要使用对应架构的libe_SQLite3.so、libSkiaSharp.so来替换运行目录下的同名文件。可联系我获取其它架构的so库。

(6)手机端:将对应的apk或ipa包在手机上安装,启动后,在登录界面设置服务器的IP地址,即可登录。

(7)内存虚拟数据库内置了测试帐号: 10000,10001,10002,10003,10004,一直到10009;密码都是 1。

         如果需要使用真实的物理数据库,则需按下列步骤进行:

(1)在SQLServer  2008+ 中新建数据库 GGTalk,然后在该库中执行 SQLServer.SQL 文件中的脚本以创建所需表。

(如果要使用MySQL数据库,则使用MySQL.sql脚本)

(2)打开服务端的配置文件GGTalk.Server.exe.config

(1)修改 UseVirtualDB 配置项的值为false。

(2)修改 DBType 为 SQLServer 或 MySQL。

(3)修改 DBIP 配置项的值为数据库的IP地址。

(4)修改 DBPwd 配置项的值为数据库管理员sa的密码。

后续其它的步骤就与虚拟数据库是一样的了。

 

2.GGMeeting 视频会议系统源码

最新版本:V3.2  (详细介绍

最后更新:2023.04.25(GGMeeting项目已更名为OVCS)

OVCS 服务端支持 Windows、Linux,客户端支持 Windows、Android、iOS、Linux、国产OS(银河麒麟、统信UOS)。

1. OVCS(服务端+PC端):开发环境为 VS 2022 。其中 PC 端源码包含 WPF 和 WinForm 版,二者选一即可。(详细介绍一文中的截图为WPF版的效果)

   VS 解决方案中的项目分别是:

(1)OVCS.Server : OVCS 的服务端。

(2)OVCS.ClientWpf : OVCS 的 Windows 客户端(基于WPF)。

(3)OVCS.Client.WinForm : OVCS 的 Windows 客户端(基于WinForm)。

(4)OVCS.ClientLinux : OVCS 的 Linux 客户端(基于 .Net Core 3.1)。

         注: Linux客户端内置的是x86/x64非托管so库,若需要其它架构的so,请联系我们免费获取。

2. OVCS Android端  :开发环境为 Android Studio 4.0+ 。

3. OVCS iOS端    :开发环境为 XCode 11+ 。

4. OVCS Web端    JavaScript 。 支持在Windows、Linux、国产OS上的浏览器中运行,需要安装OMCS Web插件:Win版本 、 Linux版本 。 

       备注:PC端增加了视频会议录制功能,可以将会议过程录制成mp4文件。(PC客户端启动后,点击主界面上方工具栏的“录制”按钮。)

 

3.ScreenMonitor 屏幕/桌面监控系统源码

最后更新:2023.01.13

项目源码下载: 服务端+PC端+安卓端

部署版本下载: 服务端+PC端+安卓端

支持:PC监控PC桌面,PC监控安卓屏幕,安卓监控PC桌面,安卓监控安卓屏幕。详细介绍请参见:如何实现监控手机屏幕?  

 

————————————————————————————————————————————

联系方式:

QQ:2027224508 

邮箱:2027224508@qq.com

 

如果大家有类似视频会议系统、在线培训系统、IM系统需要定制开发的,可以联系我们哦:)

 

虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱。有了一点甜头,目前和2、3个好朋友一起做做小项目也是不错的。

大家有什么问题和建议,都可以联系我,留言、加QQ、发邮件都可以。

欢迎大家与我探讨关于GG的一切!

GGTalk 开源即时通讯系统源码剖析之:数据库设计 - C#开源即时通讯GGTalk - 博客园

mikel阅读(763)

来源: GGTalk 开源即时通讯系统源码剖析之:数据库设计 – C#开源即时通讯GGTalk – 博客园

自从《开源即时通讯GGTalk 8.0发布,增加Linux客户端,支持在统信UOS、银河麒麟上运行!》一文在博客园发布后,有园友联系我QQ,说能不能整理个更系统更详细地介绍GGTalk源码的文章,现在博客中的介绍比较零散,对于初级程序员而言,面对GGTalk大量的源码,有点不知所措。想想也是如此,于是,我打算写一个系列的文章来完整地介绍GGTalk的方方面面,专题的名字就叫做《GGTalk源码剖析》吧。

一. 概述

这个《GGTalk源码剖析》系列的文章将基于最新的 GGTalk V8.0 进行。
GGTalk V8.0 服务端支持Windows、Linux,客户端支持 Windows、Android、iOS、Linux、以及银河麒麟、统信UOS等国产操作系统。
数据库支持SQLServer、MySQL、以及达梦数据库、人大金仓、南大通用等国产数据库。本篇文章以 MySQL 数据库为例来对GGTalk的数据库设计进行详细的介绍。
还没有GGTalk源码的朋友,可以到 GGTalk源码下载中心 下载。

二. 数据表的设计

最新版本的 GGTalk 数据库一共涉及到九张表,分别为:

  • GGUser:用户表,所有注册用户都保存在该表中。
  • GGGroup:群组表,所有创建的群都保存在该表中。
  • OfflineMessage:离线消息表,当目标用户不在线时,发送给他的消息存在该表中。
  • OfflineFileItem:离线文件表,当目标用户不在线时,发送给他的文件对应的记录存在该表中。
  • GroupBan:群禁言表,当群中的用户被禁言时,对应的记录将存在该表中。
  • ChatMessageRecord:聊天记录表,一对一的聊天记录、群聊天记录都存在该表中。
  • AddFriendRequest:加好友请求表,所有添加好友的请求消息都存在该表中。
  • AddGroupRequest:入群请求表,所有申请入群的请求消息都存在该表中。
  • GGConfiguration:配置表,用于预留存储与GGTalk相关的配置信息。

下面将分别对每一张表的字段进行说明。

1. GGUser(用户表)

所有注册用户都保存在该表中。

字段名称 字段类型 字段说明
UserID varchar(50) 用户ID,主键
PasswordMD5 varchar(100) 经过加密处理的用户密码
Phone varchar(20) 用户手机号码
Name varchar(50) 用户昵称
Friends varchar(4000) 用户好友列表,以 , 分隔
CommentNames varchar(4000) 用户好友备注列表,以 ; 分隔
Signature varchar(100) 用户个性签名
HeadImageIndex int 系统默认头像的索引
HeadImageData mediumblob 用户上传头像的二进制数据
Groups varchar(1000) 用户所在的群组列表,以 , 分隔
UserState int 用户状态:0正常,1冻结,2禁言,3停用
MobileOfflineTime datetime 移动端离线的时间节点
PcOfflineTime datetime PC端离线的时间节点
CreateTime datetime 用户注册的时间节点
Version int 用户版本

补充说明:

  • UserId同时也是 用户账号 和 用户名 。
  • Friends 字段中包含分组信息,每个分组之间以;进行分割。例如:朋友:friend1,friend2;同学:schoolmate1,schoolmate2;
  • CommentNames 字段存储用户好友备注列表数据,以用户ID + : + 备注为一个好友的备注信息,多个备注信息之间以;分割。例如:10000:张三;10001:李四
  • HeadImageIndex 字段存储系统默认头像索引数据,当用户上传头像后,HeadImageData 字段会被赋值,且HeadImageIndex 字段值被设置为-1
  • Version 字段保存用户的版本,初始值为0,每当用户的信息更新,本字段值+1。

2. GGGroup(群组表)

所有创建的群都保存在该表中。

字段名称 字段类型 字段说明
GroupID varchar(20) 群组ID,主键
Name varchar(20) 群组名称
CreatorID varchar(20) 群组创建者的用户ID
Announce varchar(200) 群公告
Members varchar(4000) 群组成员的用户ID列表,以 , 分隔
IsPrivate tinyint 是否允许群组成员之间私聊:0不允许,1允许
CreateTime datetime 创建群组的时间节点
Version int 群组版本

补充说明:

  • Version 字段保存群组在版本,初始值为0,每当群组在信息更新,本字段值+1。
  • Members 字段存储群组成员的用户ID列表数据,注意这个字段和 GGUser表 中的Groups 字段间存在联动关系。例如:当一个用户退出一个群时,这个用户的Groups中会少一个群组ID,同时这个群组的Members中会少一个用户ID。

3. OfflineMessage(离线消息记录表)

此表用于存储离线消息数据。

字段名称 字段类型 字段说明
AutoID int 自增ID,主键
SourceUserID varchar(50) 发送离线消息的用户ID
DestUserID varchar(50) 接收离线消息的用户ID
SourceType int 发送者的设备类型:1DotNET,2Android,4IOS,9Linux
GroupID varchar(50) 该字段用于群离线消息
InformationType int 信息的类型
Information longblob 信息内容
Tag varchar(100) 附带信息
TimeTransfer datetime 服务器接收到要转发离线消息的时间

补充说明:

  • 当离线用户上线时,服务器会把这条消息转发给该用户,同时这条消息会从表中删除。
  • TimeTransfer 字段存储离线文件的路径,默认在服务端程序根目录\bin\Debug\OfflineFiles\接受者的用户ID作为文件名目录下。

4. OfflineFileItem(离线文件表)

当目标用户不在线时,发送给他的文件对应的记录存在该表中。

字段名称 字段类型 字段说明
AutoID int 自增ID,主键
FileName varchar(100) 文件名
FileLength int 文件长度
SenderID varchar(50) 发送者的用户ID
SenderType int 发送者的设备类型:1DotNET,2Android,4IOS,9Linux
AccepterType int 接受者的设备类型:1DotNET,2Android,4IOS,9Linux
AccepterID varchar(50) 接收者的用户ID
RelayFilePath varchar(300) 转发文件的路径

补充说明:
离线文件默认存在服务端的运行目录下的OfflineFiles文件夹下,RelayFilePath 指明了具体的相对路径。
当离线用户上线时,服务器会把这个文件转发给该用户,同时这个文件会从表中删除。

5. GroupBan(群禁言表)

当群中的用户被禁言时,对应的记录将存在该表中。

字段名称 字段类型 字段说明
AutoID int 自增ID,主键
GroupID varchar(20) 群组ID
OperatorID varchar(20) 禁言者的用户ID
UserID varchar(20) 被禁言者的用户ID
Comment2 varchar(50) 本次禁言的备注
EnableTime datetime 本次禁言的截至时间
CreateTime datetime 本次禁言的开始时间

6. ChatMessageRecord(聊天消息记录表)

此表用于存储聊天消息数据。

字段名称 字段类型 字段说明
AutoID bigint 自增ID,主键
SpeakerID varchar(20) 发言者的用户ID
AudienceID varchar(20) 倾听者的用户ID或群组ID
IsGroupChat bit(1) 是否是群组聊天:0不是,1是
Content longblob 聊天内容
OccureTime datetime 消息发送的时间节点

补充说明:
该表除了主键之外,还建有两个联合索引:
KEY IX_ChatMessageRecord (SpeakerID,AudienceID,OccureTime) USING BTREE
KEY IX_ChatMessageRecord_1 (AudienceID,OccureTime) USING BTREE
这两个联合索引,与客户端两种查询聊天记录的方式一一对应。
如此,服务端可以快速地从数据库中加载满足条件的聊天记录返回给客户端。

7. AddFriendRequest(加好友请求表)

所有添加好友的请求消息都存在该表中。

字段名称 字段类型 字段说明
AutoID int 自增ID,主键
RequesterID varchar(50) 申请者的用户ID
AccepterID varchar(50) 接收者的用户ID
RequesterCatalogName varchar(20) 申请者的分组名称
AccepterCatalogName varchar(20) 接受者的分组名称
Comment2 varchar(500) 申请时的备注信息
State int 本次申请的状态:0请求中,1同意,2拒绝
Notified bit(1) 申请是否通知对方:0不通知,1通知
CreateTime datetime 申请添加好友的时间节点

8. AddGroupRequest(入群请求表)

所有申请入群的请求消息都存在该表中。

字段名称 字段类型 字段说明
AutoID int 自增ID,主键
RequesterID varchar(20) 申请者的用户ID
GroupID varchar(20) 群组ID
AccepterID varchar(20) 接收者的用户ID
Comment2 varchar(500) 申请时的备注信息
State int 本次申请的状态:0请求中,1同意,2拒绝
Notified bit(1) 申请是否通知对方:0不通知,1通知
CreateTime datetime 申请加入群组的时间节点

9. GGConfiguration(系统配置表)

用于预留存储与GGTalk相关的配置信息。

字段名称 字段类型 字段说明
GGKey varchar(20) 配置的键名
GGValue varchar(1000) 配置的键值

三. 小结

GGTalk 的数据库只有9张表,而且都比较简单。
每个表都有唯一的主键。
就实际使用来看,ChatMessageRecord 聊天记录表的数据量将是最大的,所以,ChatMessageRecord 表必须建联合索引,以支持快速查询。
在我们接到的定制项目中,对于那些同时在线用户量较大的(比如同时在线大于1万人)使用场景,ChatMessageRecord 我们会采取按月分表的策略来应对,在这种情况下,GGTalk 的服务端代码需要做相应的调整。有机会用到这种策略的朋友,可以和我们交流更多关于该策略的实现方案。
作为《GGTalk源码剖析》的第一篇,差不多就这样了。在接下来的一篇我们将介绍GGTalk服务端全局缓存。
敬请期待:《GGTalk 开源即时通讯系统源码剖析之:服务端全局缓存

Vue + Element ui 实现动态表单,包括新增行/删除行/动态表单验证/提交功能 - 朱季谦 - 博客园

mikel阅读(494)

来源: Vue + Element ui 实现动态表单,包括新增行/删除行/动态表单验证/提交功能 – 朱季谦 – 博客园

最近通过Vue + Element ui实现了动态表单功能,该功能还包括了动态表单新增行、删除行、动态表单验证、动态表单提交功能,趁热打铁,将开发心得记录下来,方便以后再遇到类似功能时,直接拿来应用。

简化的页面效果图如下:
image

最开始,我是用了纯粹的表格形式,后来发现,这种形式在提交的时候,不好对每个输入框做校验,若是表单形式话,就可以直接通过rule设置每个输入框的验证,因此,我就在表格里面嵌套了表单。注意一点是,el-form-item里的 :prop=”scope.$index + ‘.name'”需要对应el-input的 v-model=”studentData[scope.$index].name”,两者都是同一个字段值。

<template>
  <div >
        <div>
          <div>
            <el-button  size="small"  @click="addRow">新增</el-button>
          </div>
          <!--设置的表单-->
          <el-form :model="studentData" ref="data" label-width="auto">
          <el-table
            border
            :header-cell-style="{ 'text-align': 'center' }"
            :cell-style="{ 'text-align': 'center' }"
            :data="studentData"
            ref="table"
            style="width: 100%"
          >

            <el-table-column align="center"   label="姓名">
              <template slot-scope="scope">
              <!--表格里面嵌套表单-->
                <el-form-item
                  :prop="scope.$index + '.name'"
                  :rules="{ required: true, message: '姓名不能为空', trigger: 'blur' }"
                >
                <el-input
                  v-model="studentData[scope.$index].name"
                  autocomplete="off"
                  size="small"
                  placeholder="姓名"
                ></el-input>
                </el-form-item>
              </template>
            </el-table-column>

            <el-table-column align="center"  label="年龄">
              <template slot-scope="scope">
                  <el-form-item
                    :prop="scope.$index + '.age'"
                    :rules="{ required: true, message: '年龄不能为空', trigger: 'blur' }"
                  >
                <el-input
                  v-model="studentData[scope.$index].age"
                  autocomplete="off"
                  size="small"
                  type='number'
                  placeholder="收款方开户行号"
                ></el-input>
                  </el-form-item>
              </template>
            </el-table-column>

            <el-table-column align="center"  label="性别">
              <template slot-scope="scope">
                <el-form-item
                  :prop="scope.$index + '.sex'"
                  :rules="{ required: true, message: '性别不能为空', trigger: 'blur' }"
                >
                <el-input
                  v-model="studentData[scope.$index].sex"
                  autocomplete="off"
                  size="small"
                  placeholder="性别"
                ></el-input>
                </el-form-item>
              </template>
            </el-table-column>

            <el-table-column fixed="right" label="操作" width="100">
              <template slot-scope="scope">
                <el-button
                  @click="handleDeleteRow(studentData[scope.$index])"
                  type="text"
                  size="small"
                >删除</el-button
                >
              </template>
            </el-table-column>
            
          </el-table>
          </el-form>
        </div>
        
        <div slot="footer" class="dialog-footer" style="margin-bottom: 10px">
          <el-button size="mini"  @click="submit">提交</el-button>
          <el-button size="mini" @click="resetForm()">重置</el-button>
        </div>
  </div>
</template>

定义一个存储动态表格数据的数组变量

export default {
  data() {
    return {
      studentData:[],
    };
  },
  ......
}

在methods方法里增加相关方法,分别是新增行、删除行、提交——

methods:{

  /**
   * 新增行
   */
  addRow() {
    let index = this.studentData.length ;
    this.studentData.push({
      key: index,
      name:'',
      age:'',
      sex:'',
    });
  },

  /**
   * 删除行
   * @param row
   */
  handleDeleteRow(row){
    let datas = this.studentData;
    for (var i = 0; i < datas.length; i++){
      if (datas[i].key == row.key){
        datas.splice(i,1);
      }
    }
  },

  /**
   * 提交
   */
  submit() {
    this.$refs["data"].validate(valid => {
      //valid为true,表示表单都已经验证通过,若为false,说明存在表单验证失败
        if (valid) {
          save(this.studentData).then(response => {
            this.$message({
              message: '提交成功',
              type: 'success'
            });
          });
        }
    });
  },

  /**
   * 重置
   */
  resetForm() {
    let datas = this.studentData;
    for (var i = 0; i < datas.length; i++){
      datas[i].name='';
      datas[i].age='';
      datas[i].sex='';
    }
  },
}

设置表单验证规则,可统一在rules设置,也可以在每一输入框单独设置,我这里是单独在每一个输入框里设置,即:rules=”{ required: true, message: ‘姓名不能为空’, trigger: ‘blur’ }”就可以了,当然,还可以做一些更复杂的自定义规则。

<el-table-column align="center"   label="姓名">
          <template slot-scope="scope">
          <!--表格里面嵌套表单-->
            <el-form-item
              :prop="scope.$index + '.name'"
              :rules="{ required: true, message: '姓名不能为空', trigger: 'blur' }"
            >
            <el-input
              v-model="studentData[scope.$index].name"
              autocomplete="off"
              size="small"
              placeholder="姓名"
            ></el-input>
            </el-form-item>
          </template>
        </el-table-column>

Github 6月开源项目Top30精选🔥🔥🔥 - 知乎

mikel阅读(1235)

来源: Github 6月开源项目Top30精选🔥🔥🔥 – 知乎

6月项目精选: 主要包含 诗词库/AI模型/ChatGPT/人工智能教育/音频处理等热点项目

1.中华古诗词数据库:chinese-poetry 43.2k⭐

  • 项目地址github.com/chinese-poet
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐3,548 stars this month
  • 开源时间:2016-09-02
  • 最后更新:2023-05-29
  • 主要语言JavaScript
  • 项目分类:[资源库] [学习社区]
  • 项目标签:[中国古诗词库]
  • 推荐理由:这个项目收集了最全的中华古诗词数据库,包括唐宋两朝近一万四千位古诗人的作品,近5.5万首唐诗和26万首宋诗。此外,还包括了两宋时期1564位词人的21050首词。
  • Star历史曲线:[官网]

2.私人GPT互动:privateGPT 31.3k⭐

  • 项目地址github.com/imartinez/pr
  • Github趋势榜
    • 入选2023-06-21月榜,月增⭐12,237 stars this month
  • 开源时间:2023-05-02
  • 最后更新:2023-06-21
  • 主要语言Python
  • 项目分类:[ChatGPT] [AI]
  • 项目标签:[大语言模型] [GPT模型] [自然语言处理] [智能ChatGPT]
  • 推荐理由:这个项目提供了一个私人的GPT(生成式预训练模型)解决方案,可以在考虑数据安全、隐私保护或断网情况下与GPT和文档进行交互。它为用户提供了一个可靠且安全的方式来使用GPT模型,无论是用于个人用途还是商业应用。
  • Star历史曲线:[项目体验]

3. AI模型工具包:fairseq 26.6k⭐

  • 项目地址github.com/facebookrese
  • Github趋势榜
    • 入选2023-06-21月榜,月增⭐4,550 stars this month
  • 开源时间:2017-08-30
  • 最后更新:2023-06-24
  • 主要语言Python
  • 项目分类:[AI]
  • 项目标签:[神经网络] [AI生成] [机器学习]
  • 推荐理由:这个用Python编写的工具包是Facebook AI研究团队开发的序列到序列模型的工具包。它提供了一套丰富而强大的工具和模型,适用于机器翻译、文本生成等自然语言处理任务。
  • Star历史曲线

4.任天堂Switch模拟器:Ryujinx 23.6k⭐

  • 项目地址github.com/Ryujinx/Ryuj
  • Github趋势榜
    • 入选2023-06-05月榜,月增⭐3,831 stars this month
  • 开源时间:2018-02-05
  • 最后更新:2023-06-25
  • 主要语言C#
  • 项目分类:[游戏]
  • 项目标签:[模拟器]
  • 推荐理由:Ryujinx是用C#编写的任天堂Switch游戏机模拟器。虽然项目目前仍处于实验阶段,稳定性尚有待提高,并且需要至少8GB内存的机器配置,但对于那些具有探险精神的游戏爱好者来说,这是一个值得尝试的模拟器项目。
  • Star历史曲线:[官网] [使用文档]

5.精美UI组件:ui 22.0k⭐

  • 项目地址github.com/shadcn/ui
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐5,321 stars this month
  • 开源时间:2023-01-04
  • 最后更新:2023-06-25
  • 主要语言TypeScript
  • 项目分类:[设计] [前端]
  • 项目标签:[前端设计] [组件库]
  • 推荐理由:这个项目使用Radix UI和Tailwind CSS构建了一套设计精美的组件。它为开发者提供了一套现代化且易于使用的UI组件,可以轻松地构建出视觉上吸引人的网页和应用程序。
  • Star历史曲线:[官网] [使用文档]

6.跨平台文件管理工具:spacedrive 19.4k⭐

  • 项目地址github.com/spacedriveap
  • Github趋势榜
    • 入选2023-06-12周榜,周增⭐468 stars this week
    • 入选2023-06-24月榜,月增⭐1,877 stars this month
  • 开源时间:2021-09-27
  • 最后更新:2023-06-25
  • 主要语言Rust
  • 项目分类:[工具]
  • 项目标签:[文件管理器] [管理工具]
  • 推荐理由:Spacedrive是一个用Rust编写的跨平台文件管理工具。它基于虚拟分布式文件系统(VDFS)的Rust实现,可以将不同操作系统的设备连接起来,实现统一的文件管理。虽然项目仍在开发阶段,需要用户自行编译客户端,但它提供了一种方便且安全的方式来管理和共享文件。
  • Star历史曲线:[官网] [使用文档]

7.ChatGPT插件:chatgpt-retrieval-plugin 18.4k⭐

  • 项目地址github.com/openai/chatg
  • Github趋势榜
    • 入选2023-06-14月榜,月增⭐1,728 stars this month
  • 开源时间:2023-03-23
  • 最后更新:2023-06-24
  • 主要语言Python
  • 项目分类:[ChatGPT]
  • 项目标签:[ChatGPT插件]
  • 推荐理由:一个方便的工具,可以帮助用户轻松地找到个人或工作文件,通过询问自然语言的问题。它结合了ChatGPT的强大的对话生成能力和文档检索功能,为用户提供高效的信息查询和搜索工具。

8.Rust教程:comprehensive-rust 18.0k⭐

  • 项目地址github.com/google/compr
  • Github趋势榜
    • 入选2023-06-23月榜,月增⭐5,905 stars this month
  • 开源时间:2022-12-21
  • 最后更新:2023-06-25
  • 主要语言Rust
  • 项目分类:[编程语言] [面试求职]
  • 项目标签:[编程学习]
  • 推荐理由:这是Google开放的一个全面的Rust技术教程,涵盖了Rust的基本语法到高级主题,包括泛型、错误处理、Android开发等。通过这个教程,您将全面学习Rust的基础知识,掌握Rust应用程序的编写和常用开发技巧。
  • Star历史曲线:[官网] [使用文档]

9.潘多拉ChatGPT:pandora 16.2k⭐

  • 项目地址github.com/pengzhile/pa
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐8,649 stars this month
  • 开源时间:2023-02-17
  • 最后更新:2023-06-24
  • 主要语言Python
  • 项目分类:[ChatGPT] [AI]
  • 项目标签:[聊天机器人] [GPT4] [AI聊天]
  • 推荐理由:潘多拉是一个更多功能的ChatGPT,不仅限于命令行界面。它提供了更多的交互方式和功能,可以在不同的环境中进行聊天和对话。无论是在命令行还是其他平台上,潘多拉都为用户提供了更灵活、多样化的ChatGPT体验。
  • Star历史曲线:[官网] [项目体验] [使用文档]

10.源深度学习框架:tinygrad 15.2k⭐

  • 项目地址github.com/geohot/tinyg
  • Github趋势榜
    • 入选2023-06-22日榜,日增⭐51 stars today
    • 入选2023-06-23日榜,日增⭐790 stars today
    • 入选2023-06-24日榜,日增⭐78 stars today
    • 入选2023-06-24月榜,月增⭐3,386 stars this month
  • 开源时间:2020-10-19
  • 最后更新:2023-06-25
  • 主要语言Python
  • 项目分类:[AI]
  • 项目标签:[深度学习] [大语言模型]
  • 推荐理由:这是一个小型的开源深度学习框架。尽管代码行数不足1k,但它提供了足够简单的接口,支持深度学习模型的推理和训练。Tinygrad的设计注重简洁和易用性,使得开发者可以快速上手并构建自己的深度学习模型。
  • Star历史曲线:[项目体验] [使用文档]

11.AI人脸交换:DeepFaceLive 15.0k⭐

12.可视化爬虫软件:EasySpider 13.1k⭐

动图封面

  • 项目地址github.com/NaiboWang/Ea
  • Github趋势榜
    • 入选2023-06-21日榜,日增⭐526 stars today
    • 入选2023-06-22日榜,日增⭐200 stars today
    • 入选2023-06-23日榜,日增⭐203 stars today
    • 入选2023-06-24月榜,月增⭐7,599 stars this month
  • 开源时间:2020-07-18
  • 最后更新:2023-06-24
  • 主要语言JavaScript
  • 项目分类:[工具]
  • 项目标签:[可视化爬虫]
  • 推荐理由:一个可视化爬虫软件,用户可以通过图形化界面进行爬虫任务的设计和执行,无需编写代码。它提供了简单易用的工具,帮助用户快速爬取所需数据。
  • Star历史曲线:[官网] [使用文档] [视频介绍]

13.微软人工智能教育学习社区:ai-edu 12.2k⭐

  • 项目地址github.com/microsoft/ai
  • Github趋势榜
    • 入选2023-06-21周榜,周增⭐1,779 stars this week
    • 入选2023-06-24月榜,月增⭐7,174 stars this month
  • 开源时间:2018-11-16
  • 最后更新:2023-06-08
  • 主要语言HTML
  • 项目分类:[面试求职] [学习社区]
  • 项目标签:[AI教育] [机器学习] [系统学习]
  • 推荐理由:这是微软人工智能教育与学习共建社区的开源项目。它由微软亚洲研究院的人工智能教育团队创建,提供了基础教程、实践案例和实践项目三大模块。AI-Edu通过系统化的理论教程和丰富多样的实践案例,帮助学习者学习和掌握人工智能知识,并培养在实际项目中的开发能力。
  • Star历史曲线:[官网] [使用文档]

14.Youtube镜像版:invidious 11.7k⭐

  • 项目地址github.com/iv-org/invid
  • Github趋势榜
    • 入选2023-06-22周榜,周增⭐409 stars this week
    • 入选2023-06-24月榜,月增⭐1,744 stars this month
  • 开源时间:2018-02-07
  • 最后更新:2023-06-24
  • 主要语言Crystal
  • 项目分类:[工具]
  • 项目标签:[镜像站]
  • 推荐理由:YouTube的开源前端替代产品。它提供了一个独立的前端界面,用户可以在不访问YouTube官方网站的情况下浏览和观看YouTube的视频内容。Invidious的开源性质使得用户可以自由定制和控制他们对YouTube内容的访问和体验。

15.矢量数据库:qdrant 11.2k⭐

  • 项目地址github.com/qdrant/qdran
  • Github趋势榜
    • 入选2023-06-05月榜,月增⭐4,275 stars this month
  • 开源时间:2020-05-31
  • 最后更新:2023-06-25
  • 主要语言Rust
  • 项目分类:[中间件] [AI]
  • 项目标签:[AI应用] [矢量数据库]
  • 推荐理由:一个用于下一代AI应用程序的矢量数据库。它提供了高效的矢量索引和检索功能,支持快速的相似度搜索和相关性计算,适用于各种AI应用领域。

16.项目管理工具:plane 10.7k⭐

  • 项目地址github.com/makeplane/pl
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐8,539 stars this month
  • 开源时间:2022-11-19
  • 最后更新:2023-06-25
  • 主要语言TypeScript
  • 项目分类:[设计]
  • 项目标签:[任务跟踪] [产品设计] [瀑布模型]
  • 推荐理由:Plane是一个简单、可扩展、开源的项目和产品管理工具。它提供了一个基本的任务跟踪功能,使用户可以创建、分配和跟踪任务的进展。同时,Plane还支持各种项目管理框架,如敏捷开发、瀑布模型等,用户可以根据自己的需求选择适合的框架来管理项目。这个工具具有易用性和灵活性,可以帮助团队更好地组织和协调项目工作。

17.可视化UI定制LLM:Flowise 9.2k⭐

  • 项目地址github.com/FlowiseAI/Fl
  • Github趋势榜
    • 入选2023-06-16周榜,周增⭐1,036 stars this week
    • 入选2023-06-24月榜,月增⭐3,917 stars this month
  • 开源时间:2023-03-31
  • 最后更新:2023-06-24
  • 主要语言JavaScript
  • 项目分类:[ChatGPT] [AI]
  • 项目标签:[LangChain] [机器学习]
  • 推荐理由:一个使用LangchainJS拖放UI构建定制化低代码机器学习(LLM)流程的工具。它简化了机器学习流程的开发和部署,让用户能够通过拖放操作设计自己的机器学习工作流程,提高开发效率。

18.链接管理工具:dub 9.1k⭐

  • 项目地址github.com/steven-tey/d
  • Github趋势榜
    • 入选2023-06-19月榜,月增⭐2,228 stars this month
  • 开源时间:2022-08-28
  • 最后更新:2023-06-24
  • 主要语言TypeScript
  • 项目分类:[工具]
  • 项目标签:[管理工具]
  • 推荐理由:一个开源链接管理工具,用于现代营销团队创建、共享和跟踪短链接。它集成了Vercel边缘函数、Upstash Redis和PlanetScale MySQL等技术,提供了一个功能丰富的平台,帮助营销团队轻松创建和管理短链接,并跟踪链接的性能和分析数据。
  • Star历史曲线:[官网]

19.AI数据库:Chat2DB 8.1k⭐

  • 项目地址github.com/alibaba/Chat
  • Github趋势榜
    • 入选2023-06-20日榜,日增⭐1,694 stars today
    • 入选2023-06-21日榜,日增⭐356 stars today
    • 入选2023-06-22日榜,日增⭐357 stars today
    • 入选2023-06-24周榜,周增⭐4,386 stars this week
    • 入选2023-06-24月榜,月增⭐6,591 stars this month
  • 开源时间:2022-11-18
  • 最后更新:2023-06-24
  • 主要语言Java
  • 项目分类:[ChatGPT] [AI]
  • 项目标签:[AI Chat SQL] [智能ChatGPT]
  • 推荐理由:Chat2DB集成了AIGC的能力,能够将自然语言转换为SQL,也可以将SQL转换为自然语言,可以给出研发人员SQL的优化建议,极大的提升人员的效率,是AI时代数据库研发人员的利器,未来即使不懂SQL的运营业务也可以使用快速查询业务数据、生成报表能力。

20.本地OpenAI:LocalAI 7.5k⭐

  • 项目地址github.com/go-skynet/Lo
  • Github趋势榜
    • 入选2023-06-16月榜,月增⭐4,011 stars this month
  • 开源时间:2023-03-19
  • 最后更新:2023-06-25
  • 主要语言Go
  • 项目分类:[工具] [AI]
  • 项目标签:[深度学习] [大语言模型] [ 人工智能]
  • 推荐理由:这个用Go编写的项目是一个自托管、社区驱动的简单本地OpenAI兼容API。它可以在使用消费级硬件的CPU上作为OpenAI的替代品运行,支持ggml兼容模型,例如:LLaMA、alpaca、gpt4all、vicuna、koala、gpt4all-j、cerebras.

21.多模型聊天工具:ChatALL 7.2k⭐

  • 项目地址github.com/sunner/ChatA
  • Github趋势榜
    • 入选2023-06-19日榜,日增⭐56 stars today
    • 入选2023-06-20日榜,日增⭐77 stars today
    • 入选2023-06-21日榜,日增⭐72 stars today
    • 入选2023-06-17月榜,月增⭐5,836 stars this month
  • 开源时间:2023-04-08
  • 最后更新:2023-06-24
  • 主要语言JavaScript
  • 项目分类:[ChatGPT] [AI]
  • 项目标签:[聊天机器人] [大语言模型] [GPT模型] [智能ChatGPT]
  • 推荐理由:ChatALL是一个聊天工具,可以同时与多个聊天模型进行交互,包括ChatGPT、Bing chat、bard、羊驼、Vincuna、Claude、ChatGLM、MOSS、科大讯飞Spark和ERNIE等。它的目标是通过与多个聊天模型对话,从中发现最佳答案,提供更全面和准确的回答。
  • Star历史曲线

22.量化LLM微调工具:qlora 6.1k⭐

23.免费的GPT-4 API:gpt4free-ts 5.5k⭐

  • 项目地址github.com/xiangsx/gpt4
  • Github趋势榜
    • 入选2023-06-21周榜,周增⭐902 stars this week
    • 入选2023-06-24月榜,月增⭐4,959 stars this month
  • 开源时间:2023-05-04
  • 最后更新:2023-06-23
  • 主要语言TypeScript
  • 项目分类:[ChatGPT]
  • 项目标签:[GPT4] [逆向工程]
  • 推荐理由:gpt4free-ts是提供免费OpenAI GPT-4 API的项目,这是xtekky/gpt4free项目的TypeScript版本。它为开发者提供了使用GPT-4的API接口,使得无需支付额外费用就能够访问强大的自然语言处理能力。
  • Star历史曲线

24.实时变声器:voice-changer 5.2k⭐

  • 项目地址github.com/w-okada/voic
  • Github趋势榜
    • 入选2023-06-13月榜,月增⭐3,368 stars this month
  • 开源时间:2022-08-22
  • 最后更新:2023-06-24
  • 主要语言TypeScript
  • 项目分类:[AI]
  • 项目标签:[AI变声] [语音识别]
  • 推荐理由:一个实时的变声器工具,它可以改变声音的音调和效果。用户可以通过这个工具实时对音频进行变声处理,创造出各种有趣和创意的音效效果。
  • Star历史曲线:[视频介绍]

25.实时转录工具:ecoute 4.5k⭐

  • 项目地址github.com/SevaSk/ecout
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐3,963 stars this month
  • 开源时间:2023-05-08
  • 最后更新:2023-06-21
  • 主要语言Python
  • 项目分类:[视频图像] [ChatGPT] [AI]
  • 项目标签:[AI生成] [语音交互] [对话转录] [GPT模型]
  • 推荐理由:Ecoute是一个实时转录工具,在文本框中为用户的麦克风输入(You)和用户的扬声器输出(Speaker)提供实时转录。它还使用OpenAI的GPT-3.5为用户生成一个基于对话现场转录的建议响应。
  • Star历史曲线

26.后台模版:soybean-admin 4.4k⭐

  • 项目地址github.com/honghuangdc/
  • Github趋势榜
    • 入选2023-06-14月榜,月增⭐775 stars this month
  • 开源时间:2021-09-09
  • 最后更新:2023-06-20
  • 主要语言TypeScript
  • 项目分类:[后端]
  • 项目标签:[NaiveUI模版] [Vue3模版]
  • 推荐理由:这是一个基于Vue3、Vite3、TypeScript、NaiveUI和UnoCSS的清新优雅的中后台模板。它提供了一个现代化的用户界面,适用于中后台管理系统的开发。这个模板使用了最新的前端技术,具有响应式设计和丰富的组件库,可以帮助开发人员快速搭建出漂亮、功能丰富的中后台应用。
  • Star历史曲线:[官网] [项目体验]

27.DragGAN视觉交互:DragGAN 4.2k⭐

  • 项目地址github.com/Zeqiang-Lai/
  • Github趋势榜
    • 入选2023-06-24月榜,月增⭐3,830 stars this month
  • 开源时间:2023-05-20
  • 最后更新:2023-06-25
  • 主要语言Python
  • 项目分类:[AI]
  • 项目标签:[视觉库] [图像生成]
  • 推荐理由:DragGAN是一个全功能实现的模型,提供在线演示和本地部署试用,并已开源其代码和模型。它支持在Windows、macOS和Linux上运行,可用于图像生成和转换任务。
  • Star历史曲线

28.应用程序开发模版 :next-enterprise 3.5k⭐

29.自动量化机器人:Qbot 3.0k⭐

  • 项目地址github.com/UFund-Me/Qbo
  • Github趋势榜
    • 入选2023-06-22月榜,月增⭐2,278 stars this month
  • 开源时间:2022-11-23
  • 最后更新:2023-06-12
  • 主要语言Jupyter Notebook
  • 项目分类:[AI]
  • 项目标签:[强化学习] [深度学习] [量化交易]
  • 推荐理由:Qbot是一个面向AI的量化投资平台,旨在利用AI技术实现量化投资的潜力。该平台提供了一系列工具和功能,使投资者能够运用AI技术进行数据分析、模型构建和交易执行,为量化投资领域带来更多的智能和效益。
  • Star历史曲线:[官网] [使用文档] [视频介绍]

更多Github开源项目

以上就是本期的推荐所有项目,如果你喜欢本期的内容,欢迎收藏和关注OpenGithub社区,我们会定期推送优质的开源项目。

Github历史期刊:

听说后端的你在学 React

mikel阅读(491)

来源: 听说后端的你在学 React

一、React 是什么

在 React 之前前端有三个里程碑意义的 library/framework
  • JQuery 解决了浏览器兼容和 DOM 元素快捷操作问题,其链式操作 API 也对后续前端框架产生了深刻影响;
  • Knockout 提出了前端代码 MVVM 分层理念,数据通过模板映射为 UI 视图,大幅度减少了 DOM 操作;
  • AngularJS 在 MVVM 基础上引入了双向绑定,数据变化自动反映到 UI,视图上的操作也反向自动更新数据;其通过指令拓展 HTML 的风格提升了模板引擎的灵活性,可惜作者引入了大量借鉴服务器编程的概念,让 AugularJS 学习成本直线上升,性能也略有不足;
React 是一个声明式、高效、灵活的用于构建用户界面的 JavaScript library,React 核心理念在于将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作 “Component”。React 不是 MVC 框架,更像是其中 V,仅仅负责用户交互视图的渲染。
React 带来了三个颠覆性理念,在接下来的章节中将一一介绍:
  • JSX,使用 JavaScript 表达 UI + 交互,充分利用 JavaScript 的灵活性;
  • fx(props) = UI,数据驱动 UI,单向数据流、函数风格的页面组件;
  • Virtual DOM,服务器、客户端使用同一套代码渲染——同构,解决前端应用 SEO 问题;
二、快速初始化 React 项目

使用 Create React App [1]可以快速初始化一个 React Web 项目。
$ npx create-react-app learn-react --template typescript$ cd learn-react$ npm start

执行 npm start后浏览器会在 http://localhost:3000 打开项目首页。

三、调试 React 应用

React 提供了 React Developer Tools[2],集成到了 Chrome Dev Tools,借此可以查看 React 组件树及其对应 Props、State。
app.tsx
import React, { useState } from 'react';
function Button(props: { count: number }): JSX.Element {  const [count, setCount] = useState(props.count);  return (    <button      onClick={() => {        setCount((c) => c + 1);      }}      >      {count}    </button>  );}
function App() {  const [count, setCount] = useState(0);
  return (    <div className="App">      <Button count={5} />    </div>  );}
export default App;

index.tsx

import React from 'react';import * as ReactDOMClient from 'react-dom/client';
import App from './app';
const rootElement = document.querySelector('body') as Element;const root = ReactDOMClient.createRoot(rootElement);
root.render(<App />);

打开 Chrome Dev Tools 可以看到多了一个 Components选项卡

图片

四、Todo project

接下来边学习边做一个 Todo 项目体验一下 React。

图片

五、使用 JSX 做更好的关注点分离

在开始编写 React 程序之前需要了解一下 JSX。JSX 是 React 对 JavaScript 的语法拓展,用来在 JavaScript 文件内通过类HTML标签(HTML-like markup)表达页面的视图与交互逻辑。
<div className="container">  <CustomComponent     onClick={() => {alert('Hello')}}  >    Hello {props.name}!  </CustomComponent></div>
Web 页面由 HTML 内容、CSS 样式、JavaScript 交互构成,长期以来 Web 开发者将三者放在独立的文件中做分离,这实际上是按照技术实现的分离。
图片 图片

传统页面内容主要由 HTML 定义,JavaScript 逻辑是点缀,随着现代网页交互性增强,页面内容很大程度是由 JavaScript 逻辑动态生成,同时渲染逻辑本质上与其他 UI 逻辑内在耦合,比如在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

因此 React 使用 JSX 把渲染逻辑和 HTML 标签集成到一起。

图片 图片

这样开发者关注的不是 HTML 模板、JavaScript 渲染逻辑这样的技术实现,而是诸如 Sidebar、Form 这样的页面功能单元。

六、使用 JSX 编写 React 组件

返回 JSX 的函数就是 React 最简单的组件,可以和 HTML 标签一样嵌套使用。React 使用 props参数向组件传递数据,提升组件的复用性。
/** * JSX 语法隐式调用 React.createElement * 所以虽然代码中没有调用 React 的语句,仍然需要引入  */import React from 'react'; 
interface IButton {  /** 按钮展示文案 */  text: string;  /** 点击按钮跳转链接 */  link?: string;  /** 点击按钮自定义事件 */  onClick?: (event?: Event) => void}
function Button(props: IButton) {  const { text, link, onClick } = props;
  const redirectHandler = () => {    location.href = link;  };
  return (    <div      className="button"      onClick={onClick | redirectHandler}    >      {text}    </div>  );}
export default Button;

在使用组件时候,通过其标签的属性组装成 props 对象,传递给组件,语法和 HTML attribute 类似,但值可以是任意的 JavaScript 对象。

import React from 'react';
/** * 导入 ./button.tsx 中 export 的默认内容,命名为 Button 使用 * .tsx 拓展名可以省略 */import Button from './button';
interface IDialog {  title: string;  content: Element;  showClose: boolean;}
function Dialog(props: IDialog) {  const { title, content, showClose = false, children } = props;
  const hideDialog = () => {    // ...  }
  return (    <div>      <div className="dialog-title"> {title} </div>      <div className="dialog-body"> {content | children} </div>      {/* 没错,Button props 定义的属性,就是这样通过标签属性开放出来的 */}      <Button        title="取消"        onClick={hideDialog}      />      <Button         title="确认"        onClick={() => { }}      />    </div>  );}
export default Dialog;

组件写好后通过 react-dom [3]将组件渲染到页面。

import React from 'react';import ReactDOM from 'react-dom/client';import Dialog from './dialog';
// 把组件渲染到页面 id 为 root 的元素中const rootElement = document.getElementById('root');const root = ReactDOM.createRoot(rootElement);root.render(  <Dialog     title="demo dialog"     content="this is a dialog"    showClose={false}  />);
七、JSX 规则

React 组件有几个约定:
  • 组件名称使用 Pascal 风格(首字母大写),以和 HTML 原生标签(div、p、a 等)区分;
  • 组件仅接受 props一个参数,用来暴露组件可配置属性,其子组件被 React 通过 children属性注入;
  • 在组件内部 props 是只读的,不允许对其进行修改;
1. 必须有根节点

如同上面写的几个简单 demo,JSX 必须有 root 节点,即使多个同级元素没有父节点,也需要用虚拟节点 <></> 来包裹。
{/* 非法的 JSX */}<div id="box1"></div><div id="box2"></div>
{/* 合法的 JSX */}<>    <div id="box1"></div>  <div id="box2"></div></>
2. 所有标签需要闭合

在 HTML 中标签并不一定需要闭合。
<meta charset="UTF-8"><br><img src="https://g.alicdn.com/logo.png">
在 JSX 中可以混合 HTML 原生标签,但所有标签必须闭合。
<>  <meta charset="UTF-8" />  <br/>  <img src="https://g.alicdn.com/logo.png"/></>
3. 和 HTML 属性差异

  • 在 React 中常用的 DOM 特性和属性(包括事件处理)都使用小驼峰命名的方式,例如与 HTML 中的 tabindex 属性对应的 React 的属性是 tabIndex;
  • HTML 部分属性名称与 JavaScript 保留字冲突,在 JSX 中需要使用替代名称;
    图片
  • style 属性 value 是一个 CSS 属性组成的对象,为了让其符合 JavaScript 语法规则,属性名使用驼峰命名(fontSize、backgroundColor),而不是 CSS 属性使用的连字符,这样可以很方便设置动态样式,但静态样式应该依赖 className 和 CSS 文件的配合;
function HelloWorldComponent(props) {    const divStyle = {      // 可以很方便设置动态样式      backgroundImage: 'url(' + props.imgUrl + ')',    // 但静态样式应该尽量通过 className 设置类,通过 css file 解决    // 不推荐 color: 'blue' 这种静态样式直接在 JSX 的写法    color: 'blue',  };
  return (    <div style={divStyle}>      Hello World!    </div>  );}
  • React 对于 Form 表单支持 defaultValue 属性,设置默认值,在运行时取值使用和 HTML 一致的 value属性。
4. 自动转义 content

为了防止 XSS 攻击,JSX 会对直接设置的文本进行转义。
const content = `  这里应该展示一张图片<br>  <img src="https://sc02.alicdn.com/kf/HTB1gUuPUkzoK1RjSZFl761i4VXaw.png" />`;<div>  {content}</div>

页面效果:

图片

在安全性有保障的时候,可以通过 dangerouslySetInnerHTML禁用转义效果,展示 raw HTML
 

const content = `      这里应该展示一张图片<br>      <img src="https://sc02.alicdn.com/kf/HTB1gUuPUkzoK1RjSZFl761i4VXaw.png" />  `;<div dangerouslySetInnerHTML={{ __html: content }}/>

图片

八、在 JSX 中TODO使用 {} 支持 JavaScript 表达式

JSX 中使用 {} 包裹 JavaScript 表达式处理动态逻辑,属性 value、子元素都可以,最常见的几个用法:
  • {变量名}读取变量值,双层 {{}} 并不是特殊语法,而是 {对象} 的快捷写法
<div style={{ color: 'red' }}></div>
// 等同于
const styleObj = { color: 'red' };<div style={styleObj}></div>
  • 三元表达式处理 if-else(if-else 是语句,不是表达式)
  • map 处理循环逻辑,批量生成元素
interface IStuff {  name: string;  sex: 'male' | 'female';}
function App () {  const list: Array<IStuff> = [    { name: 'Byron', sex: 'male' },    { name: 'Casper', sex: 'male' },    { name: 'Junice', sex: 'female' },  ];
  return (    <ul className="stuff-list">      {        list.map(stuff => { // 生成多个          const { name, sex } = stuff;          return (            {            <li              /* 实际编程 className 设置有更好的表达方式,这里仅 demo 三元表达式使用 */}                className={sex === 'male' ? 'stuff-male' : 'stuff-female'}              onClick={() => { alert(name) }}            >              // 读取变量值              {name}            </li>          );        })      }    </ul>  );}
JSX 中注释也需要使用 {} 包裹,但这种写法过于不方便,大部分编译工具都可以处理双斜线风格//注释
九、JSX 的背后

JSX 的返回值既不是 DOM 元素,也不是 HTML 字符串,而是对 DOM 的一个 JSON 描述,这就是 React Element:
<button id="9527" className="btn-primary">   <span style={{ color: 'red' }}>     This is a Button   </span></button>

JSX 用类似这样的结构表达:

 

{  "type": "button",  "props": {    "id": "9527",    "className": "btn-primary",    "children": [      {        "type": "span",        "props": {          "style": { "color": "red" },          "children": "This is a Button"        }      }    ]  }}

编译后实际是这样的调用:

React.createElement("button", {  id: "9527",  className: "btn-primary"},React.createElement("span", {  style: {    color: 'red'  }}, "This is a Button"));
React.createElement(type, props, …children),上文提到过 React 会自动把 children 注入到 props,就是在这个过程。
了解了 JSX 之后可以开始编写静态的 React Component 了。
完整教程见语雀:https://www.yuque.com/sunluyong/fe4java/pwsehvspthh6gtrd

参考链接:

[1]https://create-react-app.dev/

[2]https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

[3]https://www.npmjs.com/package/react-dom

ChatGPT系统反向代理配置官方教程 

mikel阅读(672)

来源: ChatGPT系统反向代理配置官方教程 – 程序专题 源码论坛,商业源码下载,尽在锦尚中国商业源码论坛


搭建属于自己的ai平台,属实有点繁琐,但是不得不承认的是,太简单的东西,你也挣不到钱的!

1、超管后台选择接口通道为“反向代理”,填入自己海外服务器的域名。

2、添加反向代理

将海外宝塔升级到最新,然后新建一个站点 -> 站点设置 -> 反向代理,

参数见下图:目标URL是 https://api.openai.com,发送域名是 api.openai.com

注意:配置完以后,将反代地址放浏览器打开,出现下图结果说明反向代理配置成功

如果出现502错误,则按下面方法解决:

打开海外宝塔面板 -> 站点设置 -> 反向代理 -> 配置文件

在配置文件里

  1. location /
  2. {
  3. proxy_pass https://api.openai.com;
  4. proxy_set_header Host api.openai.com;
  5. proxy_set_header X-Real-IP $remote_addr;
  6. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  7. proxy_set_header REMOTE-HOST $remote_addr;
  8. proxy_set_header Upgrade $http_upgrade;
  9. proxy_set_header Connection $connection_upgrade;
  10. proxy_http_version 1.1;
  11. # proxy_hide_header Upgrade;

复制代码


#代码下面,新增

proxy_ssl_server_name on;

API网关:中间件设计和实践 | bugstack 虫洞栈

mikel阅读(1181)

来源: API网关:中间件设计和实践 | bugstack 虫洞栈

作者:小傅哥
博客:https://bugstack.cn(opens new window)
星球:https://t.zsxq.com/0diYdgP5u (opens new window)– 课程入口

沉淀、分享、成长,让自己和他人都能有所收获!😄


是滴,小傅哥又要准备搞事情了!这次准备下手API网关项目,因为这是所有互联网大厂都有的一个核心服务,承接着来自用户的滴滴打车、美团外卖、京东购物、微信支付,更是大促期间千万级访问量的核心系统。

🤔 那么它是一个什么样的项目呢?为什么会有它的存在?它是怎么设计实现的呢?都用到了哪些技术栈呢?

#一、前言:网关是啥东西

在计算机网络中,网关 (opens new window)(Gateway)是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。

API网关也是随着对传统庞大的单体应用(All in one)拆分为众多的微服务(Microservice)以后,所引入的统一通信管理系统。用于运行在外部http请求与内部rpc服务之间的一个流量入口,实现对外部请求的协议转换参数校验鉴权切量熔断限流监控风控等各类共性的通用服务。

#二、大厂:为啥都做网关

各大厂做网关,其实做的就是一套统一方案。将分布式微服务下的RPC到HTTP通信的同类共性的需求,凝练成通用的组件服务,减少在业务需求场景开发下,非业务需求的同类技术诉求的开发成本。

那么以往没有网关的时候怎么做,基本的做法就是再 RPC 服务之上再开发一个对应的 WEB 服务,这些 WEB 服务可以是 Spring MVC 工程,在 Spring MVC 工程中调用 RPC 服务,最终提供 HTTP 接口给到 H5、Web、小程序、APP 等应用中进行使用。如图 1-1 所示

图 1-1 从传统方式到网关设计

传统开发 WEB 服务的几个问题:

  • 问题1:每一个 WEB 应用,都需要与之匹配申请一套工程、域名、机器等资源,一直到部署,研发效率降低,维护成本增加。
  • 问题2:每一个 WEB 应用,都会有所涉及共性需求,限流、熔断、降级、切量等诉求,维护代码成本增加。
  • 问题3:每一个 WEB 应用,在整个使用生命周期内,都会涉及到文档的维护、工程的调试、联调的诉求,类似刀耕火种一样的开发势必降低研发效率。

所以:综上在微服务下的传统开发所遇到的这些问题,让各个大厂都有了自己自研网关的诉求,包括;阿里腾讯百度美团京东网易亚马逊等,都有自己成熟的 API 网关解决方案。毕竟这可以降低沟通成本、提升研发效率、提升资源利用率。

#三、网关:系统架构设计

如果希望实现一个能支撑百亿级吞吐量的网关,那么它就应该是按照分布式架构思维做去中心化设计,支持横向扩展。让每一台网关服务都成为一个算力,把不同的微服务RPC接口,按照权重策略计算动态分配到各个算力组中,做到分布式运算的能力。

此外从设计实现上,要把网关的通信模块、管理服务、SDK、注册中心、运营平台等依次分开单独开发实现,这样才能进行独立的组合包装使用。

这就像为什么 ORM 框架在开发的时候不是与 Spring 强绑定在一起,而是开发一个独立的组件,当需要有 Spring 融合使用的时候,再单独开发一个 Mybatis-Spring 来整合服务。

所以在这里设计网关的时候也是同样的思路,就像官网的通信不应该一开始就把 Netty 相关的服务全部绑定到 Spring 容器,这样即增加了维护成本,也降低了系统的扩展性。

诸如此类的软件架构设计,都会在这套网关微服务架构中体现,整体架构如图 1-2 所示

图 1-2 网关架构设计

整个API网关设计核心内容分为这么五块;

  • 第一块:是关于通信的协议处理,也是网关最本质的处理内容。这里需要借助 NIO 框架 Netty 处理 HTTP 请求,并进行协议转换泛化调用到 RPC 服务返回数据信息。
  • 第二块:是关于注册中心,这里需要把网关通信系统当做一个算力,每部署一个网关服务,都需要向注册中心注册一个算力。而注册中心还需要接收 RPC 接口的注册,这部分可以是基于 SDK 自动扫描注册也可以是人工介入管理。当 RPC 注册完成后,会被注册中心经过AHP权重计算分配到一组网关算力上进行使用。
  • 第三块:是关于路由服务,每一个注册上来的Netty通信服务,都会与他对应提供的分组网关相关联,例如:wg/(a/b/c)/user/… a/b/c 需要匹配到 Nginx 路由配置上,以确保不同的接口调用请求到对应的 Netty 服务上。PS:如果对应错误或者为启动,可能会发生类似B站事故。
  • 第四块:责任链下插件模块的调用,鉴权、授信、熔断、降级、限流、切量等,这些服务虽然不算是网关的定义下的内容,但作为共性通用的服务,它们通常也是被放到网关层统一设计实现和使用的。
  • 第五块:管理后台,作为一个网关项目少不了一个与之对应的管理后台,用户接口的注册维护、mock测试、日志查询、流量整形、网关管理等服务。

综上系统微服务模块结构如下:

序号 系统 描述
1 api-gateway-core 网关核心系统:用于网络通信转换处理,承接http请求,调用RPC服务,责任链模块调用
2 api-gateway-admin 网关管理系统:用于网关接口后台管理,注册下线停用控制
3 api-gateway-sdk 网关注册组件:用于注解方式采集接口,发送消息注册接口
4 api-gateway-center 网关注册中心:提供网关注册中心服务,登记网关接口信息
5 api-gateway-test-provider 网关测试工程:提供RPC接口
6 api-gateway-test-consumer 网关测试工程:消费RPC接口

#四、演示:网关运行效果

趁着周末假期小傅哥已经做了一部分的功能实现,就像小傅哥以前《手写Spring》 (opens new window)《手写Mybatis》 (opens new window)一样,此项目也是渐进式的逐步完成各个模块功能的开发。并参照优秀源码级的项目架构设计,运用抽象和分治的设计技巧,解决功能间的耦合调用和服务设计。同时也结合设计原则和相应场景下的设计模式,开发出高质量易于迭代和维护的代码。部分代码实现和运行如图 1-3 所示

图 1-3 网关运行效果

  • 左侧是API网关核心通信模块,右侧是RPC(Dubbo)服务。通过对网页端发起的 http 请求,经过API网关的协议转换和对RPC的泛化调用包装结果数据并返回到页面,就是中间这张图的运行效果了。
  • 左侧工程的实现,以渐进式分拆模块逐步完成,例如: core-01(Netty通信)、core-02(泛化调用)、core-03(执行器)等,让每一个对API网关感兴趣的读者都能从中学习到;架构的分层、功能的设计、代码的实现。

#五、邀请:一起学习技术

💐以上关API网关的项目,也是小傅哥的星球【码农会锁 (opens new window)】准备带着读者一起利用周末假期学习实践的内容。现在上车你将会通过小傅哥的视频+小册+代码+直播+作业,5方面来与你一起学习,帮助你提升技术实力,为你的职业生涯续期,也为你可以走的更远,可以多赚些钱。

#1. 适合谁学

  1. 一直使用 SpringMVC,想了解分布式架构。
  2. 常年做CRUD开发,手里缺少硬核项目,面试张不开嘴。
  3. 在校准备校招,市面都是流水账项目,面试没竞争力。
  4. 希望多沉淀核心技术,让自己能公司留的下来,也能走的出去。

#2. 能学到啥

  1. 优秀架构:学习微服务架构设计方案
  2. 整洁编码:学习源码级工程编程实现
  3. 扩充技术:学习开发中间件所需技术(Netty、CGlib、SPI、GenericReference)
  4. 打开思路:学习让自己开眼界的项目(技术并不难,但没人告诉你,就走的很难!)

#3. 开发计划

  1. 每周末和假期编写API网关,并同时录制设计和实现的视频、编写小册和定期组织直播解决读者疑惑以及分享。稳定输出,可靠学习
  2. 整个系统的设计和实现,遵循分治和抽象的设计分层原则,按照微服务构建服务模块,以源码级体验学习。
  3. 关于API网关会更注重骨架的结构和核心流程的功能,把最干净的部分交给读者,让读者更加易懂,也易扩展。

【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet) - 郭耀华 - 博客园

mikel阅读(785)

来源: 【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet) – 郭耀华 – 博客园

目标检测是很多计算机视觉任务的基础,不论我们需要实现图像与文字的交互还是需要识别精细类别,它都提供了可靠的信息。本文对目标检测进行了整体回顾,第一部分从RCNN开始介绍基于候选区域的目标检测器,包括Fast R-CNN、Faster R-CNN 和 FPN等。第二部分则重点讨论了包括YOLO、SSD和RetinaNet等在内的单次检测器,它们都是目前最为优秀的方法。

一、基于候选区域的目标检测器

1.1  滑动窗口检测器

自从 AlexNet 获得 ILSVRC 2012 挑战赛冠军后,用 CNN 进行分类成为主流。一种用于目标检测的暴力方法是从左到右、从上到下滑动窗口,利用分类识别目标。为了在不同观察距离处检测不同的目标类型,我们使用不同大小和宽高比的窗口。

滑动窗口(从右到左,从上到下)

我们根据滑动窗口从图像中剪切图像块。由于很多分类器只取固定大小的图像,因此这些图像块是经过变形转换的。但是,这不影响分类准确率,因为分类器可以处理变形后的图像。

将图像变形转换成固定大小的图像

变形图像块被输入 CNN 分类器中,提取出 4096 个特征。之后,我们使用 SVM 分类器识别类别和该边界框的另一个线性回归器

滑动窗口检测器的系统工作流程图

下面是伪代码。我们创建很多窗口来检测不同位置的不同目标。要提升性能,一个显而易见的办法就是减少窗口数量。

for window in windows 
    patch = get_patch(image, window) 
  results = detector(patch)

1.2  选择性搜索

我们不使用暴力方法,而是用候选区域方法(region proposal method)创建目标检测的感兴趣区域(ROI)。在选择性搜索(selective search,SS)中,我们首先将每个像素作为一组。然后,计算每一组的纹理,并将两个最接近的组结合起来。但是为了避免单个区域吞噬其他区域,我们首先对较小的组进行分组。我们继续合并区域,直到所有区域都结合在一起。下图第一行展示了如何使区域增长,第二行中的蓝色矩形代表合并过程中所有可能的 ROI

图源:van de Sande et al. ICCV’11

1.3  R-CNN

R-CNN 利用候选区域方法创建了约 2000 个 ROI。这些区域被转换为固定大小的图像,并分别馈送到卷积神经网络中(将原始图像根据ROI切割、reshape再送进NN学习)。该网络架构后面会跟几个全连接层,以实现目标分类并提炼边界框。

使用候选区域、CNN、仿射层来定位目标。以下是 R-CNN 整个系统的流程图:

通过使用更少且更高质量的 ROI,R-CNN 要比滑动窗口方法更快速、更准确。

ROIs = region_proposal(image)
for ROI in ROIs:
    patch = get_patch(image, ROI) 
    results = detector(pach)

 

  • 边界框回归器

候选区域方法有非常高的计算复杂度。为了加速这个过程,我们通常会使用计算量较少的候选区域选择方法构建 ROI,并在后面使用线性回归器(使用全连接层)进一步提炼边界框。

从RCNN到SSD,这应该是最全的一份目标检测算法盘点

使用回归方法将蓝色的原始边界框提炼为红色的

1.4  Fast R-CNN

R-CNN 需要非常多的候选区域以提升准确度,但其实有很多区域是彼此重叠的,因此 R-CNN 的训练和推断速度非常慢。如果我们有 2000 个候选区域,且每一个都需要独立地馈送到 CNN 中,那么对于不同的 ROI,我们需要重复提取 2000 次特征。(R-CNN很多卷积运算是重复的

此外,CNN 中的特征图以一种密集的方式表征空间特征,那么我们能直接使用特征图代替原图来检测目标吗?

直接利用特征图计算 ROI

Fast R-CNN 使用特征提取器(CNN)先提取整个图像的特征,而不是从头开始对每个图像块提取多次。然后,我们可以将创建候选区域的方法直接应用到提取到的特征图上。例如,Fast R-CNN 选择了 VGG16 中的卷积层 conv5 输出的 Feture Map 来生成 ROI,这些关注区域随后会结合对应的特征图以裁剪为特征图块,并用于目标检测任务中。我们使用 ROI 池化将特征图块转换为固定的大小,并馈送到全连接层进行分类和定位。因为 Fast-RCNN 不会重复提取特征,因此它能显著地减少处理时间。

将候选区域直接应用于特征图,并使用 ROI 池化将其转化为固定大小的特征图块

以下是 Fast R-CNN 的流程图:

在下面的伪代码中,计算量巨大的特征提取过程从 For 循环中移出来了,因此速度得到显著提升。Fast R-CNN 的训练速度是 R-CNN 的 10 倍,推断速度是后者的 150 倍。

feature_maps = process(image)
ROIs = region_proposal(feature_maps)
for ROI in ROIs:
    patch = roi_pooling(feature_maps, ROI) 
    results = detector2(patch)

Fast R-CNN 最重要的一点就是包含特征提取器、分类器和边界框回归器在内的整个网络能通过多任务损失函数进行端到端的训练,这种多任务损失即结合了分类损失和定位损失的方法,大大提升了模型准确度。

  • ROI 池化

因为 Fast R-CNN 使用全连接层,所以我们应用 ROI 池化将不同大小的 ROI 转换为固定大小。

为简洁起见,我们先将 8×8 特征图转换为预定义的 2×2 大小。

  • 下图左上角:特征图。
  • 右上角:将 ROI(蓝色区域)与特征图重叠。
  • 左下角:将 ROI 拆分为目标维度。例如,对于 2×2 目标,我们将 ROI 分割为 4 个大小相似或相等的部分。
  • 右下角:找到每个部分的最大值,得到变换后的特征图。

输入特征图(左上),输出特征图(右下),ROI (右上,蓝色框)

按上述步骤得到一个 2×2 的特征图块,可以馈送至分类器和边界框回归器中。

1.5  Faster R-CNN

Fast R-CNN 依赖于外部候选区域方法,如选择性搜索。但这些算法在 CPU 上运行且速度很慢。在测试中,Fast R-CNN 需要 2.3 秒来进行预测,其中 2 秒用于生成 2000 个 ROI。

feature_maps = process(image)
ROIs = region_proposal(feature_maps)  # Expensive!
for ROI in ROIs
    patch = roi_pooling(feature_maps, ROI) 
    results = detector2(patch)

Faster R-CNN 采用与 Fast R-CNN 相同的设计,只是它用内部深层网络代替了候选区域方法。新的候选区域网络(RPN)在生成 ROI 时效率更高,并且以每幅图像 10 毫秒的速度运行。

Faster R-CNN 的流程图与 Fast R-CNN 相同

外部候选区域方法代替了内部深层网络

  • 候选区域网络(RPN)

候选区域网络(RPN)将第一个卷积网络的输出特征图作为输入。它在特征图上滑动一个 3×3 的卷积核,以使用卷积网络(如下所示的 ZF 网络)构建与类别无关的候选区域。其他深度网络(如 VGG 或 ResNet)可用于更全面的特征提取,但这需要以速度为代价。ZF 网络最后会输出 256 个值,它们将馈送到两个独立的全连接层,以预测边界框和两个 objectness 分数,这两个 objectness 分数度量了边界框是否包含目标。我们其实可以使用回归器计算单个 objectness 分数,但为简洁起见,Faster R-CNN 使用只有两个类别的分类器:即带有目标的类别不带有目标的类别

对于特征图中的每一个位置,RPN 会做 k 次预测。因此,RPN 将输出 4×k 个坐标和每个位置上 2×k 个得分。下图展示了 8×8 的特征图,且有一个 3×3 的卷积核执行运算,它最后输出 8×8×3 个 ROI(其中 k=3)。下图(右)展示了单个位置的 3 个候选区域。

此处有 3 种猜想,稍后我们将予以完善。由于只需要一个正确猜想,因此我们最初的猜想最好涵盖不同的形状和大小。因此,Faster R-CNN 不会创建随机边界框。相反,它会预测一些与左上角名为「锚点」的参考框相关的偏移量(如x、y)。我们限制这些偏移量的值,因此我们的猜想仍然类似于锚点。

要对每个位置进行 k 个预测,我们需要以每个位置为中心的 k 个锚点。每个预测与特定锚点相关联,但不同位置共享相同形状的锚点。

这些锚点是精心挑选的,因此它们是多样的,且覆盖具有不同比例和宽高比的现实目标。这使得我们可以以更好的猜想来指导初始训练,并允许每个预测专门用于特定的形状。该策略使早期训练更加稳定和简便。

图源:https://arxiv.org/pdf/1506.01497.pdf

Faster R-CNN 使用更多的锚点。它部署 9 个锚点框:3 个不同宽高比的 3 个不同大小的锚点框。每一个位置使用 9 个锚点,每个位置会生成 2×9 个 objectness 分数和 4×9 个坐标。

  • R-CNN 方法的性能

如下图所示,Faster R-CNN 的速度要快得多。

1.6  基于区域的全卷积神经网络(R-FCN)

假设我们只有一个特征图用来检测右眼。那么我们可以使用它定位人脸吗?应该可以。因为右眼应该在人脸图像的左上角,所以我们可以利用这一点定位整个人脸。

如果我们还有其他用来检测左眼、鼻子或嘴巴的特征图,那么我们可以将检测结果结合起来,更好地定位人脸。

现在我们回顾一下所有问题。在 Faster R-CNN 中,检测器使用了多个全连接层进行预测。如果有 2000 个 ROI,那么成本非常高。

复制代码
feature_maps = process(image)
ROIs = region_proposal(feature_maps)
for ROI in ROIs
    patch = roi_pooling(feature_maps, ROI)
    class_scores, box = detector(patch)         # Expensive!
    class_probabilities = softmax(class_scores)
复制代码

 

R-FCN 通过减少每个 ROI 所需的工作量实现加速(去掉了全连接层)。上面基于区域的特征图与 ROI 是独立的,可以在每个 ROI 之外单独计算。剩下的工作就比较简单了,因此 R-FCN 的速度比 Faster R-CNN 快。

复制代码
feature_maps = process(image)
ROIs = region_proposal(feature_maps)         
score_maps = compute_score_map(feature_maps)
for ROI in ROIs
    V = region_roi_pool(score_maps, ROI)     
    class_scores, box = average(V)                   # Much simpler!
    class_probabilities = softmax(class_scores)
复制代码

现在我们来看一下 5 × 5 的特征图 M,内部包含一个蓝色方块。我们将方块平均分成 3 × 3 个区域。现在,我们在 M 中创建了一个新的特征图,来检测方块的左上角(TL)。这个新的特征图如下图(右)所示。只有黄色的网格单元 [2, 2] 处于激活状态。

在左侧创建一个新的特征图,用于检测目标的左上角

我们将方块分成 9 个部分,由此创建了 9 个特征图,每个用来检测对应的目标区域。这些特征图叫作位置敏感得分图(position-sensitive score map),因为每个图检测目标的子区域(计算其得分)。

生成 9 个得分图

下图中红色虚线矩形是建议的 ROI。我们将其分割成 3 × 3 个区域,并询问每个区域包含目标对应部分的概率是多少。例如,左上角 ROI 区域包含左眼的概率。我们将结果存储成 3 × 3 vote 数组,如下图(右)所示。例如,vote_array[0][0] 包含左上角区域是否包含目标对应部分的得分。

将 ROI 应用到特征图上,输出一个 3 x 3 数组

将得分图(Feature Map)和 ROI 映射到 vote 数组的过程叫作位置敏感 ROI 池化(position-sensitive ROI-pool)。该过程与前面讨论过的 ROI 池化非常接近。

将 ROI 的一部分叠加到对应的得分图上,计算 V[i][j]

在计算出位置敏感 ROI 池化的所有值后,类别得分是其所有元素得分的平均值。

ROI 池化

假如我们有 C 个类别要检测。我们将其扩展为 C + 1 个类别,这样就为背景(非目标)增加了一个新的类别。每个类别有 3 × 3 个得分图,因此一共有 (C+1) × 3 × 3 个得分图。使用每个类别的得分图可以预测出该类别的类别得分。然后我们对这些得分应用 softmax 函数,计算出每个类别的概率。

以下是数据流图,在我们的案例中,k=3。

 

1.7  R-CNN系列总结

我们首先了解了基础的滑动窗口算法:

for window in windows
    patch = get_patch(image, window)
    results = detector(patch)

然后尝试减少窗口数量,尽可能减少 for 循环中的工作量。

ROIs = region_proposal(image)
for ROI in ROIs
    patch = get_patch(image, ROI)
    results = detector(patch)

 

二、单次目标检测器

第二部分,我们将对单次目标检测器(包括 SSD、YOLO、YOLOv2、YOLOv3)进行综述。我们将分析 FPN 以理解多尺度特征图如何提高准确率,特别是小目标的检测,其在单次检测器中的检测效果通常很差。然后我们将分析 Focal loss 和 RetinaNet,看看它们是如何解决训练过程中的类别不平衡问题的。

2.1  单次检测器

Faster R-CNN 中,在分类器之后有一个专用的候选区域网络。

Faster R-CNN 工作流

基于区域的检测器是很准确的,但需要付出代价。Faster R-CNN 在 PASCAL VOC 2007 测试集上每秒处理 7 帧的图像(7 FPS)。和 R-FCN 类似,研究者通过减少每个 ROI 的工作量来精简流程。

feature_maps = process(image)
ROIs = region_proposal(feature_maps)
for ROI in ROIs
    patch = roi_align(feature_maps, ROI)
    results = detector2(patch)    # Reduce the amount of work here!

作为替代,我们是否需要一个分离的候选区域步骤?我们可以直接在一个步骤内得到边界框和类别吗?

feature_maps = process(image)
results = detector3(feature_maps) # No more separate step for ROIs

让我们再看一下滑动窗口检测器。我们可以通过在特征图上滑动窗口来检测目标。对于不同的目标类型,我们使用不同的窗口类型。以前的滑动窗口方法的致命错误在于使用窗口作为最终的边界框,这就需要非常多的形状来覆盖大部分目标。更有效的方法是将窗口当做初始猜想,这样我们就得到了从当前滑动窗口同时预测类别和边界框的检测器。

基于滑动窗口进行预测

这个概念和 Faster R-CNN 中的锚点很相似。然而,单次检测器会同时预测边界框和类别。例如,我们有一个 8 × 8 特征图,并在每个位置做出 k 个预测,即总共有 8 × 8 × k 个预测结果。

64 个位置

在每个位置,我们有 k 个锚点(锚点是固定的初始边界框猜想),一个锚点对应一个特定位置。我们使用相同的锚点形状仔细地选择锚点和每个位置。

使用 4 个锚点在每个位置做出 4 个预测

以下是 4 个锚点(绿色)和 4 个对应预测(蓝色),每个预测对应一个特定锚点。

4 个预测,每个预测对应一个锚点

在 Faster R-CNN 中,我们使用卷积核来做 5 个参数的预测:4 个参数对应某个锚点的预测边框,1 个参数对应 objectness 置信度得分。因此 3× 3× D × 5 卷积核将特征图从 8 × 8 × D 转换为 8 × 8 × 5。

使用 3×3 卷积核计算预测

在单次检测器中,卷积核还预测 C 个类别概率以执行分类(每个概率对应一个类别)。因此我们应用一个 3× 3× D × 25 卷积核将特征图从 8 × 8 × D 转换为 8 × 8 × 25(C=20)。

每个位置做出 k 个预测,每个预测有 25 个参数

单次检测器通常需要在准确率和实时处理速度之间进行权衡。它们在检测太近距离或太小的目标时容易出现问题。在下图中,左下角有 9 个圣诞老人,但某个单次检测器只检测出了 5 个。

 

2.2  SSD (Single Shot MultiBox Detector)

SSD 是使用 VGG19 网络作为特征提取器(和 Faster R-CNN 中使用的 CNN 一样)的单次检测器。我们在该网络之后添加自定义卷积层(蓝色),并使用卷积核(绿色)执行预测。

同时对类别和位置执行单次预测

然而,卷积层降低了空间维度和分辨率。因此上述模型仅可以检测较大的目标为了解决该问题,我们从多个特征图上执行独立的目标检测。采用多尺度特征图独立检测。

使用多尺度特征图用于检测

以下是特征图图示。

图源:https://arxiv.org/pdf/1512.02325.pdf

SSD 使用卷积网络中较深的层来检测目标。如果我们按接近真实的比例重绘上图,我们会发现图像的空间分辨率已经被显著降低,且可能已无法定位在低分辨率中难以检测的小目标。如果出现了这样的问题,我们需要增加输入图像的分辨率。

2.3  YOLO

YOLO 是另一种单次目标检测器。

YOLO  在卷积层之后使用了 DarkNet 来做特征检测。

然而,它并没有使用多尺度特征图来做独立的检测。相反,它将特征图部分平滑化,并将其和另一个较低分辨率的特征图拼接。例如,YOLO 将一个 28 × 28 × 512 的层重塑为 14 × 14 × 2048,然后将它和 14 × 14 ×1024 的特征图拼接。之后,YOLO 在新的 14 × 14 × 3072 层上应用卷积核进行预测。

YOLO(v2)做出了很多实现上的改进,将 mAP 值从第一次发布时的 63.4 提高到了 78.6。YOLO9000 可以检测 9000 种不同类别的目标。

图源:https://arxiv.org/pdf/1612.08242.pdf

以下是 YOLO 论文中不同检测器的 mAP 和 FPS 对比。YOLOv2 可以处理不同分辨率的输入图像。低分辨率的图像可以得到更高的 FPS,但 mAP 值更低。

图源:https://arxiv.org/pdf/1612.08242.pdf

  YOLOv3 使用了更加复杂的骨干网络来提取特征。DarkNet-53 主要由 3 × 3 和 1× 1 的卷积核以及类似 ResNet 中的跳过连接构成。相比 ResNet-152,DarkNet 有更低的 BFLOP(十亿次浮点数运算),但能以 2 倍的速度得到相同的分类准确率。

图源:https://pjreddie.com/media/files/papers/YOLOv3.pdf

YOLOv3 还添加了特征金字塔,以更好地检测小目标。以下是不同检测器的准确率和速度的权衡。

图源:https://pjreddie.com/media/files/papers/YOLOv3.pdf

特征金字塔网络(FPN)

检测不同尺度的目标很有挑战性,尤其是小目标的检测。特征金字塔网络(FPN)是一种旨在提高准确率和速度的特征提取器。它取代了检测器(如 Faster R-CNN)中的特征提取器,并生成更高质量的特征图金字塔。

数据流

FPN(图源:https://arxiv.org/pdf/1612.03144.pdf)

FPN 由自下而上和自上而下路径组成。其中自下而上的路径是用于特征提取的常用卷积网络。空间分辨率自下而上地下降。当检测到更高层的结构,每层的语义值增加。

FPN 中的特征提取(编辑自原论文)

SSD 通过多个特征图完成检测。但是,最底层不会被选择执行目标检测。它们的分辨率高但是语义值不够,导致速度显著下降而不能被使用。SSD 只使用较上层执行目标检测,因此对于小的物体的检测性能较差。

图像修改自论文 https://arxiv.org/pdf/1612.03144.pdf

FPN 提供了一条自上而下的路径,从语义丰富的层构建高分辨率的层。

自上而下重建空间分辨率(编辑自原论文)

虽然该重建层的语义较强,但在经过所有的上采样和下采样之后,目标的位置不精确。在重建层和相应的特征图之间添加横向连接可以使位置侦测更加准确。

增加跳过连接(引自原论文)

下图详细说明了自下而上和自上而下的路径。其中 P2、P3、P4 和 P5 是用于目标检测的特征图金字塔。

FPN 结合 RPN

FPN 不单纯是目标检测器,还是一个目标检测器和协同工作的特征检测器。分别传递到各个特征图(P2 到 P5)来完成目标检测。

FPN 结合 Fast R-CNN 或 Faster R-CNN

在 FPN 中,我们生成了一个特征图的金字塔。用 RPN(详见上文)来生成 ROI。基于 ROI 的大小,我们选择最合适尺寸的特征图层来提取特征块。

困难案例

对于如 SSD 和 YOLO 的大多数检测算法来说,我们做了比实际的目标数量要多得多的预测。所以错误的预测比正确的预测要更多。这产生了一个对训练不利的类别不平衡。训练更多的是在学习背景,而不是检测目标。但是,我们需要负采样来学习什么是较差的预测。所以,我们计算置信度损失来把训练样本分类。选取最好的那些来确保负样本和正样本的比例最多不超过 3:1。这使训练更加快速和稳定。

推断过程中的非极大值抑制

检测器对于同一个目标会做出重复的检测。我们利用非极大值抑制来移除置信度低的重复检测。将预测按照置信度从高到低排列。如果任何预测和当前预测的类别相同并且两者 IoU 大于 0.5,我们就把它从这个序列中剔除。

Focal Loss(RetinaNet)

类别不平衡会损害性能。SSD 在训练期间重新采样目标类和背景类的比率,这样它就不会被图像背景淹没。Focal loss(FL)采用另一种方法来减少训练良好的类的损失。因此,只要该模型能够很好地检测背景,就可以减少其损失并重新增强对目标类的训练。我们从交叉熵损失 CE 开始,并添加一个权重来降低高可信度类的 CE。

例如,令 γ = 0.5, 经良好分类的样本的 Focal loss 趋近于 0。

编辑自原论文

这是基于 FPN、ResNet 以及利用 Focal loss 构建的 RetianNet

RetinaNet

 

原文链接:https://medium.com/@jonathan_hui/what-do-we-learn-from-region-based-object-detectors-faster-r-cnn-r-fcn-fpn-7e354377a7c9
https://medium.com/@jonathan_hui/what-do-we-learn-from-single-shot-object-detectors-ssd-yolo-fpn-focal-loss-3888677c5f4d

深度剖析YOLO系列的原理 - w_x_w1985 - 博客园

mikel阅读(873)

来源: 深度剖析YOLO系列的原理 – w_x_w1985 – 博客园

                     深度剖析YOLO系列的原理

本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/12072225.html

目录

1. YOLO的作用

2. YOLO(v1,v2,v3)的技术演化

 


 

 

 

1. YOLO的作用

yolo是当前目标检测最顶级的算法之一,v1 版本是2016年提出来的,v2 是2017年提出来的,v3 是2018年提出的。

官网地址:https://pjreddie.com/darknet/yolo/

说它最牛掰,有两点:

一是因为它采用深层卷积神经网络,吸收了当前很多经典卷积神经网络架构的优秀思想,在位置检测和对象的识别方面,

性能达到最优(准确率非常高的情况下还能达到实时检测)。

二是因为作者还将代码开源了。真心为作者这种大公无私的心胸点赞。

美中不足的是:作者虽然将代码开源,但是在论文介绍架构原理的时候比较模糊,特别是对一些重要改进,基本上是一笔带过。

现在在网络上有很多关于 YOLO 原理的讲解,个人感觉讲得不是很清楚,总感觉有点知其然而不知其所以然。比如:

yolo 是在什么背景下出现的?

v1 是在哪个经典网络架构上发展起来的?解决了什么问题?又存在什么问题?

v2 针对v1的缺点做了哪些改进?改进后效果怎么样?又存在什么问题?

v3 针对v2的缺点做了哪些改进?

这些问题不搞清楚,我觉得对 yolo 就谈不上真正的理解。废话不多说,下面就来介绍 yolo 的技术演进。

 

2. YOLO(v1,v2,v3)的技术演化

问题1:yolo v1是在什么背景下出现的?

yolo v1是在 R-CNN 基础上发展起来的。

R-CNN(region proposals + cnn),采用卷积神经网络进行目标检测的开山之作。

 

 

主要思想:对输入图片采用selective search 搜索查询算法,提取出大约 2000 个人眼感兴趣的候选边框,然后每个边框都通过一个独立的

卷积神经网络进行预测输出,后面再加上一个SVM(支持向量机)预测分类。

优点:位置检测与对象分类准确率非常高。

缺点:运算量大,检测速度非常慢,在 GPU 加持下一帧检测时间要 13s 左右,这在工程应用上是不可接受的。

造成速度慢的原因主要有 2 个:

> 用搜索查询算法提取 2000 个候选边框

> 每个候选边框都采用一个独立的CNN通道,这意味着卷积核的参数和全连接的参数都是不一样的,总的参数个数是非常恐怖的。

针对这个缺点,yolo v1 做了哪些改进呢。

 

 

上面的图片是官网论文给出的结构图,但是个人感觉画得不太好,它容易让人误认为对输入图片进行网格化处理,每个网格化的小窗口是 7*7。

真实情况是,由最终输出是 7*7*30 大小代表的物理含义是:你可以把输入图片看成是经过了网格化(grid cell 7*7),每个网格化后的小窗口通过 CNN 预测出 1*30。

这里可能有点不好理解。总之一句话,在真正网络架构流程中,没有对输入图片进行任何网格化处理。

 

v1 改进点:

> Backbone: googLeNet22 (采用googLeNet22层卷积结构)

> 输入图片只处理一次(yolo名称的由来),通过多个卷积层提取不同的特征,每次卷积的时候共享卷积核参数。

输入图片只处理一次:表示输入图片只在第一次卷积的时候作为输入进行卷积运算,第一次卷积后的输出作为第二次卷积的输入,通过多个卷积层递进的方式来提取不同的特征。

并且这些特征通过的CNN通道都是相同的,从而可以共享卷积核参数。

> 每个 3*3 卷积核前面引入了 1*1 卷积核,作用有两个,一是提取更丰富的特征,二是减少卷积核的参数个数。

大家可能对减少卷积核参数个数的作用比较难以理解,这里举个例子。

比如输入图片大小是 56*56*256 最终转化的目标大小是 28*28*512。

直接卷积:56*56*256 & 3*3*256*512 -> 56*56*512 & pooling -> 28*28*512

卷积核参数:3*3*256*512 = 1179648

引入 1*1 卷积:56*56*256 & 1*1*256*128 -> 56*56*128 & 3*3*128*512 -> 56*56*512 & pooling -> 28*28*512

卷积核参数:1*1*256*128 + 3*3*128*512 = 622592

经过改进后,图片检测速度非常快,基本上可以达到实时。但是缺点是位置检测准确度低,并且不能检测出小对象物体。

针对 v1 的缺点,v2 做了哪些改进呢?

v2 改进点:

 

 

 

 

> Backbone:darknet19 (采用darknet 19层卷积结构)

> 输入图片批归一化处理(BN),作用是降低不是重要特征的重要性。

这句话可能听得有点晕,举个例子,

你的样本里有两个特征列,一个特征列的数值在[1,10]范围内,另一个特征列的数值在[1000,10000]范围内,

但是真实情况是,你的这两个特征列重要性可能是一样的,只不过你拿到的数据就是这样的,我们知道,

卷积神经网络训练,实质就是一系列数值运算的过程,如果你将这两个特征列直接通过卷积神经网络进行训练,

那最终生成的模型准确率肯定是不高的,所以需要进行归一化处理,将数值归一化到[0,1]范围内,

从而使损失能量在收敛的时候更加平稳。

> 采用 passthrough 算法,解决池化信息丢失的问题,增加细粒度特征的检测(小对象)。

 

 

passthrough 算法主要是为了解决 pooling(池化)的缺点,不管是最大值池化,还是平均值池化,都有一个很明显的问题,

就是会造成信息丢失,passthrough 主要思想是在池化之前,将输入信息进行拆分,一拆为四,经过拆分后的大小就和池化后的输出大小相同,

然后叠加,叠加后的结果主要就是维度变化,这样就能解决池化会造成信息丢失的问题。

> 去掉全连接(FC),将输入图片拉伸(resize)到不同尺寸然后通过卷积神经网络,这样就得到了多尺寸的输出,从而能提升对不同大小对象的预测准确度。

全连接其实就是矩阵乘法运算,矩阵乘法有一个前提,矩阵 A 的列必须与矩阵 B 的行个数相同,否则是不能进行矩阵乘法运算的。

全连接的参数大小是固定的,那么你的输入大小自然就固定了,这样就无法实现多尺寸的输出,所以这里去掉了全连接层。

经过改进后,精度提升明显,特别是对小对象的检测,缺点是对小对象检测准确度不高。

针对 v2 的缺点,v3 又做了哪些改进呢?

v3 改进点:

 

 

上面是 v3 的结构图,是我跟踪代码,查找资料,绘制这张图真心不容易,正确性绝对有保证,大家如果觉得这张图对你理解 yolo 有帮助,麻烦点个赞。

输入大小这里是416*416,输出13*13,26*26,52*52,这里一般要求输入图片大小是 32 的倍数,因为整个卷积神经网络会将图片缩小32倍,16倍,8倍,

这里取最大公倍数32。 123 = 3*(边框坐标 4 + 置信度 1 + 类对象 36)。

> Backbone: darknet53 (采用darknet 53层卷积结构,实际是52层卷积,去掉了全连接层)

可以看出 v3 的卷积层数大约是 v2 的 2.8倍,有个潜在的共识:增加模型准确率的一个直接做法是增加网络的深度和厚度,

(深度是指卷积层数,厚度指卷积核的维度或者是种类数),这里作用自然就是提升精度了。

> 用卷积取代池化

之前我们提到过池化的问题,会造成信息丢失,这里用卷积来实现池化的功能(使图片大小缩小2倍),同时不会造成信息的明显丢失。

> 采用残差网络(resnet)防止梯度消失

梯度消失或者梯度爆炸是在深层的卷积神经网络中才有可能出现的,梯度的计算是通过链式求导得到的,随着网络层的增加,链式求导项就会越来越长,

因为在每一层卷积后的输出都做了归一化处理,所以梯度只会越来越小,有可能为0,而0在后面模块运算中都为0,这样导致的直接后果是:

损失能量在收敛到某一阶段后就停止收敛,最后生成模型的精度自然就不高。而这里采用残差网络就能防止梯度消失,v3 结构图里左下角就是残差网络的结构图。

残差网络的思想:每次卷积后的输出当做残差,将卷积前的输入与残差融合,作为整个输出,即使残差为0,整个输出也不会为0。

从残差网络结构图可以看出,每个3*3卷积核前都引入了1*1卷积,这里保留了 v1 的优秀思想。

从 v3 的结构图可以看出,darknet53网络骨架里大量的引入了残差网络的思想。

> 使用空间金字塔池化网络算法(sppnet spatial pyramid pooling)实现多尺寸的输出

空间金字塔池化网络算法主要思想:不同尺寸的输入通过sppnet模块后生成一个固定尺寸的输出。

在 v3 结构图里,有两个地方用到这个思想:

一个是 13*13*512 经过 1*1 卷积,改变特征维度,变成 13*13*256,经过上采样(upsample,这里采用相邻像素插入算法),

改变特征尺寸,变成 26*26*256,然后与 26*26*512 叠加,生成 26*26*768。

另一个是 26*26*256 与 52*52*256 叠加后生成 52*52*384。

v3 的多尺寸输出与 v2 的多尺寸输出有本质不同,v2多尺寸输出是对输入图片拉伸到不同的尺寸,然后通过卷积神经网络得到不同的输出,

但是这样就存在一个图片失真的问题,因为你是对图片进行的拉伸处理。而 v3 通过sppnet实现的多尺寸输出,就能有效避免图片失真的问题。

> 13*13*123,26*26*123,52*52*123物理意义

 

 

这里用 v1 版本论文图片来解释,物理意义:

表示将输入图片网格化,有 13*13,26*26,52*52 大小,每个网格化的小窗口(grid cell)预测 3 个边框(bounding box),

每个边框包含 4 个位置坐标,1个置信度,36个对象种类。

123 = 3 *(4 + 1 + 36)

这里就存在一个问题:预测输出如此之多,直接用于损失能量的计算,运算量岂不是很恐怖?

确实是这样,所以这里先经过下面的两个步骤的处理:

(1)每个小窗口只取置信度最大的边框,因为yolo规定,只能有一个真实的对象中心坐标属于每个小窗口。

这样,就得出 13*13*3*41 => 13*13*41,26*26*3*41 => 26*26*41,52*52*3*41 => 52*52*41

13*13*41,26*26*41,52*52*41 表示一个真实对象有很多预测重叠边框,比如说上面图里属于狗的预测边框非常多,

但是我们只需要预测最准确的边框,去掉其他属于狗的重叠边框。

(2)采用NMS(非极大值抑制算法)去除重叠边框。

这样 13*13*41,26*26*41,52*52*41 => N*41 (N表示不同对象预测数目,比如说上面图理想情况下,N = 3)。

> 损失能量(采用交叉熵)

 

 

损失能量的计算是v1版本提出来的,这里放到了 v3 来说,有3个改进点:

(1)将位置检测与对象识别作为一个整体,进行训练预测,这从损失能量的计算可以直接反应出来。

(2)位置的宽度和高度先开根号,与归一化的作用相同,降低不是重要特征的重要性。

(3)增加权重参数  ,当边框预测出含有对象时,增大它的权重值,当边框预测出不含有对象时,减小它的权重值,这样就能使损失能量计算更准确。