强化学习(Reinforcement Learning)
背景
当我们思考学习的本质时,我们首先想到的可能是我们通过与环境的互动来学习。无论是在学习开车还是在交谈,我们都清楚地意识到环境是如何回应我们的行为的,我们试图通过行为来影响后续发生的事情。从互动中学习几乎是所有智能系统的理论基础。
Reinforcement learning 是机器学习里面的一个分支,善于控制一个能够在某个环境下 自主行动 的个体,通过和 环境 之间的互动,不断改进它的 行为。强化学习问题包括学习如何做、如何将环境映射为行动,从而获得最大的奖励。在强化学习中,学习器是一个制定决策的智能体,它不会被告知该执行什么动作,而是经过反复尝试运行,来发现能获得最大奖励的行为。一般情况下,行动不仅会影响当前的奖励,而且会影响下个时间点的环境,因此也会影响后续所有的奖励。因为学习系统的行动会影响到环境,环境又会影响后续的行动,所以从本质上讲,强化学习是一个闭环控制问题。
假设要构建一个像alphago那样的学习下围棋的智能体。此时,不能使用监督学习,原因主要有两个:首先,请一位go老师带领我们遍历许多棋局并告诉我们每个位置的最佳棋步的代价非常昂贵;其次,在很多情况下,根本就没有最佳棋步,一个棋步的好坏依赖于其后的多个棋步。整个过程唯一的反馈是在最后赢得或是输掉棋局时才产生。
在强化学习中,智能体(agent)被置于某一环境(environment)中。对应围棋的例子,棋手是agent,环境是棋盘。在任何时候,环境总是处于某种状态(state),该状态来自一组可能的状态之一,对于围棋,状态指的是棋盘的布局状态。决策者可以做一组可能的动作(棋子的合法移动)。一旦选择并做了某一动作,状态就随之改变。问题的解决需要执行一系列的动作,之后才得到反馈,反馈以极少发生的奖励(reward)的形式给出,通常只有在完整的动作序列执行完毕才发生。
强化学习与其他机器学习不同之处为:
- 没有教师信号,也没有label,也就是没有直接的指令告诉该执行什么动作
- 反馈有延时,不能立即返回
- 相当于输入数据是序列数据,是一个连续的决策过程
强化学习的基本概念
除了前面提到的智能体agent和环境environment的概念之外,还有策略policy、奖励reward、价值函数value function和环境的模型model,其中model并不是必须的。
policy
策略决定了agent在特定时间的行为,将当前环境的状态state映射为行动action,对应于心理学中所谓的一套刺激-反应规则。reward
每一步动作,环境都会给予agent一个奖励reward,agent唯一的目标是最大化长期获得的总奖励。奖励的大小反应了事件的好坏。奖励信号是改变策略的主要依据,如果策略选择的行动是低回报的,那么在将来,可能会更改策略来选择其他的行动。value function
reward只给出了在某个状态下的即时奖励,而价值函数给出的是长期的奖励。价值函数表示的是当前的奖励和后续奖励累计的总和。model
模仿环境的行为,如给定状态和行为,模型可以预测下一个状态和下一个奖励。在现实中,model可能存在,也有可能不存在。在强化学习中, model存在时称为基于模型的学习model-based,不存在时称为无模型学习model-free。
Finite Markov Decision Processes
MDPs 简单说就是一个智能体(Agent)采取行动(Action),从而改变自己的状态(State)获得奖励(Reward),与环境(Environment)发生交互的循环过程。
MDP 的策略完全取决于当前状态(Only present matters),这也是马尔可夫性质的体现。
The Agent–Environment Interface
强化学习问题是一个从交互中学习,以达到预期目标的简单框架。学习者和决策者被称为agent,与agent相交互的称为环境environment。交互不断进行着,agent选择执行的动作(action),环境对agent执行的动作作出反应,使得agent处于另一个新的环境中。同时,环境也会产生回报,agent试图在一段时间内最大化这些回报。
在 t t时刻,agent观测到环境信息St∈SS_t \in \mathcal{S},其中 S \mathcal{S}是所有可能状态的集合。在该环境下,agent选择一个action At∈A(St) A_t \in \mathcal{A}(S_t), A(St) \mathcal{A}(S_t)表示在状态 St S_t下所有可以执行动作的集合。在下一个时刻 t+1 t+1,由于action的作用,agent获得一个数值奖励 Rt+1∈R⊂R R_{t+1} \in \mathcal{R} \subset \mathbb{R},同时,agent处于一个新的状态 St+1 S_{t+1}。下图展示了agent和environment的交互过程。
在MDP和agent的共同作用下,产生了一个序列,也被称为轨迹
S_0, A_0, R_1, S_1, A_1, R_2, S_2, A_2, R_3, \cdots \tag{1}
在 t−1 t-1时刻,给定状态 s s和动作aa,则 t t时刻的状态s′s'和奖励 r r出现的概率为
p(s',r|s,a) \doteq \Pr\{ S_{t} = s', R_{t}=r | S_{t-1}=s, A_{t-1}=a \} \tag{2}
状态转移概率为
p(s' | s, a) \doteq \Pr\{ S_{t} = s' | S_{t-1}=s, A_{t-1}=a \} = \sum_{r \in \mathcal{R}}p(s',r|s,a) \tag{3}
state–action的期望奖励为
r(s,a) \doteq \mathbb{E}[R_{t} | S_{t-1}=s, A_{t-1}=a] = \sum_{r \in \mathcal{R}} r \sum_{s' \in \mathcal{S}} p(s', r | s, a) \tag{4}
state-action-next_state元组的期望值
r(s,a,s') \doteq \mathbb{E}[R_{t} | S_{t-1}=s, A_{t-1}=a, S_t=s'] = \sum_{r \in \mathcal{R}} r \frac{p(s', r | s, a)}{p(s'| s, a)} \tag{5}
下面以一个具体的例子来详细说明上面的式子。
回收机器人,用于在办公室收集汽水罐,它运行在可充电的电池上,并且包含探测罐子的传感器和捡起并收集罐子的夹子。如何搜寻罐子的策略是由强化学习的agent基于当前的电量做出的。agent可以让机器人做以下几件事:(1)积极搜寻一段时间;(2)等待一段时间,等待有人把罐子拿过来;(3)回去充电。因此,agent有三种action。状态由电池的状态决定。当机器人拿到罐子,则获得正的奖励,当电池用完时,获得一个大的负的奖励。假设状态的变化规律为:最好的拿到罐子的方式是主动搜寻,但是这会消耗电量,但是原地等待不会消耗电量。当是低电量的时候,执行搜索可能会耗尽电池,这种情况下,机器人必须关闭电源,等待救援。
agent执行动作仅仅依赖于电量,因此,状态集为 S={high,low} \mathcal{S} = \{ high,low \} ,agent的动作有wait, serach, recharge。因此,agent的动作集合为 A(high)={search,wait},A(low)={search,wait,recharge} \mathcal{A}(high) = \{ search, wait \}, \mathcal{A}(low) = \{ search, wait, recharge \}。
如果电量是高的,则一次搜索一般不会耗尽电池,搜索完成后还是高电量的概率为 α \alpha,是低电量的概率为 1−α 1-\alpha。当电池处于低电量时,执行一次搜索后还是低电量的概率为 β \beta,耗尽电池的概率为 1−β 1-\beta,然后需要对机器人进行充电,所以状态将转化为 s′=high s'=high。每次主动搜索会得到奖励 rsearch r_{search},等待则会获得奖励 rwait r_{wait}, rsearch>rwait r_{search}>r_{wait}。当机器人需要救援的时候,则奖励为 −3 -3。
上述系统可以看成是一个finite MDP,转移概率和期望奖励如下表和下图所示。
Goals and Rewards
在强化学习中,agent的目标是获得由环境传给它的奖励reward。在每一时刻,奖励reward是一个具体的数值 Rt∈R R_t \in \mathbb{R},agent的目标是最大化它获得的奖励的期望。这意味着不是最大化即时奖励,而是最大化一段时间内的累积奖励。
Returns and Episodes
上面只是形象地描述了强化学习的目标,下面用数学的形式来表示。
在时刻 t t之后,获得的奖励序列为Rt+1,Rt+2,Rt+3,⋯R_{t+1}, R_{t+2}, R_{t+3}, \cdots。通常情况下,我们寻找期望回报的最大值。可以将回报 Gt G_t看成是奖励序列的函数,回报最简单的形式是直接将奖励相加
G_t \doteq R_{t+1} + R_{t+2} + R_{t+3} + \cdots + R_T \tag{6}
其中, T T为最终停止的时刻。特别地,我们将一次有限步数的实验称作一个单独的episodes,也就是经过有限步数后最终会进入一个终止状态,这一类的任务也叫做episodic tasks,如打游戏。
有些情况下,agent和environment之间的交互将不会停止,这一类的任务叫做continuing tasks,如control task。此时T=∞T=\infty,这种情况下,回报有可能趋向于无穷大。如在每一步,agent获得的奖励都是+1。
此时,出现了 折扣 这一概念。agent选择一系列的动作使未来获得的折扣奖励之和最大。即,选择 At A_t,最大化折扣回报的期望
G_t \doteq R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \cdots =\sum_{k=0}^{\infty}\gamma^kR_{t+k+1} \tag{7}
其中, γ \gamma称为折扣率,且满足 0≤γ≤1 0 \leq \gamma \leq 1。
对(7)式做适当处理
\begin{align} G_t & \doteq R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \gamma^3 R_{t+4} + \cdots \\ & = R_{t+1} + \gamma (R_{t+2} + \gamma R_{t+3} + \gamma^2 R_{t+4} + \cdots )\\ & = R_{t+1} + \gamma G_{t+1} \tag{8} \end{align}
上式往往可以简化回报的计算。
Policies and Value Functions
几乎所有的强化学习都要计算价值函数——关于状态的函数或关于状态-动作的函数,来估算agent在某个状态(或者在某个状态下执行某个动作)的价值,即未来的奖励。显然,未来的奖励依赖于执行的动作,因此,value functions是针对特定的策略定义的,同一个强化学习问题,不能的策略,会有不同的价值函数。
可以将策略理解为将状态映射为动作的概率分布。如果agent在 t t时刻遵循策略π\pi,则 π(a|s) \pi(a|s)表示在状态 s s下执行动作aa的概率。
在策略 π \pi下,状态 s s的价值函数为
v_{\pi}(s) \doteq \mathbb{E}_{\pi}[ G_t | S_t=s ] = \mathbb{E}_{\pi}\left[ \sum_{k=0}^{\infty}\gamma^k R_{t+k+1}| S_t=s \right] \tag{9}
其中, Eπ(⋅) \mathbb{E_{\pi}(\cdot)}表示agent遵循策略 π \pi的条件下,随机变量的期望值。 vπ v_{\pi}被称为策略 π \pi的状态价值函数。
类似的,根据策略 π \pi,在状态 s s下执行动作aa的价值为 qπ(s,a) q_{\pi}(s,a),其值为
q_{\pi}(s,a) \doteq \mathbb{E}_{\pi}[ G_t | S_t=s, A_t=a ] = \mathbb{E}_{\pi}\left[ \sum_{k=0}^{\infty}\gamma^k R_{t+k+1}| S_t=s, A_t=a \right] \tag{10}
qπ q_{\pi}被称为策略 π \pi的动作价值函数。
价值函数贯穿强化学习和动态规划的原因主要是它们满足特定的递推关系:
\begin{align} v_{\pi}(s) & \doteq \mathbb{E}_{\pi}[ G_t | S_t=s ] \\ & = \mathbb{E}_{\pi}[ R_{t+1} + \gamma G_{t+1} | S_t=s ] \\ & = \sum_{a} \pi(a|s) \sum_{s'} \sum_{r} p(s', r | s, a) \left[r + \gamma \mathbb{E}_{\pi} [ G_{t+1} | S_{t+1}=s' ] \right] \\ & = \sum_{a} \pi(a|s) \sum_{s', r} p(s', r | s, a) \left[r + \gamma v_{\pi}(s') \right] \tag{11} \end{align}
上式被称为 vπ v_{\pi}的Bellman equation,它表示了当前状态的价值函数与后续状态的价值函数之间的关系,如下图所示。
Optimal Policies and Optimal Value Functions
求解强化学习问题就是找到一个可以获得很多奖励的策略。在任何状态下策略 π \pi的期望回报都要大于策略 π′ \pi'的期望回报时,就说策略 π \pi优于策略 π′ \pi'。如果一个策略的期望回报大于或等于其它任何的策略,则称该策略为最优策略 π∗ \pi_*。
最优状态价值函数
v_*(s) \doteq \max_{\pi} v_{\pi}(s) \tag{12}
最优动作价值函数
q_*(s,a) \doteq \max_{\pi} q_{\pi}(s,a) \tag{13}
这个函数给出了在状态 s s下,遵循策略π\pi采取动作 a a的期望回报。因此,可以将q∗q_*写成是关于 v∗ v_*的函数
q_*(s,a) = \mathbb{E} [R_{t+1} + \gamma v_*(S_{t+1}) | S_t=s, A_t=a] \tag{14}
\begin{align} v_*(s) & = \max_{a \in \mathcal{A}(s)} q_{\pi_*}(s,a) \\ & = \max_{a} \mathbb{E}_{\pi_*} [G_t | S_t=s, A_t=a] \\ & = \max_{a} \mathbb{E}_{\pi_*} [R_{t+1}+\gamma G_{t+1} | S_t=s, A_t=a] \\ & = \max_{a} \mathbb{E}[R_{t+1}+\gamma v_*(S_{t+1}) | S_t=s, A_t=a] \\ & = \max_{a} \sum_{s',r} p(s',r|s,a)[r + \gamma v_*(s')] \tag{15} \end{align}
式(15)即为 v∗ v_*的Bellman最优方程。 q∗ q_*的Bellman最优方程为
\begin{align} q_*(s,a) & = \mathbb{E} \left[ R_{t+1} + \gamma \max_{a'}q_*(S_{t+1}, a') | S_t=s,A_t=a \right] \\ & = \sum_{s',r} p(s',r|s,a)[r + \gamma \max_{a'}q_*(s', a')] \tag{16} \end{align}
仍以回收机器人为例,其Bellman最优方程为
\begin{align} v_*(h) &=\max \left\{ \begin{array}{lr} p(h|h,s)[r(h,s,h) + \gamma v_*(h)] + p(l|h,s)[r(h,s,l) + \gamma v_*(l)] \\ p(h|h,w)[r(h,w,h) + \gamma v_*(h)] + p(l|h,w)[r(h,w,l) + \gamma v_*(l)] \end{array} \right\} \\ & = \max \left\{ \begin{array}{lr} r_s+\gamma [\alpha v_*(h) +(1-\alpha)v_*(l)] \\ r_w + \gamma v_*(h)\end{array} \right\} \end{align}
\begin{equation} v_*(l) =\max \left\{ \begin{array}{lr} \beta r_s -3(1-\beta)+\gamma[(1-\beta)v_*(h) + \beta v_*(l)r_w + \gamma v_*(l)] \\ \gamma v_*(h)\end{array} \right\} \end{equation}
Dynamic Programming
动态规划dynamic programming(DP)指的是一组算法,只要给出MDP的完整模型,它们就可以用来计算最优策略。
这里,首先假设环境是一个finite MDP,即state,action和reward的集合 S,A \mathcal{S,A}和 R \mathcal{R}是有限的,它的动力学原理由概率 p(s′,r|s,a) p(s',r|s,a)表示。在强化学习中,DP的核心思想是使用价值函数来搜索好的策略。
Policy Iteration
对于任意的策略 π \pi,计算它们的状态价值函数 vπ v_{\pi},这个过程被称为策略评估。
\begin{align} v_{\pi}(s) & \doteq \mathbb{E}_{\pi}[ G_t | S_t=s ] \\ & = \mathbb{E}_{\pi}[ R_{t+1} + \gamma G_{t+1} | S_t=s ] \\ & = \mathbb{E}_{\pi}[ R_{t+1} + \gamma v_{\pi}(S_{t+1}) | S_t=s ] \\ & = \sum_a \pi(a|s) \sum_{s',r}p(s',r|s,a)[r+\gamma v_{\pi}(s')] \tag{17} \end{align}
如果系统的模型已知,上式显然可以通过求解线性方程组得到最终的解。同样,它可以通过迭代的方式求解
\begin{align} v_{k+1}(s) & \doteq \mathbb{E}_{\pi}[ R_{t+1} + \gamma v_{k}(S_{t+1}) | S_t=s ] \\ & = \sum_a \pi(a|s) \sum_{s',r}p(s',r|s,a)[r+\gamma v_{k}(s')] \tag{18} \end{align}
显然, vk=vπ v_k=v_{\pi}是一个不动点,并且,当 k→∞ k \to \infty时, vk v_k收敛到 vπ v_{\pi}。
现在以一个 4×4 4 \times 4的格子世界来具体阐述
状态集合 S={1,2,⋯,14} \mathcal{S}=\{1,2,\cdots,14 \},action的集合 A={up,down,left,right} \mathcal{A}=\{up, down, left, right\}。每转移一步,都会获得数值为-1的奖励(如 p(6,−1|5,right)=1,p(7,−1|7,right)=1,p(10,r|5,right)=0 p(6, −1|5, right) = 1, p(7, −1|7, right) = 1, p(10, r|5, right) = 0),直到到达终止状态。初始状态时,假设agent往各个方向行走的概率是相等的。整个迭代过程如下图所示
经过策略评估之后,还需进行策略改进,这里不再详细描述,算法流程如下图所示。
Value Iteration
时序差分学习Temporal-Difference(TD) Learning
Sarsa
Q-learning
Q(S_t,A_t) \gets Q(S_t,A_t) + \alpha [R_{t+1} + \gamma \max_a Q(S_{t+1},a) - Q(S_t,A_t) ]
动作价值函数 Q Q直接逼近最优动作价值函数q∗q_*,并且不需要遵循策略。这极大地简化了算法的分析,加快了收敛速度。
下面以一个例子来说明Q-learning的流程
下图展示了5间房,这5间房的某些房间是相同的,其中房间5代表出口。
用图表示为
将每个房间看成是状态state,从一个房间到另一个房间的动作看成是action。为每一个门设置一个奖励,如能到达房间5,给予100的奖励,如不能到达,则奖励为0。
假设现在在状态2,从状态2可以到状态3,而无法到状态0、1、4,因为2没法直接到0、1、4;从状态3,可以到1、4或者2;而4可以到0、3、5;其它依次类推。
以上关系,用 R R矩阵表示
令α=1\alpha=1,则贝尔曼公式转化为
Q(s,a) \gets R_{t+1} + \gamma \max_{a}Q(S_{t+1}, a)
初始化 Q Q矩阵为零矩阵
假设初始位置是state1,在R矩阵中发现从state1可以到state3或state5,随机选择一个方向,比如从1到5,则
Q(1,5) \gets R(1,5) + \gamma \max \{Q(5,1), Q(5,4), Q(5,5) \} = 100 + 0.8 * 0 = 100
Q Q矩阵转化为
再选择state3作为初始状态,选择方向1,则
Q(3,1) \gets R(3,1) + \gamma \max \{Q(1,3), Q(1,5) \} = 0 + 0.8 * \max(0, 100) = 80
Q Q矩阵转化为
经过多次循环迭代,最终结果为
正则化后为
Deep Q-Network(DQN)
在现实中,agent面临一个困难:必须从高维的输入中获得有效的环境表征,并用这些表征将过去的经验推广到新的环境。DQN就是针对这种情况提出的,它可以直接从高维输入数据中学习有效的策略。DQN巧妙地将强化学习与深度神经网络进行了结合,2015年deepmind采用的神经网络是CNN,他们用CNN来逼近最优动作价值函数
Q_*(s,a) = \max_{\pi} \mathbb{E}[R_t + \gamma R_{t+1} + \gamma^2 R_{t+2} + \cdots | S_t=s, A_t=a, \pi]
神经网络的作用
前面介绍的Q-learning是使用Q table来存储每一个状态 state,和在这个 state 每个行为 action 所拥有的 Q 值。但是现实中的问题太过于复杂,状态的数量可能多到计算机无法接收的数量级。不过, 在机器学习中, 有一种方法对处理高维数据很在行,那就是神经网络。可以将状态和动作当成神经网络的输入, 经神经网络前向传播后得到当前状态下该动作的Q值,这样就无需在表格中记录Q值,而是直接用神经网络生成Q值。还有一种形式的是只输入状态值,输出所有的动作各自的Q值,直接选择拥有最大值的动作当做下一步要做的动作。神经网络接受外部的信息,相当于眼睛鼻子耳朵收集信息,然后通过大脑加工输出每种动作的值,最后通过强化学习的方式选择动作。
DQN算法
下面是用DQN玩flappy bird的demo
参考
[1] https://ai.intel.com/demystifying-deep-reinforcement-learning/
[2] Sutton R S, Barto A G. Reinforcement learning: An introduction[M]. Cambridge: MIT press, 1998.
[3] Mnih, Volodymyr, et al. “Human-level control through deep reinforcement learning.” Nature 518.7540 (2015): 529.
强化学习(Reinforcement Learning)相关推荐
- 强化学习(Reinforcement Learning)入门学习--01
强化学习(Reinforcement Learning)入门学习–01 定义 Reinforcement learning (RL) is an area of machine learning in ...
- 强化学习 (Reinforcement Learning)
强化学习: 强化学习是机器学习中的一个领域,强调如何基于环境而行动,以取得最大化的预期利益.其灵感来源于心理学中的行为主义理论,即有机体如何在环境给予的奖励或惩罚的刺激下,逐步形成对刺激的预期,产生能 ...
- 强化学习 Reinforcement Learning(三)——是时候用 PARL 框架玩会儿 DOOM 了!!!(下)
强化学习 Reinforcement Learning(三)-- 是时候用 PARL 框架玩会儿 DOOM 了!!!(下) 本文目录 强化学习 Reinforcement Learning(三)-- ...
- 强化学习(Reinforcement Learning)入门知识
强化学习(Reinforcement Learning) 概率统计知识 1. 随机变量和观测值 抛硬币是一个随机事件,其结果为**随机变量 X ** 正面为1,反面为0,若第 i 次试验中为正面,则观 ...
- 强化学习Reinforcement Learning
Abstract Abstract 背景 强化学习算法概念 背景 (1) 强化学习的历史发展 1956年Bellman提出了动态规划方法. 1977年Werbos提出只适应动态规划算法. 1988年s ...
- 强化学习(Reinforcement Learning)中的Q-Learning、DQN,面试看这篇就够了!
文章目录 1. 什么是强化学习 2. 强化学习模型 2.1 打折的未来奖励 2.2 Q-Learning算法 2.3 Deep Q Learning(DQN) 2.3.1 神经网络的作用 2.3.2 ...
- 强化学习 (Reinforcement Learning) 基础及论文资料汇总
持续更新中... 书籍 1. <Reinforcement Learning: An Introduction>Richard S. Sutton and Andrew G.Barto , ...
- 李宏毅机器学习——强化学习Reinforcement Learning
目录 应用场景 强化学习的本质 以电脑游戏为例 强化学习三个步骤 第一步:有未知参数的函数 第二步:定义Loss 第三步:Optimization RL的难点 类比GAN Policy Gradien ...
- 强化学习Reinforcement Learning概念理解篇(一)
在学习强化学习之前,应该对强化学习有一个大致的了解,即去分析一下强化学习的结构或者组成元素: 什么是强化学习?所谓强化学习,就是在与环境的互动当中,为了达到某一个目标而精心的学习过程,因此称之为Goa ...
最新文章
- 【C 语言】文件操作 ( 学生管理系统 | 插入数据 | 查询数据 | 删除数据 )
- HDU 3037 Saving Beans (Lucas法则)
- 计划得一步一步实施,题库首先是第一步!
- Linux Cpu 利用率计算
- springboot mysql事物_在Spring Boot中使用数据库事务
- python每行乘列表_python – 在pandas数据帧中查找每行的两列列表中哪一列的最快方法...
- Java 获取两个日期之间的日期
- github库fork后,将更新提交到源库
- bitmap位图详解
- matlab 数学符号输入,matlab输入数学符号
- 《STL源码剖析》--memery
- java中decrement,Java LongAdder decrement()用法及代碼示例
- java8 zoneid_java8之localDateTime, ZoneId, Instant使用
- redis单点故障方案
- 64位系统究竟牛逼在哪里?
- 媒资系统服务器,服务器软件的配置-媒资系统安装说明.ppt
- 小生云服务器,HobitLab#2--云服务器的有效利用之搭建tiny tiny RSS
- 关于《剑指offer》的66道编程题的总结(五)
- 白话讲懂wait notify 和park unpark的使用示例和区别
- chatGPT研究-(一)使用入门及Access Denied打不开问题解决
热门文章
- QImage/cv::Mat/HObject的图像格式互相转换,4字节对齐
- html引入vue不兼容ie11,Vue在IE11版本浏览器中的兼容性问题
- 入行多年软件测试总结的经验
- 2017京东春招C/C++编程题(1)——站队
- 汉锐USB会议摄像机、1080P让商务视频会议更加轻松
- 计算机领域怎么研究区块链,计算机行业深度研究:跨链技术,区块链大航海时代的基石...
- 手把手教你用Java实现一个“网易云音乐”
- 使用git拉取项目、创建分支、提交代码教程
- 使用PS去水印的方法
- java模拟网易邮箱登录_java实现163邮箱发送邮件到qq邮箱成功案例