Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Validation support for specifying GTP commands for each binary #1459

Merged
merged 7 commits into from
Jul 16, 2018

Conversation

Hersmunch
Copy link
Member

Fixes #1455.
Also gitignore some local files and outputs.

@gcp
Copy link
Member

gcp commented May 20, 2018

@marcocalignano please review

@gcp
Copy link
Member

gcp commented May 28, 2018

Marco didn't reply?

I don't see anything wrong with this, but I have one concern: this seems to be a special case of the more generic problem of wanting to specify some GTP commands to be run at startup.

Would you be willing to rework this to just take some arbitrary startup command(s)? "time_settings blah" would then be one of them?

@Hersmunch
Copy link
Member Author

I was actually thinking about trying that anyway so that handicap games could be tested too.
Would you prefer specifying them as a string or to give a file name?
I’ll have a go at it during the week.

@marcocalignano
Copy link
Member

It is not a easy review because Game.cpp is used also by autogtp. And I was busy last week I see what I can do this week.

@gcp
Copy link
Member

gcp commented May 28, 2018

Would you prefer specifying them as a string or to give a file name?

Multiple strings I think. Asking the user to include "\n" in the command is messy. Better to allow the same command line option multiple times.

Copy link
Member

@marcocalignano marcocalignano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

autogtp seems to work with this patch

@Hersmunch
Copy link
Member Author

Thanks guys.
One more question, do we want to be able to give each side a different set of commands or is one set for both always going to be sufficient?

@marcocalignano
Copy link
Member

What do you mean by:

different set of commands

@Hersmunch
Copy link
Member Author

As in two different sets of initial gtp commands, one for each binary, as per above:

Would you be willing to rework this to just take some arbitrary startup command(s)? "time_settings blah" would then be one of them?

@marcocalignano
Copy link
Member

The problem that I see is that the Game object is shared with autogtp so you have to be careful to port the changes even in autogtp. I would a different member function that accept a string list of GTP commands. Also I would concentrate on that (Game object changes) first before you add the list in main. And yes then you should do one list for each player.
If you need help just tell me I pulled you branch so I can have a look at your commits. And if you think it is difficult I will take over no problem.

@Hersmunch
Copy link
Member Author

Got it, I appreciate the guidance.
Any thoughts on how to identify which gtp commands from the argument list are for which binary? If the gtp commands can be different then I assume there might a different amount with no obvious first command for the second binary.

@marcocalignano
Copy link
Member

Since you use parser.values the string list will be built in the order the option are found so you can have someting like:

validation -b leeaz --gtp-command "load_sgf  mysgf; set_free_handicap gc" -b leelaz_deepsearch --gtp-command "time setting 010"

@Hersmunch
Copy link
Member Author

That sounds simple but @gcp said it is messy above. Another way that does follow his preference would be to also specify the side the commands are for e.g.
validation -b leeaz --gtp-command 0 "load_sgf mysgf" --gtp_command 0 "set_free_handicap gc" -b leelaz_deepsearch --gtp-command 1 "time setting 010"
The order would be the same as they are provided.
@gcp which do you want?

@gcp
Copy link
Member

gcp commented May 30, 2018

It would become

validation -b leeaz --gtp-command "load_sgf mysgf" --gtp-command "set_free_handicap gc" -b leelaz_deepsearch --gtp-command "time setting 0 1 0"

That is, the commands refer to the last specified engine. No need to specify which one then.

To get some idea of how this can work, take a look at cutechess-cli.

@marcocalignano
Copy link
Member

@gcp Don't you like the suggestion with the ';' separator between commands? It would be easier to implement with the QT CommandLineParser.

@gcp
Copy link
Member

gcp commented May 30, 2018

The problem I see is that if a GTP command would contain a ";" this solution would break.

@marcocalignano
Copy link
Member

@gcp we can start with the separator character (a bit like sed style) so it would be:
--gtp-commnad "; loasgf my.sgf ; time settings 0 1 0" or --gtp-command "| loadsgf my.sgf | put-char ; "`
but maybe is to complicated for the user.

@killerducky
Copy link
Contributor

How about --gtp-command-file commands.txt? And put all your gtp commands in a text file.

@gcp
Copy link
Member

gcp commented May 31, 2018

we can start with the separator character

No

but maybe is to complicated for the user.

Yes

@gcp
Copy link
Member

gcp commented May 31, 2018

And put all your gtp commands in a text file.

What's wrong with the command line?

The situation I described literally already exists in cutechess-cli, which is also written in Qt IIRC. I'm not asking for rocket science here, I'm asking to replicate an existing solution that works really well :(

@Hersmunch
Copy link
Member Author

Thanks for the clarity. I'll make a start tonight.

@Hersmunch
Copy link
Member Author

Hersmunch commented May 31, 2018

I've had a look at cutechess-cli's code and instructions on running and following that will result in e.g.:
validation -b name=leeaz gtp-command="load_sgf mysgf" gtp-command="set_free_handicap gc" -b name=leelaz_deepsearch gtp-command="time setting 0 1 0" -each n="networkfile"
I'll start with this approach. Shout if you want something else though.

@Hersmunch Hersmunch changed the title Added Validation support for specifying time_settings WIP: Add Validation support for specifying GTP commands for each binary May 31, 2018
@Hersmunch
Copy link
Member Author

For this evening I have managed to change Game and Validation to be able to cope with multiple GTP commands but have left the Validations options as they were. Might get a bit more time tomorrow or sat morning.

@marcocalignano
Copy link
Member

@Hersmunch What I suggest you should define the name of the binary (leelaz) aspositional arguments and set the ParseAsPositionalArguments flag.
In this way all option after the binary name will also be consider as positional arguments so you can keep the order in the list.
Of course all the general options should be before the binary name to be parse as options in from otherwise you need to parse them twice. (which I guess we need to do anyway).

@alreadydone
Copy link
Contributor

I am trying to use validation for handicap games with a fixed binary playing black; after the existing commits I can append fixed_handicap 2 to the GTP command list by modifying the source, but black still plays the first move; I think the following changes switches the first player to white, but I am not sure if I am missing something.
https://github.com/Hersmunch/leela-zero/blob/6c4e1cc9802ede637cee392cd1dddafa42e0b5b6/validation/Validation.cpp#L48
switch play black and play white
https://github.com/Hersmunch/leela-zero/blob/6c4e1cc9802ede637cee392cd1dddafa42e0b5b6/autogtp/Game.cpp#L200
replace 0 by 1

Also, for not switching binaries between games, does commenting out the following two places suffice?
https://github.com/Hersmunch/leela-zero/blob/6c4e1cc9802ede637cee392cd1dddafa42e0b5b6/validation/Validation.cpp#L97
https://github.com/Hersmunch/leela-zero/blob/6c4e1cc9802ede637cee392cd1dddafa42e0b5b6/validation/Validation.cpp#L158

Thank you in advance for reviewing.

@alreadydone
Copy link
Contributor

Follow-up: I modified https://github.com/Hersmunch/leela-zero/blob/6c4e1cc9802ede637cee392cd1dddafa42e0b5b6/autogtp/Game.cpp#L32 also and everything seems to work.

@Hersmunch
Copy link
Member Author

@alreadydone I'll leave the support for handicap games that you mention for a separate PR.

@Hersmunch Hersmunch changed the title WIP: Add Validation support for specifying GTP commands for each binary Add Validation support for specifying GTP commands for each binary Jun 3, 2018
@marcocalignano
Copy link
Member

@Hersmunch no that is not what I meant!
TheQCommandLineOption should stay like they were before.
You only delete the binaryOption and add a positional argument for the binary files.
And you add a new option --gtp-command
After that you set the ParseAsPositionalArguments flag in the parser so everything after the first binary file will be consider a positional argument and you can get an order QStringList of that.
And please do not parse the command line with if else if.

@Hersmunch
Copy link
Member Author

Haha, whoops! Sorry about that. OK, I'll have one more go at it :)

@l1t1
Copy link

l1t1 commented Jun 7, 2018

can we learn the gogui twogtp command format,

@Hersmunch
Copy link
Member Author

Hersmunch commented Jun 7, 2018

@marcocalignano, I gave up trying to find a way for general options to be specified after a binary is specified. Hopefully this is more what you were thinking?

Usage: validation.exe [options] binary

Options:
  -?, -h, --help                    Displays this help.
  -v, --version                     Displays version information.
  -g, --gamesNum <num>              Play 'gamesNum' games on one GPU at the
                                    same time.
  -u, --gpus <num>                  Index of the GPU to use for multiple GPUs
                                    support.
  -s, --sprt <lower:upper>          Set the SPRT hypothesis (default
                                    '0.0:35.0').
  -k, --keepSgf <output directory>  Save SGF files after each self-play game.
  -n, --network <filename>          Networks to use as players in competition
                                    mode (two are needed).
  -o, --options <opt_string>        Options for the binary given by -b (default
                                    "-g -v 3200 --noponder -t 1 -q -d -r 0 -w").

  -c, --gtp-command <command>       GTP command to send to the binary on
                                    startup (default "time_settings 0 1 0").
                                    Multiple commands are sent in the order they

                                    are specified.
                                    Commands apply to the preceeding binary or
                                    both if specified before all binaries.

Arguments:
  binary                            Binary to execute for the game (default
                                    ./leelaz).
                                    Only --gtp-command options are parsed after
                                    a binary is specified

Example:
validation -n "networkfile" "leeaz" --gtp-command "load_sgf mysgf" --gtp-command "set_free_handicap gc" "leelaz_deepsearch" --gtp-command="time setting 0 1 0"

@Hersmunch
Copy link
Member Author

Hersmunch commented Jun 7, 2018

can we learn the gogui twogtp command format,

@l1t1 I had a look at https://www.mankier.com/1/gogui-twogtp but it doesn't appear to support specifying GTP commands to each side or allowing for handicap to be specified (except for maybe in an .sgf?).

@l1t1
Copy link

l1t1 commented Jun 8, 2018

@Hersmunch I found following from your link, but i haven't used them

GTP Extensions

gogui-interrupt

    Indicate interrupt ability for GoGui. TwoGtp will forward the interrupt to both programs, with the appropriate method, if they implement either gogui-interrupt or gogui-sigint. See the chapter "Interrupting Commands" in the GoGui documentation.
gogui-title

    Return a title for the current game, consisting of the game number (if option -sgffile was used) and the player names.
gogui-twogtp-black command

    Send command to the black player.
gogui-twogtp-observer command

    Send command to the observer program.
gogui-twogtp-referee command

    Send command to the referee program.
gogui-twogtp-white command

    Send command to the white player.

@marcocalignano
Copy link
Member

@Hersmunch Yes that what I was thinking, I would also specify the command line a bit better:
Usage: validation.exe [option...] [gtp-command...] [binary1] [gtp-command...] [binary2] [gtp-comand...]
Did you already wrote some of the code to parse the command line?

@Hersmunch
Copy link
Member Author

@marcocalignano I had a search around but haven't found out how to change the usage information. I agree it would be better as you describe.

Did you already wrote some of the code to parse the command line?

I'm not sure what you are asking. You can see the content of my commits, right?

@@ -23,11 +23,12 @@
#include <QFileInfo>
#include "Game.h"

Game::Game(const QString& weights, const QString& opt, const QString& binary) :
Game::Game(const QString& weights, const QString& opt, const QString& binary,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Game is used from autogtp too. So I guess this change breaks autogtp.

Copy link
Member Author

@Hersmunch Hersmunch Jun 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll double check but the new parameter is defaulted in the constructor in the Game.h

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, still works for me.

autogtp/Game.cpp Outdated
for (auto command : m_commands) {
sendGtpCommand(command);
}
QTextStream(stdout) << "Thinking time set." << endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to wait for and parse the answer of each command before you send the next.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, doesn't sendGtpCommand() already do this?
I'll add catching of a it returning false (command failing) and exit though.

QString network;
QStringList commands;
} engine_t;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make a proper Object with copy constructor, maybe even a move constructor and call it Engine. And maybe adding a member to handle the list of command.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a preference between using a struct or a class?
What do you mean by "handle the list of command"? I'm not understanding what I could add that would be helpful.

@@ -116,16 +118,35 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
}

QStringList commandList = {"time_settings 0 1 0"};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not want to add this for default, what if someone wants to change the time settings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gtp-commands given by the user are added to the end of the list so any other time_settings commands that follow will be done after this one, overwriting what this first one does. Seems to work from when I've used it.
I thought this would be easier than parsing commandList after all the user's commands had been added and looking to see if a time_settings one had been provided. It would seem cleaner to not always send this initial command though so I'd be happy to change it if anyone has ideas on a better approach.

pos_args = parser.positionalArguments();
engine_idx++;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this while loop works like we want?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my limited usage of the changes it appears to work how I expect. Have you got any particular concerns? I might have misunderstood something :)
I was surprised at first that I didn't have to remove/pop the binary from pos_args but QCommandLineParser::process() expects the string list of arguments to be from the command line and therefore ignores the first item as "Usually arguments().at(0) is the program name..." http://doc.qt.io/qt-5/qcoreapplication.html#arguments. I have only got Windows to test on though.
I could add some comment(s) if that helps?

@gcp
Copy link
Member

gcp commented Jun 26, 2018

@Hersmunch I presume you're still working on this when you find some spare time?

Andy Hersee added 5 commits June 26, 2018 20:31
Also gitignore some local files and outputs
… up but left the Validations options untouched.
…. Replaced time settings option with ability to specify any GTP commands.
…xisting option parser. Also changed default binary options from -p 1600 to -v 3200.
@Hersmunch
Copy link
Member Author

Hersmunch commented Jun 27, 2018

Yes, I intend to but just haven't had a lot of time lately.
I've got a bit more done locally that I'll tidy up and push later today or tomorrow. It'll probably need a few more commits after that though.
Edit: Actually, I'm done unless @marcocalignano has anything else for me to tidy up?

@gcp
Copy link
Member

gcp commented Jul 3, 2018

@marcocalignano OK to merge?

@marcocalignano
Copy link
Member

@gcp I didn't have time to test it but it looks fine and he tested it so go for it!

@gcp gcp merged commit 81c484e into leela-zero:next Jul 16, 2018
@gcp
Copy link
Member

gcp commented Jul 16, 2018

I had to back this out :-(

../validation/main.cpp: In function ‘int main(int, char**)’:
../validation/main.cpp:87:12: error: ‘class QCommandLineParser’ has no member named ‘setOptionsAfterPositionalArgumentsMode’; did you mean ‘clearPositionalArguments’?
     parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            clearPositionalArguments
../validation/main.cpp:87:71: error: ‘ParseAsPositionalArguments’ is not a member of ‘QCommandLineParser’
     parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~

It looks like this was changed in Qt 5.6. We require Qt 5.3 only. The default Qt in Ubuntu 16.04 is 5.5.1.

At the very least, we'll need to bump our Qt dependency to 5.6, or avoid this. Ubuntu 18.04.1 is due in about 10 days at which point 16.04 upgrades will be possible. That sounds like a reasonable time to require a newer baseline, but we'd still screw some people over with this, though.

@Hersmunch
Copy link
Member Author

:( sorry about that. Having a look at the Qt 5.2 documentation it looks like it might be possible to work around this by requiring a -- preceding each of the engines' options... is that worth trying?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants