! ?! A! g* q2 N2 f' O2 T
优化算法入门系列文章目录(更新中):
遗传算法 ( GA , Genetic Algorithm ) ,也称进化算法 。 遗传算法是受达尔文的进化论的启发,借鉴生物进化过程而提出的一种启发式搜索算法。因此在介绍遗传算法前有必要简单的介绍生物进化知识。
. M8 x1 _/ ^( {9 e) C$ V6 ~* ]/ |. K% a8 x+ F
一.进化论知识 作为遗传算法生物背景的介绍,下面内容了解即可:
种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。
个体:组成种群的单个生物。
基因 ( Gene ) :一个遗传因子。
染色体 ( Chromosome ) :包含一组的基因。
生存竞争,适者生存:对环境适应度高的、牛B的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。
遗传与变异:新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。
5 }! |% W) m8 C4 u, @1 V- z2 X 简单说来就是:繁殖过程,会发生基因交叉( Crossover ) ,基因突变 ( Mutation ) ,适应度( Fitness )低的个体会被逐步淘汰,而适应度高的个体会越来越多。那么经过N代的自然选择后,保存下来的个体都是适应度很高的,其中很可能包含史上产生的适应度最高的那个个体。
7 { e6 K2 _' i
8 w1 _2 h+ T3 n8 M& B
二.遗传算法思想 借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。
举个例子,使用遗传算法解决“0-1背包问题”的思路:0-1背包的解可以编码为一串0-1字符串(0:不取,1:取) ;首先,随机产生M个0-1字符串,然后评价这些0-1字符串作为0-1背包问题的解的优劣;然后,随机选择一些字符串通过交叉、突变等操作产生下一代的M个字符串,而且较优的解被选中的概率要比较高。这样经过G代的进化后就可能会产生出0-1背包问题的一个“近似最优解”。
" r( _) _8 r3 ^5 b
编码:需要将问题的解编码成字符串的形式才能使用遗传算法。最简单的一种编码方式是二进制编码,即将问题的解编码成二进制位数组的形式。例如,问题的解是整数,那么可以将其编码成二进制位数组的形式。将0-1字符串作为0-1背包问题的解就属于二进制编码。
1 E& E+ L$ ?$ ?' V: d) _ 遗传算法有3个最基本的操作:选择,交叉,变异。
$ U) z8 f" ]; m 选择:选择一些染色体来产生下一代。一种常用的选择策略是 “比例选择”,也就是个体被选中的概率与其适应度函数值成正比。假设群体的个体总数是M,那么那么一个体Xi被选中的概率为f(Xi)/( f(X1) + f(X2) + …….. + f(Xn) ) 。比例选择实现算法就是所谓的“轮盘赌算法”( Roulette Wheel Selection ) ,轮盘赌算法的一个简单的实现如下:
0 H* \7 z7 l3 G% O8 B/ b
[url=]
[/url]
3 f3 Z" X1 z2 h" @8 I
轮盘赌算法/*2 S7 f: a: q X0 s0 T
* 按设定的概率,随机选中一个个体. v1 b1 _! ?% m# w' ]+ @) m
* P表示第i个个体被选中的概率
# M- @2 W) x0 K! \*/$ D$ H4 i3 T3 J- `
int RWS() i7 O( q) n" y$ y6 z# R
{7 g+ n" K# R/ I0 Q6 n2 |
m =0;
2 K; S; s) Q' k# `r =Random(0,1); //r为0至1的随机数
1 ?. I" U2 B. s% T, efor(i=1;i<=N; i++)/ I7 r6 Z* x* N/ Z* M- |6 b/ @$ e3 e$ U
{; D3 H) c% M0 P" N" F, o
/* 产生的随机数在m~m+P间则认为选中了i
( _; A& u6 m1 K+ i$ R: M7 J* m5 T* 因此i被选中的概率是P1 ^; M5 w3 n* P( y5 d' f* o
*/# o3 u, v7 f9 l9 C
m = m + P;
2 K* @9 \! x0 G* o, k) |8 K2 gif(r<=m) return i;. a9 l) a: K. q. S; O* X: f8 n8 B
}
5 ^; y/ }9 K7 k; Q- ?- [}
+ i5 o3 C9 d: {, a3 T I1 z( ?5 C0 X3 s3 m+ p
[url=]
[/url]2 z( N$ y9 [& h- Y+ f( [
( k2 ^9 L5 h' E2 \7 I2 T( A) u4 A5 _- s- ^- x1 g
交叉(Crossover):2条染色体交换部分基因,来构造下一代的2条新的染色体。例如:
交叉前:
00000|011100000000|10000
11100|000001111110|00101
交叉后:
00000|000001111110|10000
11100|011100000000|00101
染色体交叉是以一定的概率发生的,这个概率记为Pc 。
! j) O! w' N& ]" f
变异(Mutation):在繁殖过程,新产生的染色体中的基因会以一定的概率出错,称为变异。变异发生的概率记为Pm 。例如:
变异前:
000001110000000010000
变异后:
000001110000100010000
适应度函数 ( Fitness Function ):用于评价某个染色体的适应度,用f(x)表示。有时需要区分染色体的适应度函数与问题的目标函数。例如:0-1背包问题的目标函数是所取得物品价值,但将物品价值作为染色体的适应度函数可能并不一定适合。适应度函数与目标函数是正相关的,可对目标函数作一些变形来得到适应度函数。
7 o4 ] @% L* G9 ?0 c" t
4 }6 Z& Z7 a ]/ G2 V三.基本遗传算法的伪代码7 @- ]1 w1 s; v/ ~: v1 @; W1 q$ q v Y
7 n) G4 U' b: Z! K
[url=]
[/url]
! @: e) M+ g. z9 L' b D% N- s- {+ S
基本遗传算法伪代码/*/ P" t& J) x) @4 e. [
* Pc:交叉发生的概率
0 A3 D/ v" ~! J5 s( k; h* Pm:变异发生的概率
8 `, e; k4 @+ ^3 x* M:种群规模8 r# ^+ O! O; y- S \7 ?
* G:终止进化的代数
- z0 W: d. O8 f7 }9 M- U* Tf:进化产生的任何一个个体的适应度函数超过Tf,则可以终止进化过程
4 T5 [" j3 ^- A% y! X3 V6 O, u- q3 W*/: W$ c8 v0 X% ?. V! N n
初始化Pm,Pc,M,G,Tf等参数。随机产生第一代种群Pop, ~8 s3 ^7 G$ z$ h- u% I3 F
" i6 R* I6 k6 s( l$ z
do6 D/ O- b, G% b4 C0 u
{ ) S9 E! p( u `" ~$ k
计算种群Pop中每一个体的适应度F(i)。
+ Y0 W/ `, o. {3 p) z5 i 初始化空种群newPop
! r9 V/ q. w0 u! V% o$ Y do6 F8 `: n. o& n+ W3 S
{8 h- r4 \% K. Q3 C$ z( B- N$ y
根据适应度以比例选择算法从种群Pop中选出2个个体0 X) Y7 v6 d' a
if ( random ( 0 , 1 ) < Pc )* ]$ C* K* ?# K$ f9 l' F4 k
{
8 w$ e6 t0 G8 d6 | 对2个个体按交叉概率Pc执行交叉操作
, l: K$ u2 S+ d }
8 U7 Q$ u: J; w1 Y0 ]/ \ if ( random ( 0 , 1 ) < Pm ); R3 d0 O7 Y7 f/ ~) f3 g
{2 @: @3 o. s! E5 g3 T3 X! p j
对2个个体按变异概率Pm执行变异操作
6 M1 a4 X C5 H0 O, d" D! N$ s6 k } [7 C/ T2 q3 A" y+ L! j+ l
将2个新个体加入种群newPop中+ v8 \0 }: Z1 `/ @1 p4 s
} until ( M个子代被创建 )
; H; L9 F2 L3 n0 j; c用newPop取代Pop
" o X3 {( _, j# R5 I; S) E( u}until ( 任何染色体得分超过Tf, 或繁殖代数超过G )/ W* ^5 l4 }" p8 W
4 V* N! e5 X0 u* Q2 ]8 w1 P Z% r; y) u) c1 C' |
[url=]
[/url]+ Y) R0 B! l" v
1 @! \3 a6 g! P u5 e% P/ D8 G
$ A! j" A. j6 L
' Q1 ^ F7 ]) m
四.基本遗传算法优化 下面的方法可优化遗传算法的性能。
精英主义(Elitist Strategy)选择:是基本遗传算法的一种优化。为了防止进化过程中产生的最优解被交叉和变异所破坏,可以将每一代中的最优解原封不动的复制到下一代中。
插入操作:可在3个基本操作的基础上增加一个插入操作。插入操作将染色体中的某个随机的片段移位到另一个随机的位置。
五. 使用AForge.Genetic解决TSP问题 AForge.NET是一个C#实现的面向人工智能、计算机视觉等领域的开源架构。AForge.NET中包含有一个遗传算法的类库。
$ s, k, q, n* z% }& m, l+ G
2 Y1 @" F4 `/ f 介绍一下AForge的遗传算法用法吧。AForge.Genetic的类结构如下:
4 o2 q9 ]* P/ J+ I6 ?- P
图1. AForge.Genetic的类图
0 j! H) K. q& B4 `" `3 T; u7 @# ]8 y
下面用AForge.Genetic写个解决TSP问题的最简单实例。测试数据集采用网上流传的中国31个省会城市的坐标:
" J9 E+ u' h, \( z5 I$ ]1 ?
[url=]
[/url]
2 }8 k9 S+ d1 e/ C. y( r$ e/ a( O130423127 o( o a8 `3 }7 ^' t
36391315
1 f5 j. l: r0 w4 l0 ~5 M6 E+ c$ H41772244
" c9 _* K. t9 E& H37121399
( L7 ?" j) L. a* X34881535. ^1 j. c/ k" [4 Q
33261556
' e6 e" t, {* R: j8 C32381229% y4 r9 `- n9 T# o7 |* K% G
41961004* c5 b. {2 ]9 t3 f
4312790
' ?2 @% t# P* B) i7 a* d, [ Y. h; z4386570
2 X; ^7 `% ^$ h/ a0 f& `7 _30071970- U9 ?5 [* V- T$ |3 ?; g
25621756
, J4 b$ F' B8 b, }! e278814912 b( l6 R, ]* v4 a
23811676- G; @# K: G% O5 q/ K
1332695; j- T/ U8 W E7 e+ v
371516782 y) Y9 u( `- a5 E7 D: ]
391821793 P: D/ e2 B1 E6 f3 }# m; Y
40612370
6 g1 k: r9 p: M) S) v37802212
9 q+ Z9 w. i- y7 i& k367625780 Y4 B& `2 X# t% C+ ^$ x# Y6 p
402928389 c: K3 f! k/ e- t& Q
426329310 b+ P+ A4 q$ Q& G
34291908
0 |3 ?8 ?4 [+ d1 Q" { A+ ~# O35072367/ H0 P3 c+ ^, r( n; K. U
33942643& K# a, C$ a: H* |
34393201! u* X1 f% m# ?8 N" z: G+ F
293532404 v9 p; ^( T1 U
31403550
8 ~( ]; i. X+ `3 ` _# d$ ^5 `0 O25452357# V% K# O6 _: u7 {
27782826, t$ I2 p: d' R- t* L8 l
237029758 J7 M# _# U3 f+ x4 b6 M, N2 h
[url=]
[/url]- H: [& S) y& s
' T% L; B( C! R2 o# L# ~+ R' S0 y1 ~4 E
* Z0 [ b2 L/ ^& X
! F. l8 k4 A; g( Y( v操作过程:
(2) 创建C#空项目GenticTSP。然后在AForge目录下找到AForge.dll和AForge.Genetic.dll,将其拷贝到TestTSP项目的bin/Debug目录下。再通过“Add Reference...”将这两个DLL添加到工程。
(3) 将31个城市坐标数据保存为bin/Debug/Data.txt 。
(4) 添加TSPFitnessFunction.cs,加入如下代码:
( b( G, L/ P1 C
[url=]
[/url]
4 y: n: l3 @! T. S" n0 f
TSPFitnessFunction类using System;
# X, B- y, \) I+ Y$ Dusing AForge.Genetic;% W/ T5 v' n& l* c( R! |% M
( P& B) e" D4 ]1 N( I3 P
namespace GenticTSP f6 C& s' q1 F) N M: A; H# x
{( L8 s2 ~) N R& N' k% {* t; O$ ~
///<summary>
, _4 d/ ]8 ^3 ]6 Z$ c2 }/// Fitness function for TSP task (Travaling Salasman Problem). w2 ~% d: w1 D+ N
///</summary>
+ ~2 T; v; F2 m- Mpublicclass TSPFitnessFunction : IFitnessFunction4 F/ y& S- {% ~6 R( s% B: u6 N
{! K A/ r" K4 L) r, T+ E
// map; E1 x8 \/ j3 \0 U
privateint[,] map =null;
; Y1 u4 M: m; Z3 s& Y# ]
$ E& Q9 u) y1 r* t7 ~# h// Constructor, t: E: c- X/ a1 {4 x
public TSPFitnessFunction(int[,] map)
# H M& ]# e2 J8 w{( c( I! [3 e9 n$ ]0 g( f s
this.map = map;
" |# X8 e, J& P7 z} v# E/ i6 ` x7 i+ f N5 ?9 D( V. _
* r3 q l+ ]: n+ w
///<summary>
. Q I+ ]9 @ S/ o$ l: Y2 x6 H; d/// Evaluate chromosome - calculates its fitness value5 u; M8 |1 |# [! K
///</summary>) P; i6 g$ Q- I, ?7 }& i
publicdouble Evaluate(IChromosome chromosome)
" k' {% g, A9 ]# q+ t6 d{2 g8 e. O% Z X) [9 _
return1/ (PathLength(chromosome) +1);' P; _: s4 @/ p
}/ P+ `9 u( @. ~1 G
0 m# \! H: i5 M+ Z0 q5 m///<summary>
0 c/ C& O2 l. P7 |- W4 f+ b/// Translate genotype to phenotype
4 \; F' s7 m/ R; O( F3 W7 @///</summary>9 f1 m8 ^$ A: T# J7 Q, t- `
publicobject Translate(IChromosome chromosome). C. B# x, q* D6 t) ~' `0 p
{
. ]. G* ?3 i+ _( y. Sreturn chromosome.ToString();
. ~: M& ]0 ]4 ]- s! S! ~}
7 ~# y! `: W2 H5 u8 e! l
' Y# U; a+ r6 Z2 m; M' G///<summary>! s0 ?. W. M3 o; g" s; V( V! ?
/// Calculate path length represented by the specified chromosome h% E5 v" y1 @. s6 T5 r) Q. O
///</summary>( I' @ I) c5 j( n
publicdouble PathLength(IChromosome chromosome)
8 ] O2 o& A( x, n: y5 I+ ^& l{# w4 L# R* F; _/ N
// salesman path: Z; d5 d( Q1 `: j2 Q1 c$ ]
ushort[] path = ((PermutationChromosome)chromosome).Value;
0 p0 G/ L! ]. q, w1 c) ]$ p
2 Q4 ~# k) u( G0 d8 y) [$ B r! y" L A// check path size$ O6 L/ g; n/ @9 R: _2 H) L( [8 B
if (path.Length != map.GetLength(0))
) J, `1 T" d) s" u) v{9 U5 H# J# q9 H" c/ t- W
thrownew ArgumentException("Invalid path specified - not all cities are visited");; _# d! k; r) l& v0 N1 I3 m
}. Q' e$ T( H/ Z, q, K; P; P
2 O% R- G# _2 F3 B. ]4 L
// path length! W) S& C% { O% }/ H# A! M
int prev = path[0];* `+ n z( v; f; ], u8 c X* t; W
int curr = path[path.Length -1];
- o$ f* l/ w; v& Y9 H7 y% D
+ ]8 [5 ^* |. x {- {// calculate distance between the last and the first city
6 m( x q" z# U# Cdouble dx = map[curr, 0] - map[prev, 0];
4 u& w- u9 C/ r) s3 l# N ndouble dy = map[curr, 1] - map[prev, 1];
1 o) A O! E- R$ g# B3 wdouble pathLength = Math.Sqrt(dx * dx + dy * dy);" w8 }- V, x e1 u$ h
/ g& k* L. u0 D L3 Q3 u
// calculate the path length from the first city to the last
/ n# d2 _/ ^3 q8 [for (int i =1, n = path.Length; i < n; i++)4 ~$ g2 w( z5 W$ ^4 i! `/ E: N
{
0 O$ n* U; \8 p! X7 S// get current city
8 K' K: i8 Y ^) v4 n Ocurr = path;
: H; c% H2 O, k: }5 S! P- `+ P0 j2 x! w1 ^
// calculate distance9 {, v) e* }; y& k3 P$ d, @
dx = map[curr, 0] - map[prev, 0];+ ]) | }. O/ O6 u2 b7 G3 ]; I
dy = map[curr, 1] - map[prev, 1];
& e5 R$ _7 x& |% {! n! wpathLength += Math.Sqrt(dx * dx + dy * dy);
% _6 t Z$ W! M7 i% q
- _" D- x) Z# {6 h Z// put current city as previous
% b3 T V. a& J/ h9 [' \! f- lprev = curr;
: R0 e+ {% v0 o4 `8 a# y( |6 q}
- x, k) Q9 E0 u/ W- ]# X* N' u [, l3 F [$ o2 E
return pathLength;
% ?8 W$ t7 y C}" B, T* d6 A- u
}
2 h) p2 j0 n$ R2 k; x1 l/ y}1 l% S" d, X8 U) L$ b; n ^% R1 e
5 O; B$ V8 x' l( ^5 d* P3 X( s* w q5 y, Z( j9 d
[url=]
[/url]6 |" ?5 M6 b x% }7 g2 d
: V- w4 @* g F' t! [: g3 Z- {6 w4 n' H: M8 n# _# l3 r
7 ] x% I! { a }
(5) 添加GenticTSP.cs,加入如下代码:
/ x* ^/ z" N3 f3 T8 d' C! I
[url=]
[/url]
. T- r6 u, Z, d' l/ h
GenticTSP类using System;/ ^& S' O' b: T; }* q3 B% r$ d
using System.Collections.Generic;
8 `7 K; q) c4 C( P; Uusing System.Linq;& v! E m; c9 ~; O
using System.Text;; `3 r( B/ ?8 G/ h" G1 ~6 b
using System.IO;3 x2 i; K0 Q/ c1 d' U. |. W6 n
$ J) d( h0 G4 G' H. e
using AForge;
8 }* s( {0 \ ~- s" @* T2 Qusing AForge.Genetic;6 V. |2 H1 Y- c, L/ p6 K
) ?1 G1 V6 V) D/ c! X# B# Q/ y) L' r! [7 H! j' s( X
namespace GenticTSP5 o2 k! q, ~8 E4 U+ r
{
) c. V/ h8 t- h0 I" pclass GenticTSP
6 I1 @0 Z7 C' [# J2 I0 B; C% k8 X{
2 k- w- J$ {& Q) L2 Z3 |8 G9 ~3 _
P \. |4 D( T( r3 Q% Rstaticvoid Main()
- K' F, c/ _) P- c$ V! h{# _- C2 y5 G m2 G2 o; Z. Y
StreamReader reader =new StreamReader("Data.txt");
' L; t7 D/ ^$ ~0 S( F% G
- \2 ?* L5 W# l! I7 k* oint citiesCount =31; //城市数
6 }! I* V/ v1 [0 b0 M- ?% N, h2 g4 l# t$ f- U n# B% D
int[,] map =newint[citiesCount, 2];6 T6 U: M3 T4 S$ h( Q
# A9 [5 \0 D. E8 Q3 e; v8 i; O
for (int i =0; i < citiesCount; i++)6 k' R- p7 A$ C; D/ }( x
{
, b7 i: x! u+ {! _4 I: y4 Dstring value = reader.ReadLine();. b) C# D9 N3 D5 u' M7 ~0 w
string[] temp = value.Split('');
. n3 c+ S X5 i2 |- |: J* dmap[i, 0] =int.Parse(temp[0]); //读取城市坐标
# d3 O4 F w: p3 C4 K/ O( `% Imap[i, 1] =int.Parse(temp[1]);
. q! A) \5 d# e) I3 c% w}
6 {$ e6 c- o7 ]( O3 s9 _- n" i" U1 Q) g' u2 j$ |/ c
// create fitness function+ E( k3 m, J8 i4 I& {
TSPFitnessFunction fitnessFunction =new TSPFitnessFunction(map);4 g% g, O9 T# Q7 d
, u& b1 x0 Q3 u
int populationSize = 1000; //种群最大规模- f! |0 ` X, U
1 D! `* D# S* F; h; E7 F2 a
/* 0 r& d6 \8 @0 b* I
* 0:EliteSelection算法
0 {! w' W0 }) \% m0 `* S* 1:RankSelection算法
' t- G f, v" e& D6 T" F) Y* 其他:RouletteWheelSelection 算法! n g$ H( \8 a# B& A& z4 t
* *// L: u7 |7 ^) ~+ Q; Q
int selectionMethod =0;3 C4 G, f3 x5 G- I" C
$ D/ Y+ V( @4 v8 f: z) ]& o6 J// create population: i; m; T# w+ `) p5 J! T2 a
Population population =new Population(populationSize,$ ]2 s' V5 t3 ]0 H
new PermutationChromosome(citiesCount),' I+ [( V1 {8 s$ k- K
fitnessFunction,
# |' E" H' [; t8 e' k(selectionMethod ==0) ? (ISelectionMethod)new EliteSelection() :" m4 W% x$ Q6 F3 ^' l }& W
(selectionMethod ==1) ? (ISelectionMethod)new RankSelection() :
4 \/ L$ U0 ^+ ~/ y6 o(ISelectionMethod)new RouletteWheelSelection()- r+ h5 H7 n1 `% s
);3 h3 n4 O% m/ l q' w% y2 D
, k( a) U4 }4 x+ O, |, p# u
// iterations
" u u, ]* k: \% L, Z+ tint iter =1;/ s! `' Y) U$ Z$ V
int iterations =5000; //迭代最大周期3 y" D; M o C) a0 j5 ?) [8 y
0 |& t% f* E, e W8 @5 o# q
// loop
% _8 g- x+ y$ S( z7 f: ~+ ^while (iter < iterations)
7 E5 Q' F+ z' \, L{
& n3 A0 C8 E: x& e6 Z// run one epoch of genetic algorithm
- q2 w% n g) N: q# |( P- p6 I) ppopulation.RunEpoch();; V" i; h, M2 c$ Q) j
& g# X1 P" w& h/ ~// increase current iteration) R- \3 X v' ^4 K' j- _9 v* @' ~
iter++;2 i+ `' k4 c0 }$ K
}6 Q! ?0 l" d7 S& y
% ~9 {2 B7 s7 W- v1 R E% K" mSystem.Console.WriteLine("遍历路径是: {0}", ((PermutationChromosome)population.BestChromosome).ToString());
( `! M% i; l' q3 oSystem.Console.WriteLine("总路程是:{0}", fitnessFunction.PathLength(population.BestChromosome));
( `' e* Z: I/ W. ZSystem.Console.Read();0 [; A; d# _+ U) J4 {7 b/ Y2 c
6 q' L# l4 O* y) p( }8 ~
}, h) _/ Z1 Z- Q+ n t+ q( J
}
4 f d9 u; g7 V- D}5 e! _9 X( H! s- m
- Y: Q7 p/ P2 b0 x+ F H5 U6 t5 e9 Y4 j: P Z% i& K
[url=]
[/url]& f8 I9 v1 V5 \% }8 ]
2 u9 V1 d9 Q1 s
0 `9 g/ Q" {- w' U- f* }
7 |, X4 v* i! w1 T; s- c) t' x& B& j3 S+ l5 }1 u0 @6 _
网上据称这组TSP数据的最好的结果是 15404 ,上面的程序我刚才试了几次最好一次算出了15402.341,但是最差的时候也跑出了大于16000的结果。
我这还有一个版本,设置种群规模为1000,迭代5000次可以算出15408.508这个结果。源代码在文章最后可以下载。
( l! g" S" P/ Q- {! w5 n
总结一下使用AForge.Genetic解决问题的一般步骤:
(1) 定义适应函数类,需要实现IFitnessFunction接口
(2) 选定种群规模、使用的选择算法、染色体种类等参数,创建种群population
(3)设定迭代的最大次数,使用RunEpoch开始计算
4 M. u0 w1 m3 T1 n5 E