mxxhcm's blog

  • 首页

  • 标签

  • 分类

  • 归档

reinforcement learning an introduction 第4章笔记

发表于 2019-04-07 | 更新于 2019-12-17 | 分类于 强化学习

原理

Policy iteration有两种方式实现,一种是使用两个数组,一个保存原来的值,一个用来进行更新,这种方法是雅克比方法,或者叫同步的方法,因为他可以并行的进行。
In-place的方法是高斯赛德尔方法。就是用来解方程组的迭代法。

Dynamic Programming

DP指的是给定环境的模型,通常是一个MDP,计算智能体最优策略的一类算法。经典的DP算法应用场景有限,因为它需要环境的模型,计算量很高,但是DP的思路是很重要的。许多其他的算法都是在尽量减少计算量和对环境信息情况,尽可能获得和DP接近的性能。
通常我们假定环境是一个有限(finite)的MDP,也就是state, action, reward都是有限的。尽管DP可以应用于连续(continuous)的state和action space,但是只能应用在几个特殊的场景上。一个常见的做法是将连续state和action quantize(量化),然后使用有限MDP。
DP关键在于使用value function寻找好的policy,在找到了满足Bellman optimal equation的optimal value function之后,可以找到optimal policy,参见第三章推导:
Bellman optimal equation:
\begin{align*}
v_{*}(s) &= max_a\mathbb{E}\left[R_{t+1}+\gamma v_{*}(S_{t+1})|S_t=s,A_t=a\right] \\
&= max_a \sum_{s’,r} p(s’,r|s,a){*}\left[r+\gamma v_{*}(s’)\right] \tag{1}
\end{align*}

\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) \left[r + \gamma max_a q_{*}(s’,a’)\right] \tag{2}
\end{align*}

Policy Evaluation(Prediction)

给定一个policy,计算state value function的过程叫做policy evaluation或者prediction problem。
根据$v(s)$和它的后继状态$v(s’)$之间的关系:
\begin{align*}
v_{\pi}(s) &= \mathbb{E}_{\pi}[G_t|S_t = s]\\
&= \mathbb{E}_{\pi}\left[R_{t+1}+\gamma G_{t+1}|S_t = s\right]\\
&= \sum_a \pi(a|s)\sum_{s’}\sum_rp(s’,r|s,a) \left[r + \gamma \mathbb{E}_{\pi}\left[G_{t+1}|S_{t+1}=s’\right]\right] \tag{3}\\
&= \sum_a \pi(a|s)\sum_{s’,r}p(s’,r|s,a) \left[r + \gamma v_{\pi}(s’) \right] \tag{4}\\
\end{align*}
只要$\gamma \lt 1$或者存在terminal state,那么$v_{\pi}$的必然存在且唯一。这个我觉得是迭代法解方程的条件。数值分析上有证明。
如果环境的转换概率$p$是已知的,可以列出方程组,直接求解出每个状态$s$的$v(s)$。这里采用迭代法求解,随机初始化$v_0$,使用式子$(4)$进行更新:
\begin{align*}
v_{k+1}(s) &= \mathbb{E}\left[R_{t+1} + \gamma v_k(S_{t+1})\ S_t=s\right]\\
&= \sum_a \pi(a|s)\sum_{s’,r}p(s’,r|s,a) \left[r + \gamma v_k(s’) \right] \tag{5}
\end{align*}
直到$v_k=v_{\pi}$到达fixed point,Bellman equation满足这个条件。当$k\rightarrow \infty$时收敛到$v_{\pi}$。这个算法叫做iterative policy evaluation。
在每一次$v_k$到$v_{k+1}$的迭代过程中,所有的$v(s)$都会被更新,$s$的旧值被后继状态$s’$的旧值加上reward替换,正如公式$(5)$中体现的那样。这个目标值被称为expected update,因为它是基于所有$s’$的期望计算出来的(利用环境的模型),而不是通过对$s’$采样计算的。
在实现iterative policy evaluation的时候,每一次迭代,都需要重新计算所有$s$的值。这里有一个问题,就是你在每次更新$s$的时候,使用的$s’$如果在本次迭代过程中已经被更新过了,那么是使用更新过的$s’$,还是使用没有更新的$s’$,这就和迭代法中的雅克比迭代以及高斯赛德尔迭代很像,如果使用更新后的$s’$,这里我们叫它in-place的算法,否则就不是。具体那种方法收敛的快,还是要看应用场景的,并不是in-place的就一定收敛的快,这是在数值分析上学到的。
下面给出in-place版本的iterative policy evation算法伪代码。
iterative policy evation 算法
输入需要evaluation的policy $\pi$
给出算法的参数:阈值$\theta\gt 0$,当两次更新的差值小于这个阈值的时候,就停止迭代,随机初始化$V(s),\forall s\in S^{+}$,除了$V(terminal) = 0$。
Loop
$\qquad \delta \leftarrow 0$
$\qquad$ for each $s\in S$
$\qquad\qquad v\leftarrow V(s)$ (保存迭代之前的$V(s)$)
$\qquad\qquad V(s)\leftarrow\sum_a \pi(a|s)\sum_{s’,r}p(s’,r|s,a) \left[r + \gamma v_k(s’) \right] $
$\qquad\qquad \nabla \leftarrow max(\delta,|v-V(s)|)$
$\qquad$end for
until $\delta \lt \theta$

Policy Improvement

为什么要进行policy evaluation,或者说为什么要计算value function?
其中一个原因是为了找到更好的policy。假设我们已经知道了一个deterministic的策略$\pi$,但是在其中一些状态,我们想要知道是不是有更好的action选择,如$a\neq \pi(s)$的时候,是不是这个改变后的策略会更好。好该怎么取评价,这个时候就可以使用值函数进行评价了,在某个状态,我们选择$a \neq \pi(s)$,在其余状态,依然遵循策略$\pi$。用公式表示为:
\begin{align*}
q_{\pi}(s,a) &= \mathbb{E}\left[R_{t+1}+\gamma v_{\pi}(S_{t+1})|S_t=s,A_t = a\right]\\
&=\sum_{s’,r}p(s’,r|s,a)\left[r+\gamma v_{\pi}(s’)\right] \tag{6}
\end{align*}
那么,这个值是是比$v(s)$要大还是要小呢?如果比$v(s)$要大,那么这个新的策略就比$\pi$要好。
用$\pi$和$\pi’$表示任意一对满足下式的deterministic policy:
$$q_{\pi}(s,\pi’(s)) \ge v_{\pi}(s) \tag{7}$$
那么$\pi’$至少和$\pi$一样好。可以证明,任意满足$(7)$的$s$都满足下式:
$$v_{\pi’}(s) \ge v_{\pi}(s) \tag{8}$$
对于我们提到的$\pi$和$\pi’$来说,除了在状态$s$处,$v_{\pi’}(s) = a \neq v_{\pi}(s)$,在其他状态处$\pi$和$\pi’$是一样的,都有$q_{\pi}(s,\pi’(s)) = v_{\pi}(s)$。而在状态$s$处,如果$q_{\pi}(s,a) \gt v_{\pi}(s)$,注意这里$a=\pi’(s)$,那么$\pi’$一定比$\pi$好。
证明:
\begin{align*}
v_{\pi}(s) &\le q_{\pi}(s,\pi’(s))\\
& = \mathbb{E}\left[R_{t+1} + \gamma v_{\pi}(S_{t+1})|S_t = s, A_t = \pi’(s) \right]\\
& = \mathbb{E}_{\pi’}\left[R_{t+1} + \gamma v_{\pi}(S_{t+1})|S_t = s \right]\\
& \le \mathbb{E}_{\pi’}\left[R_{t+1} + \gamma q_{\pi}(S_{t+1},\pi’(S_{t+1}))|S_t = s \right]\\
& = \mathbb{E}_{\pi’}\left[ R_{t+1} + \gamma \mathbb{E}_{\pi’}\left[R_{t+2} +\gamma v_{\pi}(S_{t+2})|S_{t+1}, A_{t+1}=\pi’(S_{t+1})|S_t = s \right]\right]\\
& = \mathbb{E}_{\pi’}\left[ R_{t+1} + \gamma R_{t+2} +\gamma^2 v_{\pi}(S_{t+2})|S_t = s \right]\\
& \le \mathbb{E}_{\pi’}\left[ R_{t+1} + \gamma R_{t+2} +\gamma^2 R_{t+3} +\gamma^3 v_{\pi}(S_{t+3})|S_t = s \right]\\
& \le \mathbb{E}_{\pi’}\left[ R_{t+1} + \gamma R_{t+2} +\gamma^2 R_{t+3} +\gamma^3 R_{t+4} + \cdots |S_t = s \right]\\
&=v_{\pi’}(s)
\end{align*}
所以,在计算出一个policy的value function的时候,很容易我们就直到某个状态$s$处的变化是好还是坏。扩展到所有状态和所有action的时候,在每个state,根据$q_{\pi}(s,a)$选择处最好的action,这样就得到了一个greedy策略$\pi’$,给出如下定义:
\begin{align*}
\pi’(s’) &= argmax_{a} q_{\pi}(s,a)\\
& = argmax_{a} \mathbb{E}\left[R_{t+1} + \gamma v_{\pi}(S_{t+1} |S_t=a,A_t=a)\right] \tag{9}\\
& = argmax_{a} \sum_{s’,r}p(s’,r|s,a)\left[r+v_{\pi}(s’) \right]
\end{align*}
可以看出来,该策略的定义一定满足式子$(7)$,所以$\pi’$比$\pi$要好或者相等,这就叫做policy improvement。当$\pi’$和$\pi$相等时,,根据式子$(9)$我们有:
\begin{align*}
v_{\pi’}(s’)& = max_{a} \mathbb{E}\left[R_{t+1} + \gamma v_{\pi’}(S_{t+1} |S_t=a,A_t=a)\right] \tag{9}\\
& = max_{a} \sum_{s’,r}p(s’,r|s,a)\left[r+v_{\pi’}(s’) \right]
\end{align*}
这和贝尔曼最优等式是一样的???殊途同归!!!
但是,需要说的一点是,目前我们假设的$\pi$和$\pi’$是deterministic,当$\pi$是stochastic情况的时候,其实也是一样的。只不过,原来我们每次选择的是使得$v_{\pi}$最大的action。对于stochastic的情况来说,输出的是每个动作的概率,可能有几个动作都能使得value function最大,那就让这几个动作的概率一样大,比如是$n$个动作,都是$\frac{1}{n}$。

Policy Iteration

我们已经讲了Policy Evaluation和Policy Improvement,Evalution会计算出一个固定$\pi$的value function,Improvment会根据value function改进这个policy,然后计算出一个新的policy $\pi’$,对于新的策略,我们可以再次进行Evaluation,然后在Improvement,就这样一直迭代,对于有限的MDP,我们可以求解出最优的value function和policy。这就是Policy Iteration算法。

Policy Iteration算法
1.初始化
$V(s)\in R,\pi(s) in A(s)$
$\qquad$
2.Policy Evaluation
Loop
$\qquad\Delta\leftarrow 0 $
$\qquad$ For each $s\in S$
$\qquad\qquad v\leftarrow V(s)$
$\qquad\qquad V(s)\leftarrow \sum_{s’,r}p(s’,r|s,a)\left[r+\gamma V(s’)\right]$
$\qquad\qquad \Delta \leftarrow max(\Delta, |v-V(s)|) $
until $\Delta \lt \theta$
3.Policy Improvement
$policy-stable\leftarrow true$
For each $s \in S$
$\qquad old_action = \pi(s)$
$\qquad \pi(s) = argmax_a \sum_{s’,a’}p(s’,r|s,a)\left[r+\gamma V(s’)\right]$
$\qquad If\ old_action \neq \pi(s), policy-stable\leftarrow false$
If policy-stable,停止迭代,返回$V$和$\pi$,否则回到2.Policy Evalution继续执行。

Value Iteration

从Policy Iteration算法中我们可以看出来,整个算法分为两步,第一步是Policy Evaluation,第二步是Policy Improvement。而每一次Policy Evaluation都要等到Value function收敛到一定程度才结束,这样子就会非常慢。一个替代的策略是我们尝试每一次Policy Evaluation只进行几步的话,一种特殊情况就是每一个Policy Evaluation只进行一步,这种就叫做Value Iteration。给出如下定义:
\begin{align*}
v_{k+1}(s) &= max_a \mathbb{E}\left[R_{t+1} + \gamma v_k(S_{t+1})| S_t=s, A_t = a\right]\\
&= max_a \sum_{s’,r}p(s’,r|s,a) \left[r+\gamma v_k(s’)\right] \tag{10}
\end{align*}
它其实就是把两个步骤给合在了一起,原来分开是:
\begin{align*}
v_{\pi}(s) &= \mathbb{E}\left[R_{t+1} + \gamma v_k(S_{t+1})| S_t=s, A_t = a\right]\\
&= \sum_{s’,r}p(s’,r|s,a) \left[r+\gamma v_k(s’)\right]\\
v_{\pi’}(s) &= max_a \sum_{s’,r}p(s’,r|s,a) \left[r+\gamma v_{\pi}(s’)\right]\\
\end{align*}
另一种方式理解式$(10)$可以把它看成是使用贝尔曼最优等式进行迭代更新,Policy Evaluation用的是贝尔曼期望等式进行更新。下面给出完整的Value Iteration算法

Value Iteration 算法
初始化
阈值$\theta$,以及随机初始化的$V(s), s\in S^{+}$,$V(terminal)=0$。
Loop
$\qquad v\leftarrow V(s)$
$\qquad$Loop for each $s\in S$
$\qquad\qquad V(s) = max_a\sum_{s’,r}p(s’,r|s,a)\left[r+\gamma V(s’)\right]$
$\qquad\qquad\Delta \leftarrow max(Delta, |v-V(s)|)$
until $\Delta \lt \theta$
返回 输出一个策略$\pi\approx\pi_{*}$,这里书中说是deterministic,我觉得都可以,$\pi$也可以是stochastic的,最后得到的$\pi$满足:
$\pi(s) = argmax_a\sum_{s’,r}p(s’,r|s,a)\left[r+\gamma V(s’)\right]$

Asychronous Dynamic Programming

之前介绍的这些DP方法,在每一次操作的时候,都有对所有的状态进行处理,这就很耗费资源。所以这里就产生了异步的DP算法,这类算法在更新的时候,不会使用整个的state set,而是使用部分state进行更新,其中一些state可能被访问了很多次,而另一些state一次也没有被访问过。
其中一种异步DP算法就是在plicy evalutaion的过程中,只使用一个state。
使用DP算法并不代表一定能减少计算量,他只是减少在策略没有改进之前陷入无意义的evaluation的可能。尽量选取那些重要的state用来进行更新。
同时,异步DP方便进行实时的交互。在使用异步DP更新的时候,同时使用一个真实场景中的agent经历进行更新。智能体的experience可以被用来确定使用哪些state进行更新,DP更新后的值也可以用来指导智能体的决策。

Generalized Policy Iteration

之前介绍了三类方法,Policy Iteration,Value iteration以及Asychronous DP算法,它们都有两个过程在不断的迭代进行。一个是evaluation,一个是improvement,这类算法统一的被称为Generalized Policy Iteration(GPI),可以根据不同的粒度进行细分。基本上所有的算法都是GPI,policy使用value function进行改进,value function朝着policy的真实值函数改进,如果value function和policy都稳定之后,那么说他们都是最优的了。
GPI中evalution和improvemetnt可以看成既有竞争又有合作。竞争是因为evaluation和improment的方向通常是相对的,policy改进意味着value function不适用于当前的policy,value function更新意味着policy不是greedy的。然后长期来说,他们共同作用,想要找到最优的值函数和policy。
GPI可以看成两个目标的交互过程,这两个目标不是正交的,改进一个目标也会使用另一个目标有所改进,直到最后,这两个交互过程使得总的目标变成最优的。

Efficiency of Dynamic Programming

用$n$和$k$表示MDP的状态数和动作数,DP算法保证在多项式时间内找到最优解,即使策略的总数是$k^n$个。
DP比任何在policy space内搜索的算法要快上指数倍,因为policy space搜索需要检查每一个算法。Linear Programming算法也可以用来解MDP问题,在某些情况下最坏的情况还要比DP算法快,但是LP要比只适合解决state数量小的问题。而DP也能处理states很大的情况。

Summary

  • 使用贝尔曼公式更新值函数,可以使用backup diagram看他们的直观表示。
  • 基本上所有的强化学习算法都可以看成GPI(generalized policy iteraion),先评估某个策略,然后改进这个策略,评估新的策略…这样子循环下去,直到收敛,找到一个不在变化的最优值函数和策略。
    GPI不一定是收敛的,本章介绍的这些大多都是收敛的,但是还有一些没有被证明收敛。
  • 可以使用异步的DP算法。
  • 所有的DP算法都有一个属性叫做bootstrapping,即基于其他states的估计更新每一个state的值。因为每一个state value的更新都需要用到他们的successor state的估计。

They update estimates onthe basis of other estimates。

reinforcement learning an introduction 第9章笔记

发表于 2019-04-04 | 更新于 2019-12-17 | 分类于 强化学习

On-policy Prediction with Approximation

这一章讲的是利用on-policy的数据估计函数形式的值函数,on-policy就是说利用一个已知的policy $\pi$生成的experience来估计$v_{\pi}$。和之前讲的不同的是,前面几章讲的是表格形式的值函数,而这一章是使用参数为$\mathbf{w}\in R^d$的函数表示。即$\hat{v}(s,\mathbf{w})\approx v_{\pi}(s)$表示给定一个权值vector $\mathbf{w}$,state $s$的状态值。这个函数可以是任何形式的,可以是线性函数,也可以是神经网络,还可以是决策树。

值函数估计

目前这本书介绍的所有prediction方法都是更新某一个state的估计值函数向backed-up value(或者叫update target)值移动。我们用符号$s\mapsto u$表示一次更新。其中$s$是要更新的状态,$u$是$s$的估计值函数的update target。例如,Monte Carlo更新的value prediction是:$S_t \mapsto G_t$,TD(0)的update是:$S_t \mapsto R_{t+1} + \gamma \hat{v}(S_{t+1}, \mathbf{w}_t)$,$n$-step TD update是:$S_t \mapsto G_{t:t+n}$。在DP policy evaluation update中是:$s\mapsto E_{\pi}[R_{t+1}+\gamma\hat{v}(S_{t+1}, \mathbf{w}_t)| S_t =s]$,任意一个状态$s$被更新了,同时在其他真实experience中遇到的$S_t$也被更新了。

之前表格的更新太trivial了,更次更新$s$向$u$移动,其他状态的值都保持不变。现在使用函数实现更新,在状态$s$处的更新,可以一次性更新很多个其他状态的值。就像监督学习学习input和output之间的映射一样,我们可以把$s\mapsto g$的更新看做一个训练样本。这样就可以使用很多监督学习的方法学习这样一个函数。
但是并不是所有的方法都适用于强化学习,因为许多复杂的神经网络和统计学方法都假设训练集是静态不变的。然而强化学习中,学习是online的,即智能体不断地与环境进行交互产生新的数据,这就需要这个方法能够从不断增加的数据中高效的学习。
此外,强化学习通常需要function approximation能够处理target function不稳定的情况,即target function随着事件在不断的变化。比如,在基于GPI的control方法中,在$\pi$不断变化的情况下,我们想要学习出$q_{\pi}$。即使policy保持不变,如果使用booststrapping方法(DP和TD学习),训练样本的target value也在不断的改变,因为下一个state的value值在不断的改变。所以不能处理这些不稳定情况的方法有点不适合强化学习。

预测目标(The Prediction Objective)

表格形式的值函数最终都会收敛到真值,状态值之间也都是解耦的,即更新一个state不影响另一个state。
但是使用函数拟合,更新一个state的估计值就会影响很多个其他状态,并且不可能精确的估计所有states的值。假设我们的states比weights多的多,让一个state的估计更精确也意味着使得其他的state越不accurate。我们用一个state $s$上的分布,$\mu(s)\ge 0,\sum_s\mu(s)=1$代表对每个state上error的权重。然后使用$\mu(s)$对approximate value $\hat{v}(s,\mathbf{w})$和true value $v_{\pi}(s)$的squared error进行加权,得到Mean Squared Value Error,表示为$\bar{VE}$:
$$\bar{VE}(\mathbf{w}) = \sum_{s\in S}\mu(s)[v_{\pi}(s) - \hat{v}(s, \mathbf{w})]^2$$
通常情况下,$\mu(s)$是在state $s$处花费时间的百分比。在on-policy训练中,这叫做on-policy分布。在continuing tasks中,策略$\pi$下的on-policy分布是一个stationary distribution。
在episodic tasks中,on-policy分布有一些不同,因为它还取决于每个episodic的初始状态,用$h(s)$表示在一个episodic开始状态为$s$的概率,用$\eta(s)$表示在一个回合中,state $s$平均被访问的次数。
$$\eta(s) = h(s) + \sum_{\bar{s}}\eta(\bar{s})\sum_a\pi(a|\bar{s})p(s|\bar{s},a), forall\ s \in S$$
其中$\bar{s}$是$s$的前一个状态,$s$处的时间为以状态$s$开始的概率$h(s)$加上它由前一个状态$\bar{s}$转换过来消耗的时间。
列出一个方程组,可以解出来$\eta(s)$的期望值。然后进行归一化,得到:
$$\mu(s)=\frac{\eta{s}}{\sum_{s’}\eta{s’}}, \forall s \in S.$$
这是没有折扣因子的式子,如果有折扣因子的话,可以看成一种形式的

OS boot and partition

发表于 2019-04-03 | 更新于 2019-12-17 | 分类于 计算机系统

硬盘逻辑划分

分区可以说是对硬盘的一种格式化。创建分区设置好硬盘的各项物理参数,指定了硬盘主引导记录(即Master Boot Record,一般简称为MBR)和引导记录备份的存放位置。而对于文件系统以及其他操作系统管理硬盘所需要的信息则是通过以后的高级格式化,即 Format命令来实现。面、磁道和扇区硬盘分区后,将会被划分为面(Side)、磁道(Track)和扇区(Sector)。需要注意的是,这些只是个 虚拟的概念,并不是真正在硬盘上划轨道。

面,磁头,柱面 硬盘一般是由一片或几片圆形薄片叠加而成的。每个圆形薄片都有两个“面”,这两个面都可以用来存储数据的。按照面的顺序,依次称为0 面,1面,…,每个面都都有一个读写磁头,也常用0头,1头,…,按照硬盘容量和规格的不同,硬盘面数(或头数)也各有差异。每个硬盘上所有硬盘面数磁道号相同的磁道叠起来,称为一个柱面(Cylinder)。

磁道,扇区 由于磁盘通过旋转磁头读取或者写入数据,磁头旋转的时候就形成了一个圆周。这样的圆周就称为一个磁道。如果磁头沿着面的半径移动,就到了另外一个磁道。根据硬盘的不同,磁道数可以从几百到数千不等;一个磁道上可以容纳数KB 的数据,而主机读写时往往并不需要一次读写那么多,于是,磁道又被划分成若干段,每段称为一个扇区。一个扇区一般存放512字节的数据。对同一磁道中的扇区进行编号:1扇区,2扇区,…
计算机对硬盘的读写,出于效率的考虑,以扇区为基本单位。即计算机如果只需要硬盘上存储的某个字节,也必须一次把这个字节所在的扇区中的512字节全部 读入内存,再使用所需的那个字节。为了区分每个山区,在每个扇区存取的数据前、后两端,都有一些特定的数据,这些数据构成了扇区的界限标志,标志中含有扇区的编号和其他信息。计算机凭借着这些标志来识别扇区。

硬盘分区

硬盘的数据按照特点和作用可以分为$5$部分,引导区,DBR区,FAT区,DIR区和DATA区。
引导区常见的有MBR和GPT。
DBR是操作系统引导记录区
FAT区存放的是文件簇信息。常见的有FAT16和FAT32
DIR是根目录区
DATA区存放数据

BIOS,UEFI和MBR,GPT

BIOS和UEFI是常见的引导,MBR和GPT是分区表类型。
BIOS(Basic Input Output System)
UEFI(Unifed Extensible Firmware Interface)
MBR(Master Boot Record)
GPT(GUID Partion Table)

MBR

传统的MBR,位于整个硬盘的$0$磁道$0$柱面$1$扇区,也叫主引导扇区,总计$512$个字节。MBR只占用了$446$个字节,剩下的$64$个字节用来保存硬盘的分区表(Disk Partion Talbe, DPT),最多只有四个表项,也就是我们常遇到的最多只能设置四个主分区(或者$3$个主分区,$1$个扩展分区和无限制个数的逻辑驱动器),每个表项只有$16$个字节,每一个分区使用$4$个字节存储总扇区数,每个分区不能大于$2TB(2^{32}\times 512 bytes$),就是$2^{32}$个扇区,每个扇区按$512$字节来算,其他$12$个字节用来存储分区的其他信息。如图所示:
mbr

GPT

GPT分区需要需要操作系统更支持,可以有任何个数个主分区,每个分区都可以大于$2$T,它是基于UEFI使用的磁盘分区架构。

UEFI

UEFI是用来取代BIOS的,UEFI启动系统引导的方法是查找硬盘分区中第一个FAT分区内的引导文件进行系统分区,不具体指定分区表区。
FAT分区内可以存放MBR分区表,也可以存放GPT分区表。

从GPT硬盘启动

从GPT分区硬盘启动需要满足三个条件:

  • 操作系统支持,windows只有64为操作系统支持
  • 硬盘使用GPT分区
  • 主板使用UEFI模式

引导和分区类型匹配

BIOS + MBR

所有系统都支持,不支持大于$2$T的硬盘。

BIOS + GPT

BIOS可以使用GPT分布表,将GPT硬盘作为资料盘,但是不能用来引导系统,而且必须使用$64$位系统。

UEFI(legacy) + MBR

可以将UEFI设置为legacy(传统模式),支持MBR启动,和BIOS+MBR一样,也可以建立FAT分区,放置UEFI启动文件。

UEFI + GPT

可以把大于$2$T的硬盘当做系统盘,必须使用$64$位系统。

双系统

安装双系统直接进windows,使用EasyUEFI/Easybcd(工具)添加linux启动项,或者使用windows命令,bcdedit进行编辑(文档参见msdn,推荐使用这种方法)。
双系统直接进ubuntu,使用grub引导,执行update-grub自动修改/boot/grub/grub.cfg 文件。然后重启就会发现有了这个开机启动项,见参考文献[3]。

可以参考参考文献[3],或者参考文献[4]。

参考文献

1.https://blog.csdn.net/hyy5801965/article/details/51136395
2.https://www.cnblogs.com/zhangming-blog/articles/5392115.html
3.https://askubuntu.com/a/945988
4.https://askubuntu.com/a/217970
5.http://lanlingzi.cn/post/notes/2016/0313_grub_win10/

reinforcement learning an introduction 第13章笔记.md

发表于 2019-04-03 | 更新于 2019-07-25 | 分类于 强化学习

Policy gradient

这章介绍的是使用一个参数化策略(parameterized policy)直接给出action,而不用借助一个value funciton选择action。但是需要说一下的是,Policy gradient方法也可以学习一个Value function,但是value function是用来帮助学习policy parameters的,而不是用来选择action。我们用$\mathbf{\theta} \in R^{d’}$表示policy’s parameters vector,用$\pi(a|s, \mathbf{\theta}) = Pr[A_t = a|S_t = s, \mathbf{\theta}_t = \mathbf{\theta}]$表示environment在时刻$t$处于state $s$时,智能体根据参数为$\mathbf{\theta}$的策略$\pi$选择action $a$。
如果policy gradient方法使用了一个value function,它的权重用$\mathbf{w} \in R^d$表示,即$\hat{v}(s,\mathbf{w})$。

用$J(\mathbf{\theta})$表示policy parameters的标量performance measure。使用梯度上升(gradient ascent) 方法来最大化这个performance:
$$\mathbf{\theta}_{t+1} = \mathbf{\theta}_t + \alpha \widehat{\nabla J(\mathbf{\theta}_t}),\tag{1}$$
其中$\widehat{\nabla J(\mathbf{\theta}_t)} \in R^{d’}$是一个随机估计(stachastic estimate),它的期望是performance measure对$\mathbf{\theta_t}$的梯度。不管它们是否使用value function,这种方法就叫做policy gradient方法。既学习policy,又学习value function的方法被称为actor-critic,其中actor指的是学到的policy,critic指的是学习到的value funciton,通常是state value function。

policy估计和它的优势

参数化policy的条件

policy可以用任何方式参数化,只要$\pi(a|s,\mathbf{\theta}),\mathbf{\theta}\in R^{d’}$对于它的参数$\mathbf{\theta}$是可导的,即只要$\nabla_{\pi}(a|s,\mathbf{\theta})$(即:$\pi(a|s,\mathbf{\theta})$相对于$\mathbf{\theta}$的偏导数列向量)存在,并且$\forall s\in S, a\in A(s)$偏导数都是有限的即可。

stochastic policy

为了保证exploration,通常策略是stochastic,而不是deterministic,即$\forall s,a,\mathbf{\theta}, \pi(a|s,\mathbf{\theta})\in (0,1)$

参数化方式的选择

softmax

对于有限且离散的action space,一个很自然的参数化方法就是对于每一个state-action对都计算一个参数化的数值偏好$h(s,a,\mathbf{\theta})\in R$。通过计算一个exponetial softmax,这个数值大的动作有更大的概率被选中:
$$\pi(a|s,\mathbf{\theta}) = \frac{e^{h(s,a,\mathbf{\theta} )}}{\sum_be^{h(s,b,\mathbf{\theta} )}}, \tag{2}$$
其中$b$是在state $s$下所有可能采取的动作,它们的概率加起来为$1$,这种方法叫做softmax in aciton preferences。

NN和线性方法

参数化还可以选择其他各种各样的方法,如AlphaGo中使用的NN,或者可以使用如下的线性方法:
$$h(s,a, \mathbf{\theta}) = \mathbf{\theta}^Tx(s,a), \tag{3}$$

优势

和action value方法相比,policy gradient有多个优势。
第一个优势是使用action preferences的softmax,同时用$\epsilon-greedy$算法用$\epsilon$的概率随机选择action得到的策略可以接近一个deterministic policy。
而单单使用action values的方法并不会使得策略接近一个deterministic policy,但是action-value方法会逐渐收敛于它的true values,翻译成概率来表示就是在$0$和$1$之间的一个概率值。但是action preferences方法不收敛于任何值,它们产生optimal stochastic policy,如果optimal policy是deterministic,那么optimal action的preferences应该比其他所有suboptimal actions都要高。

第二个优势是使用action preferences方法得到的参数化策略可以使用任意的概率选择action。在某些问题中,最好的approximate policy可能是stochastic的,actor-value方法不能找到一个stochastic optimal policy,它总是根据action value值选出来一个值最大的action,但是这时候的结果通常不是最优的。

第三个优势是policy parameterization可能比action value parameterization更容易学习。当然,也有时候可能是action value更容易。这个要根据情况而定

第四个优势是policy parameterizaiton比较容易添加先验知识到policy中。

policy gradient理论

除了上节说的实用优势之外,还有理论优势。policy parameterization学到关于参数的一个连续函数,action probability概率可以平滑的变化。然而$\epsilon-greedy$算法中,action-value改变以后,action probability可能变化很大。很大程度上是因为policy gradient方法的收敛性要比action value方法强的多。因为policy的连续性依赖于参数,使得policy gradient方法接近于gradient ascent。
这里讨论episodic情况。定义perfromance measure是episode初始状态的值。假设每一个episode,都从state $s_0$开始,定义:
$$J(\mathbf{\theta}) = v_{\pi_\mathbf{\theta}}(s_0), \tag{4}$$
其中$v_{\pi_\mathbf{\theta}}(s_0)$是由参数$\mathbf{\theta}$确定的策略$\pi_{\mathbf{\theta}}$的true value function。假设在episodic情况下,$\gamma=1$。

使用function approximation,一个需要解决的问题就是如何确保每次更新policy parameter,performance measure都有improvement。因为performence不仅仅依赖于action的选择,还取决于state的分布,然后它们都受policy parameter的影响。给定一个state,policy parameter对于actions,reward的影响,都可以相对直接的利用参数知识计算出来。但是policy parameter对于state 分布的影响是一个环境的函数,通常是不知道的。当梯度依赖于policy改变对于state分布的影响未知时,我们该如何估计performance相对于参数的梯度。

Episodic case证明

为了简化表示,用$\pi$表示参数为$\theta$的policy,所有的梯度都是相对于$\mathbf{\theta}$求的
\begin{align*}
\nabla v_{\pi}(s) &= \nabla [ \sum_a \pi(a|s)q_{\pi}(s,a)], \forall s\in S \tag{5}\\
&= \sum_a [\nabla\pi(a|s)q_{\pi}(s,a)], \forall s\in S \tag{6}\\
&= \sum_a[\nabla\pi(a|s)q_{\pi}(s,a) + \pi(a|s)\nabla q_{\pi}(s,a)] \tag{7}\\
&= \sum_a[\nabla\pi(a|s)q_{\pi}(s,a) + \pi(a|s)\nabla \sum_{s’,r}p(s’,r|s,a)(r+\gamma v_{\pi}(s’))] \tag{8}\\
&= \sum_a[\nabla\pi(a|s)q_{\pi}(s,a) + \pi(a|s) \nabla \sum_{s’,r}p(s’,r|s,a)r + \pi(a|s)\nabla \sum_{s’,r}p(s’,r|s,a)\gamma v_{\pi}(s’))] \tag{9}\\
&= \sum_a[\nabla\pi(a|s)q_{\pi}(s,a) + 0 + \pi(a|s)\sum_{s’}\gamma p(s’|s,a)\nabla v_{\pi}(s’) ] \tag{10}\\
&= \sum_a[\nabla\pi(a|s)q_{\pi}(s,a) + 0 + \pi(a|s)\sum_{s’}\gamma p(s’|s,a)\\
&\ \ \ \ \ \ \ \ \sum_{a’}[\nabla\pi(a’|s’)q_{\pi}(s’,a’) + \pi(a’|s’)\sum_{s’’}\gamma p(s’’|s’,a’)\nabla v_{\pi}(s’’))] ], \tag{11}展开\\
&= \sum_{x\in S}\sum_{k=0}^{\infty}Pr(s\rightarrow x, k,\pi)\sum_a\nabla\pi(a|x)q_{\pi}(x,a) \tag{12}
\end{align*}
第(5)式使用了$v_{\pi}(s) = \sum_a\pi(a|s)q(s,a)$进行展开。第(6)式将梯度符号放进求和里面。第(7)步使用product rule对q(s,a)求导。第(8)步利用$q_{\pi}(s, a) =\sum_{s’,r}p(s’,r|s,a)(r+v_{\pi}(s’)$ 对$q_{\pi}(s,a)$进行展开。第(9)步将(8)式进行分解。第(10)步对式(9)进行计算,因为$\sum_{s’,r}p(s’,r|s,a)r$是一个定制,求偏导之后为$0$。第(11)步对生成的$v_{\pi}(s’)$重复(5)-(10)步骤,得到式子(11)。如果对式子(11)中的$v_{\pi}(s)$一直展开,就得到了式子(12)。式子(12)中的$Pr(s\rightarrow x, k, \pi)$是在策略$\pi$下从state $s$经过$k$步转换到state $x$的概率,这里我有一个问题,就是为什么,$k$可以取到$\infty$,后来想了想,因为对第(11)步进行展开以后,可能会有重复的state,重复的意思就是从状态$s$开始,可能会多次到达某一个状态$x$,$k$就能取很多次,大不了$k=\infty$的概率为$0$就是了。

所以,对于$v_{\pi}(s_0)$,就有:
\begin{align*}
\nabla J(\mathbf{\theta}) &= \nabla_{v_{\pi}}(s_0)\\
&= \sum_{s\in S}( \sum_{k=0}^{\infty}Pr(s_0\rightarrow s,k,\pi) ) \sum_a\nabla_{\pi}(a|s)q_{\pi}(s,a)\\
&=\sum_{s\in S}\eta(s)\sum_a \nabla_{\pi}(a|s)q_{\pi}(s,a)\\
&=\sum_{s’\in S}\eta(s’)\sum_s\frac{\eta(s)}{\sum_{s’}\eta(s’)}\sum_a \nabla_{\pi}(a|s)q_{\pi}(s,a)\\
&=\sum_{s’\in S}\eta(s’)\sum_s\mu(s)\sum_a \nabla_{\pi}(a|s)q_{\pi}(s,a)\\
&\propto \sum_{s\in S}\mu(s)\sum_a\nabla\pi(a|s)q_{\pi}(s,a)
\end{align*}
最后,我们可以看出来performance对policy求导不涉及state distribution的导数。Episodic 情况下的策略梯度如下所示:
$$\nabla J(\mathbf{\theta})\propto \sum_{s\in S}\mu(s)\sum_aq_{\pi}(s,a)\nabla\pi(a|s,\mathbf{\theta}), \tag{13}$$
其中梯度是performacne指标$J$关于$\mathbf{\theta}$的偏导数列向量,$\pi$是参数$\mathbf{\theta}$对应的策略。在episodic情况下,比例常数是一个episode的平均长度,在continuing情况下,常数是$1$,实际上这个正比于就是一个等式。分布$\mu$是策略$\pi$下的on-policy分布。

REINFORCE: Monte Carlo Policy Gradient

对于式子(1),我们需要进行采样,让样本梯度的期望正比于performance measure对于$\mathbf{\theta}$的真实梯度。比例系数不需要确定,因为步长$\alpha$的大小是手动设置的。Policy gradient理论给出了一个正比于gradient的精确表达式,我们要做的就是选择采样方式,它的期望等于或者接近policy gradient理论给出的值。

all-actions

使用随机变量的期望替换对随机变量求和的取值,我们可以将式子(13)进行如下变化:
\begin{align*}
\nabla J(\mathbf{\theta})&\propto \sum_{s\in S}\mu(s)\nabla\pi(a|s,\mathbf{\theta})\sum_aq_{\pi}(s,a)\\
&=\mathbb{E}_{\pi}\left[\nabla\pi(a|S_t,\mathbf{\theta})\sum_aq_{\pi}(S_t,a)\right]\tag{14}
\end{align*}
接下来,我们可以实例化该方法:
$$\mathbf{\theta}_{t+1} = \mathbf{\theta}_t+\alpha\sum_a\hat{q}(S_t,s,\mathbf{w})\nabla\pi(a|S_t,\mathbf{\theta}), \tag{15}$$
其中$\hat{q}$是$q_{\pi}$的估计值,这个算法被称为all-actions方法,因为它的更新涉及到了所有的action。然而,我们这里介绍的REINFORCE仅仅使用了$t$时刻的action $A_t$。。

REINFORCE

和引入$S_t$的方法一样,使用随机变量的期望代替对与随机变量的可能取值进行求和,我们在式子(14)中引入$A_t$,
\begin{align*}
\nabla J(\mathbf{\theta}) &= \mathbb{E}_{\pi}\left[\sum_aq_{\pi}(S_t,a)\nabla\pi(a|S_t,\mathbf{\theta})\right]\\
& = \mathbb{E}_{\pi}\left[\sum_aq_{\pi}(S_t,a)\pi(a|S_t,\mathbf{\theta})\frac{\nabla\pi(a|S_t,\mathbf{\theta})}{\pi(a|S_t,\mathbf{\theta})}\right]\\
& = \mathbb{E}_{\pi}\left[q_{\pi}(S_t,A_t)\frac{\nabla\pi(A_t|S_t,\mathbf{\theta})}{\pi(A_t|S_t,\mathbf{\theta})}\right]\\
\end{align*}

DQN replay buffer tensorflow 实现与解析

发表于 2019-03-27 | 更新于 2019-12-17 | 分类于 强化学习

代码

这个DQN的Replay Buffer实现只用到了numpy库,可以很容易的进行扩展。主要有五个函数。接下来分函数进行解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import numpy as np
import random


class ReplayBuffer:
# config : memory_size, batch_size, history_length, state_format, screen_height, screen_width,
def __init__(self, config):
self.memory_size = config.memory_size
self.batch_size = config.batch_size

self.screens = np.empty((self.memory_size, config.screen_height, config.screen_width), dtype=np.float16)
self.actions = np.empty(self.memory_size, dtype=np.uint8)
self.rewards = np.empty(self.memory_size, dtype=np.int8)
self.terminals = np.empty(self.memory_size, dtype=np.bool)
self.history_length = config.history_length # state使用多少张screens拼接在一起,论文中是4张
self.state_format = config.state_format
self.dims = (config.screen_height, config.screen_width)
# state and next_state
self.states = np.empty((self.batch_size, self.history_length)+self.dims, dtype=np.float16)
self.next_states = np.empty((self.batch_size, self.history_length)+self.dims, dtype=np.float16)

self.count = 0 # 记录总共有多少条记录
self.current = 0 # 获取当前是第几条

def add(self, screen, action, reward, terminal):
self.screens[self.current] = screen
self.actions[self.current] = action
self.rewards[self.current] = reward
self.terminals[self.current] = terminal
self.count = max(self.current + 1, self.count)
self.current = (self.current + 1) % self.memory_size

def __len__(self):
return self.count

def clear(self):
self.current = 0
self.count = 0

def getState(self, index):
assert self.count > 0
# 每一个样本都要取self.history_length那么长。
if index >= self.history_length - 1:
return self.screens[index-(self.history_length - 1):index+1, ...]
else:
# 如果当前下标比self.history_length还要小,那么就要从buffer的结尾处取了。
indexes = [(index - i )% self.count for i in reversed(range(self.history_length))]
return self.screens[indexes, ...]


def sample(self):
assert self.count > self.history_length
indexes = []
while len(indexes) < self.batch_size:
while True:
index = random.randint(self.history_length, self.count + 1) # 相当于从self.histor_length之后进行采样
# 如果包含current,就重新采样。(current是刚生成的样本)
if index > self.current and self.current - self.history_length <= index:
continue
# 如果包含一个episode的结束状态,重新采样
if self.terminals[(index - self.history_length):self.history_length].any():
continue
break

self.states[len(indexes),...] = self.getState(index - 1)
self.next_states[len(indexes),...] = self.getState(index)
indexes.append(index)

actions = self.actions[indexes]
rewards = self.rewards[indexes]
terminals = self.terminals[indexes]

if self.state_format == 'NHWC':
return np.transpose(self.states, (0, 2, 3, 1)), actions, rewards, np.transpose(self.next_states, (0, 2, 3, 1)),terminals
else:
return self.states, actions, rewards, self.next_states, terminals

init函数

ReplayBuffer的init的输入参数为一个config文件,包含了创建ReplayBuffer的参数,memory_size是Buffer大小,batch_size为训练和测试的batch大小,screens, actions, rewards, terminals分别存放的是每次采样得到的screen, action, reward和terminal(当前episode是否结束)。history_length是原文中提到的连续处理四张图片的四,而不仅仅是一张。state_format指的是’NHWC’还是’NCHW’,即depth通道在第$1$维还是第$3$维,states存放的是一个tensor,shape为$(batch_size, screen_height, screen_width, history_length)$,count记录当前Buffer的大小,current记录当前experience插入的地方。

add方法

该方法实现了向ReplayBuffer中添加experience。

__len__方法

放回Buffer当前的大小

clear方法

清空Buffer

sample方法

从buffer中进行采样,返回一个元组,(states, actions, rewards, next_states, terminals)

getState方法

给定一个index,寻找它的前history_length - 1 个screens。

参考文献

1.https://github.com/devsisters/DQN-tensorflow

神经网络-dropout

发表于 2019-03-23 | 更新于 2019-12-17 | 分类于 机器学习

dropou是干什么的

Dropout 是一种正则化技术,通过学习鲁棒的特征来防止过拟合。

为什么会有过拟合

如果输入和正确输出之间有很复杂的映射关系,而网络又有足够多的隐藏单元去正确的建模,那么通常会用很多组权重都能在训练集上得到好的结果。但是每一组权重在测试集上的结果都比训练集差,因为它们只在训练集上训练了,而没有在测试集上训练。

什么是dropout

在网络中每一个隐藏单元的输出单元都有$0.5$的概率被忽略,所以每一个隐藏单元需要学会独立于其他的隐藏单元决定输出结果。

This technique reduces complex co-adaptations of neurons, since a neuron cannot rely on the presence of particular other neurons. It is, therefore, forced to learn more robust features that are useful in conjunction with many different random subsets of the other neurons. [0]

On each presentation of each training case, each hidden unit is randomly omitted from the network with a probability of 0.5, so a hidden unit cannot rely on other hidden units being present.[1]

Dropout stops the mechanism of training neurons of any layers as a family, so reduces co-adaptability.[3]

另一种方式可以把dropout看成对神经网络做平均。一种非常有效的减少测试误差的方法就是对一系列神经网络预测的结果取平均。理想的方式是训练很多个网络,然后分别在每个网络上进行测试,但是这样子的计算代价是很高的。随机的dropout让在合理的时间内训练大量不同的网络变得可能。当我们丢弃一个神经元的时候,它对loss函数没有任何贡献,所以在反向传播的时候,梯度为$0$,权值不会被更新。这就相当于我们对网络进行了一个下采样,训练过程的每次迭代中,采样网络的一部分进行训练,这样我们就得到了一个共享参数的集成模型。对于每一次训练,网络结构都是相同的,但是每次选择的参数都有很大可能是不同的,而且权重是共享的。

The neurons which are “dropped out” in this way do not contribute to the forward pass and do not participate in backpropagation. So every time an input is presented, the neural network samples a different architecture, but all these architectures share weights.

在测试的时候,使用"mean networks",就是保留网络中所有的权重,但是要把激活函数的输出(activations)乘上$0.5$,因为相对训练的时候,每个神经元都有$0.5$的概率被激活,这个时候如果不乘上的话,最后就相当于测试的时候激活的神经元是训练时候的两倍。在实践中证明,这和对一系列经过dropout的网络取平均值的结果是很像的。(为什么就是两倍?)

Dropout can also be thought of as an ensemble of models that share parameters. When we drop a neuron, it has no effect on the loss function and thus the gradient that flows through it during backpropagation is effectively zero and so its weights will not get updated. This means that we are basically subsampling a part of the neural network and we are training it on a single example. In every iteration of training, we will subsample a different part of the network and train that network on the datapoint at that point of time. Thus what we have essentially is an ensemble of models that share some parameters.[3]

一个具有$N$个隐藏节点的网络,和一个用于计算类别标签的softmax输出层,使用mean networks就相当于对$2^N$个网络输出的标签概率做几何平均(并不是数学上的几何平均)。(为什么是几何平均?这里其实不是几何平均,只是一个等权重加权。)

a) The authors of the referenced article don’t use the ‘geometric mean’ of the predictions, but “an equally weighted geometric mean” of them.
b) They propose geometric mean over arithmetic mean for giving more value to more frequent data, probably according to the understanding by them of the underlying relations.
If, for example, you take the arithmetic mean of ${10, 10, 100}$, you get $40$, but if you take their geometric mean you get $\sqrt[3]{10000} \approx 21.54$, meaning the ‘odd’ measurement ($100$) plays a smaller role to the mean.
c) Even the geometric mean might be misleading, if the data are not assigned their true ‘weight’, meaning their occurrence or probability of occurrence, while assuring that this assignment of weights is equally important for all data.
Hence “equally weighted geometric mean”.[2]

如果采取dropout之后的网络输出不一样,那么mean network的输出能够保证赋值一个更高的可能性到正确标签。mean network的方根误差要比dropout网络方根误差的平均值要好,也就是说先对网络做平均然后计算误差要比先计算误差然后再平均要好。

实际上,$0.5$这个值不是固定的,可以根据不同情况进行微调。

why dropout works

其实这个和上面介绍中差不多,给出一种直观的解释。给一个例子[4],有一个三层的神经网络,在下图中,红圈中的节点对于正确的输出起到了决定性的作用,在BP的过程中,它的权值不断增加,但是它可能在训练集上效果很好,但是测试集上很差。
dropout
当采用了dropout以后,我们随意丢弃一些节点,如果把上图的关键节点丢了,那么网络必须重新学习其他的节点,才能够正确的进行分类。如下图,网络必须在另外可能没有丢弃的三个节点中选择一个用于正确分类。所以,这样子上图中的关键节点的作用就会被减轻,在新数据集上的鲁棒性可能就会更好。
dropout

实现

numpy 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def forward(x, w1, w2, w3, training=False):
z1 = np.dot(x, w1)
y1 = np.tanh(z1)

z2 = np.dot(y1, w2)
y2 = np.dot(z2)
# dropout in layer 2
if training:
m2 = np.random.binomial(1, 0.5, size=z2.shape)
else:
m2 = 0.5

y2 *= m2
z3 = np.dot(y2, w3)
y3 = z3
return y1, y2, y3, m2

pytorch库

参考文献

1.https://arxiv.org/pdf/1207.0580.pdf
2.https://www.cs.toronto.edu/~hinton/absps/JMLRdropout.pdf
3.https://www.quora.com/What-is-dropout-in-deep-learning
4.https://www.quora.com/What-is-the-use-of-geometric-mean-in-dropout-neural-networks-It-says-that-by-approximating-an-equally-weighted-geometric-mean-of-the-predictions-of-an-exponential-number-of-learned-models-that-share-parameters
5.https://www.quora.com/Why-exactly-does-dropout-in-deep-learning-work
6.https://www.quora.com/How-does-the-dropout-method-work-in-deep-learning-And-why-is-it-claimed-to-be-an-effective-trick-to-improve-your-network
7.https://pgaleone.eu/deep-learning/regularization/2017/01/10/anaysis-of-dropout/

matplotlib笔记

发表于 2019-03-21 | 更新于 2019-12-17 | 分类于 python

show()

介绍

show()函数是一个阻塞函数,调用该函数,显示当前已经绘制的图像,然后需要手动关闭打开的图像,程序才会继续执行。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0,10,1)

y1 = x**2
y2 = 2*x +5

plt.plot(x,y1)
plt.savefig("0_1.png")
plt.show() # 调用show()会阻塞,然后关掉打开的图片,程序继续执行

plt.plot(x,y2)
plt.show()

savefig()

介绍

该文件接收一个参数,作为文件保存的路径。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0, 10, 1)

y1 = x**2
y2 = 2*x +5

plt.plot(x,y1)
plt.savefig("2.png") # 保存图像,名字为2.png
plt.show()

figure()

介绍

figure()函数相当于生成一张画布。如果不显示调用的话,所有的图像都会绘制在默认的画布上。可以通过调用figure()函数将函数图像分开。figure()会接受几个参数,num是生成图片的序号,figsize指定图片的大小。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0,10,1)

y1 = x**2
y2 = 2*x +5

# figure
plt.figure()
plt.plot(x,y1)

plt.figure(num=6,figsize=(10,10))
plt.plot(x,y2)
plt.show()

imshow()

介绍

该函数用来显示图像,接受一个图像矩阵。调用完该函数之后还需要调用show()函数。

代码示例

代码地址

1
2
3
4
5
6
7
8
import matplotlib.pyplot as plt
import numpy as np

img = np.random.randint(0, 255, [32, 32])
print(img.shape)

plt.imshow(img)
plt.show()

subplot()

介绍

绘制$m\times n$个子图

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0, 10, 1)
y1 = 2 * x
y2 = 3 * x
y3 = 4 * x
y4 = 5 * x

plt.figure()

plt.subplot(2, 2, 1)
plt.plot(x, y1, marker='s', lw=4)

plt.subplot(2, 2, 2)
plt.plot(x, y2, ls='-.')

plt.subplot(2, 2, 3)
plt.plot(x, y3, color='r')

plt.subplot(2, 2, 4)
plt.plot(x, y4, ms=10, marker='o')

plt.show()

subplots()

介绍

将一张图分成$m\times n$个子图。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np


figure,axes = plt.subplots(2, 3, figsize=[40,20])
axes = axes.flatten()

x = np.arange(0, 20)
y1 = pow(x, 2)
axes[0].plot(x, y1)

y5 = pow(x, 3)
axes[5].plot(x, y5)

plt.show()

ax()

介绍

获得当前figure的坐标轴,用来绘制。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-3.5,3.5,0.5)
y1 = np.abs(2 * x)
y2 = np.abs(x)

plt.figure(figsize=(10,10))
ax = plt.gca() # gca = get current axis
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('red')
ax.xaxis.set_ticks_position("bottom")
ax.yaxis.set_ticks_position("left")
ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',0))

# both work
ax.plot(x,y1,lw=2,marker='-',ms=8)
plt.plot(x,y2,lw=3,marker='^',ms=10)

# xlim and ylim
# ax.xlim([-3.8, 3.3])
# AttributeError: 'AxesSubplot' object has no attribute 'xlim'
plt.xlim([-3.8, 3.3])
plt.ylim([0, 7.2])

# xlabel and ylabel
# ax.xlabel('x',fontsize=20)
# AttributeError: 'AxesSubplot' object has no attribute 'xlabel'
plt.xlabel('x',fontsize=20)
plt.ylabel('y = 2x ')

# xticklabel and yticaklabel
# ax.xticks(x,('a','b','c','d','e','f','g','h','i','j','k','l','m','n'),fontsize=20)
# AttributeError: 'AxesSubplot' object has no attribute 'xticks'
plt.xticks(x,('a','b','c','d','e','f','g','h','i','j','k','l','m','n'),fontsize=20)

# both work
ax.legend(['t1','t2'])
plt.legend(['y1','y2'])

plt.show()

ion()和ioff()

介绍

交互式绘图,可以在一张图上不断的更新。

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import matplotlib.pyplot as plt
import numpy as np

count = 1
flag = True

plt.figure()
ax = plt.gca()
x = np.arange(20)
plt.figure()
ax2 = plt.gca()

while flag:
plt.ion()
y = pow(x[:count], 2)
temp = x[:count]
ax.plot(temp, y, linewidth=1)
plt.pause(1)
plt.ioff()

ax2.plot(x, x+count)
count += 1
if count > 20:
break

plt.show()

seanborn

介绍

对matplotlib进行了一层封装

代码示例

代码地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

values = np.zeros((21,21), dtype=np.int)
fig, axes = plt.subplots(2, 3, figsize=(40,20))
plt.subplots_adjust(wspace=0.1, hspace=0.2)
axes = axes.flatten()

# cmap is the paramter to specify color type, ax is the parameter to specify where to show the picture
# np.flipud(matrix), flip the column in the up/down direction, rows are preserved
figure = sns.heatmap(np.flipud(values), cmap="YlGnBu", ax=axes[0])
figure.set_xlabel("cars at second location", fontsize=30)
figure.set_title("policy", fontsize=30)
figure.set_ylabel("cars at first location", fontsize=30)
figure.set_yticks(list(reversed(range(21))))

figure = sns.heatmap(np.flipud(values), ax=axes[1])
figure.set_ylabel("cars at first location", fontsize=30)
figure.set_yticks(list(reversed(range(21))))
figure.set_title("policy", fontsize=30)
figure.set_xlabel("cars at second location", fontsize=30)

plt.savefig("hello.pdf")
plt.show()
plt.close()

color

介绍

指定线条的颜色,用color=’'实现。常见的颜色有:‘b’, ‘g’, ‘r’, ‘c’, ‘m’, ‘y’, ‘k’, ‘w’。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np

color = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']

for i in range(len(color)):
x = np.array([1, 2, 3, 4, 5])
y = np.array([1, 2, 3, 4, 5])
plt.plot(x, y+i, color=color[i])

plt.show()


plt.plot(range(10), range(10), color='w')
plt.show()

注意事项

color=‘w’,'w’是white,所以画出来的图你是看不到的。。。这困扰了我好久。。。。

gradient descent and backproporgation

发表于 2019-03-18 | 更新于 2019-12-17 | 分类于 机器学习

梯度下降和反向传播,他们两个之间的关系?

导数,偏导数,梯度,方向倒数

导数

定义:
$$f^{’}(x_0) = {\lim_{\Delta x \to 0}}\frac{\Delta y}{\Delta x} = \lim_{\Delta x \to 0}\frac{f(x_0+\Delta x)-f(x_0)}{\Delta x}$$
反映的是函数y=f(x)在某一点处沿x轴正方向的变化率。也能表示在x点处的斜率

偏导数

定义:
$$\frac{\partial }{\partial x}f(x,y,z) = \lim_{\Delta x \to 0}\frac{f(x + \Delta x,y,z) - f(x,y,z)}{\Delta x}$$
导数与偏导数本质都是一样的,当自变量的变化量趋于0时,函数值的变化量与自变量变化量比值的极限,偏导数就是函数在某一点上沿坐标轴正方向上的变化率。比如函数f(x,y,z),f(x,y,z)在某一点处可以分别求对于x,y,z轴正方向的偏导数。

方向导数

方向导数是某一点在某一趋近方向上的导数值,是函数在这个方向上的变化率。
定义:三元函数u=f(x,y,z)在点P(x,y,z)沿着l方向(方向角为$\alpha,\beta,\gamma$)的方向导数定义为
$$\frac{\partial f}{\partial l} = \lim_{\rho \to 0}\frac{f(x+\Delta x,y+\Delta y,z+\Delta z)-f(x,y,z)}{\rho}$$

梯度

梯度是方向导数中最大的那个向量,这个向量我们就称他为梯度,因为梯度是向量,所以才有梯度上升和下降的说法。梯度方向是函数增长最快的方向,梯度反方向是函数下降最快的方向。

梯度下降

神经网络的训练一般是通过定义一个loss函数,然后通过优化这个loss函数,实现神经网络的训练,一般的loss函数主要是定义了训练样本的预测结果和真实结果之间的差异,比如说定义交叉熵等。
至于优化loss函数的方法,就是通过梯度下降法来实现,该算法从任一点开始,沿该点梯度的反方向运动一段距离,再沿新位置的梯度反方向运行一段距离 … 如此迭代。解一直朝下坡最陡的方向运动,希望能运动到函数的全局最小点,梯度下降法是寻找函数局部最优解的有效方法(这里说的是局部最优解,而不是全局最优解,但是一般我们遇到的问题都是凸问题,局部最优解就是全局最优解),至于我们为什么不直接进行求解呢,因为计算量太大,如果有几百个参数的话,是不可行的(感觉这里说的不清楚,应该更具体的描述一下)。

反向传播算法

使用梯度下降算法的时候,我们需要计算函数的梯度,反向传播算法解释计算神经网络中误差函数梯度的一种方法。

手动实现bp

可以查看。

参考文献

1.https://zhuanlan.zhihu.com/p/25355758
2.https://www.zhihu.com/question/36301367/answer/142096153
3.http://neuralnetworksanddeeplearning.com/

python pandas笔记

发表于 2019-03-18 | 更新于 2019-12-17 | 分类于 python

pd.read_***()

pd.read_csv()

1
2
import pandas
pandas.read_csv(filepath_or_buffer, sep=', ', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, skipfooter=0, skip_footer=0, doublequote=True, delim_whitespace=False, as_recarray=None, compact_ints=None, use_unsigned=None, low_memory=True, buffer_lines=None, memory_map=False, float_precision=None)

filepath_or_buffer: 文件路径,或者一个字符串,url等等
sep: str,分隔符,默认是’,'
delimiter: str,定界符,如果指定该参数,sep参数失效
delimiter_whitespace: boolean,指定是否吧空格作为分界符如果指定该参数,则delimiter失效
header: int or list of ints,指定列名字,默认是header=0,表示把第一行当做列名,如果header=[0,3,4],表示吧第0,3,4行都当做列名,真正的数据从第二行开始,如果没有列名,指定header=None
index_col: int or sequence or False,指定哪几列作为index,index_col=[0,1],表示用前两列的值作为一个index,去访问后面几列的值。
prefix: str,如果header为None的话,可以指定列名。
parse_dates: boolean or list of ints or names,or list of lists, or dict 如果是True,解析index,如果是list of ints,把每一个int代表的列都分别当做一个日期解析,如果是list of lists,将list中的list作为一个日期解析,如果是字典的话,将dict中key作为一个新的列名,value为这个新的列的值。
keep_date_col: boolean,如果parser_dates中是将多个列合并为一个日期的话,是否保留原始列
date_parser: function,用来解析parse_dates中给出的日期列,是自己写的函数,函数参数个数和一个日期的列数相同。

chunksize: 如果文件太大的话,分块读入

1
2
3
data = pd.read_csv("input.csv",chunksize=1000)
for i in data:
...

DataFrame

声明一个DataFrame

data = pandas.DataFrame(numpy.arange(16).reshape(4,4),index=list(‘abcd’),columns=(‘wxyz’)
w x y z
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
index 是index列的值
columns 是列名

访问某一列

1
2
3
data = pandas.DataFrame(numpy.arange(16).reshape(4,4),index=list('abcd'),columns=('wxyz')
data['w']
data.w

写入某一列

只能先访问列 再访问行
data[‘w’] = [] # =左右两边shape必须一样
data[‘w’][0] #某一列的第0行

groupby

1
2
3
4
5
6
7
data = pandas.DataFrame(np.arange(16).reshape(4,4),index=list('abcd'),columns=('wxyz'))
for key,value in data.groupby("w"): # group by 列名什么的,就是说某一列的值一样分一组
value = value.values # value是一个numpy数组
value_list = value.tolist() #将numpy数组转换为一个list
for single_list in value_list:
single_list = str(single_list)
...

argparse笔记

发表于 2019-03-18 | 更新于 2019-12-17 | 分类于 python

简单的例子

创建一个parser

1
parser = argparse.ArgumentParser(description='Process Intergers')

添加参数

1
parser.add_argument(,,)

解析参数

1
arglist = parser.parse_args()

代码示例

完整代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import argparse

def parse_args():
parser = argparse.ArgumentParser("input parameters")
parser.add_argument("--batch_size", type=int, default=32)
parser.add_argument("--episodes", type=int, default=1)
parser.add_argument("--lr", type=float, default=0.01)
parser.add_argument("--momentum", type=float, default=0.9)
args_list = parser.parse_args()
return args_list


def main(args_list):
print(args_list.batch_size)


if __name__ == "__main__":
args_list = parse_args()
main(args_list)

ArgumentParser objects

The ArgumentParser object will hold all the information necessary to parse the command line into python data types

1
2
3
4
5
6
7
8
9
10
11
12
13
class argparse.ArgumentParser(
prog=None,
usage=None,
description=None,
epilog=None,
parents=[],
formatter_class=argparse.HelpFormatter,
prefix_chars='-',
fromfile_prefix_chars=None,
argument_default=None,
conflict_handler='error',
add_help=True
)

创建一个名为test.py的程序如下

1
2
3
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()

~#:python test.py -h

usage: test.py [-h]
optional arguments:
-h, --help show this help message and exit

prog参数

设置显示程序的名称

直接使用默认显示的程序名

~#:python test.py -h

usage: test.py [-h]
optional arguments:
-h, --help show this help message and exit

使用prog参数进行设置

修改test.py的程序如下

1
2
3
import argparse
parser = argparse.ArgumentParser(prog="mytest")
args = parser.parse_args()

~#:python test.py -h

usage: mytest [-h]
optional arguments:
-h, --help show this help message and exit

usage后的名称变为我们prog参数指定的名称

usage

使用默认的usage

使用指定的usage

description

使用默认的description

使用指定的description

epilog

使用默认的epilog

使用指定的epilog

parents

formatter_class

prefix_chars

指定其他的prefix,默认的是-,比如可以指定可选参数的前缀为+

fromfile_prefix_chars

argument_default

conflict_handler

将conflict_handler设置为resolve就可以防止override原来older arguments

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser(conflict_handler='resolve')
parser.add_argument('--foo','-f',help="old help")
parser.add_argument('-f',help="new_help")
parser.print_help()

add_help

1
2
3
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.print_help()

输出

usage: [-h]
optional arguments:
-h, --help show this help message and exit
将add_help设置为false

1
2
3
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.print_help()

输出

usage:

The add_argument() method

1
2
3
4
5
6
7
8
9
10
11
12
13
ArgumentParser.add_argument(
name or flags...
[,action],
[,nargs],
[,const],
[,default],
[,type],
[,choices],
[,required],
[,help],
[,metavar],
[,dest]
)

例子

1
2
3
4
5
6
7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f','-foo','-a', defaults=, type=, help=)
parser.add_argument('hello')
parser.add_argument('hi')
args = parser.parse_args(['Hello','-f','123','Hi'])
print(args)

name or flags

添加可选参数

parser.add_argument(’-f’, ‘–foo’, ‘-fooo’)

添加必选参数

parser.add_argument(‘bar’)

调用parse_args()

当parse_args()函数被调用的时候,可选参数会被-prefix所识别,剩下的参数会被分配给必选参数的位置。如下代码中,'3’对应的就是’hello’的参数,‘this is hi’对应的就是’hi’的参数,而’123’是’-f’的参数。

1
2
3
4
5
6
7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f','-foo','-a')
parser.add_argument('hello', type=int)
parser.add_argument('hi')
args = parser.parse_args(['3','-f','123','this is hi'])
print(args)

输出

Namespace(f=‘123’, hello=‘Hello’, hi=‘Hi’)

action

store,the default action

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
args = parser.parse_args(['--foo','1'])
print(args)

输出

Namespace(foo=‘1’)

store_const

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_const', const=42)
args = parser.parse_args(['--foo')
print(args)

输出

Namespace(foo=42)

store_true and store_false

1
2
3
4
5
6
7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_true')
parser.add_argument('--bar', action='store_false')
parser.add_argument('--baz', action='store_false')
args = parser.parse_args('--foo --bar'.split())
print(args)

输出

Namespace(bar=False, baz=True, foo=True)

这里为什么是这样呢,因为默认存储的都是True,当你调用–bar,–foo参数时,会执行action操作,会把action指定的动作执行

d.append

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='append')
args = parser.parse_args('--foo 1 --foo 2 --foo 3'.split())
print(args)

输出

Namespace(foo=[‘1’, ‘2’, ‘3’])

append_const

1
2
3
4
5
6
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--str', action='append_const',const=str)
parser.add_argument('--int', action='append_const',const=int)
args = parser.parse_args('--str --int'.split())
print(args)

输出

Namespace(int=[<class ‘int’>], str=[<class ‘str’>])

count

统计一个keyword argument出现了多少次

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--co', '-c',action='count')
args = parser.parse_args(['-ccc'])
print(args)

输出

Namespace(co=3)

help

1
2
3
4
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args('--help'.split())
print(args)

输出,如果是交互式环境的话,会退出python

usage: [-h]

optional arguments:
-h, --help show this help message and exit

version

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--version', action='version',version='version 3')
args = parser.parse_args('--version'.split())
print(args)

输出,如果是交互式环境的话,会退出python

version 3

nargs 指定参数个数

N

如果是可选参数的话,或者不指定这个参数,或者必须指定N个参数
如果是必选参数的话,必须指定N个参数,不能多也不能少,也不能为0个

1
2
3
4
5
6
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',nargs=3)
parser.add_argument('bar',nargs=4)
args = parser.parse_args('bar 3 4 5'.split())
print(args)

输出

Namespace(bar=[‘bar’, ‘3’, ‘4’, ‘5’], foo=None)

?

1
2
3
4
5
6
7
8
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',nargs='?',const='c',default='d')
parser.add_argument('bar',nargs='?',default='d')
args = parser.parse_args('3'.split())
print(args)
args = parser.parse_args('3 --foo'.split())
print(args)

输出

Namespace(bar=‘3’, foo=‘d’)
Namespace(bar=‘3’, foo=‘c’)

如果显式指定可选参数,但是不给它参数,那么如果有const的话,就会显示const的值,否则就会显示None

*

nargs设置为*的话,不能直接用const=’'来设置const参数,需要使用其他方式

1
2
3
4
5
6
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',nargs='*',default='d')
parser.add_argument('bar',nargs='*',default='d')
args = parser.parse_args('3 --foo 3 4'.split())
print(args)

输出

Namespace(bar=[‘3’], foo=[‘3’, ‘4’])

+

nargs设置为+,参数个数必须大于等于1

1
2
3
4
5
6
7
8
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',nargs='+',default='d')
parser.add_argument('bar',nargs='+',default='d')
args = parser.parse_args('3 3'.split())
print(args)
args = parser.parse_args('--foo 3'.split())
print(args)

输出

Namespace(bar=[‘3’], foo=‘d’)
Namespace(bar=[‘3’], foo=[‘3’])

const

action=’'store_const" or action=“append_const”

the examples are in the action

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_const', const=42)
args = parser.parse_args(['--foo')
print(args)

输出

Namespace(foo=42)

like -f or --foo and nargs=’?’

the examples are the same as examples in the nargs=’?’

1
2
3
4
5
6
7
8
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',nargs='?',const='c',default='d')
parser.add_argument('bar',nargs='?',default='d')
args = parser.parse_args('3'.split())
print(args)
args = parser.parse_args('3 --foo'.split())
print(args)

输出

Namespace(bar=‘3’, foo=‘d’)
Namespace(bar=‘3’, foo=‘c’)
如果显式指定可选参数,但是不给它参数,那么如果有const的话,就会显示const的值,否则就会显示None

default

default对于可选参数来说,是有用的,当可选参数没有在command line中显示出来时被使用,但是对于必选参数来说,只有nargs=?或者*才能起作用。

对于可选参数

1
2
3
4
5
6
7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo',default=43)
args = parser.parse_args([])
print(args)
args = parser.parse_args('--foo 3'.split())
print(args)

输出

Namespace(foo=‘43’)
Namespace(foo=‘3’)

对于必选参数

对于nargs=‘+’是会出错

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('bar',nargs='+',default='d')
args = parser.parse_args([])
print(args)

输出

usage: [-h] bar [bar …]
: error: the following arguments are required: bar

对于nargs=‘*’或者nargs=’?'就行了

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('bar',nargs='?',default='d')
args = parser.parse_args([])
print(args)

输出

Namespace(bar=‘d’)

type

将输入的字符串参数转换为你想要的参数类型
对于文件类型来说,这个文件必须在当前目录存在。

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--door',type=int)
parser.add_argument('filename',type=file)
parser.parse_args(['--door','3','hello.txt'])

输出

Namespace(door=3)
这里的door就是int类型的

choices

输入的参数必须在choices这个范围中,否则就会报错

1
2
3
4
import argparse
parser = argparse.ArgumentParse()
parser.add_argument('--door',type=int,choices=range(1,9))
parser.parse_args(['--door','3'])

输出

Namespace(door=3)

required

如果将required设置为True的话,那么这个可选参数必须要设置的

1
2
3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--foo-bar', '--foo',required=True)

help

help可以设置某个参数的简要介绍。
使用help=argparse.SUPRESS可以在help界面中不显示这个参数的介绍

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--foo-bar', '--foo',help='fool you ')
parser.add_argument('-xs', '--y',help=argparse.SUPPRESS)
parser.print_help()

输出

usage: [-h] [-f FOO_BAR]

optional arguments:
-h, --help show this help message and exit
-f FOO_BAR, --foo-bar FOO_BAR, --foo FOO_BAR
fool you

dest

dest就是在help输出时显示的optional和positional参数后跟的名字(没有指定metavar时)
如下,dest就是FOO
-foo FOO

positional argument

dest is normally supplied as the first argument to add_argument()

可选参数

对于optional argument选择,–参数最长的一个作为dest,如果没有最长的,选择第一个出现的,如果没有–参数名,选择-参数。

1
2
3
4
5
6
7
8
9
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--foo-bar', '--foo')
parser.add_argument('-xs', '--y')
args = parser.parse_args('-f 1 -xs 2'.split())
print(args)
args = parser.parse_args('--foo 1 --y 2'.split())
print(args)
parser.print_help()

输出

Namespace(foo_bar=‘1’, y=‘2’)
Namespace(foo_bar=‘1’, y=‘2’)
usage: [-h] [-f FOO_BAR] [-xs Y]

optional arguments:
-h, --help show this help message and exit
-f FOO_BAR, --foo-bar FOO_BAR, --foo FOO_BAR
-xs Y, --y Y

metavar

如果指定metavar变量名的话,那么help输出的postional和positional参数后跟的名字就是metavar的名字而不是dest的名字

1
2
3
4
5
6
7
8
9
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--foo-bar', '--foo',metavar="FOO")
parser.add_argument('-xs', '--y',metavar='XY')
args = parser.parse_args('-f 1 -xs 2'.split())
print(args)
args = parser.parse_args('--foo 1 --y 2'.split())
print(args)
parser.print_help()

输出

Namespace(foo_bar=‘1’, y=‘2’)
Namespace(foo_bar=‘1’, y=‘2’)
usage: [-h] [-f FOO] [-xs XY]

optional arguments:
-h, --help show this help message and exit
-f FOO, --foo-bar FOO, --foo FOO
-xs XY, --y XY

1…293031…34
马晓鑫爱马荟荟

马晓鑫爱马荟荟

记录硕士三年自己的积累

337 日志
26 分类
77 标签
RSS
GitHub E-Mail
© 2022 马晓鑫爱马荟荟
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v6.6.0