Last active
April 22, 2020 06:26
-
-
Save nanzi/b8da07df1f8832153cc6bd401d3266d4 to your computer and use it in GitHub Desktop.
FFT analysis tool for Go AI sai's autogtp comments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// Search a sai sgf directory for comments FFT analysis | |
import ( | |
"bytes" | |
"fmt" | |
"github.com/fohristiwhirl/sgf" | |
"github.com/mjibson/go-dsp/fft" | |
"io/ioutil" | |
"math/cmplx" | |
"os" | |
"path/filepath" | |
"strconv" | |
"strings" | |
) | |
func main() { | |
if len(os.Args) < 2 { | |
fmt.Printf("Usage: %s dirname \n", filepath.Base(os.Args[0])) | |
return | |
} | |
files, err := ioutil.ReadDir(os.Args[1]) | |
if err != nil { | |
panic(err.Error()) | |
} | |
fmt.Println("0_ComposedPart(SortMe),FFTParts,Result,Black,White,Match,Black_View_In_Frequncy ") | |
var matches []string | |
for _, f := range files { | |
fullpath := filepath.Join(os.Args[1], f.Name()) | |
matchHash := f.Name() | |
matchHash6 := "[" + matchHash[:7] + "]" //protect for numbers | |
node, err := sgf.Load(fullpath) | |
if err != nil { | |
fmt.Printf("%v\n", err) | |
} | |
root := node.GetRoot() | |
pb, okRb := root.GetValue("PB") | |
if !okRb { | |
fmt.Printf("Can't find black player info in %s ! Set as \"none\" ", matchHash6) | |
pb = "none" | |
} | |
pw, okRw := root.GetValue("PW") | |
if !okRw { | |
fmt.Printf("Can't find black player info in %s ! Set as \"none\" ", matchHash6) | |
pw = "none" | |
} | |
res, okRr := root.GetValue("RE") | |
if !okRr { | |
fmt.Printf("Can't find result info in %s ! Set as \"none\" ", matchHash6) | |
res = "none" | |
} | |
comts := node.SaiComt() | |
totalMoves := len(comts) | |
// read all comments and save as float64 slice in parts | |
// https://github.com/sai-dev/sai/issues/13 | |
// | |
var aomSeries []float64 // alpkt_online_median, approximate median of alpkt over the move explored subtree | |
var alpktSeries []float64 // alpkt is more or less the points in favor of black, including komi. Raw network estimate of alpkt (more noisy) | |
var betaSeries []float64 // beta is a measure of certainty of the score. Raw network estimate of beta, if above 1 the score is almost decided | |
var piSeries []float64 // pi, raw network win-rate estimate at current komi, for black | |
var aeaSeries []float64 // agent_eval_avg, average of agent win-rate over the move explored subtree | |
var axlSeries []float64 // agent_x_lambda, size of the integration interval (useful only if lambda>0) | |
var isBSeries []float64 // isBluder, flag, useful only for self-plays, a random move may be a blunder (if it loses at least 5% win-rate probability) in that case training info is saved only after last blunder | |
for mv := 0; mv < totalMoves; mv++ { | |
comment := strings.Split(comts[mv], ", ") | |
alpkt_online_median, _ := strconv.ParseFloat(comment[0], 64) | |
alpkt, _ := strconv.ParseFloat(comment[1], 64) | |
beta, _ := strconv.ParseFloat(comment[2], 64) | |
pi, _ := strconv.ParseFloat(comment[3], 64) | |
aea, _ := strconv.ParseFloat(comment[4], 64) | |
axl, _ := strconv.ParseFloat(comment[5], 64) | |
isBluder, _ := strconv.ParseFloat(comment[6], 64) | |
aomSeries = append(aomSeries, alpkt_online_median) | |
alpktSeries = append(alpktSeries, alpkt) | |
betaSeries = append(betaSeries, beta) | |
piSeries = append(piSeries, pi) | |
aeaSeries = append(aeaSeries, aea) | |
axlSeries = append(axlSeries, axl) | |
isBSeries = append(isBSeries, isBluder) | |
//debug | |
//fmt.Print(comment) | |
} | |
aomFFT := fft.FFTReal(aomSeries) | |
alpktFFT := fft.FFTReal(alpktSeries) | |
betaFFT := fft.FFTReal(betaSeries) | |
piFFT := fft.FFTReal(piSeries) | |
aeaFFT := fft.FFTReal(aeaSeries) | |
axlFFT := fft.FFTReal(axlSeries) | |
isBFFT := fft.FFTReal(isBSeries) | |
// debug | |
//fmt.Println(alpktSeries) | |
//fmt.Println(betaSeries) | |
// Handle the fft complex array : Amplitude & Phase | |
var aomAmp, alpktAmp, betaAmp, piAmp, aeaAmp, axlAmp, isBAmp, aomPhase, alpktPhase, betaPhase, piPhase, aeaPhase, axlPhase, isBPhase []float64 | |
var fftHead = [14]string{"0aom-Amp", "1alpkt-Amp", "2beta-Amp", "3pi-Amp", "4aea-Amp", "5axl-Amp", "6isB-Amp", "0aom-Phase", "1alpkt-Phase", "2beta-Phase", "3pi-Phase", "4aea-Phase", "5axl-Phase", "6isB-Phase"} | |
var fftInfo [14][]float64 | |
for i := 0; i < totalMoves; i++ { | |
m0 := cmplx.Abs(aomFFT[i]) | |
m1 := cmplx.Abs(alpktFFT[i]) | |
m2 := cmplx.Abs(betaFFT[i]) | |
m3 := cmplx.Abs(piFFT[i]) | |
m4 := cmplx.Abs(aeaFFT[i]) | |
m5 := cmplx.Abs(axlFFT[i]) | |
m6 := cmplx.Abs(isBFFT[i]) | |
aomAmp = append(aomAmp, m0) | |
alpktAmp = append(alpktAmp, m1) | |
betaAmp = append(betaAmp, m2) | |
piAmp = append(piAmp, m3) | |
aeaAmp = append(aeaAmp, m4) | |
axlAmp = append(axlAmp, m5) | |
isBAmp = append(isBAmp, m6) | |
p0 := cmplx.Phase(aomFFT[i]) | |
p1 := cmplx.Phase(alpktFFT[i]) | |
p2 := cmplx.Phase(betaFFT[i]) | |
p3 := cmplx.Phase(piFFT[i]) | |
p4 := cmplx.Phase(aeaFFT[i]) | |
p5 := cmplx.Phase(axlFFT[i]) | |
p6 := cmplx.Phase(isBFFT[i]) | |
aomPhase = append(aomPhase, p0) | |
alpktPhase = append(alpktPhase, p1) | |
betaPhase = append(betaPhase, p2) | |
piPhase = append(piPhase, p3) | |
aeaPhase = append(aeaPhase, p4) | |
axlPhase = append(axlPhase, p5) | |
isBPhase = append(isBPhase, p6) | |
} | |
fftInfo[0] = aomAmp | |
fftInfo[1] = alpktAmp | |
fftInfo[2] = betaAmp | |
fftInfo[3] = piAmp | |
fftInfo[4] = aeaAmp | |
fftInfo[5] = axlAmp | |
fftInfo[6] = isBAmp | |
fftInfo[7] = aomPhase | |
fftInfo[8] = alpktPhase | |
fftInfo[9] = betaPhase | |
fftInfo[10] = piPhase | |
fftInfo[11] = aeaPhase | |
fftInfo[12] = axlPhase | |
fftInfo[13] = isBPhase | |
// arrange SortableHeader:winner/color/mod/phase into matches | |
var ( | |
winner string | |
loser string | |
res0 string = res[:1] | |
playerB string = pb[len(pb)-8:] | |
playerW string = pw[len(pw)-8:] | |
) | |
if res0 == "B" { | |
winner = playerB | |
loser = playerW | |
} | |
if res0 == "W" { | |
winner = playerW | |
loser = playerB | |
} | |
if res0 == "0" { | |
winner = "Jigo" + playerB | |
loser = playerW | |
} | |
for m := 0; m < 14; m++ { | |
var matchInfo bytes.Buffer | |
matchInfo.WriteString(fftHead[m]) // Amp/Phase | |
matchInfo.WriteString("-") | |
matchInfo.WriteString(winner) | |
matchInfo.WriteString("-") | |
matchInfo.WriteString(res0) | |
matchInfo.WriteString("-") | |
matchInfo.WriteString(loser) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(fftHead[m]) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(res0) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(playerB) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(playerW) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(matchHash6) | |
for _, f := range fftInfo[m] { | |
f := strconv.FormatFloat(f, 'f', 7, 64) | |
matchInfo.WriteString(",") | |
matchInfo.WriteString(f) | |
} | |
matches = append(matches, matchInfo.String()) | |
} | |
} | |
for _, m := range matches { | |
fmt.Println(m) | |
} | |
return | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SaiComt returns all Black move comments in sgf. | |
func (self *Node) SaiComt() map[int]string { | |
vals := make(map[int]string) | |
move_count := 0 | |
node := self.GetRoot() | |
node = node.MainChild() | |
// size := node.RootBoardSize() | |
for { | |
comt, ok := node.GetValue("C") // Assuming just 1, as per SGF specs. | |
if ok { | |
vals[move_count] = comt | |
} else { | |
vals[move_count] = "0" | |
} | |
move_count++ | |
node = node.MainChild() | |
if node == nil { | |
//fmt.Println("no nodes") | |
break | |
} | |
node = node.MainChild()//Jump across white move, if white comment is copied from black | |
if node == nil { | |
//fmt.Println("no nodes") | |
break | |
} | |
} | |
return vals | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment