Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

Git_Clone大项目超过1G失败解决方案

发表于 2019-03-09

SourceForge.net,又称SF.net,是开源软件的开发者进行开发管理的集中式场所,也是全球最大开源软件开发平台和仓库。FlightGear的源代码就托管在该平台。最近在使用Git克隆FlightGear的子项目fgdata时,老是到1G时失败。具体情况如下:

1
2
3
4
5
6
7
8
9
# git clone fgdata大项目时超过1G就会出错
$ git clone https://git.code.sf.net/p/flightgear/fgdata
Cloning into 'fgdata'...
remote: Counting objects: 61455, done.
remote: Compressing objects: 100% (27321/27321), done.
error: RPC failed; curl 56 GnuTLS recv error (-110): The TLS connection was non-properly terminated.
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

经多种方案尝试,使用如下方法可避免该问题:

1
$ git clone git://git.code.sf.net/p/flightgear/fgdata

参考链接

  1. FGdata downloading error,by flightgear forum.
  2. SourceForge Support,by sourceforge.
  3. git clone 太慢怎么办?, by aneasystone.

Flightgear在Linux/Debian中的下载编译安装教程

发表于 2019-03-08 | 更新于 2021-01-26

编译安装

使用如下脚本在Linux/Debian操作系统下从源代码构建开源飞行模拟器FlightGear.

1
2
3
4
5
6
7
8
9
cd  <your working directory for building FlightGear>
wget -O download_and_compile.sh http://sourceforge.net/p/flightgear/fgmeta/ci/next/tree/download_and_compile.sh?format=raw
chmod +x download_and_compile.sh
mkdir -p stable
mkdir -p next
cd stable
../download_and_compile.sh -s
cd ../next
../download_and_compile.sh -p n

需要注意的是,该脚本git clone fgdata时超过1G时就会报错退出,解决方案见链接4。

此外,如果之前安装过FlightGear的旧版本,编译过程也有可能报错,清理之前旧版本之后即可解决问题。

启动模拟器

启动FlightGear命令如下:

1
2
3
cd <your working directory for building FlightGear>
cd stable
./run_fgfs.sh

fgfs常用选项

fgfs为flightgear的飞行模拟器主程序,在命令行中输入fgfs –launcher即可打开启动器,选择飞机、位置等配置,然后开始模拟飞行。下面介绍fgfs的一些常用选项。

  • –launcher

    打开启动器。

  • –fg-root=path

    告诉flightgear到path下寻找数据文件,如飞机、地景等。

  • –fg-scenery=path

    告诉flightgear到path下寻找地景文件。

  • –fg-aircraft=path

    告诉flightgear到path下寻找飞机文件。

  • –language=code

    指定会话语音, 例如 pl, nl, it, fr, en, de。

  • –aircraft= 飞行器

    载入特定飞行器。

  • –show-aircraft

    打印可用的飞行器列表。

参考链接

  1. Howto:Get Local Copies of Flightgear Source Code,by flightgear wiki.
  2. Scripted Compilation on Linux Debian/Ubuntu, by flightgear wiki.
  3. Building FlightGear,by flightgear wiki.
  4. Git_Clone大项目超过1G失败解决方案,by jack huang.
  5. Building using CMake - Windows,by flightgear.
  6. Visual Studio之RelWithDebInfo模式,“被忽视”的编译模式,by inter_peng.

博弈论简介

发表于 2019-02-26 | 更新于 2021-08-13

博弈论(英语:game theory),又译为对策论,经济学的一个分支,1944年冯·诺伊曼与奥斯卡·摩根斯特恩合著《博弈论与经济行为》,标志着现代系统博弈理论的的初步形成,因此他被称为“博弈论之父”。博弈论被认为是20世纪经济学最伟大的成果之一。目前在生物学、经济学、国际关系、计算机科学、政治学、军事战略和其他很多学科都有广泛的应用。

概述

博弈论考虑游戏中的个体的预测行为和实际行为,并研究它们的优化策略。表面上不同的相互作用可能表现出相似的激励结构(incentive structure),所以它们是同一个游戏的特例。其中一个有名有趣的应用例子是囚徒困境。

具有竞争或对抗性质的行为称为博弈行为。在这类行为中,参加斗争或竞争的各方各自具有不同的目标或利益。为了达到各自的目标和利益,各方必须考虑对手的各种可能的行动方案,并力图选取对自己最为有利或最为合理的方案。比如日常生活中的下棋,打牌等。博弈论就是研究博弈行为中斗争各方是否存在着最合理的行为方案,以及如何找到这个合理的行为方案的数学理论和方法。

分类

博弈论知识结构

图1 博弈论知识结构

动态博弈

动态博弈是指参与人的行动有先后顺序,而且行动在后者可以观察到行动在先者的选择,并据此作出相应的选择。

静态博弈

静态博弈是指博弈中参与者同时采取行动,或者尽管参与者行动的采取有先后顺序,但后行动的人不知道先采取行动的人采取的是什么行动。

完全信息静态博弈

纳什均衡

纳什均衡,又称为非合作博弈均衡,是博弈论的一个重要术语,以约翰·纳什命名。在一个博弈过程中,无论对方的策略选择如何,当事人一方都会选择某个确定的策略,则该策略被称作支配性策略。如果两个博弈的当事人的策略组合分别构成各自的支配性策略,那么这个组合就被定义为纳什均衡。

术语

  • 局中人(players):在一场竞赛或博弈中,每一个有决策权的参与者成为一个局中人。只有两个局中人的博弈现象称为“两人博弈”,而多于两个局中人的博弈称为 “多人博弈”。

  • 策略(strategies):一局博弈中,每个局中人都有选择实际可行的完整的行动方案,即方案不是某阶段的行动方案,而是指导整个行动的一个方案,一个局中人的一个可行的自始至终全局筹划的一个行动方案,称为这个局中人的一个策略。如果在一个博弈中局中人都总共有有限个策略,则称为“有限博弈”,否则称为“无限博弈”。

  • 得失(payoffs):一局博弈结局时的结果称为得失。每个局中人在一局博弈结束时的得失,不仅与该局中人自身所选择的策略有关,而且与全局中人所取定的一组策略有关。所以,一局博弈结束时每个局中人的“得失”是全体局中人所取定的一组策略的函数,通常称为支付(payoff)函数。

  • 次序(orders):各博弈方的决策有先后之分,且一个博弈方要作不止一次的决策选择,就出现了次序问题;其他要素相同次序不同,博弈就不同。

  • 博弈涉及到均衡:均衡是平衡的意思,在经济学中,均衡意即相关量处于稳定值。在供求关系中,某一商品市场如果在某一价格下,想以此价格买此商品的人均能买到,而想卖的人均能卖出,此时我们就说,该商品的供求达到了均衡。所谓纳什均衡,它是一稳定的博弈结果。

参考链接

  1. 博弈论,by wikipedia.
  2. 博弈论, by 智库百科.
  3. 漫画:什么是 “智猪博弈” ?,by 小灰.
  4. Matlab_对策论、微分稳定方程,by Lanyun.
  5. Minimax算法及实例分析,by witnessai1.
  6. 庞特里亚金最大化原理,by wikipedia.
  7. AI的博弈论,一份插图教程,by 磐创AI.

Linux代理工具简介

发表于 2019-02-23 | 更新于 2022-05-20

下面介绍两个Linux代理工具shadowsock和proxychains。

shadowsock

Shadowsocks可以指一种基于Socks5代理方式的加密传输协议,也可以指实现这个协议的各种开发包。当前包使用Python、C、C++、C#、Go语言等编程语言开发,大部分主要实现(iOS平台的除外)采用Apache许可证、GPL、MIT许可证等多种自由软件许可协议开放源代码。Shadowsocks分为服务器端和客户端,在使用之前,需要先将服务器端部署到服务器上面,然后通过客户端连接并创建本地代理。

1
2
3
4
# 安装方法
sudo apt-get install shadowsocks
# 使用方法
nohup /usr/bin/sslocal -c /etc/shadowsocks/server.json

proxychains

ProxyChains是一个开源代理工具,能够强制使任何应用的TCP连接使用SOCKS4,SOCKS或者HTTP(S)代理进行连接。

1
2
3
4
5
6
7
8
# 安装配置
sudo apt install proxychains
sudo gedit /etc/proxychains.conf
socks5 127.0.0.1 1080
# 使用方法
proxychains firefoxt
proxychains aria2c
proxychains wget

参考链接

  1. Shadowsocks,by wikipedia.
  2. SOCKS,by wikipedia.
  3. 将 Tor socks 转换成 http 代理,by linux 中国.
  4. Linux 科学上网,by fanzhongwei.
  5. Debian系列——Ubuntu18.04为例,by github.

分布式系统的CAP理论简介

发表于 2019-02-17

分布式系统定义

分布式系统是其组件分布正在连网的计算机上,组件之间通过传递消息进行通信和动作协调的系统[1]。通过该定义可知,分布式系统具有以下重要特征:组件的并发性、缺乏全局时钟、组件故障的独立性。

CAP理论

CAP理论:一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

  • 一致性(Consistency)
  • 可用性(Availability)
  • 分区容错性(Partition Tolerance)

一致性(Consistency)

在分布式系统中,是指对于一组服务器,给定一组操作,我们需要一个协议使得最后它们的结果达成一致。更详细的解释就是,当其中某个服务器收到客户端的一组指令时,它必须与其它服务器交流以保证所有的服务器都是以同样的顺序收到同样的指令,这样的话所有的服务器会产生一致的结果,看起来就像是一台机器一样。

分布式系统的一致性算法分为:

  • 弱一致性(最终一致性),例如DNS域名解析。
  • 强一致性,例如主从同步、多数派(读/写)、Paxos、Raft(multi Paxos)、ZAB(multi Paxos)。

可用性(Availability)

对于一个可用性的分布式系统,每一个非故障的节点必须对每一个请求作出响应。所以,一般我们在衡量一个系统的可用性的时候,都是通过停机时间来计算的。

通常我们描述一个系统的可用性时,我们说淘宝的系统可用性可以达到5个9,意思就是说他的可用水平是99.999%,即全年停机时间不超过 $(1-0.99999)36524*60 = 5.256 min$ ,这是一个极高的要求。

分区容错性(Partition Tolerance)

分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。

好的分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体。比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,或者是机器之间有网络异常,将分布式系统分隔未独立的几个部分,各个部分还能维持分布式系统的运作,这样就具有好的分区容错性。

简单点说,就是在网络中断,消息丢失的情况下,系统如果还能正常工作,就是有比较好的分区容错性。

参考连接

  1. George Coulouris, Jean Dollimore, Tim Kindberg,Gordon Blair,金蓓弘,马应龙,等译. 分布式系统概念与设计[M].2013.
  2. Zookeeper之分布式系统的一致性算法, by 养兔子的大叔.
  3. 分布式计算,by wikipedia.
  4. 分布式系统的CAP理论,by HollisChuang.

最优化算法之动态规划入门

发表于 2019-02-10

动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

动态规划中包含三个重要子概念:

  • 最优子结构
  • 边界
  • 状态转移公式

对有重叠子问题和最优子结构性质的问题,在建模之后,即获得其状态转移公式和边界之后,可采用下列算法求解:

  • 递归求解
  • 备忘录算法
  • 动态规划求解

参考链接

  1. 动态规划,by wikipedia.
  2. 漫画:什么是动态规划?,by 程序员小灰.

PID控制算法原理分析

发表于 2019-02-09

最近研究深度强化学习算法,进而对控制理论感兴趣,发现了PID这个广泛使用的控制算法。大概了解记录一下。PID控制器(比例-积分-微分控制器),由比例单元(P)、积分单元(I)和微分单元(D)组成。透过Kp,Ki和Kd三个参数的设定。PID控制器主要适用于基本上线性,且动态特性不随时间变化的系统。

PID控制器的方块图

图1 PID控制器的方块图

PID是以它的三种纠正算法而命名。受控变数是三种算法(比例、积分、微分)相加后的结果,即为其输出,其输入为误差值(设定值减去测量值后的结果)或是由误差值衍生的信号。若定义 $u(t)$为控制输出,PID算法可以用下式表示:

$$ {u}(t)= {MV}(t)=K_{p}e(t)+K_i\int _{0}^{t}{e(\tau )}{d\tau }+K_d{\frac{d}{dt}}e(t)$$

其中:

$K_{p}$:比例增益,是调适参数

$K_{i}$:积分增益,也是调适参数

$K_{d}$:微分增益,也是调适参数

$e$:误差=设定值(SP)- 回授值(PV)

$t$:目前时间

$\tau$ :积分变数,数值从0到目前时间 $t$

参考链接

  1. PID控制器,by wikipedia.
  2. PID控制算法原理(抛弃公式,从本质上真正理解PID控制),by 确定有穷自动机.

分布式系统架构入门

发表于 2019-02-01 | 更新于 2024-03-02

随着互联网高速公路的不断发展,以往的单机应用系统逐渐没落,分布式系统逐渐成为主流。

分布式系统定义

分布式系统是其组件分布正在连网的计算机上,组件之间通过传递消息进行通信和动作协调的系统[1]。通过该定义可知,分布式系统具有以下重要特征:组件的并发性、缺乏全局时钟、组件故障的独立性。

现代分布式系统的例子有:

  • Web搜索
  • 大型多人在线游戏
  • 金融交易

分布式系统架构演变

大多数的开发者最开始接触的是单机系统架构,即所有的数据和程序都在一台计算机上,这是分布式系统架构演变的起点。随着用户规模的不断增长和用户需求的不断变化,分布式系统架构开始不断演变。

系统架构演化历程-初始阶段架构

系统架构演化历程-初始阶段架构

初始阶段的小型系统中应用程序、数据库、文件等所有的资源都在一台服务器上。随着业务量的增长,小型系统的负载将越来越重。但如果没有达到单台机器的性能瓶颈,则根本没必要进行分布式架构,可以考虑机器升级,提高机器配置解决问题。或者考虑技术升级,更换更加高效或者场景适合的技术。

系统架构演化历程-应用服务和数据服务分离

系统架构演化历程-应用服务和数据服务分离

数据量增加,单台服务器性能及存储空间不足,需要将应用和数据分离,并发处理能力和数据存储空间得到了很大改善。

系统架构演化历程-使用缓存改善性能

系统架构演化历程-使用缓存改善性能

系统访问特点遵循二八定律,即80%的业务访问集中在20%的数据上。缓存分为本地缓存和远程分布式缓存,本地缓存访问速度更快但缓存数据量有限,同时存在与应用程序争用内存的情况。

系统架构演化历程-使用应用服务器集群

系统架构演化历程-使用应用服务器集群

使用集群是系统解决高并发、海量数据问题的常用手段。通过向集群中追加资源,提升系统的并发处理能力,使得服务器的负载压力不再成为整个系统的瓶颈。

系统架构演化历程-数据库读写分离

系统架构演化历程-数据库读写分离

数据库访问通常是读多写少。针对这个情况,就是写一个主库,但是主库挂多个从库,然后从多个从库来读,以支撑更高的读并发压力。

系统架构演化历程-反向代理和CDN加速

系统架构演化历程-反向代理和CDN加速

为了应付复杂的网络环境和不同地区用户的访问,通过CDN和反向代理加快用户访问的速度,同时减轻后端服务器的负载压力。CDN与反向代理的基本原理都是缓存。

系统架构演化历程-分布式文件系统和分布式数据库

系统架构演化历程-分布式文件系统和分布式数据库

任何强大的单一服务器都满足不了大型系统持续增长的业务需求,数据库读写分离随着业务的发展最终也将无法满足需求,需要使用分布式数据库及分布式文件系统来支撑。分布式数据库是系统数据库拆分的最后方法,只有在单表数据规模非常庞大的时候才使用,更常用的数据库拆分手段是业务分库,将不同的业务数据库部署在不同的物理服务器上。

系统架构演化历程-使用NoSQL和搜索引擎

系统架构演化历程-使用NoSQL和搜索引擎

随着业务越来越复杂,对数据存储和检索的需求也越来越复杂,系统需要采用一些非关系型数据库如NoSQL和分数据库查询技术如搜索引擎。应用服务器通过统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。

系统架构演化历程-业务拆分

系统架构演化历程-业务拆分

为了应对日益复杂的业务场景,通常使用分而治之的手段将整个系统业务分成不同的产品线,应用之间通过超链接建立关系,也可以通过消息队列进行数据分发,当然更多的还是通过访问同一个数据存储系统来构成一个关联的完整系统。

  • 纵向拆分:将一个大应用拆分为多个小应用,如果新业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统纵向拆分相对较为简单,通过梳理业务,将较少相关的业务剥离即可。

  • 横向拆分:将复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务横向拆分需要识别可复用的业务,设计服务接口,规范服务依赖关系。

系统架构演化历程-分布式服务

系统架构演化历程-分布式服务

分布式服务关键技术

分布式服务应用将会面临以下问题:

  • 当服务越来越多时,服务URL配置管理变得非常困难,硬件负载均衡器的单点压力也越来越大。
  • 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
  • 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
  • 服务多了,沟通成本也开始上升,调某个服务失败该找谁?服务的参数都有什么约定?
  • 一个服务有多个业务消费者,如何确保服务质量?
  • 随着服务的不停升级,总有些意想不到的事发生,比如cache写错了导致内存溢出,故障不可避免,每次核心服务一挂,影响一大片,人心慌慌,如何控制故障的影响面?服务是否可以功能降级?或者资源劣化?

为解决上述问题,可采用以下关键技术。

消息队列架构

消息队列通过消息对象分解系统耦合性,不同子系统处理同一个消息。

消息队列原理

面向服务架构

服务框架通过接口分解系统耦合性,不同子系统通过相同的接口描述进行服务启用服务框架是一个点对点模型服务框架面向同构系统适合:移动应用、互联网应用、外部系统。

面向服务架构原理

服务总线架构

服务总线架构同面向服务架构一样,均是通过接口分解系统耦合性,不同子系统通过相同的接口描述进行服务启用。服务总线架构是一个总线式的架构模型。

服务总线架构原理

分布式系统交互的通信模式

分布式系统交互的通信模式共有五种:

  • request/response模式(同步模式):客户端发起请求一直阻塞到服务端返回请求为止。
  • Callback(异步模式):客户端发送一个RPC请求给服务器,服务端处理后再发送一个消息给消息发送端提供的callback端点,此类情况非常合适以下场景:A组件发送RPC请求给B,B处理完成后,需要通知A组件做后续处理。
  • Future模式:客户端发送完请求后,继续做自己的事情,返回一个包含消息结果的Future对象。客户端需要使用返回结果时,使用Future对象的.get(),如果此时没有结果返回的话,会一直阻塞到有结果返回为止。
  • Oneway模式:客户端调用完继续执行,不管接收端是否成功。
  • Reliable模式:为保证通信可靠,将借助于消息中心来实现消息的可靠送达,请求将做持久化存储,在接收方在线时做送达,并由消息中心保证异常重试。

常用的分布式服务框架

现在业界比较成熟的服务框架有很多,比如:Hessian、CXF、Dubbo、Dubbox、Spring Cloud、gRPC、thrift等技术实现,都可以进行远程调用。

  • Spring Cloud:Spring全家桶,用起来很舒服,只有你想不到,没有它做不到。可惜因为发布的比较晚,国内还没出现比较成功的案例,大部分都是试水,不过毕竟有Spring作背书,还是比较看好。
  • Dubbox:相对于Dubbo支持了REST,估计是很多公司选择Dubbox的一个重要原因之一,但如果使用Dubbo的RPC调用方式,服务间仍然会存在API强依赖,各有利弊,懂的取舍吧。
  • Thrift:如果你比较高冷,完全可以基于Thrift自己搞一套抽象的自定义框架吧。
  • Montan:可能因为出来的比较晚,目前除了新浪微博16年初发布的,
  • Hessian:如果是初创公司或系统数量还没有超过5个,推荐选择这个,毕竟在开发速度、运维成本、上手难度等都是比较轻量、简单的,即使在以后迁移至SOA,也是无缝迁移。
  • rpcx/gRPC:在服务没有出现严重性能的问题下,或技术栈没有变更的情况下,可能一直不会引入,即使引入也只是小部分模块优化使用。

参考链接

  1. George Coulouris, Jean Dollimore, Tim Kindberg,Gordon Blair,金蓓弘,马应龙,等译. 分布式系统概念与设计[M].2013.
  2. 聊聊分布式系统的架构套路,by 大蕉.
  3. 分布式架构的演进,by 稳稳的幸福y.
  4. 互联网 Java 工程师进阶知识完全扫盲,by dooc.
  5. 聊聊Dubbo(一):为何选择, by 猿码道.
  6. “12306”的架构到底有多牛逼?,by 绘你一世倾城.
  7. How Pinterest scaled to 11 million users with only 6 engineers,by engineerscodex.

元强化学习研究笔记

发表于 2019-01-27 | 更新于 2019-01-31

元强化学习定义

什么是元强化学习?这得从深度学习开始说起。

Deep Learning研究一个从x到y的映射mapping,只是这个映射函数f是用一个端到端的深度神经网络来表示。如果是计算机视觉中的图像识别,那么x就是图片,y就是标签;如果是自然语言处理中的文本翻译,那么x就是比如中文,y就是英文;如果是深度增强学习中的玩Atari游戏,那么x就是屏幕画面,y就是输出的动作。深度学习研究的就是通过深度神经网络来学习一个针对某一特定任务task的模型。通过大量的样本进行训练,训练完,这个模型就可以用在特定任务上。

而Meta Learning研究Task!Meta Learning的目的是希望学习很多很多的task,然后有了这些学习经验之后,在面对新的task的时候可以游刃有余,学的快又学的好!那为什么叫Meta呢?Deep Learning是在Task里面研究,现在Meta Learning是在Task外面,更高层级来研究。也就是在Meta Learning的问题上,Task是作为样本来输入的。

Meta RL(Meta Reinforcement Learning)是Meta Learning应用到Reinforcement Learning的一个研究方向,核心的想法就是希望AI在学习大量的RL任务中获取足够的先验知识Prior Knowledge然后在面对新的RL任务时能够 学的更快,学的更好,能够自适应新环境!

元强化学习意义

元强化学习试图解决深度强化学习存在的如下问题:

  • 它的样本利用率非常低。换言之为了让模型的表现达到一定高度需要极为大量的训练样本。
  • 最终表现很多时候不够好。在很多任务上用非强化学习甚至非学习的其它方法,如基于模型的控制(model based control),线性二次型调节器(Linear Quadratic Regulator)等等可以获得好得多的表现。最气人的是这些模型很多时候样本利用率还高。当然这些模型有的时候会有一些假设比如有训练好的模型可以模仿,比如可以进行蒙特卡洛树搜索等等。
  • DRL成功的关键离不开一个好的奖励函数(reward function),然而这种奖励函数往往很难设计。在Deep Reinforcement Learning That Matters作者提到有时候把奖励乘以一个常数模型表现就会有天和地的区别。但奖励函数的坑爹之处还不止如此。奖励函数的设计需要保证:
    • 加入了合适的先验,良好的定义了问题和在一切可能状态下的对应动作。坑爹的是模型很多时候会找到作弊的手段。Alex举的一个例子是有一个任务需要把红色的乐高积木放到蓝色的乐高积木上面,奖励函数的值基于红色乐高积木底部的高度而定。结果一个模型直接把红色乐高积木翻了一个底朝天。仔啊,你咋学坏了,阿爸对你很失望啊。
    • 奖励函数的值太过稀疏。换言之大部分情况下奖励函数在一个状态返回的值都是0。这就和我们人学习也需要鼓励,学太久都没什么回报就容易气馁。都说21世纪是生物的世纪,怎么我还没感觉到呢?21世纪才刚开始呢。我等不到了啊啊啊啊啊。
    • 有的时候在奖励函数上下太多功夫会引入新的偏见(bias)。
    • 要找到一个大家都使用而又具有好的性质的奖励函数。这里Alex没很深入地讨论,但链接了一篇陶神(Terence Tao)的博客,大家有兴趣可以去看下。
  • 局部最优/探索和剥削(exploration vs. exploitation)的不当应用。Alex举的一个例子是有一个连续控制的环境里,一个类似马的四足机器人在跑步,结果模型不小心多看到了马四脚朝天一顿乱踹后结果较好的情况,于是你只能看到四脚朝天的马了。
  • 对环境的过拟合。DRL少有在多个环境上玩得转的。你训练好的DQN在一个Atari game上work了,换一个可能就完全不work。即便你想要做迁移学习,也没有任何保障你能成功。
  • 不稳定性。
    • 读DRL论文的时候会发现有时候作者们会给出一个模型表现随着尝试random seed数量下降的图,几乎所有图里模型表现最终都会降到0。相比之下在监督学习里不同的超参数或多或少都会表现出训练带来的变化,而DRL里运气不好可能很长时间你模型表现的曲线都没有任何变化,因为完全不work。
    • 即便知道了超参数和随机种子,你的实现只要稍有差别,模型的表现就可以千差万别。这可能就是Deep Reinforcement Learning That Matters一文里John Schulman两篇不同文章里同一个算法在同一个任务上表现截然不同的原因。
    • 即便一切都很顺利,从我个人的经验和之前同某DRL研究人员的交流来看只要时间一长你的模型表现就可能突然从很好变成完全不work。原因我不是完全确定,可能和过拟合和variance过大有关。

元强化学习方法

Meta RL(Meta Reinforcement Learning)是Meta Learning应用到Reinforcement Learning的一个研究方向。因此元强化学习的研究借鉴了元学习的思想和方法。

元学习方法

HyperNetwork 生成参数

HyperNetwork是一个蛮有名的网络,简单说就是用一个网络来生成另外一个网络的参数。那么我们这里非常直接,我们的设想就是希望用一个hypernetwork输入训练集数据,然后给我输出我的对应模型也就是上图f的参数,我们希望输出的这个参数能够使得在测试图片上取得好的识别效果。那么,有了这样设计,这个hypernetwork其实就是一个meta network。大家可以看到,本来基本的做法是用训练集直接训练这个模型f,但是现在我们用这个hypernetwork不训练了,直接给你输出参数,这等价于hypernetwork学会了如何学习图像识别,这也是为什么meta learning也同时叫做learning to learn的原因。我们通过hypernetwork学会学习。训练好了这个模型,连反向传播梯度下降都不要了,直接给你参数,是不是很酷?

Conditional Neural Network 条件神经网络

直接把D_train当做条件输入到f中,那么这个f本身就变成一个meta network了。也就是条件神经网络实际上能够得到和上面的hypernetwork一样的意义。因为我们可以想,只要条件D_train变了,那么y_test肯定也就变了。所以这里就非常非常直接了。把数据全部输入进去,让神经网络自己学就行了,不外乎就是去设计一个合适的网络结构而已。那么,这里最最简单粗暴的网络结构就是SNAIL算法使用temporal convolutional network,也就是wavenet的架构:

MAML 基于梯度的做法

MAML的核心步骤就是

  • 采集Task,得到D_train和D_test

  • 使用D_train对神经网络f训练少数几步,得到新的参数

  • 利用新的参数训练D_test,然后使得梯度下降更新一开始的参数。

三种解决办法的优缺点

先说HyperNetwork生成参数的做法。这种做法最大的问题就在于参数空间是很大的,所以要生成合适的参数特别是巨量的参数其实是比较困难的,所以目前绝大多数生成参数的做法都是只生成少量参数,比如一层的MLP,或者对于参数的空间进行一定的限制,比如就在[-1,1]之间,否则空间太多,有无数种选择输出一样的结果,就很难训了。但是采样HyperNetwork又有其灵活性,意味着我们可以只更新少部分参数,而不用全部。

接下来就是条件神经网络了。这又有什么问题呢?我觉得在性能上绝对会是最好的,很直接,但是不好看,一直要拖着一个条件,网络很大。不管是生成参数还是MAML,他们的模型网络就是独立的,之后只要输入x就行了,而条件神经网络每次都要输入条件,很烦啊。

那么MAML呢?可能最烦人的就是二次梯度了,这意味着MAML的训练会很慢,那么就很难hold住大网络了。实际上MAML目前对于大的网络结构比如Resnet效果并不好。然后MAML是使用D_train的Loss来更新整个网络,对比HyperNetwork缺少灵活性。这个Loss就是最好的吗?不见得。如果D_train是无监督数据,那怎么办?所以MAML是有局限性的。

目前各种各样的Meta Learning研究,在方法论上都逃不出这三种方法。要么改改网络结构,要么结合一下上面的方法,比如先MAML再生成参数,或者hypernetwork和conditional neural network混着用等等。那么什么才是终极必杀呢?可能还是要具体问题具体看吧,对于不同的问题采用不同办法效果会不一样。这些都值得我们去探索。

元强化学习方法

参考链接

  1. Meta Learning单排小教学,by Flood Sung.
  2. 最前沿: Meta RL论文解读,by Flood Sung.
  3. 这里有一篇深度强化学习劝退文,by Frankenstein.
  4. 周志华:满足这三大条件,可以考虑不用深度神经网络,by 周志华教授.

依赖注入入门

发表于 2019-01-26

依赖注入定义

在软件工程中,依赖注入是种实现控制反转用于解决依赖性设计模式。一个依赖关系指的是可被利用的一种对象(即服务提供端) 。依赖注入是将所依赖的传递给将使用的从属对象(即客户端)。该服务是将会变成客户端的状态的一部分。 传递服务给客户端,而非允许客户端来建立或寻找服务,是本设计模式的基本要求。

依赖注入意义

依赖存在的问题

如果在 Class A 中,有 Class B 的实例,则称 Class A 对 Class B 有一个依赖。例如下面类 Human 中用到一个 Father 对象,我们就说类 Human 对类 Father 有一个依赖。

1
2
3
4
5
6
7
8
public class Human {
...
Father father;
...
public Human() {
father = new Father();
}
}

仔细看这段代码我们会发现存在一些问题:

  • 如果现在要改变 father 生成方式,如需要用new Father(String name)初始化 father,需要修改 Human 代码;
  • 如果想测试不同 Father 对象对 Human 的影响很困难,因为 father 的初始化被写死在了 Human 的构造函数中;
  • 如果new Father()过程非常缓慢,单测时我们希望用已经初始化好的 father 对象 Mock 掉这个过程也很困难。

依赖注入的好处

上面将依赖在构造函数中直接初始化是一种 Hard init 方式,弊端在于两个类不够独立,不方便测试。我们还有另外一种 Init 方式,如下:

1
2
3
4
5
6
7
8
public class Human {
...
Father father;
...
public Human(Father father) {
this.father = father;
}
}

上面代码中,我们将 father 对象作为构造函数的一个参数传入。在调用 Human 的构造方法之前外部就已经初始化好了 Father 对象。像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。

现在我们发现上面 1 中存在的两个问题都很好解决了,简单的说依赖注入主要有两个好处:

  • 解耦,将依赖之间解耦。
  • 因为已经解耦,所以方便做单元测试,尤其是 Mock 测试。

依赖注入实现

Java中的依赖注入

依赖注入的实现有多种途径,而在 Java 中,使用注解是最常用的。通过在字段的声明前添加 @Inject 注解进行标记,来实现依赖对象的自动注入。

1
2
3
4
5
6
7
public class Human {
...
@Inject Father father;
...
public Human() {
}
}

上面这段代码看起来很神奇:只是增加了一个注解,Father 对象就能自动注入了?这个注入过程是怎么完成的?

实质上,如果你只是写了一个 @Inject 注解,Father 并不会被自动注入。你还需要使用一个依赖注入框架,并进行简单的配置。现在 Java 语言中较流行的依赖注入框架有 Google Guice、Spring 等,而在 Android 上比较流行的有 RoboGuice、Dagger 等。

PHP中的依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Application
{
function __construct(Auth $auth, Session $session)
{
$this->auth = $auth;
$this->session = $session;
}

// ... 程式 ...
}

$auth = new Auth('localhost', 'root', '');
$session = new Session();
$application = new Application($auth, $session);

$application->login('admin', 'admin');

参考链接

  1. 依赖注入,by wikipedia.
  2. 依赖注入,by android-cn.
上一页1…444546…54下一页

Jack Huang

535 日志
69 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse