예제 #1
0
파일: stats.go 프로젝트: akiross/gogp
func (stats *Stats) SaveSnapshot(pop *base.Population, quiet bool, cntKeys, staKeys, intCntKeys []string) (snapName, snapPopName string) {
	timeDelay := time.Since(stats.lastTime)
	stats.lastTime = time.Now()

	// Sort population, to easy reading when printing and drawing
	sort.Sort(pop)
	// Build paths
	prefix := fmt.Sprintf("%v/snapshot/%v-", stats.basedir, stats.basename)
	snapName = fmt.Sprintf(prefix+"snapshot-%v.png", stats.snapCount)
	snapPopName = fmt.Sprintf(prefix+"pop_snapshot-%v.png", stats.snapCount)
	logPrefix := fmt.Sprintf("%v/log/%v-", stats.basedir, stats.basename)
	bestTree := fmt.Sprintf(logPrefix+"tree-%v.json", stats.snapCount)

	writeIndividual(pop.BestIndividual(), bestTree)

	const wideField = 40

	if !quiet {
		if stats.snapCount == 0 {
			fmt.Print("Generation |  Tree depth (mean, stdev) |  Tree size (mean, stdev) |       Fitness (min, mean, max, stdev)       |  XO Improv (abs, rel) | MUT Improv (abs, rel) |    Time delay |")
			for _, k := range staKeys {
				fmt.Printf(" %21s |", k)
			}
			for _, k := range cntKeys {
				fmt.Printf(" %21s |", k)
			}
			for _, k := range intCntKeys {
				fmt.Printf(" %*s |", wideField, k)
			}
			fmt.Println()
		}
		fmt.Printf("%10v |   %11.4f %11.4f |  %11.4f %11.4f | %10.2f %10.2f %10.2f %10.2f | %10v %10.3f | %10v %10.3f | %13v |",
			stats.obsCount-1,
			stats.depth.PartialMean(), math.Sqrt(stats.depth.PartialVar()),
			stats.size.PartialMean(), math.Sqrt(stats.size.PartialVar()),
			stats.min.Get(), stats.fitness.PartialMean(), stats.max.Get(), math.Sqrt(stats.fitness.PartialVar()),
			stats.xoImpr.AbsoluteFrequency(), stats.xoImpr.RelativeFrequency(),
			stats.mutImpr.AbsoluteFrequency(), stats.mutImpr.RelativeFrequency(),
			fmt.Sprintf("%v", timeDelay),
		)

		for _, k := range staKeys {
			if sst, ok := pop.Set.Statistics[k]; ok {
				fmt.Printf(" %6d %6g %6g %10.6g %10.6g |", sst.Variance.Count(), sst.Min.Get(), sst.Max.Get(), sst.PartialMean(), sst.PartialVarBessel())
				sst.Clear()
			} else {
				fmt.Printf(" %6v %6v %6v %10v %10v |", "-", "-", "-", "-", "-")
			}
		}
		for _, k := range cntKeys {
			if cst, ok := pop.Set.Counters[k]; ok {
				fmt.Printf(" %10d %10.6g |", cst.AbsoluteFrequency(), cst.RelativeFrequency())
				cst.Clear()
			} else {
				fmt.Printf(" %10v %10v |", "-", "-")
			}
		}
		for _, k := range intCntKeys {
			if nst, ok := pop.Set.IntCounters[k]; ok {
				keys := nst.Counted()
				if len(keys) == 0 {
					fmt.Printf(" %*s |", wideField, "0:0")
				} else {
					vals := make([]string, len(keys))
					for i, n := range keys {
						vals[i] = fmt.Sprintf("%d:%d", n, nst.AbsoluteFrequency(n))
					}
					fmt.Printf(" %*s |", wideField, strings.Join(vals, ","))
					nst.Clear()
				}
			} else {
				fmt.Printf(" %*s |", wideField, "0:0")
			}
		}
		fmt.Println()
	}
	// Increment snapshot count
	stats.snapCount++
	return
}
예제 #2
0
파일: evolve.go 프로젝트: akiross/gogp
func Evolve(calcMaxDepth func(*imgut.Image) int, fun, ter []gp.Primitive, drawfun func(*base.Individual, *imgut.Image)) {
	startTime := time.Now()

	// Setup options
	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	numGen := fs.Int("g", 100, "Number of generations")
	popSize := fs.Int("p", 1000, "Size of population")
	saveInterval := fs.Int("n", 25, "Generations interval between two snapshot saves")
	tournSize := fs.Int("T", 3, "Tournament size")
	pCross := fs.Float64("C", 0.8, "Crossover probability")
	pMut := fs.Float64("M", 0.1, "Bit mutation probability")
	quiet := fs.Bool("q", false, "Quiet mode")
	fElite := fs.Bool("el", false, "Enable elite individual")

	fInitFull := fs.Bool("full", true, "Enable full initialization")
	fInitGrow := fs.Bool("grow", true, "Enable grow initialization")
	fInitRamped := fs.Bool("ramp", true, "Enable ramped initialization")

	fMutSin := fs.Bool("ms", false, "Enable Single Mutation")
	fMutNod := fs.Bool("mn", false, "Enable Node Mutation")
	fMutSub := fs.Bool("mt", false, "Enable Subtree Mutation")
	fMutAre := fs.Bool("ma", false, "Enable Area Mutation")
	fMutLsubt := fs.Bool("mlt", false, "Enable Level-Subtree Mutation")
	fMutLoc := fs.Bool("ml", false, "Enable Local Mutation")

	fSelect := fs.String("sel", "torun", "Pick selection method (tourn, rmad, irmad)")

	fMultiMut := fs.Bool("mM", false, "Enable multiple mutations")
	fFitness := fs.String("fit", "rmse", "Pick fitness function (rmse, mse, rmsed, ssim)")

	//advStats := fs.Bool("stats", false, "Enable advanced statistics")
	//nps := fs.Bool("nps", false, "Disable population snapshot (no-pop-snap)")
	targetPath := fs.String("t", "", "Target image (PNG) path")
	var basedir, basename string
	cpuProfile := fs.String("cpuprofile", "", "Write CPU profile to file")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "  basedir (string) to be used for saving logs and files\n")
		fmt.Fprintf(os.Stderr, "  basename (string) to be used for saving logs and files\n")
	}

	fs.Parse(os.Args[1:])

	// Check if the argument
	args := fs.Args()

	if len(args) != 2 {
		fs.Usage()
		fmt.Fprintf(os.Stderr, "\nBasename/basedir parameter not specified\n")
		return
	} else {
		basedir = args[0]
		basename = args[1]
	}

	sta := stats.Create(basedir, basename)

	// Build settings
	var settings base.Settings
	// Primitives to use
	settings.Functionals = fun
	settings.Terminals = ter
	// Draw function to use
	settings.Draw = drawfun

	settings.Ramped = *fInitRamped
	if settings.Ramped {
		fmt.Println("Using ramped initialization")
	}

	// Pick initialization method based on flags
	var genFuncBit func(minH, maxH int, funcs, terms []gp.Primitive) *node.Node

	if *fInitFull && !*fInitGrow {
		fmt.Println("Using init strategy: full")
		genFuncBit = node.MakeTreeFull // Initialize tree using full
	} else if !*fInitFull && *fInitGrow {
		fmt.Println("Using init strategy: balanced grow")
		genFuncBit = node.MakeTreeGrowBalanced // Initialize using grow
	} else {
		fmt.Println("Using init strategy: half-and-half")
		genFuncBit = node.MakeTreeHalfAndHalf // Initialize using both (half and half)
	}
	settings.GenFunc = func(maxDep int) *node.Node {
		t := genFuncBit(0, maxDep, fun, ter) // /* TODO */ sistemare la minH
		s := settings
		if _, ok := s.IntCounters[tree_init_depth]; !ok {
			s.IntCounters[tree_init_depth] = new(counter.IntCounter)
		}
		s.IntCounters[tree_init_depth].Count(node.Depth(t))
		return t
	}

	// Build statistic map
	settings.Statistics = make(map[string]*sequence.SequenceStats)
	settings.Counters = make(map[string]*counter.BoolCounter)
	settings.IntCounters = make(map[string]*counter.IntCounter)

	// Names of extra statistics
	statsKeys := []string{}
	countersKeys := []string{}
	intCountersKeys := []string{}

	intCountersKeys = append(intCountersKeys, tree_init_depth)

	if *fMutSin {
		countersKeys = append(countersKeys, mut_single_event, mut_single_improv, mut_single_node_leaves)
		intCountersKeys = append(intCountersKeys, mut_single_node_depth, mut_single_node_repld)
	}
	if *fMutNod {
		countersKeys = append(countersKeys, mut_multi_event, mut_multi_improv, mut_multi_node_leaves)
		intCountersKeys = append(intCountersKeys, mut_multi_node_depth, mut_multi_node_repld)
	}
	if *fMutSub {
		countersKeys = append(countersKeys, mut_tree_event, mut_tree_improv, mut_tree_node_leaves)
		intCountersKeys = append(intCountersKeys, mut_tree_node_depth, mut_tree_node_repld)
	}
	if *fMutAre {
		countersKeys = append(countersKeys, mut_area_event, mut_area_improv, mut_area_node_leaves)
		intCountersKeys = append(intCountersKeys, mut_area_node_depth, mut_area_node_repld)
	}
	if *fMutLsubt {
		countersKeys = append(countersKeys, mut_lsubt_event, mut_lsubt_improv, mut_lsubt_improv)
		intCountersKeys = append(intCountersKeys, mut_lsubt_node_depth, mut_lsubt_node_repld)
	}
	if *fMutLoc {
		countersKeys = append(countersKeys, mut_local_event, mut_local_improv)
		//		intCountersKeys = append(intCountersKeys, "mut_local_") TODO
	}
	if *fMultiMut {
		intCountersKeys = append(intCountersKeys, mut_count_multi)
	}

	if *cpuProfile != "" {
		f, err := os.Create(*cpuProfile)
		if err != nil {
			fmt.Println("ERROR", err)
			panic("Cannot create cpuprofile")
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Load the target
	var err error
	settings.ImgTarget, err = imgut.Load(*targetPath)
	if err != nil {
		fmt.Fprintln(os.Stderr, "ERROR: Cannot load image", *targetPath)
		panic("Cannot load image")
	}
	if !*quiet {
		fmt.Println("Image format RGB?", settings.ImgTarget.ColorSpace == imgut.MODE_RGB, settings.ImgTarget.ColorSpace)
	}

	// Compute the right value of maxDepth
	settings.MaxDepth = calcMaxDepth(settings.ImgTarget)
	if !*quiet {
		fmt.Println("For area of", settings.ImgTarget.W*settings.ImgTarget.H, "pixels, max depth is", settings.MaxDepth)
	}

	// Create temporary surface, of same size and mode
	//settings.ImgTemp = imgut.Create(settings.ImgTarget.W, settings.ImgTarget.H, settings.ImgTarget.ColorSpace)
	// Create temporary surface for the entire population
	pImgCols := int(math.Ceil(math.Sqrt(float64(*popSize))))
	pImgRows := int(math.Ceil(float64(*popSize) / float64(pImgCols)))
	imgTempPop := imgut.Create(pImgCols*settings.ImgTarget.W, pImgRows*settings.ImgTarget.H, settings.ImgTarget.ColorSpace)

	// Define the operators
	settings.CrossOver = makeCrossover(&settings)
	settings.Mutate = makeMultiMutation(&settings, *fMultiMut, *fMutSin, *fMutNod, *fMutSub, *fMutAre, *fMutLsubt, *fMutLoc)

	// Fitness
	if *fFitness == "mse" {
		settings.FitFunc = base.MakeFitMSE(settings.ImgTarget)
	} else if *fFitness == "rmsed" {
		statsKeys = append(statsKeys, "fit-delta-rmse")
		settings.FitFunc = base.MakeFitEdge(settings.ImgTarget, settings.Statistics)
	} else if *fFitness == "ssim" {
		settings.FitFunc = base.MakeFitSSIM(settings.ImgTarget)
	} else {
		statsKeys = append(statsKeys, "fit-delta-rmse")
		settings.FitFunc = base.MakeFitRMSE(settings.ImgTarget)
	}

	// Selection
	ts := *tournSize
	if *fSelect == "rmad" {
		settings.Select = base.MakeSelectRMAD(ts, ts*ts, settings.BetterThan)
	} else if *fSelect == "irmad" {
		settings.Select = base.MakeSelectIRMAD(ts, ts*ts, settings.BetterThan)
	} else {
		settings.Select = base.MakeSelectTourn(ts, settings.BetterThan)
	}

	// Seed rng
	if !*quiet {
		fmt.Println("Number of CPUs", runtime.NumCPU())
		runtime.GOMAXPROCS(runtime.NumCPU())
		fmt.Println("CPUs limits", runtime.GOMAXPROCS(0))
	}

	// Build population
	pop := new(base.Population)
	pop.Set = &settings
	//pop.TournSize = *tournSize
	pop.Initialize(*popSize)

	// Save initial population FIXME it's for debugging
	/*
		for i := range pop.Pop {
			pop.Pop[i].Draw(imgTemp)
			imgTemp.WritePNG(fmt.Sprintf("pop_ind_%v.png", i))
		}
	*/

	// Number of parallel generators to setup
	pipelineSize := 1 // Was 4 FIXME but there are statistics used in parallel and not ready for concurrent access
	// Containers for pipelined operators
	chXo := make([]<-chan ga.PipelineIndividual, pipelineSize)
	chMut := make([]<-chan ga.PipelineIndividual, pipelineSize)

	// Save best individual, for elitism
	var elite ga.Individual = nil

	// Save time before starting
	//genTime := time.Now()

	// Loop until max number of generation is reached
	for g := 0; g < *numGen; g++ {
		// Compute fitness for every individual with no fitness
		fitnessEval := pop.Evaluate()
		fitnessEval = fitnessEval
		//
		//if !*quiet {
		//	fmt.Println("Generation ", g, "fit evals", fitnessEval, time.Since(genTime))
		//	genTime = time.Now()
		//}

		// Compute various statistics
		sta.Observe(pop)

		// Statistics and samples
		if g%*saveInterval == 0 {
			snapName, snapPopName := sta.SaveSnapshot(pop, *quiet, countersKeys, statsKeys, intCountersKeys)
			// Save best individual
			if false {
				pop.BestIndividual().Fitness()
				pop.BestIndividual().(*base.Individual).ImgTemp.WritePNG(snapName)
			}
			// Save best individual code

			//	pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp)
			//	settings.ImgTemp.WritePNG(snapName)
			// Save pop images
			pop.Draw(imgTempPop, pImgCols, pImgRows)
			imgTempPop.WritePNG(snapPopName)
		}

		// Setup parallel pipeline
		selectionSize := len(pop.Pop) // int(float64(len(pop.Pop))*0.3)) if you want to randomly generate new individuals
		chSel := ga.GenSelect(pop, selectionSize, float32(g)/float32(*numGen), elite)
		for i := 0; i < pipelineSize; i++ {
			chXo[i] = ga.GenCrossover(chSel, *pCross)
			chMut[i] = ga.GenMutate(chXo[i], *pMut)
		}
		var sel []ga.PipelineIndividual = ga.Collector(ga.FanIn(chMut...), selectionSize)

		// Replace old population and compute statistics
		for i := range sel {
			pop.Pop[i] = sel[i].Ind.(*base.Individual)
			sta.ObserveCrossoverFitness(sel[i].CrossoverFitness, sel[i].InitialFitness)
			sta.ObserveMutationFitness(sel[i].MutationFitness, sel[i].CrossoverFitness)
		}

		// When elitism is activated, get best individual
		if *fElite {
			elite = pop.BestIndividual()
		}

		// Build new individuals
		//base.RampedFill(pop, len(sel), len(pop.Pop))
	}
	fitnessEval := pop.Evaluate()
	fitnessEval = fitnessEval
	// Population statistics
	sta.Observe(pop)

	//if !*quiet {
	//	fmt.Println("Generation", *numGen, "fit evals", fitnessEval)
	//	fmt.Println("Best individual", pop.BestIndividual())
	//}

	snapName, snapPopName := sta.SaveSnapshot(pop, *quiet, countersKeys, statsKeys, intCountersKeys)
	// Save best individual
	if false {
		pop.BestIndividual().Fitness()
		pop.BestIndividual().(*base.Individual).ImgTemp.WritePNG(snapName)
	}
	//	pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp)
	//	settings.ImgTemp.WritePNG(snapName)
	// Save pop images
	pop.Draw(imgTempPop, pImgCols, pImgRows)
	imgTempPop.WritePNG(snapPopName)

	if !*quiet {
		fmt.Println("Best individual:")
		fmt.Println(pop.BestIndividual())
	}

	elapsedTime := time.Since(startTime)
	fmt.Println("Execution took %s", elapsedTime)

	/*
		bestName := fmt.Sprintf("%v/best/%v.png", basedir, basename)
		if !*quiet {
			fmt.Println("Saving best individual in", bestName)
			fmt.Println(pop.BestIndividual())
		}
		pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp)
		settings.ImgTemp.WritePNG(bestName)
	*/
}