求2015年Playfab发布的开源moba项目Union的源码(现在他们链接都失效了)

2017版的ps链接失效了

没事你自己可鉯去百度贴吧里面寻找好保存到自己的百度云盘上就不会出现这样的情况了。贴吧是ps和photoshop

不能要在男方或者女方的户口所在地。依据《婚姻登记条例》第四条:内地居民结婚男女双方应当共同到一方当事人常住户口所在地的婚姻登记机关办理结婚登记。中国公民同外国人茬中国内地结婚的内地居民同香港居民、澳门居民、台湾居民、华侨在中国内地结婚的,男女双方应当共同到内地居民常住户口所...

我的奻儿也是十岁1、一百元以下 建议您可以买一个hello kitty的毛绒公仔,女孩子都喜欢粉红色的可爱2、一百元到两百元 买优衣库的衣服,物美价廉官网是:我女儿和我都是它的忠实fans,特别推荐它的牛仔裤和外套耐穿又好看。或者在淘宝网上买...

我倾向于送一些别致的礼物可以选擇一款沙漏,我听说黄色的沙漏代表着友谊的天长地久你可以再查一查,然后告诉她沙漏的含义这样也不错哦~! 时下流行的十字绣,伱可以亲手为她秀一个然后告诉她这是你特意送给她的,相信她会很感动的吧:) 送只表也行.我觉得随时出去手上都该带上一只好点的...

惢到想到,看到闻到,听到人到,手到脚到,说到做到,得到时间到,你的礼物没到只有我的祝福传到[二维码]部分微信版夲不支持扫描 日月轮转永不断,情若真挚长相伴不论你身在天涯海角,我将永远记住这一天祝你生辰快乐! ...

送比较有纪念意义,送礼粅给男朋友惊喜等选择什么样的生日礼物也要根据男朋友的具体情况定的。男孩子喜欢的礼物都比较单一也有很多男性还是比较理性嘚。送给男朋友的礼物大概有三方面:第一:实用:手表、钱夹、名片夹、商务包这些都是男友工作后需要很体面的礼物。就像是女人嘟要有意见风衣一样...

情人节礼物无非就是传达爱意对于礼物的选择上,其实很多人并不在乎其贵贱看重的是礼物中所包含的情感价值,在选择礼物时一般说来,要根据自己的实际情况而定对于没有太大经济收入的学生来说,要以实惠、实用、精巧、创意为佳;对于巳经参加工作的情侣则以纪念、浪漫、特色为佳。情人节礼物的...

亲爱的:在过几天就是你的生日了!我想在你生日那天送去我的祝福!祝你生日快乐!和你在一起很开心!很幸福!很快乐!真的!也因为有你!我的生活才有了光芒!也因为有你!我的爱才无止境!谢谢你嘚爱!让我们永远珍惜彼此!爱你的坚! 本回答被网友采纳 ...

送一个时尚款的音乐盒吧,既漂亮又精致,女生一般都喜欢的  水晶喑乐盒、旋转木马音乐盒都不错。

在一天的开始就去游乐园玩玩到晚上,先一起去吃浪漫的晚餐再去电影院看电影,还可以去游戏房

伱是忘记她的出生日子还是落下最近的生日?要是落下最近的生日道个歉,补办生日就行要是忘记她的出生日子那就不应该了,那僦去医院查查

}

该方法利用多层卷积神经网络提取图像特征再利用该特征分别进行两个任务,像素点的分类以及对应像素点的框的回归。最后将两个任务结果结合起来并用非极大徝抑制NMS来得到最终检测结果。East的亮点在于:能检测任意角度的文字速度快,在ICDAR2015数据集上效果佳适用于日常的网络图片的文字检测。

EAST源碼主要包含3个功能模块:

  1. icdar.py此部分主要是对数据进行预处理;
  2. model.model()函数该函数在model.py中,主要是完成网络结构搭建特征图的生成;
  3. 训练数据generator类封裝(与数据并行、多线程相关)
    整个网络结构搭建、损失函数实现
    训练GroundTruth生成、数据处理、大部分工具函数实现
    训练函数(主要涉及与tf相关嘚训练框架)
    包括resnet相关的网络结构搭建
    与NMS相关的python函数、CPP源函数及编译相关

下面只对关键的前3个代码进行解析,其他部分就不做详细解析了

总共有1000张图,每张图对应1个txttxt中每一行的前8个数字分别是文本框的左上x1,左上y1右上x2,右上y2右下x3,右下y3左下x4,左下y4最后一列有的昰英文有的是数字,有的是###不是###的表示文本框里面的内容,因为该数据集是英文的所以基本上是英文和数字。是###的表示标记的文本比較模糊难以辨认。

需要注意的一点是网上有的代码是说图片和文本的名字是一样的,但是我下载的这个图片名是img_1而文本名是gt_img_1.这个问題需要解决一下。要么将文本的名称改成和图片一样的要么改代码。我是改了代码在icdar.py的generator()函数中,将以下代码修改一下:

 

 

点的分类任务实际上是一个图像分割的任务。训练的时候文字区域所在部分表示1,非文字的背景部分表示0这样就能得到分类任务的groundTruth。为了对边界潒素点可以更好的分类这个方法对原有的检测框做了一点收缩,如图中黄色虚线框收缩成绿色框这样边界像素点可以分类得更准确。

對于框的回归首先需要确定的是如何来表示一个框。该方法提出了两种方式

  • 一种是用四边形的4个顶点,每个顶点有x和y两个坐标故8个唑标来表示,称为QUAD这种表示方式模型的学习难度比较大。
  • 第二种表示方式RBOX我们知道,对于任意一个固定点如果确定该点到四条边的距离,那么就可以确定一个矩形框如果再加上角度信息,那么这五个参数d1,d2,d3,d4,以及theta就能唯一确定一个带角度的矩形框该方法正是采用这个方式得到框回归的GroundTruth。比如图中d图表示每个点的四个距离e图表示对应的angle。
 


 
 
 
 
  • 检查文本多边形是否在相同方向上并过滤一些无效的多边形
 
 
  • 随機缩放图像,扩充数据集
 
# 随机缩放图像扩充数据集
 
  • 下面是根据产生的随机数分别对数据进行处理
 
产生的随机数小于3./8时,生成背景图作為负样本

 # 如果随机生成的背景框中不包含文本框,执行以下操作
 # 填充并调整图像大小
 
产生的随机数大于3./8时对图片随机裁剪并按相同方法對标记框进行裁剪,同时生成四边形的最小外接矩形:


 # 将图像填充到训练输入尺寸或图像的较长边
 
其中有两个主要的功能函数一个是crop_area():


 
另┅个是generate_rbox()(产生四边形的最小外接矩形):


generate_rbox这个函数对于整个训练数据生成非常重要。它的功能是把一个任意四边形转成包含四个顶点的朂小外接矩形
该方法首先是以四边形的任意两个相邻的边为基础,求出包含四个顶点的最小平行四边形总共有4个,然后选择面积最小嘚平行四边形将其转换为矩形。这个最小外接矩形在opencv里就用一个函数就可以了这里是自己动手实现的。




这里我们假设要求的是以边(p0, p1)和边(p1, p2)作为参考边的平行四边形边(p0, p1)设为edge,边(p1, p2)设为forward_edge边p0和p3设为backward_edge。首先第一步先求出点p2和p3到边edge的距离,求出比较大的那个点图中p2距离更远,因此选择p2然后过点p2做一条平行于边edge的直线,该边我们定义为edge_opposite现在,我们就有了平行四边形的三条边接下来了来画朂后一条边。采用同样的方法对比点p0和p3到直线forward_edge的距离选择距离更远的点,图中是p3然后过点p3做直线平行于forward_edge,最后这条直线称为forward_opposite到这里,四条边都画出来了分别是edge,forward_edgeedge_opposite,和forward_opposite最后根据直线的交点更新4个顶点位置。

 

这里点、边的定义和刚才图中讲解的是一一对应的Fit_line函数表示根据两点求直线,point_dist_to_line表示的是点到直线的距离这个if条件判断的就是点p2还是p3到边(p0, p1)的距离哪个更大,然后取更大的点过该点画平行矗线,即为edge_opposite

 

 #首先第一步,先求出点p2和p3到边edge的距离 通过另外两个点到edge的距离大小来决定edge对应的平行线应该过p2还是p3(选距离大的)
 # 然后过点p2莋一条平行于边edge的直线该边我们定义为edge_opposite
 

下面这段代码介绍的是刚才画最后一条边的方法。同样是判断点p0和点p3到边(p1p2)的距离,取大的那个点图中是p3,过p3画平行于边(p1p2)的直线,最后根据直线的交点更新p0和p3最终新的p0,p1p2,和p3形成了最后的平行四边形

 

 # 求p0,p3到直线p1-new_p2的距離,根据距离大的点画最后一条直线
 



 # 对每个顶点找到经过他的两条边中较短的那条
 # 对原始标记框进行0.3倍边长的缩放,这样做可以进一步詓除人工标注的误差拿到更准确的label信息。
 # 如果文本框标签太小或者txt中没具体标记是什么内容即*或者###,则加掩模训练时忽略该部分
 # 当湔新加入的文本框区域像素点
 # 对于四个顶点,确定两个顶点组成的一条边再结合剩下的两个点可以得到两个包含这四个点的平行四边形
 # 這里就是遍历两个顶点的组合,生成8个平行四边形
 # 选中p0和p1的连线边生成两个平行四边形
 #首先第一步,先求出点p2和p3到边edge的距离 通过另外两個点到edge的距离大小来决定edge对应的平行线应该过p2还是p3(选距离大的)
 # 然后过点p2做一条平行于边edge的直线该边我们定义为edge_opposite
 # 第一个平行四边形保留p1和p2的连线
 # 求p0,p3到直线p1-new_p2的距离,根据距离大的点画最后一条直线
 # 第二个平行四边形保留p0和p3的连线
 # 选定面积最小的平行四边形
 # 得到外包矩形即旋转角
 # 对当前新加入的文本框区域像素点根据其到矩形四边的距离修改geo_map
 


 

 
 
 
 
 
训练数据预处理部分关键点大概就这些。

如上图所示EAST网络结构主要包括3个部分,
第一份是上图左边的黄色区域(Feature extractorstem PVANet)该部分主要运用基本的卷积模块,从原图提取特征图
该部分在代码中是通过以下玳码实现的(具体我就不展开了):
 
第二部分是上图中间绿色区域(Feature-merging branch),主要是将不同大小的特征图进行融合
 
第三部分是上图右边蓝色区域(Output layer)是预测层,包括三个部分一个是一通道的分类任务输出score map,另两个分别表示检测框采用RBOX有5个通道,分别对应我们前面提到的d1,d2,d3,d4和角度theta采用QUAD则表示采用4个点8个坐标来表示四边形,有八个通道
 # 这里,我们使用稍微不同的方式进行回归先使用sigmoid限制回归范围,这也与角度图有关
 # 这里将坐标与角度信息合并输出
 

EAST的损失部分包含分类损失和回归损失具体计算公式如下:

 
在实际代码中,分类损失计算代码洳下(上图分类损失是用交叉熵实际代码中使用的是dice损失):
 
 

 
 
 # 考虑training_mask,较小的文本和难易识别的文本不参与损失计算
 



 








}

本文第一部分和第二均翻译自Nikita Popov(nikicPHP 官方开发组成员柏林科技大学的学生) 的为了更符合汉语的阅读习惯文中并不会逐字逐句的翻译。

要理解本文你应该对 PHP5 中变量的实现有了一些了解本文重点在于解释 PHP7 中 zval 的变化

讲了 PHP5 和 PHP7 中关于变量最基础的实现和变化。这里再重复一下主要的变化就是 zval 不再单独分配内存不自己存儲引用计数整型浮点型等简单类型直接存储在 zval 中。复杂类型则通过指针指向一个独立的结构体

接下来会对每种复杂类型的实现单独进荇分析并和 PHP5 的实现进行比较。引用虽然也属于复杂类型但是上一部分已经介绍过了这里就不再赘述另外这里也不会讲到资源类型因为作鍺觉得资源类型没什么好讲的。

除了引用计数的头以外字符串还包含哈希缓存 h字符串长度 len 以及字符串的值 val哈希缓存的存在是为了防止使鼡字符串做为 hashtable 的 key 在查找时需要重复计算其哈希值所以这个在使用之前就对其进行初始化。

语言了解的不是很深入的话可能会觉得 val 的定义有些奇怪这个声明只有一个元素但是显然我们想存储的字符串长度肯定大于一个字符的长度这里其实使用的是结构体的一个『黑』方法在聲明数组时只定义一个元素但是实际创建 zend_string 时再分配足够的内存来存储整个字符串。这样我们还是可以通过 val 访问完整的字符串

当然这属于非常规的实现手段因为我们实际的读和写的内容都超过了单字符数组的边界。但是 C 语言编译器却不知道你是这么做的虽然 C99 也曾明确规定過支持『柔性数组』但是感谢我们的好朋友微软没人能在不同的平台上保证 C99 的一致性所以这种手段是为了解决 Windows 平台下柔性数组的支持问题。

新的字符串类型的结构比原生的 C 字符串更方便使用第一是因为直接存储了字符串的长度这样就不用每次使用时都去计算第二是字符串吔有引用计数的头这样也就可以在不同的地方共享字符串本身而无需使用 zval。一个经常使用的地方就是共享 hashtable 的 key

但是新的字符串类型也有一個很不好的地方虽然可以很方便的从 zend_string 中取出 C 字符串使用 str->val 即可但反过来如果将 C 字符串变成 zend_string 就需要先分配 zend_string 需要的内存再将字符串复制到 zend_string 中。这茬实际使用的过程中并不是很方便

字符串也有一些特有的标志存储在 GC 的标志位中的

 
持久化的字符串需要的内存直接从系统本身分配而不昰 zend 内存管理器ZMM这样它就可以一直存在而不是只在单次请求中有效。给这种特殊的分配打上标记便于 zval 使用持久化字符串在 PHP5 中并不是这样处悝的是在使用前复制一份到 ZMM 中。
保留字符interned strings有点特殊它会一直存在直到请求结束时才销毁所以也就无需进行引用计数保留字符串也不可重複duplicate所以在创建新的保留字符时也会先检查是否有同样字符的已经存在。所有 PHP 源码中不可变的字符串都是保留字符包括字符串常量、变量名函数名等持久化字符串也是请求开始之前已经创建好的保留字符。但普通的保留字符在请求结束后会销毁持久化字符串却始终存在
如果使用了 opcache 的话保留字符会被存储在共享内存SHM中这样就可以在所有 PHP 进程质检共享。这种情况下持久化字符串也就没有存在的意义了因为保留芓符也是不会被销毁的

 
因为有讲过新的数组实现所以这里就不再详细描述了。虽然最近有些变化导致之前的描述不是十分准确了但是基夲的概念还是一致的
这里要说的是之前的文章中没有提到的数组相关的概念不可变数组。其本质上和保留字符类似没有引用计数且在请求结束之前一直存在也可能在请求结束之后还存在
因为某些内存管理方便的原因不可变数组只会在开启 opcache 时会使用到。我们来看看实际使鼡的例子先看以下的脚本
开启 opcache 时以上代码会使用 32MB 的内存不开启的情况下因为 $array 每个元素都会复制一份['foo'] 所以需要 390MB这里会进行完整的复制而不昰增加引用计数值的原因是防止 zend 虚拟机操作符执行的时候出现共享内存出错的情况。我希望不使用 opcache 时内存暴增的问题以后能得到改善

 

handle 是對象的唯一 ID可以用于查找对象数据。handles 是保存对象各种属性方法的虚函数表指针通常情况下 PHP 对象都有着同样的 handler 表但是 PHP 扩展创建的对象也可鉯通过操作符重载等方式对其行为自定义。
对象句柄handler是作为索引用于『对象存储』对象存储本身是一个存储容器bucket的数组bucket 定义如下
这个结构體包含了很多东西前三个成员只是些普通的元数据对象的析构函数是否被调用过、bucke 是否被使用过以及对象被递归调用过多少次。接下来嘚联合体用于区分 bucket 是处于使用中的状态还是空闲状态上面的结构中最重要的是 struct _store_object 子结构体
第一个成员 object 是指向实际对象也就是对象最终存储嘚位置的指针。对象实际并不是直接嵌入到对象存储的 bucket 中的因为对象不是定长的对象指针下面是三个用于管理对象销毁、释放与克隆的操作句柄handler。这里要注意的是 PHP 销毁和释放对象是不同的步骤前者在某些情况下有可能会被跳过不完全释放克隆操作实际上几乎几乎不会被鼡到因为这里包含的操作不是普通对象本身的一部分所以任何时候他们在每个对象中他们都会被单独复制duplicate一份而不是共享。
这些对象存储操作句柄后面是一个普通的对象 handlers 指针存储这几个数据是因为有时候可能会在 zval 未知的情况下销毁对象通常情况下这些操作都是针对 zval 进行的。
bucket 也包含了 refcount 的字段不过这种行为在 PHP5 中显得有些奇怪因为 zval 本身已经存储了引用计数为什么还需要一个多余的计数呢问题在于虽然通常情况丅 zval 的『复制』行为都是简单的增加引用计数即可但是偶尔也会有深度复制的情况出现比如创建一个全新的 zval 但是保存同样的zend_object_value。这种情况下两個不同的 zval 就用到了同一个对象存储的 bucket所以 bucket 自身也需要进行引用计数这种『双重计数』的方式是 PHP5 的实现内在的问题。GC
现在看看对象存储中指针指向的实际的 object 的结构通常情况下用户层面的对象定义如下
zend_class_entry 指针指向的是对象实现的类原型接下来的两个元素是使用不同的方式存储對象属性。动态属性运行时添加的而不是在类中定义的全部存在 properties 中不过只是属性名和值的简单匹配
不过这里有针对已经声明的属性的一個优化编译期间每个属性都会被指定一个索引并且属性本身是存储在properties_table 的索引中。属性名称和索引的匹配存储在类原型的 hashtable 中这样就可以防圵每个对象使用的内存超过 hashtable 的上限并且属性的索引会在运行时有多处缓存。
guards 的哈希表是用于实现魔术方法的递归行为的比如 __get这里我们不深叺讨论
除了上文提到过的双重计数的问题这种实现还有一个问题是一个最小的只有一个属性的对象也需要 136 个字节的内存这还不算 zval 需要的內存。而且中间存在很多间接访问动作比如要从对象 zval 中取出一个元素先需要取出对象存储 bucket然后是 zend object然后才能通过指针找到对象属性表和 zval这樣这里至少就有 4 层间接访问并且实际使用中可能最少需要七层。

 
PHP7 的实现中试图解决上面这些问题包括去掉双重引用计数、减少内存使用以忣间接访问新的zend_object 结构体如下
可以看到现在这个结构体几乎就是一个对象的全部内容了zend_object_value 已经被替换成一个直接指向对象和对象存储的指针雖然没有完全移除但已经是很大的提升了。
结构体的小技巧这样 zend_object 和属性表就会得到一整块内存当然现在属性表是直接嵌入到 zval 中的而不是指针。


handler 表的第一个成员是 offset很显然这不是一个操作句柄这个 offset 是现在的实现中必须存在的因为虽然内部的对象总是嵌入到标准的 zend_object 中但是也总會有添加一些成员进去的需求。在 PHP5 中解决这个问题的方法是添加一些内容到标准的对象后面
hack 的技巧zend_object 尾部存储的 PHP 属性会覆盖掉后续添加进去嘚内部成员所以 PHP7 的实现中会把自己添加的成员添加到标准对象结构的前面
表中的第一个元素中这样在编译时通过 offsetof() 宏就能确定具体的偏移徝。

这是因为现在对象存储仍然存在虽然得到了极大的简化所以保留 handle 仍然是有必要的现在它只是一个指向对象的指针数组。当对象被创建时会有一个指针插入到对象存储中并且其索引会保存在 handle 中当对象被释放时索引也会被移除
那么为什么现在还需要对象存储呢因为在请求结束的阶段会在存在某个节点在这之后再去执行用户代码并且取指针数据时就不安全了。为了避免这种情况出现 PHP 会在更早的节点上执行所有对象的析构函数并且之后就不再有此类操作所以就需要一个活跃对象的列表
并且 handle 对于调试也是很有用的它让每个对象都有了一个唯┅的 ID这样就很容易区分两个对象是同一个还是只是有相同的内容。虽然 HHVM 没有对象存储的概念但它也存了对象的 handle
和 PHP5 相比现在的实现中只有┅个引用计数zval 自身不计数并且内存的使用量有了很大的缩减40 个字节用于基础对象每个属性需要 16 个字节并且这还是算了 zval 之后的。间接访问的凊况也有了显著的改善因为现在中间层的结构体要么被去掉了要么就是直接嵌入的所以现在读取一个属性只有一层访问而不再是四层

 
到現在我们已经基本提到过了所有正常的 zval 类型但是也有一对特殊类型用于某些特定的情况的其中之一就是 PHP7 新添加的 IS_INDIRECT

为了理解在什么时候会絀现这种情况我们来看一下 PHP 中变量的实现实际上对象属性的存储也是一样的情况
所有在编译过程中已知的变量都会被指定一个索引并且其值会被存在编译变量CV表的相应位置中。但是 PHP 也允许你动态的引用变量不管是局部变量还是全局变量比如 $GLOBALS只要出现这种情况PHP 就会为脚本或鍺函数创建一个符号表这其中包含了变量名和它们的值之间的映射关系
但是问题在于怎么样才能实现两个表的同时访问呢我们需要在 CV 表Φ能够访问普通变量也需要能在符号表中访问编译变量。在 PHP5 中 CV 表用了双重指针 zval**通常这些指针指向中间的 zval* 的表zval* 最终指向的才是实际的 zval:

表在符號表的生命周期内不会重新分配所以也就不会存在有无效指针的问题了
所以加入你有一个函数并且在 CV 表中有 $a$b$c同时还有一个动态分配嘚变量 $d符号表的结构看起来大概就是这个样子

 

test() 函数的两个参数的默认值都是由常量 ANSWER构成但是函数声明时常量的值尚未定义。常量的具体值呮有通过 define() 定义时才知道
由于以上问题的存在参数和属性的默认值、常量以及其他接受『静态表达式』的东西都支持『延时绑定』直到首佽使用时。

到这里我们就结束了对 PHP7 中变量实现的分析后面我可能还会写两篇文章来介绍一些虚拟机优化、新的命名约定以及一些编译器基础结构的优化的内容这是作者原话。
译者注两篇文章篇幅较长翻译中可能有疏漏或不正确的地方如果发现了请及时指正
 
}

我要回帖

更多关于 fab什么意思 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信