分类: 默认

  • 深度学习的可解释性问题

    深度学习,作为人工智能的一种重要技术,已经在各个领域取得了显著的成果。深度学习具有极强的表征学习能力,可以极大降低特征工程的要求。而特征工程由取决于业务理解,在深度学习出现前,谁的模型效果好更多取决于谁的特征选的好。所以在深度学习时代,谁的数据多,模型训练快,就有更好的模型效果。

    深度学习自身的优势带来了大量的业务场景的迭代和更新,但是模型的可解释性也非常重要,特别是对于一些特殊业务,比如风控、金融、医疗等。

    深度学习的可解释性问题,简单来说,就是我们难以理解和解释深度学习模型的决策过程和原理。这是因为深度学习模型通常由数百万甚至数十亿的参数构成,这些参数通过复杂的数学运算相互作用,形成了模型的决策过程。这种过程对于人类来说是难以理解的,因此,深度学习模型被称为“黑箱”。

    深度学习的可解释性问题对其应用产生了一定的影响,从业务上对于可解释性的诉求主要来自三个方面:

    • 模型改进
    • 模型透明度和可信性
    • 模型识别和偏差防止

    提高深度学习可解释性的方法

    1. 特征可视化

    特征可视化是一种常用的方法,它通过可视化神经网络的中间层来理解模型是如何识别和处理输入的。针对不同的中间层,它的效果也是不同的。

    比如卷积核可视化是一种找到使某个卷积核输出最大的图像,从而理解该卷积核关注的特征的方法。这种方法可以帮助我们理解模型的卷积层是如何提取输入数据的特征的。

    2. 模型敏感性分析

    模型敏感性分析是另一种常用的方法,它通过改变输入并观察输出的变化来理解模型对输入的敏感性。例如,我们可以通过添加噪声或者移除某些特征,然后观察模型的输出是否发生变化,以此来理解哪些特征对模型的预测最重要。

    3. 局部可解释模型

    局部可解释模型(LIME)是一种可以解释任何机器学习模型的方法。它通过在输入空间中采样,并在这些点上训练一个简单的模型(如线性模型),来近似原始模型的行为。然后,我们可以通过解释这个简单模型来理解原始模型的行为。

    4. 深度学习解释器

    深度学习解释器(如SHAP,DeepLIFT等)是一种可以量化每个特征对模型输出的贡献的方法。这些方法可以帮助我们理解哪些特征对模型的预测最重要,从而提高模型的可解释性。

    5. 神经网络剪枝

    神经网络剪枝是一种可以简化模型的方法,它通过移除不重要的神经元或者连接来减少模型的复杂性。这样可以使模型更容易理解,从而提高其可解释性。…

  • OpenRewrite和Spring Boot Migrator

    OpenRewrite

    OpenRewrite是一个开源的代码重写工具,旨在帮助开发人员进行大规模的代码重构和迁移。它提供了一个强大的规则引擎,可以根据自定义规则来修改代码,并支持多种编程语言和框架。

    功能特点

    代码重构:OpenRewrite可以自动识别和应用各种代码重构模式,如重命名变量、提取方法、内联方法等,以提高代码质量和可维护性。

    代码迁移:OpenRewrite可以帮助开发人员将代码从一种编程语言或框架迁移到另一种,例如从Java 8迁移到Java 11,或从Spring MVC迁移到Spring Boot。

    规则引擎:OpenRewrite提供了一个灵活的规则引擎,开发人员可以根据自己的需求定义和应用代码重写规则。这使得OpenRewrite非常适合于定制化的代码重构和迁移任务。

    IDE集成:OpenRewrite可以与常见的集成开发环境(IDE)集成,如IntelliJ IDEA和Eclipse,以便开发人员可以在开发过程中直接使用它。


    应用场景

    代码重构:当代码质量下降、可维护性变差或存在性能问题时,开发人员可以使用OpenRewrite来自动化执行各种代码重构操作,以改进代码质量和可读性。

    代码迁移:当需要将代码从一种编程语言或框架迁移到另一种时,OpenRewrite可以帮助开发人员自动执行大部分迁移工作,减少手动修改的工作量和错误率。

    规则定制:开发人员可以根据自己的需求定义和应用代码重写规则,以满足特定的重构或迁移需求。

    Spring Boot Migrator

    Spring Boot Migrator是一个用于升级和迁移Spring Boot应用程序的工具。它提供了一组功能,可以帮助开发人员将旧版本的Spring Boot应用程序迁移到新版本,以便利用新的功能和修复的问题。

    功能特点

    • 依赖升级:Spring Boot Migrator可以自动分析应用程序的依赖关系,并提供建议的依赖升级路径。它可以检测到过时的依赖项,并提供更新的版本,以确保应用程序能够使用最新的功能和修复的问题。
    • 配置迁移:Spring Boot Migrator可以帮助开发人员将旧版本的配置文件迁移到新版本的Spring Boot应用程序。它可以自动识别配置文件中的变化,并提供相应的修改建议,以确保配置文件与新版本的应用程序兼容。
    • 代码重构:Spring Boot Migrator可以自动识别旧版本Spring Boot应用程序中的过时代码,并提供相应的重构建议。这有助于开发人员改进代码质量和可维护性,并使其适应新版本的Spring Boot。

    SBM的主要用途就是Spring Boot的迁移和升级。

  • Mermaid图表绘制工具

    Mermaid是一个开源的图表绘制工具,它使用简单的文本语法来描述图表,支持绘制流程图、时序图、甘特图等多种类型的图表。Mermaid的设计目标是提供一种简单、直观的方式来创建图表,使得非专业的用户也能轻松绘制出美观的图表。

    对比于Plantuml,Mermaid内置支持的图表类型更多,且相对美观度高一些。Mermaid还有一个便利就是它在GitHub 和 GitLab 等流行源代码存储库中得到原生支持,从而可以在 Markdown 文档中嵌入并轻松更新 Mermaid。

    使用示例

    下面是一个简单的Mermaid语法示例,用于绘制一个流程图:

    graph LR
        A[开始] --> B[中间步骤]
        B --> C[结束]

    通过上述代码,可以生成一个包含三个节点的流程图,节点之间的关系用箭头表示。

    这只是Mermaid语法的一个简单示例,实际上Mermaid支持更复杂的语法和功能,可以绘制出更丰富的图表。

    集成

    Mermaid可以方便集成在WordPress里面,下面是一些示例

    journey title My working day section Go to work Make tea: 5: Me Go upstairs: 3: Me Do
  • Torznab 协议

    在使用Sonarr等工具的时候,我们总会遇到找不到资源的情况,特别是一些冷门的中文资源(国产剧等)就更复杂了。

    Sonarr搜索资源用的比较多的是搭配Jackett走Torznab协议。Torznab 协议是一种用于搜索引擎的协议,它可以帮助搜索引擎更方便地搜索 BitTorrent 网络中的资源。

    Torznab 协议有以下特点:

    1. 标准化:Torznab 协议是一种标准化的协议,可以帮助搜索引擎更方便地搜索 BitTorrent 网络中的资源。
    2. 可扩展性:Torznab 协议支持多种参数,可以帮助搜索引擎更精确地搜索所需的内容。
    3. 易于实现:Torznab 协议的实现相对简单,开发者可以根据自己的需求选择适当的客户端库和示例代码,来实现搜索引擎的功能。
    4. 支持多种语言:Torznab 协议的客户端库支持多种编程语言,包括 C#、Java、Python、Ruby 等。
    5. 支持多种索引站点:Torznab 协议可以支持多种索引站点,包括私有站点和公共站点,可以帮助搜索引擎更全面地搜索 BitTorrent 网络中的资源。

    当一个资源无法是私有或者根本就不是标准BitTorrent网络资源时,我们可以自己实现一套,帮助Sonarr自动下载需要的资源。

    参数

    Torznab 协议支持多种参数,以下是常见的一些参数:

    • apikey:API 密钥,用于身份验证和授权。
    • q:搜索关键字,用于指定搜索的内容。
    • cat:资源分类,用于指定搜索的资源类型,如电影、电视剧、音乐等。
    • limit:搜索结果数量限制,用于指定搜索结果的数量。
    • offset:搜索结果偏移量,用于指定搜索结果的起始位置。
    • imdbid:IMDb 编号,用于指定搜索的电影或电视剧。
    • tvdbid:TVDB 编号,用于指定搜索的电视剧。
    • tvmazeid:TVMaze 编号,用于指定搜索的电视剧。
    • season:季数,用于指定搜索的电视剧季数。
  • V8预构建

    V8 是 Google 为 Chrome 浏览器设计的 JavaScript 执行引擎,其初衷与目标是为 Chrome 设计一个领先行业的高性能 JavaScript 引擎。V8之后的流行和广泛应用已经超过了单纯为Chrome服务的目的的,大量应用也通过嵌入V8获得了JavaScript相关能力。

    V8的代码庞大,构建工具使用Ninja,由于外部依赖和网络问题,部分工具获取本来就比较困难,加上使用V8的场景一般需要交叉编译,比如在ubuntu上编译后给Android使用,编译费时费力。由于官方没有提供预构建包,这个工作必须要自己完成,网络上虽然有大量第三方个人构建的,但是由于配置复杂性和版本多样,很多并不符合需求。

    V8的版本选择我比较偏好跟随Node,比如Node当前版本使用的V8版本为10.8.168.25。

    首先是确定需求,比如我目前比较需要一个完整的静态包,那么需要的参数如下

    is_component_build = false
    use_custom_libcxx = false
    v8_enable_i18n_support = false
    v8_use_external_startup_data = false
    v8_symbol_level = 0
    v8_static_library = true
    v8_monolithic = true

    这样最终产物就是libv8_monolith.a。配置可以基于v8gen.py生成不同平台和系统的,然后再追加我们的参数,比如android armv8就可以使用

    python3 ./tools/dev/v8gen.py 
  • 华为运动健康转为TCX数据

    华为运动健康转为TCX数据

    华为运动健康是华为下面的健康APP,配合华为各种穿戴和健康类设备,可以获取丰富的运动健康数据。其中一部分设备价格低廉,数据获取性价比高,而且还可以结合部分手机传感器,提高精度的同时也降低了成本。华为APP自身虽然提供了一部分分析功能,但是相对简单,而且内部算法不透明,加上华为运动健康导出数据不带心率,这样数据根本没法直接使用。这种情况下就需要对数据进行二次处理和分析。我们用最廉价的方案 ,手环+GPS手机针对跑步、骑行数据举例。

    原始数据获取

    华为运动健康APP可以导出数据,但是数据只包含GPS坐标,没有心率、步频等数据,这样的数据实际上是没有价值的。这里有两个办法,一个是换区,由于国内外数据权利和安全等规定不同,海外区可以申请获取数据,虽然需要一定的手动操作,但是毕竟可以直接获取。第二个方法就是借助第三方APP,比如Health Sync导出数据。Health Sync提供一个月的试用,价格也不贵,相对来说是一个上手容易的选择,但是遗憾的是Health Sync导出的数据有一些问题,特别是在坐标偏移上,而且同步的数据也是经过加工的,本质上不是原始数据。

    Health Sync获取数据的原理是通过华为运动健康的API获取数据,然后转为第三方平台的格式。这里我们也可以使用同样的思路。

    通过参考华为官方的开发者文档,我们可以明确如下步骤:

    • 申请开发者账号
    • 申请健康数据权限
    • 使用自己的账号进行Oauth2登陆
    • 使用凭证访问数据

    申请步骤就不提了,大家可以按需操作。Oauth2的认证方式有4种,既然考虑到单纯获取数据,直接走无服务化的模式,access token有效期1小时,每次使用都需要登陆。

    由于官方SDK只有Android和JS的包,只能使用Rest API。这个API设计要按照文档来,详情数据是通过列表获取的,原始数据的数据类型如下:

    • com.huawei.instantaneous.exercise_heart_rate
    • com.huawei.instantaneous.location.sample
    • com.huawei.instantaneous.steps.rate
    • com.huawei.instantaneous.speed

    分别对应心率、位置、步频、速度,由于设备本身的限制,心率和GPS相对可用,步频采样频率低,可供参考,华为还有一个sTag,精英版是2个,佩戴在足部,这个可以提供将近10种跑步数据,这个设备提供的步频、步幅有价值。

    原始数据格式基本都是根据dataTypeName判断数据类型,再根据数据类型,从values里面针对获取。下面是一段示例

    {
      "startTime": 1673587058212000000,
      "endTime": 1673587679688000000,
      "dataCollectorId": "raw:com.huawei.instantaneous.exercise_heart_rate:com.huawei.health:HUAWEI Health:HUAWEI Health:1190533025:1190533025",
      "samplePoints": [
        {
          "startTime": 1673587060000000000,
          "endTime": 1673587060000000000,
          
  • 使用UpdraftPlus备份博客数据到阿里云OSS

    WordPress的UpdraftPlus插件进行博客数据备份,包括数据库数据、各类文件等,还支持灵活的备份周期和保留策略。

    默认情况备份都是备份到当前服务器的,如果出现了一些问题或者需要迁移,显然这样不太满足需求。最好讲数据进行远程备份。

    UpdraftPlus有付费版本,付费版本支持更多类型的远程存储,但是免费版本就提供了S3的支持,可以支持很多云服务厂商。阿里云的OSS价格便宜,买年包几元钱可以买一年40G的存储。如果你的博客服务器也是阿里云的,还可以走内网存储。

    配置示例如图

    S3位置就是的oss bucket name,节点可以根据你的情况选择,主要看地域和是否内网。访问密钥就是账号的key对,可以创建一个专用子账号,如果图简单,也可以用主账号的。…

  • 跨语言编程

    日常工作中由于公司业务和IT资产的原因,可能并没有接触到这块。但是跨语言编程是现代程序语言中非常重要的一个方向,也被广泛应用于复杂系统的设计与实现中。

    场景

    跨语言可以用于很多场景,但是常用的有以下几种

    基于系统级语言实现系统的关键路径

    一些高级语言或者说脚本语言受限于封装的运行环境,对于一些系统操作比较困难,也就是底层能力比较弱,在和操作系统或者硬件打交道的时候更多的是基于C/C++此类系统级语言去进行这次底层操作。上层语言直接调用。

    依赖当前语言不支持的能力

    不同语言都有适用的领域,也有能力的上限。比如早期的Java对于线程以下操作比较弱,相关API不完善,直接依赖其他语言开发的封装层更容易操作。

    复用库和业务方法

    这个场景的情况最多,这个有可能公司遗留遗产,也可能是公司其他系统的核心二次封装成SDK给其他部门调用。也可能是成熟开源库在当前语言没有替代品,比如在java中使用opencv。

    复用不一定是为了业务功能,很多时候也处于性能考虑,在特定场景特定语言优势比较明显,比如矩阵操作等。

    原理

    跨语言调用方法一就是RPC调用,通过网络端口提供服务,并通过约定的请求格式进行通讯。这个方法简单成熟,非常适合不同语言负责的是不同领域的场合。比如一个帮助系统(Python),调用一个自然语言处理模块(C++)进行分词等操作。由于基于RPC通讯,双方本质上只依赖于协议,具体实现解耦。方便扩展更多语言的调用方,也方便双方独立升级。

    另外一种更紧密的结合就是在同一个CPU运行,不管语言、环境等等花里胡哨的东西,最后都要走到CPU执行指令这里。这里细分两种,一种是中间代码是相同的,那么他们就通过编译工具进行融合,比如LLVM IR。更宽泛的调用时基于FFI,只要ABI时相同或者兼容的。

    虽然原理类似,具体落实在使用上,每种语言使用的具体技术工具可以不同,比如Java中JNI就是Java调用的C的,而Golang可以使用CGO。

    实践

    常见的组合很多,这里看下Java+C和Flutter+Rust。这两种组合也恰好代表了两种使用场景。一般来说Java和C混合编程多是出于性能上的考虑,而Flutter+Rust的组合更多是出于复用逻辑的考虑。

    Java+C

    基于JNI可以实现这点,但是JNA框架可以更方便完成这个事情。

    <dependency<groupIdnet.java.dev.jna</groupId<artifactIdjna-platform</artifactId<version5.6.0</version</dependency

    引用以来后直接根据你的依赖库就行定义就行了。

    public interface CLibrary extends Library {
            CLibrary INSTANCE = (CLibrary) Native.loadLibrary(
                            (Platform.isWindows() 
  • 优化托管于阿里云函数计算的Node.js应用 – 以Parse为例

    本文首发于阿里云开发者社区:https://developer.aliyun.com/article/871751,修改后发布在本博客

    上文介绍了如何快速迁移Parse到阿里云函数计算,但是这只是一个跑起来的例子,还有一些问题需要我们优化。本文会介绍常见的优化点和方法,从方法来看适用于所有Serverless平台的应用。

    Serverless的缺陷

    没有任何技术形态是完美的,Serverless提供了良好的可伸缩性和并发性,提供了细粒度的资源分配,优化了成本,相对的也有难以调试等缺点。

    这些问题是Serverless这种技术形态自身造成的,并不是阿里云函数计算独有的。不同的云厂商可以通过周边建设来弥补一些问题,比如阿里云函数计算的日志和监控相对比较完善,Serverless Devs工具解决了一部分调试问题。

    用更传统的观点来理解Serverless的本质,可以看作扩容缩容策略极端激进的集群,而每个函数都是部署在这一个一个机器上而已。云厂商的机器特别迷你,计价单位颗粒小。而缩容策略可以将为0,扩容策略可以近乎无限大,缩容策略是固定,不可以自定义。

    那么对于一个随时可能创建随时可能被销毁的机器,部署于其中的服务要面临两个方面的问题

    • 服务销毁
    • 服务启动

    服务销毁时内存、文件系统的数据都丢失了。服务启动的时候需要一些必要的初始化,需要启动程序。

    我们先看下销毁引起的持久化问题。

    持久化改进

    Parse是支持文件上传的,存储文件的FileAdapter是可以自定义的。

    一般来说对于文件需求,可以直接使用阿里云对象存储OSS,一般选择标准型就可以了。

    Parse官方不支持阿里云OSS,理论上可以使用parse-server-s3-adapter,但是我之前没有配置过,可以完全可以自定义,直接使用OSS官方的SDK就行了。

    'use strict';
    
    var OSS = require('ali-oss').Wrapper;
    const DEFAULT_OSS_REGION = "oss-cn-hangzhou";
    
    function requiredOrFromEnvironment(options, key, env) {
        options[key] = options[key] || process.env[env];
        if (!options[key]) 
  • 迁移Nodejs项目到阿里云函数计算 – 以Parse为例

    迁移Nodejs项目到阿里云函数计算 – 以Parse为例

    本文首发于:https://developer.aliyun.com/article/869641 修改后发布在本博客。

    Parse Platform是一个开源的BAAS框架,可以大幅加速各类应用快速迭代。官方提供了各位常见SDK,对于开发者也可以缩短了应用的开发周期,实在没有的,还可以用Rest API。

    原来的Parse.Inc还提供托管,但是后面关闭了,国内也有一些托管服务商。

    Parse Platform基于NodeJs,背后的数据库可以选择MongoDB或者PG,文件和PUSH服务可选很多。

    自己搭建一个Parse是相当容易了,官方提供了命令行工具,也有Docker镜像,但是这种模式需要至少一台云主机和一个MongoDB数据库,相对来说有一定成本,特别是对于一些探索性的APP,流量低,访问需求不稳定,后期可能有突发流量。

    综合来看Serverless平台是一个不错的选择,本文以阿里云为例,介绍如何快速基于阿里云函数计算和阿里云Serverless DB搭建一个Parse。

    本文需要基本的Serverless平台使用经验。由于篇幅所限,本文只涉及最基本的跑起来,包括发布和数据库存储,文件存储和其他优化不涉及。

    阿里云函数计算

    阿里云函数计算是事件驱动的全托管计算服务。通过函数计算,用户无需管理服务器等基础设施,只需编写代码并上传。函数计算会准备好计算资源,以弹性、可靠的方式运行代码,另外还提供日志查询、性能监控、报警等功能。

    函数计算的费用由调用次数+函数实例资源使用量+公网出流量组成,另外如果长期使用,还可以购买资源包,相对价格更低。

    阿里云每月为每个账号提供一定的免费资源,对于少量使用可以完全覆盖。

    迁移

    普遍性的来说,迁移一个既有系统到Serverless平台主要有以下几个步骤

    • 识别系统的外部依赖
    • 创建适用于Serverless平台的部署工程
    • 修改即有系统代码
    • 部署

    识别外部依赖

    Parse的外部比较简单,从官方文档的说明和配置示例可见

    • Node 8 or newer
    • MongoDB version 3.6
    • Python 2.x (For Windows users, 2.7.1 is the required