一些机器学习算法的简介

本节开始,介绍《Computer Science Theory for the Information Age》一书中第六章(这里先暂时跳过第三章),主要涉及学习以及学习的理论——VC理论。而本文主要是介绍一下什么是学习,以及一些常见的学习算法。

(一)学习概念

首先,我们用一个例子来介绍什么是学习。假设我们想要用一个算法来识别不同类型的车,比如小汽车、卡车、拖拉机等。根据我们的思维以及对这个领域的知识可知道,我们可以用一系列特征来区分它们,比如我们可以用轮子的数量,发动机的动力,门的数量,车的长度,座位的数量等等来区分。假如我们有$d$个特征,那么我们可以用一个$d$-维的向量来表示一个待区分的物体,我们把这个向量叫做特征向量

一个学习算法使用一个特征向量来表示一个目标,然后算法通过询问一个领域专家,知道了每个向量所对应的类别。学习算法的任务就是根据专家所给出的每一个特征向量以及对应的类别,然后学习出一个准则,用这个准则去判断每个特征向量对应的类别。

我们给出的一系列特征向量以及对应的标签叫做训练集,而一个学习者的任务是给出一系列准则能正确地判断出训练集中的每一个特征向量。当然,我们可以给出这样的准则:“对于每一个特征向量,用专家给出的标签作为输出”。也就是说,这个准则是一个观察到的表。但通常我们希望这个准则尽可能的简洁,并且可以用于预测观察外的目标(即这个准则的泛化能力)。

很显然,如果我们的训练集足够大,那么我们训练出来的准则在目标空间中将工作的更出色。这一点可以用后面介绍的VC-理论进行验证。在这里,我们只讨论两类的情况,对于多类别的都可以转化为多个两类的问题,比如小汽车与非小汽车,卡车与非卡车。

在$d$维空间里,最简单的准则就是超平面,这个平面将空间分成两个半空间。这个准则实际上是对每个特征值进行加权求和,然后给出一个阈值,若超过这个阈值就是属于某一类,不超过阈值的就属于另一类。

(二)感知器算法

在Jordan Lecture Note里面已经介绍过感知器算法,但这里为了完整性也为了能更好的理解感知器算法,所以就在讨论一下。另外,此处的感知器收敛定理的证明比前面的更为简介易懂。在$d$维空间中,给出$n$个已标签的目标$\alpha_1,\alpha_2,\cdots,\alpha_n$,一个线性分类器的任务就是找到一个$d$维权重向量$w$,并且存在一个阈值$b$,使$w^T\alpha_i>b$对于每一个标签为+1的$\alpha_i$都成立,$w^T\alpha_i<b$对于每一个标签为-1的$\alpha_i$都成立。对于这样的一个$(w,b)$,我们把它叫做线性分类器。

对于上述的不等式,我们可以用一个具有多项式时间的线性规划(LP)算法解出来。但是,如果训练集是线性可分的话,我们可以用一个更简单快速的算法来计算,也就是感知器学习算法

我们用$\hat{\alpha}_i=(\alpha_i,1),\hat{w}=(w,b)$,并且加上$l_i=+1,-1$的标签可以将上述方程改写成$(\hat{w}^T\hat{\alpha}_i)l_i>0,1\leq i \leq n$。为了简单起见,一下我们将$\hat{\alpha},\hat{w}$写成$\alpha,w$。

感知器算法是一个非常简单的算法,它的目标是通过以下不等式找到$w$的解:

\begin{equation}(w^T\alpha_i)l_i>0,1\leq i\leq n\label{equ:perceptronCon}\end{equation}

由于式子\ref{equ:perceptronCon}右边为零,故可将$\alpha_i$收缩为$\|\alpha_i\|=1$。算法的执行过程如下:

  1. 初始化$w_0=0$.
  2. 对任一个$\alpha_i$,若满足$(w^T\alpha_i)l_i\leq 0$,将$w$更新为$w_{j+1}=w_j+l_i\alpha_i$。
  3. 重复第二步直到所有$\alpha_i$都满足$(w^T\alpha_i)l_i>0$

事实上,这个算法是对每一个不满足$(w^T\alpha_i)l_i>0$的$\alpha_i$,通过改变$w$使其尽可能满足,即更新后的$(w_{j+1}^T\alpha_i)l_i=w_j^T\alpha_il_i+\alpha_i^T\alpha_il_i^2=w_j^T\alpha_il_i+\|\alpha_i\|^2$,比原来的增加了一个正数。但这个更新只是使$\alpha_i$更容易满足条件,而对其他的$\alpha_j(j\neq i)$,有可能使其更不满足条件。但感知器收敛定理告诉我们,当数据是线性可分的情况下,经过有限步,算法总是可以找到这个$w$.

定义一 对于一个满足$w^T\alpha_il_i>0(1\leq i\leq n)$的解$w$,其中\|$\alpha_i\|=1$,我们定义样本的间隔为所有点到超平面$\{x|w^Tx=0\}$的最小距离,即$\mathop{min}_i \frac{w^T\alpha_i}{\|w\|}l_i$.

由于点$\alpha_i$到超平面的距离为$\frac{w^T\alpha_i}{\|w\|}$,这个距离有可能是负的,而乘上标签,即可使其值为正。以下证明感知器算法的收敛性。

定理一 假设式子\ref{equ:perceptronCon}有一个间隔为$\delta > 0$的解$w^*$(这个条件保证了数据的线性可分)。那么感知器算法能够在最多$\frac{1}{\delta^2}$次迭代内找到一个$w$满足$w^T\alpha_il_i>0,1\leq i\leq n$。

证明:根据间隔的定义可知,$\delta=\mathop{min}_i \frac{(w^*)^T\alpha_i}{\|w^*\|}l_i$,由于收缩$w^*$的值并不影响超平面的位置,故不失一般性,我们可以假设$\|w^*\|=1$,那么$\delta=\mathop{min}_i (w^*)^T\alpha_il_i$。首先,我们来看$w$与$w^*$的夹角的余弦值$\mathop{cos}(w,w^*)=\frac{w^Tw^*}{\|w\|}$。

对于每一次迭代,$w^Tw^*$的增量至少为$\delta$:

$$w_{j+1}^Tw^*=w_j^Tw^*+\alpha_i^Tw^*l_i\geq w_j^Tw^*+\delta$$

所以经过$t$步迭代后$w_t^Tw^*\geq t\delta$,注意初始$w_0^Tw^*=0$。对于每一次迭代$\|w\|^2$的增加两至多为$\delta$:

$$\|w_{j+1}\|^2=\|w_j+\alpha_il_i\|^2=\|w_j\|^2+2(w_j^T\alpha_i)l_i+\|\alpha_i\|^2l_i^2\leq \|w_j\|^2 + 1$$

上式成立是因为$w^T\alpha_il_i\leq 0$。所以经过$t$步后:$\|w_t\|^2\leq t$,其中初始时$\|w_0\|^2=0$。综上,经过$t$步后:

$$1\leq\mathop{cos}(w_t,w^*)=\frac{w_t^Tw^*}{\|w_t\|}\geq\frac{t\delta}{\sqrt{t}}=\sqrt{t}\delta$$

所以$t\leq\frac{1}{\delta^2}$.

这个算法告诉我们,如果我们要找一个间隔为$\delta$的超平面,那么至多只需要迭代$\frac{1}{\delta^2}$步。这里的间隔越小,所需要的迭代次数越大。

现在我们来看对于间隔至少为$\delta$的假设有多强。假设$\alpha_i$是从单位超球面随机均匀的选取的,那么根据前面的知识可以知道,球的表面积大都聚集在离赤道$\mathcal{O}(\frac{1}{\sqrt{d}})$的距离内,也就是对于一个固定的超平面,以这个超平面为赤道画一个超球,然后在求上均匀随机选取点,那么间隔超过$\frac{c}{\sqrt{d}}$的概率将非常的低。但是这样仅仅说明对于某个固定的超平面间隔很小,并不能说对于所有的超平面的间隔都很小。而用后面介绍的VC维,我们可以证明对这样选取的点,其超平面的间隔都很小。所以对于这样一个简单的随机模型,假定分隔面至少为$\delta$是无效的。但在现实世界中是存在间隔很大的例子,这是由于在现实世界中,均匀分布这个假设是无效的。所以最大间隔分类器和它的理论就可以用上。

(三)最大化间隔算法

这一节我们介绍最大化间隔分类器,关于这部分的内容在前面《Jordan Lecture Note》系列也已经介绍过了,但这里为了笔记的完整性,还是简单的在介绍一下。

对于线性分类器,我们要找的是以下不等式的解$w$:

$$(w^T\alpha_i)l_i>0, 1\leq i\leq n, \|\alpha_i\|=1$$

它的间隔为$\delta=\mathop{min}_i \frac{l_i(w^T\alpha_i)}{\|w\|}$,所以最大间隔模型就是最大化这个间隔,即:

\begin{align}\mathop{max}&\quad \delta\nonumber\\\mathop{s.t.}&\quad (w^T\alpha_i)l_i>0, 1\leq i\leq n\label{equ:maxMargin}\end{align}

由于这是一个非凸的优化模型,我们现在将其转化为凸优化模型。令$v=\frac{w}{\delta\|w\|}$,则$\|v\|=\|\frac{w}{\delta\|w\|}\|=\frac{1}{\delta}$,故最大化$\delta$等价与最小化$v$。另外,将$(w^T\alpha_i)l_i>0$用$l_i(v^T\alpha_i)>1$来等价替换,即:

\begin{align*}&(w^T\alpha_i)l_i>0\Longrightarrow \frac{w^T\alpha_i}{\|w\|\delta}l_i>1\Longrightarrow (v^T\alpha_i)l_i>1\\&(v^T\alpha_i)l_i>1\Longrightarrow \frac{w^T\alpha_i}{\|w\|\delta}l_i >1\Longrightarrow (w^T\alpha_i)l_i>0\end{align*}

所以模型\ref{equ:maxMargin}转化为:

\begin{align}\mathop{min}_v&\quad \frac{1}{2}\|v\|^2\nonumber\\\mathop{s.t.}&\quad l_i(v^T\alpha_i)l_i>1, \forall i\label{equ:model:maxMargin}\end{align}

要解决上述模型的方法有很多种,比如梯度投影法SMO算法,这里我们不去探讨如何解这些模型。接下去我们来说明最后的解$v$所具有的特性。假设空间$V$是由满足$l_iv^T\alpha_i=1$的$\alpha_i$所张成的,那么$v$一定在空间$V$中。这里采用反证法来证明,假设$v$不再空间$V$中,那么$v$可以分解成两个分量$v=v_1+v_2$,其中$v_1$正交与$V$空间,$v_2$在$V$空间中。我们将$v_1$缩小一定的比例,即$v_1\longrightarrow\bar{v_1}$,则$l_i(\bar{v_1}+v_2)^T\alpha_i=1$仍然满足约束条件,但$\|v\|$的值确变小,这与$\|v\|$是最小值相矛盾,故假设不成立。

将满足$l_i(v^T\alpha_i)=1$的$\alpha_i$称为支撑向量(support vector),那么$v$是由支撑向量线性表示的。

上面所讨论的都是存在$w$使所有$\alpha_i$都满足式子\ref{equ:perceptronCon},也就是说数据是线性可分的,但是假如对于式子\ref{equ:perceprtonCon},我们至多只能找到$(1-\epsilon)n$个点满足式子\ref{equ:perceptronCon},那么求解$w$的解就成为一个NP-hard问题。但是,我们可以换另一种方法去解决这个问题。首先,我们对于每一个被错误分类的点加一个单位损失,然后我们去最小化这个损失,称这个为0-1损失。但由于这是一个不连续的函数,不好解。所以引进另一个损失,称为链损失(hing-loss)。这个链损失为0-1损失的上界,当我们要最小化0-1损失时,可以通过最小化0-1损失的上界来达到最小化0-1损失。现在来看看链损失是如何引进的。

引进一个slack变量$y_i,i=1,2,\cdots,n$,$y_i$用于测量$\alpha_i$分类的错误性,得到这样的一个模型:

\begin{align}\mathop{min}_{v,y_i}&\quad \frac{1}{2}\|v\|^2+C\sum_{i=1}^ny_i\nonumber\\\mathop{s.t}&\quad (v^T\alpha_i)l_i\geq 1-y_i,i=1,2,\cdots,n\nonumber\\&\quad y_i\geq 0,i=1,2,\cdots,n\label{model:slack}\end{align}

将上述模型的限制条件归入到优化的目标函数,然后将模型转化为:$\mathop{min}_{v}\quad \frac{1}{2}\|v\|^2+C\sum_{i=1}^n(1-(v^T\alpha_i)l_i)^+$,其中$(x)^+$表示,当$x$小于零时,其值取零,这里的第二项称为链损失。

(四)非线性分类器,核函数

先来看一个例子。假设有一个二维的数据$\alpha_i$,当$\alpha_i$位于第一、三象限时其label为正,当$\alpha_i$位于第二、四象限时其label为负。对于这样的一个数据,它是不存在一个线性分类器能够将正负label分开的,而且使用slack变量进行求解的效果也是非常不好的。但很显然这个例子可以用一个多项式$P(x_1,x_2)=x_1x_2$来进行分类,对于$x_1x_2>0$为正,$x_1x_2<0$为负。换句话说,对于一些线性不可分的数据,我们可以用一个度最多为$D$的多项式$P(\alpha)=0$来进行分类,但是要如何去找到这个多项式才能产生好的分类效果?以及对于一个多项式,它的单项式的个数有可能是指数级的,这给计算带来了麻烦。

我们可以把上述问题等价的看成将$d$维的数据$\alpha_i$变换到一个$m$维的空间,其中$m$维空间中的每一个分量是原来空间坐标的单项式函数,记这个映射为$\phi(x)$。假如对于$d=2,D=2$,那么$\phi(x)=(x_1,x_2,x_1^2,x_1x_2,x_2^2)$,对于$d=3,D=2$,$\phi(x)=(x_1,x_2,x_3,x_1x_2,x_2x_3,x_2x_3,x_1^2,x_2^2,x_3^2)$。于是模型变成:

\begin{align}\mathop{min}&\quad \frac{1}{2}\|w\|^2\nonumber\\\mathop{s.t.}&\quad (w^T\phi(\alpha_i))l_i\geq 1, \forall i\label{model:phi}\end{align}

但是,由于$\phi(\alpha_i)$和$w$的维度非常的高,故对应的$w$维度也非常的高,如果显式去计算上述模型,那么计算量将非常巨大。因此,我们希望能够不通过$w$和$\phi$即可解决上诉模型,即用Kernel的方法。注意这也是引入Kernel的基本思想之一。

引理一 模型\ref{model:phi}的任何解$w$必定是$\phi(\alpha_i)$的线性组合。

这个引理的证明方法跟上面证明$v$在$V$空间内一样,所以就不在证明了。

由于$w$是$\phi(\alpha_i)$的线性组合,故$w=\sum_{i}^ny_i\phi(\alpha_i)$,其中$y_i$为线性组合的系数。所以:

$$\|w\|^2=(\sum_{i=1}^ny_i\phi(\alpha_i))^T(\sum_{j=1}^ny_j\phi(\alpha_j))=\sum_{i,j}y_iy_j\phi(\alpha_i)^T\phi(\alpha_j)$$

所以模型变为:

\begin{align}\mathop{min}&\quad\sum_{i,j}y_iy_j\phi(\alpha_i)^T\phi(\alpha_j)\nonumber\\\mathop{s.t.}&\quad l_i(\sum_jy_j\phi(\alpha_j)^T\phi(\alpha_i))\geq 1, \forall i\label{model:kernel}\end{align}

从这个模型我们可以看到,事实上假如我们可以直接计算出$\phi(\alpha_i)^T\phi(\alpha_j)$,那么我们是不需要去知道$\phi(x)$的。所以我们将上述点乘记为$K_{ij}=\phi(\alpha_i)^T\phi(\alpha_j)$。所以模型可以改写成:

\begin{align}\mathop{min}&\quad\sum_{i,j}y_iy_jK_{ij}\nonumber\\\mathop{s.t.}&\quad l_i\sum_jy_jK_{ij}\geq 1, \forall i\label{model:kernel2}\end{align}

写成矩阵形式为:

\begin{align}\mathop{min}&\quad y^T\mathbf{K}y\nonumber\\\mathop{s.t.}&\quad \mathbf{L}(\mathbf{K}y)\geq 1\label{model:KernelMatrix}\end{align}

其中矩阵$\mathbf{K}$由$K_{ij}$组成,称为kernel矩阵,矩阵$\mathbf{L}$为对角矩阵,其对角元素为$l_i$,$y=(y_1,\cdots,y_n)^T$。从上面的模型来看,我们只需要指定矩阵$\mathbf{K}$就可以,而计算$\mathbf{K}$的复杂度只有$n^2$,会远远小于$\phi$的维度。

这里有一个问题,就是给定一个矩阵$\mathbf{K}$,我们怎样才能知道其是否对应着一个映射$\phi$。下面的定理则给出了答案:

定理二 如果一个矩阵$\mathbf{K}$是Kernel矩阵(也就是说存在一个映射$\phi$使$K_{ij}=\phi(x_i)^T\phi(x_j)$)当且仅但$\mathbf{K}$是半正定的。

证明:我们先证明充分性,也就是矩阵$\mathbf{K}$为半正定,则一定存在满足条件的映射。

由于$\mathbf{K}$是对称矩阵,故存在一个正交矩阵$\mathbf{A}$,使$\mathbf{K}=\mathbf{A}^{-1}\mathbf{\Lambda}\mathbf{A}$,其中$\mathbf{\Lambda}$为对角线矩阵,每个元素为$\mathbf{K}$的特征值,且特征值均大于等于零。记

\begin{equation*}\mathbf{\Lambda}=\left[\begin{array}&\lambda_1\\&\lambda_2\\&&\ddots\\&&&\lambda_n\end{array}\right]=\left[\begin{array}&\sqrt{\lambda_1}\\&\sqrt{\lambda_2}\\&&\ddots\\&&&\sqrt{\lambda_n}\end{array}\right]\left[\begin{array}&\sqrt{\lambda_1}\\&\sqrt{\lambda_2}\\&&\ddots\\&&&\sqrt{\lambda_n}\end{array}\right]\triangleq \mathbf{\Lambda}_1^2\end{equation*}

所以$\mathbf{K}=\mathbf{A}^T\mathbf{\Lambda}_1^2\mathbf{A}\triangleq\mathbf{BB}^T$,我们可以定义$\phi(\alpha_i)$为$\mathbf{B}$的第$i$行,所以充分性得证。

然后证明必要性,即由某种映射$\phi$所得到的矩阵$\mathbf{K}$为半正定矩阵。

令矩阵$\mathbf{B}$的第$i$行为$\phi(\alpha_i)$,所以根据矩阵$\mathbf{K}$的定义有,$\mathbf{K}=\mathbf{BB}^T$,所以对于任何向量$\beta$,有$\beta^T\mathbf{K}\beta\geq 0$,即矩阵$\mathbf{K}$为半正定。

例子:令$K_{ij}=(\alpha_i^T\alpha_j)^p$,p为正整数。我们来证明矩阵$\mathbf{K}$是半正定,即证对任何向量$u$,有$u^T\mathbf{K}u=\sum_{ij}K_{ij}u_iu_j\geq 0$。

\begin{align*}\sum_{ij}K_{ij}u_iu_j&=\sum_{ij}(\alpha_i^T\alpha_j)^pu_iu_j=\sum_{ij}u_iu_j(\sum_k\alpha_{ik}\alpha_{jk})^p\\&=\sum_{ij}u_iu_j(\sum_{k_1,k_2,\cdots,k_p}\alpha_{ik_1}\alpha_{ik_2}\cdots\alpha_{ik_p}\alpha_{jk_1}\alpha_{jk_2}\cdots\alpha_{jk_p})\\&=\sum_{k_1,k_2,\cdots,k_p}\sum_{ij}u_i\alpha_{ik_1}\alpha_{ik_2}\cdots\alpha_{ik_p}u_j\alpha_{jk_1}\alpha_{jk_2}\cdots\alpha_{jk_p}\\&=\sum_{k_1,k_2,\cdots,k_p}(\sum_iu_i\alpha_{ik_1}\alpha_{ik_2}\cdots\alpha_{ik_p})^2\geq 0\end{align*}

注意上述的下标$k_1,k_2,\cdots,k_p$可以是相同的。另外,用同样的方法我们也可以证明矩阵$\mathbf{K},K_{ij}=\sum_{p=0}^\infty c_p(\alpha_i^T\alpha_j)^p,c_p\geq 0$也是半正定。有了上述结果我们就可以证明高斯函数也可以作为Kernel函数,即矩阵$\mathbf{K},K_{ij}=exp(-\frac{\|\alpha_i-\alpha_j\|^2}{2\sigma^2})$也是半正定的:

\begin{align*}exp(-\frac{\|\alpha_i-\alpha_j\|^2}{2\sigma^2})&=exp(-\frac{\|\alpha_i\|^2}{2\sigma^2})exp(-\frac{\|\alpha_j\|^2}{2\sigma^2})exp(\frac{\alpha_i^T\alpha_j}{\sigma^2})\\&=exp(-\frac{\|\alpha_i\|^2}{2\sigma^2})exp(-\frac{\|\alpha_j\|^2}{2\sigma^2})\sum_{t=0}^\infty(\frac{(\alpha_i^T\alpha_j)^t}{t!\sigma^{2t}})\end{align*}

其中最后一项是对$e^x$的泰勒展开。记矩阵$\mathbf{L}$为$L_{ij}=\sum_{t=0}^\infty(\frac{(\alpha_i^T\alpha_j)^t}{t!\sigma^{2t}})$,则矩阵$\mathbf{L}$为半正定。又有$\mathbf{K}=\mathbf{DLD}^T$,其中$\mathbf{D}$为以$exp(-\frac{\|\alpha_i\|^2}{2\sigma^2})$为元素的对角矩阵。所以$\mathbf{K}$也是半正定。

Computer Science Theory for the Information Age-4: 一些机器学习算法的简介的更多相关文章

  1. Computer Science Theory for the Information Age-1: 高维空间中的球体

    高维空间中的球体 注:此系列随笔是我在阅读图灵奖获得者John Hopcroft的最新书籍<Computer Science Theory for the Information Age> ...

  2. Computer Science Theory for the Information Age-6: 学习理论——VC定理的证明

    VC定理的证明 本文讨论VC理论的证明,其主要内容就是证明VC理论的两个定理,所以内容非常的枯燥,但对于充实一下自己的理论知识也是有帮助的.另外,VC理论属于比较难也比较抽象的知识,所以我总结的这些证 ...

  3. Computer Science Theory for the Information Age-3: 高维空间中的高斯分布和随机投影

    高维空间中的高斯分布和随机投影 (一)在高维球体表面产生均匀分布点的方法 我们来考虑一个采样问题,就是怎样在高维单位球体的表面上均匀的采样.首先,考虑二维的情况,就是在球形的周长上采样.我们考虑如下方 ...

  4. Computer Science Theory for the Information Age-2: 高维空间中的正方体和Chernoff Bounds

    高维空间中的正方体和Chernoff Bounds 本文将介绍高维空间中正方体的一些性质,以及一个非常常见也是非常有用的概率不等式——Chernoff Bounds. 考虑$d$维单位正方体$C=\{ ...

  5. Computer Science Theory for the Information Age-5: 学习理论——VC维的定义以及一些例子

    学习理论——VC维的定义以及一些例子 本文主要介绍一些学习理论上的东西.首先,我们得明确,从训练集上学习出来的分类器的最终目标是用于预测未知的样本,那么我们在训练的时候该用多少的样本才能使产生的分类器 ...

  6. Discovering the Computer Science Behind Postgres Indexes

    This is the last in a series of Postgres posts that Pat Shaughnessy wrote based on his presentation ...

  7. [转载] A set of top Computer Science blogs

    This started out as a list of top Computer Science blogs, but it more closely resembles a set: the o ...

  8. CSCI 1100 — Computer Science 1 Homework

    CSCI 1100 — Computer Science 1 Homework 8CS1 Multiverse: ClassesOverviewThis homework is worth 100 p ...

  9. 2012年Elsevier旗下Computer Science期刊最新SCI影响因子排名

    Latest Impact Factor figures from Elsevier's Computer Science Journals Medical Image Analysis Impact ...

随机推荐

  1. 扩展Fitnesse的ScriptTable:支持if-then

    Fitnesse的ScriptTable只能顺序执行所有行,本博文介绍如何让ScriptTable支持if-then,来条件执行一行. 首先普及一下概念,什么是Fitnesse,听一听.NET版Cuc ...

  2. cocos2d-x 添加背景音乐和音效-SimpleAudioEngine

    首先,要想使用音效,需要启用音效引擎库CocosDenshion中的SimpleAudioEngine类, #include "SimpleAudioEngine.h" Cocos ...

  3. android测试本地服务调试流程

    我今天调试的整个过程 1,安卓发现连不上本地的tomcat 2,使用浏览器直接尝试,发现可以连上 3,怀疑是安卓APP和浏览器访问有差异,后上网搜索不到APP,只有浏览器尝试       再不就是改I ...

  4. 【原】Storm 入门教程目录

    Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...

  5. 【Hadoop代码笔记】Hadoop作业提交之Child启动reduce任务

    一.概要描述 在上篇博文描述了TaskTracker启动一个独立的java进程来执行Map任务.接上上篇文章,TaskRunner线程执行中,会构造一个java –D** Child address ...

  6. 在NodeJS中配置aws ec2

    获取access key和secret access key           自己账户下有security credentials的选项                      然后点击Acce ...

  7. NodeJS:树的反序列化

    !!不知问啥,cnblog的MarkDown编辑器不好使了. 本文也在我的博客edwardesire.com上,欢迎品尝. 树的反序列化就是将序列数组安装线索组成树结构,今次项目数据库存储决策节点的方 ...

  8. VB调用自持字体

    VB调用自制字体我这里有一个C#的例子,请问如何在VB中实现啊. 我们写exe程序时,默认字体是宋体,比较难看,指定了其他字体,但是其他用户上没有你指定的这个字体的话,也会变成默认的宋体.解决的办法有 ...

  9. 优秀java开源项目与解决方案推荐与概论

    http://www.oschina.net/project/lang/19/java http://www.open-open.com/ http://java-source.net/ https: ...

  10. DelphiXE Android自适应屏幕办法

    相关资料: http://www.delphitop.com/html/FireMonkey/2658.html http://bbs.csdn.net/topics/390919460 1.Scal ...