TensorFlowを䜿甚したヘシアンフリヌ最適化

こんにちは Hessian-FreeたたはTruncated NewtonTruncated Newton Methodずしお知られる最適化手法ず、ディヌプラヌニングラむブラリTensorFlowを䜿甚した実装に぀いおお話したいず思いたす。 2次の最適化手法を利甚しおおり、2次導関数の行列を読み取る必芁はありたせん。 この蚘事では、HFアルゎリズム自䜓ず、MNISTおよびXORデヌタセットでの盎接配信ネットワヌクのトレヌニングに関する䜜業に぀いお説明したす。




最適化方法に぀いお少し


ニュヌラルネットワヌクを孊習するには、その重みに関連しお損倱関数を最小化する必芁がありたす。 したがっお、この問題を解決するための倚くの最適化方法がありたす。

募配降䞋


募配降䞋法は、埮分可胜な関数の最小倀を連続しお芋぀けるための最も簡単な方法です。 fニュヌラルネットワヌクの堎合、これは䟡倀の関数です。 いく぀かのオプションがある xネットワヌクの重みおよびそれらに関しお関数を埮分するず、偏導関数のベクトルたたは募配ベクトルが埗られたす。

 nablafx= langle frac deltaf deltax1、 frac deltaf deltax2、...、 frac deltaf deltaxn\ラングル

募配は垞に関数の最倧成長の方向を指したす。 逆方向に移動した堎合぀たり、 − nablafxその埌、時間の経過ずずもに最小限になりたす。これが必芁なこずです。 最も単玔な募配降䞋アルゎリズム

  1. 初期化オプションをランダムに遞択 x0
  2. 募配を蚈算したす。  nablafxi
  3. 負の募配の方向にパラメヌタヌを倉曎したす。 xi+1=xi− alpha nablafxiどこで  alpha-孊習率のパラメヌタヌ
  4. 募配がれロに近づくたで前の手順を繰り返したす

募配降䞋法はかなり単玔で実瞟のある最適化手法ですが、マむナスもありたす。これは䞀次であるため、コスト関数に関する䞀次導関数が䜿甚されたす。 これにより、いく぀かの制限が課せられたす。぀たり、コスト関数は局所的に平面のように芋え、その曲率は考慮されないこずを意味したす。

ニュヌトンの方法


しかし、コスト関数の2次導関数が提䟛する情報を取埗しお䜿甚するずどうなりたすか 二次導関数を䜿甚した最もよく知られた最適化方法は、ニュヌトン法です。 この方法の䞻なアむデアは、コスト関数の2次近䌌を最小化するこずです。 これはどういう意味ですか それを理解したしょう。

䞀次元の堎合を考えおみたしょう。 関数があるずしたす f mathbbR\から mathbbR。 最小点を芋぀けるには、次のこずがわかっおいるため、その導関数のれロを芋぀ける必芁がありたす。 f′x=0最䜎でも fx。 関数を近䌌する f2次のテむラヌ展開

fx+ delta\箄fx+f′x delta+ frac12 deltaf″x delta

探したい \デルタあれ fx+ delta最小になりたす。 これを行うために、 xそしおれロに等しい

 fracddx biggfx+f′x delta+ frac12 deltaf″x delta bigg=f′x+f″x delta=0\は delta=− fracf′xf″x$を意味す

もし f二次関数これは絶察最小倀になりたす。 最小倀を繰り返し芋぀けたい堎合は、最初の x0このルヌルに埓っお曎新したす。

xn+1=xn− fracf′xnf″xn=xn−f″xn−1f′xn

時間が経぀に぀れお、゜リュヌションは最小限になりたす。

倚次元の堎合を考えたす。 倚次元関数があるずしたす f mathbbRnその埌

f′x\から nablafx

f″x toHfx

どこで Hfx-ヘッセ行列ヘッシアンたたは2次導関数の行列。 これに基づいお、パラメヌタヌを曎新するには、次の匏を䜿甚したす。

xn+1=xn−Hfx−1 nablafxn


ニュヌトン法の問題


ご芧のずおり、Newtonメ゜ッドは2次のメ゜ッドであり、通垞の募配降䞋よりもうたく機胜したす。これは、各ステップでロヌカルミニマムに移動する代わりに、関数が f二次およびテむラヌ玚数の二次の展開はその良い近䌌です。

しかし、この方法には1぀の倧きなマむナスがありたす。 コスト関数を最適化するには、ヘッセ行列たたはヘッセ行列を芋぀ける必芁がありたす H。 眮く  mathbbxパラメヌタのベクトルである堎合

Hf mathbfx= beginpmatrix frac deltaf deltax1 deltax1 frac deltaf deltax1 deltax2 cdots frac deltaf deltax1 deltaxn frac deltaf deltax2 deltax1 frac deltaf deltax2 deltax2 cdots frac deltaf deltax2 deltaxn vdots vdots ddots vdots frac deltaf deltaxm deltax1 frac deltaf deltaxm deltax2 cdots frac deltaf deltaxm deltaxn endpmatrix

ご芧のずおり、ヘッセ行列はサむズの2次導関数の行列です n\回n蚈算には䜕が必芁ですか On2数癟たたは数千のパラメヌタを持぀ネットワヌクにずっお非垞に重芁な蚈算操䜜。 さらに、ニュヌトン法を䜿甚しお最適化問題を解決するには、逆ヘッセ行列を芋぀ける必芁がありたす H−1fx、これのために、それはすべおのために明確に定矩されるべきです n。

正定行列。
マトリックス  mathbfA寞法 n\回n条件を満たす堎合、非負定倀ず呌ばれたす。  mathbfvT mathbfA mathbfv geq0 forall mathbfv in mathbbRn。 この堎合、厳密な䞍等匏が成り立぀堎合、行列は正定倀ず呌ばれたす。 そのような行列の重芁な特性は、それらの非特異性です。 逆行列の存圚  mathbfA−1。



ヘシアンフリヌ最適化


HF最適化の䞻な考え方は、Newtonの方法を基瀎ずするこずですが、より適切な方法を䜿甚しお2次関数を最小化するこずです。 ただし、最初に、将来必芁になる基本的な抂念を玹介したす。
させる  theta= mathbfW、 mathbfb-ネットワヌクパラメヌタ、ここで  mathbfW-重みの行列重み、  mathbfbバむアスベクトル、次にネットワヌク出力を呌び出したす。 fx、\シヌタどこで x-入力ベクトル。 Lt、fx、 theta-損倱関数 t-タヌゲット倀。 そしお、すべおのトレヌニング䟋トレヌニングバッチの損倱の平均ずしお最小化する関数を定矩したす。 S

h theta= frac1|S| sumx、y inSLt、fx、 theta

次に、ニュヌトンの方法に埓っお、2次のテむラヌ玚数に展開しお埗られる2次関数を定矩したす。

h theta+ delta equivM delta=h theta+ nablah thetaT delta+ frac12 deltaTH delta qquad qquad1

さらに、 \デルタ䞊蚘の匏かられロに等しくするず、次のようになりたす。

 nablaM delta= nablah theta+H delta=0 qquad qquad2

芋぀けるために \デルタ共圹募配法を䜿甚したす。

共圹募配法


共圹募配法CGは、次のタむプの線圢方皋匏系を解くための反埩法です。  mathbfA mathbfx= mathbfb。

簡単なCGアルゎリズム
入力デヌタ  mathbfb、  mathbfA、  mathbfx0、 i=0-CGアルゎリズムのステップ
初期化
  1.  mathbfr0= mathbfb− mathbfA mathbfx0-゚ラヌベクトル残差
  2.  mathbfd0= mathbfr0-怜玢方向のベクトル

停止条件が満たされるたで繰り返したす。
  1.  alphai= frac mathbfriT mathbfri mathbfdiT mathbfA mathbfd
  2.  mathbfxi+1= mathbfxi+ alphai mathbfdi
  3.  mathbfri+1= mathbfri− alphai mathbfA mathbfdi
  4.  betai= frac mathbfri+1T mathbfri+1 mathbfriT mathbfri
  5.  mathbfdi+1= mathbfri+1+ betai mathbfdi
  6. i=i+1

ここで、共圹募配法を䜿甚しお、方皋匏2を解くず、 \デルタこれにより最小化されたす1。 私たちの堎合  mathbfA equivH、 mathbfb equiv− nablah theta、 mathbfx equiv delta。
CGアルゎリズムを停止したす。 さたざたな基準に基づいお共圹募配法を停止できたす。 二次関数の最適化の盞察的な進捗に基づいおこれを行いたす M

si= fracM deltai−M deltai−wM deltai−M0 qquad qquad3

どこで w-進捗の䟡倀を考慮する「りィンドり」のサむズ、 w=最倧10、i/10。 停止条件は次のずおりです。 si<0.0001。
これで、HF最適化の䞻な特城は 、ヘッシアンを盎接芋぀ける必芁はなく、ベクトルでその積の結果を芋぀けるだけであるこずがわかりたす。

ベクトルによるヘシアン乗算


前述したように、この方法の魅力は、ヘッシアンを盎接数える必芁がないこずです。 ベクトルによる2次導関数の行列の積の結果を蚈算する必芁があるだけです。 このためにあなたは想像するこずができたす H\シヌタvの掟生物ずしお H\シヌタ方向に v

H thetav= lim epsilon to0 frac nablah theta+ epsilonv− nablah theta epsilon

しかし、実際にこの匏を䜿甚するず、十分に小さい蚈算に関連する倚くの問題が発生する可胜性がありたす \むプシロン。 そのため、ベクトルによる行列の正確な積を蚈算する方法がありたす。 埮分挔算子を玹介したす Rvx。 ある皋床の導関数を瀺したす x䟝存する \シヌタ方向に v

Rvx= lim epsilon to0 fracx theta+ epsilonv−x theta epsilon= frac deltax delta thetav

これは、ヘッセ行列の積をベクトルで蚈算するには、次の蚈算が必芁であるこずを瀺しおいたす。

Hv=R nablah theta qquad qquad4



HF最適化のいく぀かの改善


1.䞀般化ニュヌトンガりス行列䞀般化ガりスニュヌトン行列。
ヘッセ行列の䞍定性は、非凞非凞関数を最適化するための問題であり、2次関数の䞋限の欠劂に぀ながる可胜性がありたす。 Mそしおその結果、その最小倀を芋぀けるこずは䞍可胜です。 この問題は倚くの方法で解決できたす。 たずえば、信頌区間を導入するず、曲率行列に正の半確定成分を远加する眰金に基づいお最適化たたは枛衰が制限されたす Hそしお圌女を前向きにした。

実際の結果に基づいお、この問題を解決する最良の方法は、ニュヌトンガりス行列を䜿甚するこずです Gヘッセ行列の代わりに

G= frac1|S| sumx、y inSJTHLJ qquad qquad5

どこで J-ダコビアン、 Hl-損倱関数の二次導関数の行列 Lt、fx、 theta。
行列の積を芋぀けるには Gベクトルで v Gv=jthljv、最初にベクトルによるダコビアンの積を求めたす。

Jv=Rvfx、 theta

次に、ベクトルの積を蚈算したす Jv行列ぞ Hlそしお最埌に行列を掛けたす Jに HLJv。

2.ダンピング。
暙準のニュヌトン法では、匷く非線圢な目的関数の最適化が䞍十分な堎合がありたす。 この理由は、最適化の初期段階では、開始点が最小点から遠いため、非垞に倧きく積極的である可胜性があるためです。 この問題を解決するために、ダンプが䜿甚されたす-二次関数を倉曎する方法 Mたたは、新しい制限が \デルタそのような制限内にありたす M良い近䌌のたたになりたす h。
Tikhonovの正則化Tikhonov正則化たたはTikhonovのダンピングTikhonov枛衰。 機械孊習のコンテキストで䞀般的に䜿甚される「正芏化」ずいう甚語ず混同しないでくださいこれは、関数に二乗ペナルティを远加する最も有名なダンプ方法です M

 hatM delta equivM delta+ frac lambda2 deltaT delta=f theta+ nablah thetaT delta+ frac12 deltaT hatH delta

どこで  hatH=H+ lambdaI、  lambda geq0-ダンプパラメヌタヌ。 蚈算 Hvこのように行われたす

 hatHv=H+ lambdaIv=Hv+ lambdav qquad qquad6


3. Levenberg-MarquardtのヒュヌリスティックLevenberg-Marquardtヒュヌリスティック。
チホノフのダンピングは、パラメヌタヌの動的調敎によっお特城付けられたす \ラムダ。 倉曎 \ラムダLM-メ゜ッドのコンテキストでよく䜿甚されるLevenberg-Marquardtルヌルに埓いたす最適化メ゜ッドは、Newtonメ゜ッドの代替です。 LM-ヒュヌリスティックを䜿甚するには、いわゆる瞮小率を蚈算する必芁がありたす。

 rho= frach thetak+ deltak−h deltakMk deltak−Mk0= frach thetak+ deltak−h deltak nablah thetakT deltak+ frac12 deltakTH deltak qquad qquad7

どこで k-HFアルゎリズムのステップ番号、  deltak-CG最小化の䜜業の結果。
Levenberg-Marquardtのヒュヌリスティックによれば、曎新芏則が埗られたす \ラムダ

 begincasesif  rho>3/4 then  lambda gets2/3 lambdaif  rho<1/4 then  lambda gets3/2 lambda endcases qquad qquad8


4.共圹募配のアルゎリズムの初期条件事前調敎。
HF最適化のコンテキストでは、いく぀かの可逆倉換行列がありたす C䞀緒に倉わる Mそのような  delta=C−1\ガンマ代わりに \デルタ最小化する \ガンマ。 この機胜をCGアルゎリズムに適甚するには、倉換された゚ラヌベクトルの蚈算が必芁です。 yi=P−1riどこで P=CTC。

簡単なPCG前凊理付き共圹募配アルゎリズム
入力デヌタ  mathbfb、  mathbfA、  mathbfx0、 P、 i=0-CGアルゎリズムのステップ
初期化
  1.  mathbfr0= mathbfb− mathbfA mathbfx0-゚ラヌベクトル残差
  2.  mathbfy0-方皋匏の解 Py0=r0
  3.  mathbfd0= mathbfy0-怜玢方向のベクトル

停止条件が満たされるたで繰り返したす。
  1.  alphai= frac mathbfriT mathbfyi mathbfdiT mathbfA mathbfd
  2.  mathbfxi+1= mathbfxi+ alphai mathbfdi
  3.  mathbfri+1= mathbfri− alphai mathbfA mathbfdi
  4.  mathbfyi+1-方皋匏の解 Pyi+1=ri
  5.  betai= frac mathbfri+1T mathbfyi+1 mathbfriT mathbfyi
  6.  mathbfdi+1= mathbfyi+1+ betai mathbfdi
  7. i=i+1

マトリックス遞択 P非垞に簡単な䜜業です。 たた、実際には、フルランクの行列の代わりに察角行列を䜿甚するず、かなり良い結果が埗られたす。 マトリックスを遞択するためのオプションの1぀ P-これは察角フィッシャヌ行列経隓的フィッシャヌ察角の䜿甚です

P=diag barF= frac1|S| sumx、y inS nablaLt、fx、 theta2 qquad qquad9


5. CGの初期化-アルゎリズム。
むニシャルを初期化するこずをお勧めしたす  delta0、共圹募配アルゎリズムの堎合、倀  deltakHFアルゎリズムの前のステップで芋぀かりたした。 この堎合、いく぀かの枛衰定数を䜿甚できたす。  delta0= epsilon deltak、  epsilon in0、1。 むンデックスは泚目に倀したす kHFアルゎリズムのステップ番号を指し、順番にむンデックス0  delta0CGアルゎリズムの初期ステップを指したす。

完党なヘシアンフリヌ最適化アルゎリズム
入力デヌタ \シヌタ、 \ラムダ-ダンプパラメヌタヌ k-アルゎリズムの反埩のステップ
初期化
  1.  delta0=0

メむンのHF最適化サむクル
  1. 行列を蚈算する P
  2. 芋぀ける  deltakCGたたはPCGを䜿甚しお最適化問題を解決したす。  deltak=CG− nablah thetak、H、 epsilon deltak−1、P
  3. ダンプパラメヌタヌの曎新 \ラムダLevenberg-Marquardtヒュヌリスティックを䜿甚
  4.  thetak+1= thetak+ alpha thetak、  alpha-孊習率パラメヌタヌ
  5. k=k+1

したがっお、ヘッセ行列を䜿甚しない最適化手法により、倧次元関数の最小倀を芋぀ける問題を解決できたす。 ヘッセ行列を盎接芋぀ける必芁はありたせん。


TensorFlowでのHF最適化の実装


理論は確かに優れおいたすが、実際にこの最適化手法を実装しお、その結果を確認しおみたしょう。 HFアルゎリズムを蚘述するために、PythonずTensorFlow深局孊習ラむブラリを䜿甚したした。 その埌、パフォヌマンスチェックずしお、最適化のためにHFメ゜ッドを䜿甚しお、XORおよびMNISTデヌタセット䞊のいく぀かのレむダヌで盎接配信ネットワヌクをトレヌニングしたした。

共圹募配法の実装TensorFlow蚈算グラフの䜜成。

def __conjugate_gradient(self, gradients): """ Performs conjugate gradient method to minimze quadratic equation and find best delta of network parameters. gradients: list of Tensorflow tensor objects Network gradients. return: Tensorflow tensor object Update operation for delta. return: Tensorflow tensor object Residual norm, used to prevent numerical errors. return: Tensorflow tensor object Delta loss. """ with tf.name_scope('conjugate_gradient'): cg_update_ops = [] prec = None #  P   (9) if self.use_prec: if self.prec_loss is None: graph = tf.get_default_graph() lop = self.loss.op.node_def self.prec_loss = graph.get_tensor_by_name(lop.input[0] + ':0') batch_size = None if self.batch_size is None: self.prec_loss = tf.unstack(self.prec_loss) batch_size = self.prec_loss.get_shape()[0] else: self.prec_loss = [tf.gather(self.prec_loss, i) for i in range(self.batch_size)] batch_size = len(self.prec_loss) prec = [[g**2 for g in tf.gradients(tf.gather(self.prec_loss, i), self.W)] for i in range(batch_size)] prec = [(sum(tensor) + self.damping)**(-0.75) for tensor in np.transpose(np.array(prec))] #    Ax = None if self.use_gnm: Ax = self.__Gv(self.cg_delta) else: Ax = self.__Hv(gradients, self.cg_delta) b = [-grad for grad in gradients] bAx = [b - Ax for b, Ax in zip(b, Ax)] condition = tf.equal(self.cg_step, 0) r = [tf.cond(condition, lambda: tf.assign(r, bax), lambda: r) for r, bax in zip(self.residuals, bAx)] d = None if self.use_prec: d = [tf.cond(condition, lambda: tf.assign(d, p * r), lambda: d) for p, d, r in zip(prec, self.directions, r)] else: d = [tf.cond(condition, lambda: tf.assign(d, r), lambda: d) for d, r in zip(self.directions, r)] Ad = None if self.use_gnm: Ad = self.__Gv(d) else: Ad = self.__Hv(gradients, d) residual_norm = tf.reduce_sum([tf.reduce_sum(r**2) for r in r]) alpha = tf.reduce_sum([tf.reduce_sum(d * ad) for d, ad in zip(d, Ad)]) alpha = residual_norm / alpha if self.use_prec: beta = tf.reduce_sum([tf.reduce_sum(p * (r - alpha * ad)**2) for r, ad, p in zip(r, Ad, prec)]) else: beta = tf.reduce_sum([tf.reduce_sum((r - alpha * ad)**2) for r, ad in zip(r, Ad)]) self.beta = beta beta = beta / residual_norm for i, delta in reversed(list(enumerate(self.cg_delta))): update_delta = tf.assign(delta, delta + alpha * d[i], name='update_delta') update_residual = tf.assign(self.residuals[i], r[i] - alpha * Ad[i], name='update_residual') p = 1.0 if self.use_prec: p = prec[i] update_direction = tf.assign(self.directions[i], p * (r[i] - alpha * Ad[i]) + beta * d[i], name='update_direction') cg_update_ops.append(update_delta) cg_update_ops.append(update_residual) cg_update_ops.append(update_direction) with tf.control_dependencies(cg_update_ops): cg_update_ops.append(tf.assign_add(self.cg_step, 1)) cg_op = tf.group(*cg_update_ops) dl = tf.reduce_sum([tf.reduce_sum(0.5*(delta*ax) + grad*delta) for delta, grad, ax in zip(self.cg_delta, gradients, Ax)]) return cg_op, residual_norm, dl 

行列を蚈算するコヌド P初期条件前提条件を芋぀けるには、次のようになりたす。 同時に、Tensorflowは提瀺されたトレヌニング䟋党䜓の募配を蚈算した結果を芁玄するため、各䟋で募配を個別に取埗するために少しひねる必芁があり、これが解の数倀安定性に圱響を䞎えたした。 したがっお、圌らが蚀うように、あなた自身の危険ずリスクで、事前調敎の䜿甚が可胜です。

  prec = [[g**2 for g in tf.gradients(tf.gather(self.prec_loss, i), self.W)] for i in range(batch_size)] 

ベクトル4によるヘッセ行列の積の蚈算。 この堎合、Tikhonovダンプが䜿甚されたす6。

  def __Hv(self, grads, vec): """ Computes Hessian vector product. grads: list of Tensorflow tensor objects Network gradients. vec: list of Tensorflow tensor objects Vector that is multiplied by the Hessian. return: list of Tensorflow tensor objects Result of multiplying Hessian by vec. """ grad_v = [tf.reduce_sum(g * v) for g, v in zip(grads, vec)] Hv = tf.gradients(grad_v, self.W, stop_gradients=vec) Hv = [hv + self.damp_pl * v for hv, v in zip(Hv, vec)] return Hv 

䞀般化されたニュヌトン・ガりス行列5を䜿甚したいずき、小さな問題に遭遇したした。 ぀たり、TensorFlowは、他のTheanoディヌプラヌニングフレヌムワヌクTheanoにはこのために特別に蚭蚈されたRop関数がありたすのように、ベクトルに察するダコビアンの仕事を蚈算する方法を知りたせん。 TensorFlowでアナログ操䜜を行う必芁がありたした。

  def __Rop(self, f, x, vec): """ Computes Jacobian vector product. f: Tensorflow tensor object Objective function. x: list of Tensorflow tensor objects Parameters with respect to which computes Jacobian matrix. vec: list of Tensorflow tensor objects Vector that is multiplied by the Jacobian. return: list of Tensorflow tensor objects Result of multiplying Jacobian (df/dx) by vec. """ r = None if self.batch_size is None: try: r = [tf.reduce_sum([tf.reduce_sum(v * tf.gradients(f, x)[i]) for i, v in enumerate(vec)]) for f in tf.unstack(f)] except ValueError: assert False, clr.FAIL + clr.BOLD + 'Batch size is None, but used '\ 'dynamic shape for network input, set proper batch_size in '\ 'HFOptimizer initialization' + clr.ENDC else: r = [tf.reduce_sum([tf.reduce_sum(v * tf.gradients(tf.gather(f, i), x)[j]) for j, v in enumerate(vec)]) for i in range(self.batch_size)] assert r is not None, clr.FAIL + clr.BOLD +\ 'Something went wrong in Rop computation' + clr.ENDC return r 

そしお、䞀般化されたニュヌトン・ガりス行列の積をベクトルで既に実珟しおいたす。

  def __Gv(self, vec): """ Computes the product G by vec = JHJv (G is the Gauss-Newton matrix). vec: list of Tensorflow tensor objects Vector that is multiplied by the Gauss-Newton matrix. return: list of Tensorflow tensor objects Result of multiplying Gauss-Newton matrix by vec. """ Jv = self.__Rop(self.output, self.W, vec) Jv = tf.reshape(tf.stack(Jv), [-1, 1]) HJv = tf.gradients(tf.matmul(tf.transpose(tf.gradients(self.loss, self.output)[0]), Jv), self.output, stop_gradients=Jv)[0] JHJv = tf.gradients(tf.matmul(tf.transpose(HJv), self.output), self.W, stop_gradients=HJv) JHJv = [gv + self.damp_pl * v for gv, v in zip(JHJv, vec)] return JHJv 

䞻な孊習プロセスの機胜を以䞋に瀺したす。 たず、CG / PCGを䜿甚しお2次関数が最小化され、次にネットワヌクの重みの䞻な曎新が行われたす。 Levenberg-Marquardtヒュヌリスティックに基づくダンプパラメヌタヌも調敎されたす。

  def minimize(self, feed_dict, debug_print=False): """ Performs main training operations. feed_dict: dictionary Input training batch. debug_print: bool If True prints CG iteration number. """ self.sess.run(tf.assign(self.cg_step, 0)) feed_dict.update({self.damp_pl:self.damping}) if self.adjust_damping: loss_before_cg = self.sess.run(self.loss, feed_dict) dl_track = [self.sess.run(self.ops['dl'], feed_dict)] self.sess.run(self.ops['set_delta_0']) for i in range(self.cg_max_iters): if debug_print: d_info = clr.OKGREEN + '\r[CG iteration: {}]'.format(i) + clr.ENDC sys.stdout.write(d_info) sys.stdout.flush() k = max(self.gap, i // self.gap) rn = self.sess.run(self.ops['res_norm'], feed_dict) #      if rn < self.cg_num_err: break self.sess.run(self.ops['cg_update'], feed_dict) dl_track.append(self.sess.run(self.ops['dl'], feed_dict)) #  ,    (3) if i > k: stop = (dl_track[i+1] - dl_track[i+1-k]) / dl_track[i+1] if not np.isnan(stop) and stop < 1e-4: break if debug_print: sys.stdout.write('\n') sys.stdout.flush() if self.adjust_damping: feed_dict.update({self.damp_pl:0}) dl = self.sess.run(self.ops['dl'], feed_dict) feed_dict.update({self.damp_pl:self.damping}) self.sess.run(self.ops['train'], feed_dict) if self.adjust_damping: loss_after_cg = self.sess.run(self.loss, feed_dict) #  (7) reduction_ratio = (loss_after_cg - loss_before_cg) / dl # - (8) if reduction_ratio < 0.25 and self.damping > self.damp_num_err: self.damping *= 1.5 elif reduction_ratio > 0.75 and self.damping > self.damp_num_err: self.damping /= 1.5 

HF最適化のテスト


蚘述されたHFオプティマむザヌをテストしたす。このため、XORデヌタセットを䜿甚した簡単な䟋を䜿甚し、MNISTデヌタセットを䜿甚したより耇雑な䟋を䜿甚したす。 孊習成果を確認し、いく぀かの情報を芖芚化するために、TesnorBoardを䜿甚したす。 たた、TensorFlow蚈算のかなり耇雑なグラフが取埗されたこずにも泚意しおください。


TensorFlow Computingグラフ。

XORデヌタセットに関するネットワヌクアヌキテクチャずトレヌニング。
2぀の入力ニュヌロン、2぀の隠れニュヌロン、1぀の出力のサむズの単玔なネットワヌクを䜜成したしょう。 アクティベヌション関数ずしお、シグモむドを䜿甚したす。 損倱関数ずしお、察数損倱を䜿甚したす。

  #   """ Log-loss cost function """ loss = tf.reduce_mean(( (y * tf.log(out)) + ((1 - y) * tf.log(1.0 - out)) ) * -1, name='log_loss') #XOR  XOR_X = [[0,0],[0,1],[1,0],[1,1]] XOR_Y = [[0],[1],[1],[0]] #  sess = tf.Session() hf_optimizer = HFOptimizer(sess, loss, y_out, dtype=tf.float64, use_gauss_newton_matrix=True) init = tf.initialize_all_variables() sess.run(init) #  max_epoches = 100 print('Begin Training') for i in range(max_epoches): feed_dict = {x: XOR_X, y: XOR_Y} hf_optimizer.minimize(feed_dict=feed_dict) if i % 10 == 0: print('Epoch:', i, 'cost:', sess.run(loss, feed_dict=feed_dict)) print('Hypothesis ', sess.run(out, feed_dict=feed_dict)) 

ここで、HF最適化ヘッセ行列を䜿甚、HF最適化ニュヌトンガりス行列を䜿甚、および0.01に等しい孊習速床パラメヌタヌを䜿甚した通垞の募配降䞋を䜿甚しお、孊習結果を比范したす。 反埩回数は100です。


募配降䞋の損倱赀線。 ヘッセ行列を䜿甚したHF最適化の損倱オレンゞ色の線。 ニュヌトンガりス行列によるHF最適化の損倱青線。

同時に、Newton-Gauss行列を䜿甚したHF最適化が最速で収束する䞀方で、100回の反埩の募配降䞋では非垞に小さいこずが刀明したした。 募配降䞋の損倱関数がHF最適化に匹敵するためには、玄100,000回の反埩が必芁でした。


募配降䞋の損倱、100,000回の反埩。

MNISTデヌタセットに関するネットワヌクアヌキテクチャずトレヌニング。
手曞きの数字認識の問題を解決するために、入力ニュヌロン784、非衚瀺300、出力10のサむズのネットワヌクを䜜成したす。 損倱の関数ずしお、クロス゚ントロピヌを䜿甚したす。 トレヌニング䞭に提䟛されるミニバッチのサむズは50です。

  with tf.name_scope('loss'): one_hot = tf.one_hot(t, n_outputs, dtype=tf.float64) xentropy = tf.nn.softmax_cross_entropy_with_logits(labels=one_hot, logits=y_out) loss = tf.reduce_mean(xentropy, name="loss") with tf.name_scope("eval"): correct = tf.nn.in_top_k(tf.cast(y_out, tf.float32), t, 1) accuracy = tf.reduce_mean(tf.cast(correct, tf.float64)) n_epochs = 10 batch_size = 50 with tf.Session() as sess: """ Initializing hessian free optimizer """ hf_optimizer = HFOptimizer(sess, loss, y_out, dtype=tf.float64, batch_size=batch_size, use_gauss_newton_matrix=True) init = tf.global_variables_initializer() init.run() #   for epoch in range(n_epochs): n_batches = mnist.train.num_examples // batch_size for iteration in range(n_batches): x_batch, t_batch = mnist.train.next_batch(batch_size) hf_optimizer.minimize({x: x_batch, t: t_batch}) if iteration%10==0: print('Batch:', iteration, '/', n_batches) acc_train = accuracy.eval(feed_dict={x: x_batch, t: t_batch}) acc_test = accuracy.eval(feed_dict={x: mnist.test.images, t: mnist.test.labels}) print('Loss:', sess.run(loss, {x: x_batch, t: t_batch})) print('Target', t_batch[0]) print('Out:', sess.run(y_out_sm, {x: x_batch, t: t_batch})[0]) print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test) acc_train = accuracy.eval(feed_dict={x: x_batch, t: t_batch}) acc_test = accuracy.eval(feed_dict={x: mnist.test.images, t: mnist.test.labels}) print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test) 

XORの堎合ず同様に、HF最適化ヘッセ行列、HF最適化ニュヌトンガりス行列、および孊習速床パラメヌタヌ0.01の通垞の募配降䞋を䜿甚しお、孊習結果を比范したす。 反埩回数は200、぀たりです。 ミニバッチのサむズが50の堎合、200は完党な時代ではありたせんトレヌニングセットのすべおの䟋が䜿甚されるわけではありたせん。 すべおをより速くテストするためにこれを行いたしたが、これでも䞀般的な傟向が芋えたす。


巊の図は、テストサンプルの粟床です。 右の図は、トレヌニングサンプルの粟床です。 募配降䞋の粟床赀線。 ヘッセ行列オレンゞ色の線を䜿甚したHF最適化の粟床。 ニュヌトンガりス行列を䜿甚したHF最適化の粟床青線。


募配降䞋の損倱赀線。 ヘッセ行列を䜿甚したHF最適化の損倱オレンゞ色の線。 ニュヌトンガりス行列によるHF最適化の損倱青線。

䞊の図からわかるように、ヘッセ行列を䜿甚したHF最適化はあたり安定しお動䜜したせんが、いく぀かの時代で孊習するず最終的に収束したす。 最良の結果は、ニュヌトンガりスマトリックスを䜿甚したHF最適化によっお瀺されたす。


孊習の完党な時代。 巊の図は、テストサンプルの粟床です。 右の図は、トレヌニングサンプルの粟床です。 募配降䞋の粟床青緑色の線。 ニュヌトンガりス行列を䜿甚したHF最適化の損倱ピンクの線。


孊習の完党な時代。 募配降䞋の損倱青緑色の線。 ニュヌトンガりス行列を䜿甚したHF最適化の損倱ピンクの線。

共圹募配のアルゎリズムの初期条件で共圹募配の方法を䜿甚するず事前調敎、蚈算自䜓が倧幅に遅くなり、通垞のCGよりも速く収束したせんでした。


PCGアルゎリズムを䜿甚したHF最適化の損倱。

これらのすべおのグラフから、Newton-Gauss行列ず暙準共圹募配法を䜿甚したHF最適化によっお最良の結果が瀺されたこずがわかりたす。
完党なコヌドはGitHubで衚瀺できたす。


たずめ


その結果、PythonでのHFアルゎリズムの実装は、TensorFlowラむブラリを䜿甚しお䜜成されたした。 䜜成䞭に、アルゎリズムの䞻な機胜を実装するずきに、いく぀かの問題が発生したした。぀たり、Newton-Gauss行列のサポヌトず事前調敎です。 これは、TensorFlowが私たちが望むほど柔軟なラむブラリではなく、研究甚に蚭蚈されおいないためです。 実隓目的では、Theanoを䜿甚するほうが自由床が高くなるため、やはり良いです。 しかし、私は最初にこれをすべおTensorFlowで行うこずにしたした。 プログラムがテストされ、ニュヌトンガりス行列を䜿甚したHFアルゎリズムが最良の結果を䞎えるこずがわかりたした。 共圹募配のアルゎリズムの初期条件事前調敎を䜿甚するず、䞍安定な数倀結果が埗られ、蚈算が倧幅に遅くなりたしたが、これはTensorFlowの特性によるものず思われたす事前調敎の実装のために、私は非垞にゆがめなければなりたせんでした。


゜ヌス


この蚘事では、アルゎリズムの䞻芁な本質を理解できるように、ヘッセ行列の理論的偎面-無料の最適化に぀いお簡単に説明したす。 玠材の詳现な説明が必芁な堎合は、基本的な理論情報を取埗した情報源を匕甚したす。この情報に基づいお、PythonがHFメ゜ッドを実装したした。

1 ヘシアンを䜿甚しない最適化によるディヌプでリカレントなネットワヌクのトレヌニングJames MartensおよびIlya Sutskever、トロント倧孊-HFの完党な説明-最適化。
2 ヘッセ行列のない最適化によるディヌプラヌニングJames Martens、トロント倧孊-HFを䜿甚した結果を含む蚘事-最適化。
3 ヘッセ行列による高速完党乗算Barak A. Pearlmutter、Siemens Corporate Research -ヘッセ行列ずベクトルの乗算の詳现な説明。
4 苊痛を䌎わない共圹募配法の玹介Jonathan Richard Shewchuk、カヌネギヌメロン倧孊 -共圹募配法の詳现な説明。

Source: https://habr.com/ru/post/J350794/


All Articles