All Posts

Discuz! Q的搜索引擎优化(SEO)攻略

Discuz! Q目前版本对搜索引擎的内容索引还不是很好,前后端分离的单页程序在没有针对搜索引擎优化时(可行的优化包括服务端渲染或静态化),搜索引擎目前只能抓取到一个默认的前端模版,所以你会看到你的页面被搜索引擎索引后显示的是 “## Build Setup” 这样的默认index前端模版上的description meta标签里内容。 为了让搜索引擎能覆盖更多的小番麻友圈的内容,从而给站点带来精准的搜索流量,我尝试对Discuz! Q做了一些搜索引擎优化(主要是内容索引覆盖方面),这里介绍一下。 我们先来看看做了优化后在各个搜索引擎索引的效果: 微软Bing搜索: Google搜索: 百度搜索: 原文首发于小番麻友圈。 我们可以看到,在做了优化后,一方面搜索引擎可以更准确的描述每个页面的内容(标题,描述),另一方面网站可被索引的页面也大大增加了。目前优化刚刚上线几天,微软Bing搜索和Google的爬虫很快就爬到了大部分页面,而百度的爬虫更新则比较慢只更新了一部分(当然更新速度也跟站点的权重有关,更新:两周后索引有较大增加),但也可以看到首页的索引已经被更新为我们希望的标题和描述不再是## Build Setup了。 下面介绍一下优化的方法。由于Discuz! Q目前还没有开源,为了避免后续版本更新带来的合并代码的困难,我这次的优化没有直接在Discuz! Q上改,而是单独做成了一个discuzQ_seo_app。我把代码放在github上开源出来,如果你有同样的需求也可以使用:https://github.com/Jamesweng/discuzQ_seo_app 优化这块我的思路 这是一项针对搜索引擎的优化,并非面向终端用户的功能。代码方面能够尽量分离避免太大的耦合,可以减少后续两方面(面向搜索引擎/面向用户)的维护成本。所以在实现上我采用了API对接的方式。discuzQ_seo_app这个面向搜索引擎的程序,只依赖于Discuz! Q的列表/详情等几个数据API接口,自行后端渲染出适合搜索引擎阅读的页面。在顶层流量分发方面,从nginx里分出搜索引擎的流量(识别user-agent),将搜索引擎的流量导向discuzQ_seo_app,而正常的用户流量导向Discuz! Q服务。 discuzQ_seo_app的部署使用方法

教会AI认识麻将牌之实践篇

开头视频先认识下今天的主角 -【小番】App (谢谢周董的新歌《Mojito》) 说起打麻将我一直是处于比较业余并且不思进取的水平,各个地方的麻将规则不一,繁琐的规则也懒得放脑袋里记忆了,于是每次跟朋友打麻将都是现场临时约定规则,怎么简单怎么来,周边也有不少年轻的小伙伴我一样。 年前回家前跟朋友聚会又打了几圈麻将,几个人又经历了一遍边上网查算番规则边打牌,生怕少算番多亏了五毛钱的过程,于是萌生做个麻将算番APP的想法,解决我们几个懒人的打牌需求。 当时趁着那几天想法热乎,花了一周多撸了一个iOS App 取名叫【小番】就给弄上架了(第一次写swift,发现居然有双感叹号!!这样的运算符,当时我就惊呆了)。小番使用国标规则来算番, 最大番数88番,当一副牌有多种胡法时取最大番数的胡法(基本牌划分的动态规划怎么写来着?),其中各种特殊规则wikipedia里可以写出满满几屏,照着学了一遍。一开始我们就对【小番】的需求比较明确, 把在线麻将游戏的便捷性融入到线下朋友间社交打牌欢乐里 。所以【小番】刚诞生就带了一副AI的眼睛,以便更快更好的服务好大家。 刚开始的【小番】认识麻将牌的能力一般,70%左右。基本上摄像头识别完还需要手动再补上几张牌,所谓人工+智能结合。AI模型准备上我只是做完一次目标检测深度学习模型的数据采集,标注,训练,评估及移动端推理的实现流程。中间没有太多优化,本着先看看有多少人愿意为这项功能买单的想法,把App撸完就上架了😁。 App出来后碰上疫情期间大家也都家里呆着了,App好久也没实践上,中间去江西朋友家呆了一段时间打牌用了一次,发现一些易用性的问题修正了一下,在统一算番规则方面【小番】发挥了实际作用起到了公平公正的效果(让我当晚输了100块钱)。App上架后忙别的事情有段时间也没多管了。最近各地疫情反复,周末看了一下App Store排行榜,发现在没有任何推广的情况下,小番最近还爬到过娱乐版前50名内,改变了我对目前的应用市场没有推广不会有人购买的看法。于是周末花了点时间再好好优化了一把模型,把【小番】识别牌的精准度提到98%以上。 优化后的【小番】,即使是带有一定透视角度的,20多张不同牌同屏也可以一次轻松识别,做到快速认牌算番的效果。行文至此,好玩的东西就介绍完了。各位看官, 目前【小番】新版本上线,特价2折优惠活动中 ,赶紧App Store搜索下载一个收藏起来 ,以备逢年过节打牌使用吧😁(近30层深度神经网络,平均每层不到3毛钱哦)。 下面进入技术干货的部分,实践中怎么提高模型麻将牌识别的精确度和召回率?行业内的人清楚,AI模型是容易做出demo,但产品化过程中需要投入非常多精力打磨的一项技术。以前做个性化推荐和定向广告推荐,深知数据的优化对效果的作用远大于算法自身形式的优化作用。所以这次在模型效果打磨的过程中,我优先着重考虑数据方面的优化。 问题定义 麻将牌识别是一类目标检测问题(Object Detection),目标检测与只输出单一标签的图像分类问题(Image Classification)不同,目标检测问题的输出包含两个信息:图片中可能包含的多个物体的位置,以及各自的分类标签。麻将牌识别在目标检测问题里属于多个小目标(目标相对于完整图像大小)的同时检测,含34个分类(不计花牌),需要考虑不同灯光亮度,投影角度,桌面背景,麻将牌面样式变化下的识别。类似的,自动驾驶的视觉感知部分也包含了一些目标检测(红绿灯,车辆,雪糕筒等)问题。 目标检测算法 解决目标检测算法的常见模型主要分为两类,以R-CNN/Fast R-CNN/Faster R-CNN为代表的两步法:先用启发式搜索(R-CNN/Fast R-CNN)的算法或者特定的网络(Faster R-CNN)找出图片中可能的物体区域(region proposals),然后用卷积神经网络对各个物体区域做一次图像分类。Faster R-CNN可以做到比较高的精确度检测目标,但检测延迟方面比较高,不适于需要视频实时检测的场景。 另一类算法是以SSD(Single Shot MultiBox Detector)和YOLO(You Only Look Once)为代表的一步检测法,这类算法将位置检测的外包矩形和分类概率统一编码到一个卷积神经网络预测输出里。具体的,图像可以以一定的步长划分成格子,每个格子关联几个(比如6个)不同比例的Anchor Box(比如1:1, 1:2, 2:1等),每个格子的每个Anchor Box可以预测一个中心点(x, y)和长宽(l, w)的偏移量以及对应区域是某个分类的概率p,训练过程中通过梯度下降来调整模型参数最小化损失函数。目标检测的损失函数由两部分组成:分类损失函数及定位误差,为减少过拟合的情况也会加入正则化损失,3者做一个加权线性组合。 SSD及YOLO算法在延时和精确度方面平衡比较好,可以满足视频实时检测(30FPS)的需求。本质上SSD和YOLO这类目标检测算法可以理解成一个框架,在这个框架里有多个组成部分或决策算法,不同的选择组成具体的目标检测模型。比如框架中做为主干的特征抽取网络部分,ssd原始使用的vgg16,yolo使用的Darknet53,在平衡速度和精确度时,也可以选择其他的特征抽取网络,如为移动设备优化的mobilenet v1,v2,或者inception等,不同的选择可以组合出多种不同的具体模型。今年最新发布的YOLO v4模型在COCO的数据集上速度和精确度都达到了不错的提升。 麻将识别模型训练 首先是训练数据准备,尝试在网上搜了一圈没有找到现有的麻将牌目标检测的标注数据,于是开始自己的数据采集和标注。 训练数据分为两部分,一部分人工真实数据,一部分生成数据(大量)。真实数据采集使用视频录制的方式,分两种场景,单个麻将牌(34类),以及多张牌组合(14张)。摆好牌后移动手机拍摄不同角度下的成像,完了用脚本从视频里自动截取出来x张图片进行标注。标注工具使用labelimg工具,可以比较方便的框出麻将牌打上标签,准备就绪后就是一顿狂标注,标注后的图片类似这个样子,生成对应的PASCAL VOC格式的xml文件。 第一部分数据接近真实使用场景(一次检测大于14张牌,牌相对于图像的大小也接近实际情况)。但由于只有一副麻将牌,场景比较单一数据量也比较小,训练过程种容易产生过拟合的情况于是引入第二部分数据。第二部分数据是真正帮助提高模型泛化能力的生成数据,这部分数据使用了两个数据源来合成,34张麻将牌的不同样式的图片共600多张,以及4000多张纹理图片的数据集。随机合成生成的场景图片:每次挑两张麻将进行一定的随机旋转/缩放/亮度及对比度调整/投影变换后放在一张随机选的纹理图上作为背景,生成合成图片以及对应的标注数据(麻将牌的外框作为最小外包矩形参与随机变换使得标注信息需要的label&bounding box都是已知信息,可以按模版生成标注xml文件不需要人工标注)。用这个办法可以轻松生成数万个标注图片,生成的数据长下面这个样子。注意 生成数据时直接生成模型输入需要的分辨率 ,减少模型预处理的resize步骤和加载图片数据不必要的内存开销。 像SSD和YOLO等算法都带有一定的数据增强(Data Augmentation)预处理功能,比如随机的的对训练数据进行垂直/水平翻转或者随机截取区域放大等操作,一方面提升模型的通用能力,也减少对训练数据overfitting的问题。由于我在自动化生成数据方面考虑了不同情况的图像变换并且生成了大量的训练数据,对模型自带的数据增强功能并不太依赖。 数据集准备好后(80%数据做训练,20%做测试),使用tensorflow进行模型训练,基于一个预先训练好的图像特征抽取模型(比如ssd_mobilenet_v1_coco)进行迁移学习,减少从零开始训练模型需要的学习图像特征抽取(学习基本的图像理解能力,比如边缘检测,基本形状检测等基础功)的时间,也减少需要的训练图片数据量。 由于生成的模型最终是在手机上做推理,我在手机上使用Tensorflow Lite框架,训练后导出的模型需要转成tflite格式。tflite相对于tensorflow模型少了不少运算符的支持,比如ssd模型的预处理步骤需要放到模型外来做,处理时需要注意根据模型输入图片RGB信息接受的浮点数范围(有模型用[-1,1],也有模型用[0, 1])做相应的正则化,另外也需要检测推理时输入图片或者视频的RGB通道顺序和模型需求是一样的, 任何一个小地方的数据不一致都会使你的模型效果大打折扣 。 在麻将算番这个应用场景下,由于浮点类型的tflite模型在手机上的性能已经不错,没有进一步再对模型的浮点数进行int8离散化处理(quantization)。性能方面在iOS上可以进一步提升: 可以使用Tensorflow Lite的CoreML delegate来做推理 ,利用手机内置AI芯片的并行处理能力来无损的提升推理速度。 AI模型性能的提升使得深度学习在手机及IOT设备上的应用越来越多,Tensorflow Lite在嵌入式设备甚至微控制器上也提供了运行时环境,为不同应用场景在速度与精确度方面的平衡提供了更多的选择,相信后续会有越来越多便捷生活的AI应用产生。Life's getting better.

曲奇泡芙一年回顾

2019年3月10号开始,写【曲奇泡芙】这个公众号至今也将近快有一年了,期间断断续续更新了21篇原创内容。算了一下平均约17天产一篇,空的时候一个星期写一篇,忙的时候3个月写一篇。个人号更新比较低频,但写内容的初衷没有变,希望学过的东西有所累积,也希望该号能有持续的技术干货输出。另外后台持续增长的关注数和源源不断的文章打赏也是支持本号继续写下去的一个动力:D。 文章发布在公众号之外我也会维护在自己的博客网站(weng.ai)上,我有个脚本负责自动同步发布在微信公众号上的文章到自己的网站上。网站的好处是你可以有公众号之外的功能,比如给文章添加标签索引,方便归类整理浏览。为了避免人工参与,我有个算法来给文章生成关键词标签。 如下图,是算法生成的过去一年21篇发文的标签图,基本体现了这个公众号过去一年的内容主题。 历史发文标签回顾 以下为过去21篇发文的具体标签生成,基本上除了个别标红的奇怪词语作为标签不太合适,以及部分同义词没有被归为同类,基本能满足需要。有写公众号的同学也欢迎把你的号在后台发我,帮你生成过去一年文章的标签图( 如 上 图 )。 聊起车联网技术时,我们可能想说什么 标签:车联网,技术,架构,车辆,自动驾驶 汽车电子架构,进化或改革? 标签:汽车电子架构,改革,架构,功能,汽车 从AVB到TSN - 时效性网络来了 标签:TSN,时效性,AVB,网络,传输 特斯拉Model 3 Key Card里的黑科技 标签:特斯拉,科技,卡片,智能卡,NFC 端与云的融合 标签:融合,服务,云端,嵌入式,车载 停车场寻车难? 蓝牙5.

GraphQL + Space Cloud 简化你的API设计

服务端API的设计与开发,为客户端提供产品业务所需要的各种功能和数据接口。随着APP产品的迭代更新,APP Server提供的接口往往也会进行多个版本的迭代更新 。 如何优雅的维护接口的稳定性,设计扩展性满足将来一定的业务需求变更,一直是从事服务端接口开发工程师需要不断思考的问题。 特别的,当你同一个服务的接口需要服务于多个需求不尽相同的客户端时,你的接口设计工作会变得尤其重要: 你可能会开始为接口提供各种option,以支持不同的客户端接入使用不同的option满足不同的需求; 你可能会将数据接口粒度拆分得更小,以支持不同客户端组合不同的API得到自己需要的数据; 你可能还需要提供通用的batch批量请求接口,以解决客户端通过蜂窝网络远程调用多个数据接口延时增大的问题,又或者为某个客户端接入量身定制满足需要的接口; 之所以会产生这样的接口维护成本,一个原因在于这里API接口的设计承担了数据表示的职责:为前端的UI/UX提供展现所需要的数据。比如APP上的个人中心页面,UI/UX需要展现昵称,头像,性别的数据,这是一个来自UI/UX对数据接口返回的需求。 有没有可能将来自UI/UX的需求尽量控制在UI/UX的实现端(客户端)从而减少UI展示层的逻辑变化的复杂度对后端接口的影响呢? GraphQL 专注于数据建模 2012年Facebook移动端从H5改用IOS原生应用重新开发时遇到了类似的问题,新的APP产品设计使得原来的很多REST API不再适用或者使用过滤繁琐。解决这一问题,Facebook在接入层添加了一层称为GraphQL的查询语言。并于2015年,发布了GraphQL的规范及其javascript版本的参考实现。 如果说传统的REST接口类似一个售货机,每次按一个按钮获得一个对应的货物,需要5个不同货物你需要按5下,那么GraphQL仿佛一个智能按钮,可以让你通过表达你的需求一次获得需要的所有货物。 GraphQL让服务的设计者可以专注于数据建模,而非接口的数据表示和组织。 服务的设计者完成数据建模定义好服务的数据能力,服务使用者可以通过GraphQL表达自己的需求来按需得到自己需要的数据,不多也不少。其中GraphQL中的Graph意指数据模型中数据之间的关联关系类似于连接不同节点的边构成一个图。 具体的,GraphQL有3个主要组成部分: Queries:客户端的请求即一个查询; Resolvers:服务端通过resolver的方式告诉GraphQL每个查询字段的数据如何获取;这也使得API数据模型和后端的数据库表结构/外部存储得以解耦; Schema:描述服务端的能力的数据模型,客户端基于这个数据模型进行查询操作。 GraphQL通过一个统一的HTTP API接口来传递数据:通过文本描述数据请求需求,接口返回匹配需求的数据。如下图,行1~8为客户端请求的GraphQL形式的需求描述,该请求查询id为1的作者的名字,以及要求返回其关联的id为5的一本书的标题;行10~21为对应的匹配客户端数据需求的返回。 在这里我们可以看到,客户端有了表达自身数据需求的灵活性。 类似的GraphQL中也定义了对数据进行修改的语法。 从2016年开始,随着GraphQL在不同编程语言上的生态的丰富,这项技术开始被Twitter,Yelp,Airbnb等公司应用于自己的产品中,如下图目前GraphQL已经在近100家不同规模的企业中开始使用。 Space Cloud 加速API开发 如果说GraphQL做的事情是把服务端提供的接口职责与使用者划分清楚,那么Space Cloud想做的事情是在这个职责范围内如何让开发工作可以更快的完成。 如下图,Space Cloud是一个新的API接入层解决方案,它可以对接后端不同类型的数据库,微服务以及文件存储,为前端提供统一的GraphQL接口。Space Cloud使得对数据库进行CRUD(增删改查)操作的接口可以被快速实现,提供对接微服务接口的能力使得系统原有REST风格的接口可以被组装并以GraphQL接口的形式统一对外提供。 具体的,Space Cloud服务部署后,提供了一个管理界面(Misson Control)。如下图,在管理界面上新建项目后,你可以在界面上新建数据库连接(提供数据库实例的连接信息),并通过运行GraphQL的方式新建数据表。 如上图的GraphQL往数据库中创建了trainer & pokemon两张表,在ID上建立了外键关联。与此同时,在未写任何代码的条件下通过GraphQL接口对外提供了这两个数据模型的增删查改接口能力。你可以开始使用GraphQL接口进行查询数据/插入数据等,Space Cloud为你实现了背后的数据resolver逻辑。比如下面是一个连表查询的操作及其返回的结果(注意,这里你并不需要写连表查询的SQL语句)。 通常来说,我们有很多接口逻辑不是简单的数据库增删改查可以完成,这种情况Space Cloud提供了微服务接口接入的功能。类似的,你可以在Space Cloud的管理界面上声明你的REST API的接口信息(请求路径,参数,响应格式等)。比如你有两个微服务的HTTP接口: /add接口:接收两个参数,返回两个数的和; /double接口:接收一个参数,返回其乘以2的值; 在完成接口的声明后,你就自动的获得了通过GraphQL访问接口能力,同样的不需要任何编程。而借助与GraphQL的并行和嵌套语法,你自动的获得了将微服务与数据库操作进行组合或者并行查询的能力。比如以下的查询,客户端可以在一次请求中,并行地完成某个数据的查询操作以及对两个微服务接口的调用; 再比如以下的查询,客户端可以在一次请求中,完成对某个数据 的查询操作并对其返回结果中的某个字段调用另一个微服务接口(/double)进行加工处理。 而这些功能的实现,还未进行太多的编码工作,是不是很酷? Space Cloud基于Apache 2.

vsomeip - GENIVI的SOME/IP开源实现

“Color is a power which directly influences the soul.” 车载以太网作为主干的整车网络拓扑架构中,以太网节点(如域控制器)之间进行数据通讯需要协商使用共同的应用层协议。在车载场景中的以太网应用中,根据不同的应用特点适用不同的应用层协议,如用于ECU诊断和刷写的DoIP(Diagnostics over Internet Protocol)协议,用于消息订阅发布的MQTT(Message Queuing Telemetry Transport)协议,以及用于控制消息通讯的 面向服务 的 SOME/IP(Scalable Service-Oriented Middleware over IP)协议等。 面向服务的架构可以将使用AUTOSAR Classic的功能ECU以及使用AUTOSAR Adaptive或其他智能操作系统的域控制器桥接起来,通过SOME/IP协议进行控制消息通讯。 面向服务的SOME/IP协议 SOME/IP协议于2011年由当时在BMW集团的Lars Völker设计,并于2013年纳入AUTOSAR 4.

赋能车载数据服务器 - S32G域控制器芯片

近几天的CES 2020上,NXP公司发布了新一代的S32G车载网络处理器。作为NXP S32系列最新的处理器,S32G将汽车行业整车EE架构往高性能,分域架构的现代设计落地进一步推进。 根据ABI研究的报告,目前路上跑着超过4千万的网联汽车,车辆每小时可以产生超4G的车辆数据。基于大规模的车辆数据服务可以为整车厂和车主带来新的机会和体验。大规模的车辆原始数据全量传输到云端处理在延时和带宽方面不能满足应用场景的要求, 数据驱动的车载服务对车载数据处理能力提出了更高的要求 。 随着整车架构朝着分域控制,跨域融合的方向改进,新的EE架构采用的面向服务的网关预计需要10倍于当前车载网关微控制器的性能。除了算力的提升,新的架构也对车载网络,功能安全,信息安全等方面也提出了更高要求。 互联网+汽车的思想自上而下在沉淀和优化 互联网+汽车的思想最初源于造车新势力研发的整车产品,近几年来逐渐在全行业中扩散。 特斯拉及4,5年前国内涌现的造车新势力热潮,经过若干年的实战,一些宝贵经验正在行业链条中沉淀下来。 新型的一级供应商的产生为整车厂提供互联网+的智能化零部件使得整车产品的设计得以更进一步的优化,而部分传统车企也纷纷与各大互联网企业建立合作成立智能网联公司。在这场互联网+汽车的演化活动中,芯片厂商的入场更是将互联网+的优化思想推向了极致,使得上层产品得以更大的简化整体设计的同时提供更强大的产品功能。 以OTA为例,为什么当前整车OTA是一件比手机OTA复杂度高非常多并且容易出错的事情?在传统汽车EE架构中存在着数十到上百数量的功能ECU,这些功能ECU由不同的供应商提供,不存在统一的中央代码仓库,其中运行着各种不同的操作系统及应用软件,以至于整车代码行数规模达到上亿级。过去分散的功能架构使得汽车不像现代手机一样有中央大脑处理器集中处理软件逻辑。 在分散的EE架构中做整车OTA,就好比把30个人的脚绑在一起大家同时往前迈一步一样,这个协调难度比起只有2~3个人做这件事情困难很多 。现代EE架构的设计致力于将软件逻辑集中处理,不断的减少整车的ECU数量降低复杂度及成本。车规芯片处理能力的发展使得软件逻辑得以集中,数据更好的共享。 从中央网关到车载数据服务器 数据作为服务(Data-As-A-Service),网关控制器的芯片处理能力的增强以及其连接车辆数据的中央地位使得其天然适合作为一个车载数据服务器。在分域架构的整车设计里,不同的域控制器向网关注册服务,发现服务及使用服务。域控制器和面向服务网关构成了整车内部的一个分布式系统。拥有数据及算力的车载数据服务器不再是简单的路由转发报文角色,一方面可为整车提供公共的数据存储和共享服务,另一个方面可根据需要对数据加工处理产生新的数据(如跨域融合数据)服务于各个域。原先在云端处理的部分车联网数据业务也可以部署到车载端,为车载HMI及自动驾驶提供实时服务。 过去以信号及控制驱动的设计思想慢慢在转变为以数据及服务驱动的现代整车EE架构设计。 互联网+汽车为车载数据的价值挖掘打开了一扇门,数据分析的目标是产生影响,从原始数据中获取信息学习到知识,达成深刻见解进而领悟出智慧方可最终产生影响。现代整车EE架构使得车辆数据可以被集中处理和挖掘价值,而不再是各路总线上转瞬即逝的一些信号。 NXP S32G 域控制器芯片 S32G芯片的一些关键特性包含: 性能方面:S32G处理器提供了符合ASIL D要求的MCU和MPU处理器,特定应用的网络硬件加速以支持复杂环境下的实时性要求; 信息安全:S32G包含高性能的硬件安全加速以及用于可信密钥管理的PKI支持; 功能安全:S32G提供ASIL D要求的处理器,包含支持同步模式(lock-step)的ARM Cotex-M7微控制器,以及多个ARM Cortex-A53应用处理内核的lock-step clusters功能。 S32G的架构图如上,包含了3对Cortex-M7内核,以同步模式运行。每一对中的两个内核运行着相同的指令,为处理的异常错误检测能力提供了支持,而不同对的内核可以执行不同的任务。另外四个Cortex-A53内核可以配置为同步模式运行(2x2),这样每对内核就可以同时在两个内核上运行任务,或者如果不需要这种处理冗余,四个A53内核也可以配置为独立运行模式。 通讯方面,S32G有20个CAN接口,4个千兆以太网接口和2个PCIe 3.