Add uploading
This commit is contained in:
parent
b03ddadf86
commit
131607a3f9
|
@ -25,3 +25,4 @@ yarn-error.log*
|
|||
db.sqlite3
|
||||
__pycache__
|
||||
*.swp
|
||||
/uploaded_agents
|
||||
|
|
33
README.md
33
README.md
|
@ -30,16 +30,19 @@ The definitions of the fields are as follows:
|
|||
|
||||
| type | Resource | Parameters | Description |
|
||||
|------|---------------------------|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||
| GET | tournament/launch | `eval_num`, `name` | Launch tournment on the game. Each pair of models will play `eval_num` times. Results will be saved in database. |
|
||||
| GET | tournament/launch | `eval_num`, `name` | Launch tournment on the game. Each pair of models will play `eval_num` times. Results will be saved in database. |
|
||||
| GET | tournament/query\_game | `name`, `index`, `agent0`, `agent1`, `win`, `payoff` | Query the games with the given parameters |
|
||||
| GET | tournament/query\_payoff | `name`, `agent0`, `agent1`, `payoff` | Query the payoffs with the given parameters |
|
||||
| GET | tournament/replay | `name`, `agent0`, `agent1`, `index` | Return the replay data (only support Leduc Holdem for now) |
|
||||
| GET | tournament/replay | `name`, `agent0`, `agent1`, `index` | Return the replay data |
|
||||
| POST | tournament/upload\_agent | `model`(Python file), `name`, `game`, `entry` | Upload a model file. `name` is model ID, `entry` is the class name of the model |
|
||||
| GET | tournament/delete\_agent | `name` | Delete the agent of the given name |
|
||||
| GET | tournament/list\_agents | | list all the agents |
|
||||
|
||||
## Example API
|
||||
| API | Description |
|
||||
|-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||
| http://127.0.0.1:8000/tournamentlaunch?eval_num=200&name=leduc-holdem | Evaluate on Leduc Holdem with 200 games for each pair of models |
|
||||
| http://127.0.0.1:8000/tournament/replay?name=leduc-holdem&agent0=leduc-holdem-rule-v1&agent1=leduc-holdem-cfr&index=3 | Obtain the replay data between rule model and CFR model. Obtain teh data of the 3rd game |
|
||||
| http://127.0.0.1:8000/tournament/launch?eval_num=200&name=leduc-holdem | Evaluate on Leduc Holdem with 200 games for each pair of models |
|
||||
| http://127.0.0.1:8000/tournament/replay?name=leduc-holdem&agent0=leduc-holdem-rule-v1&agent1=leduc-holdem-cfr&index=3 | Obtain the replay data between rule model and CFR model. Obtain the data of the 3rd game |
|
||||
| http://127.0.0.1:8000/tournament/query_game | Get all the game data |
|
||||
| http://127.0.0.1:8000/tournament/query_game?name=leduc-holdem | Get all the game data of Leduc Holdem |
|
||||
| http://127.0.0.1:8000/tournament/query_payoff | Get all the payoffs |
|
||||
|
@ -55,6 +58,28 @@ Some models have been pre-registered as baselines
|
|||
| doudizhu-random | doudizhu | A random model |
|
||||
| doudizhu-rule-v1 | doudizhu | Dou Dizhu rule model |
|
||||
|
||||
## Example of uploading a new model
|
||||
A example model file is prepared:
|
||||
```
|
||||
cd server/upload_test
|
||||
```
|
||||
Upload the model with `curl`:
|
||||
```
|
||||
curl -F 'model=@example_model.py' -F "name=leduc-new" -F "entry=LeducHoldemRuleModelV2" -F "game=leduc-holdem" http://127.0.0.1:8000/tournament/upload_agent
|
||||
```
|
||||
Launch the tounament with:
|
||||
```
|
||||
curl 'http://127.0.0.1:8000/tournament/launch?eval_num=200&name=leduc-holdem'
|
||||
```
|
||||
We list the uploaded agent with
|
||||
```
|
||||
curl http://127.0.0.1:8000/tournament/list_agents
|
||||
```
|
||||
We can delete the agent with
|
||||
```
|
||||
curl 'http://127.0.0.1:8000/tournament/delete_agent?name=leduc-new'
|
||||
```
|
||||
|
||||
|
||||
# Others
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
''' Leduc Hold 'em rule model
|
||||
'''
|
||||
import rlcard
|
||||
from rlcard.models.model import Model
|
||||
|
||||
class LeducHoldemRuleAgentV2(object):
|
||||
''' Leduc Hold 'em Rule agent version 2
|
||||
'''
|
||||
def __init__(self):
|
||||
self.use_raw = True
|
||||
|
||||
def step(self, state):
|
||||
''' Predict the action when given raw state. A simple rule-based AI.
|
||||
Args:
|
||||
state (dict): Raw state from the game
|
||||
|
||||
Returns:
|
||||
action (str): Predicted action
|
||||
'''
|
||||
legal_actions = state['raw_legal_actions']
|
||||
state = state['raw_obs']
|
||||
hand = state['hand']
|
||||
public_card = state['public_card']
|
||||
action = 'fold'
|
||||
'''
|
||||
When having only 2 hand cards at the game start, choose fold to drop terrible cards:
|
||||
Acceptable hand cards:
|
||||
Pairs
|
||||
AK, AQ, AJ, AT
|
||||
A9s, A8s, ... A2s(s means flush)
|
||||
KQ, KJ, QJ, JT
|
||||
Fold all hand types except those mentioned above to save money
|
||||
'''
|
||||
if public_card:
|
||||
if public_card[1] == hand[1]:
|
||||
action = 'raise'
|
||||
else:
|
||||
action = 'fold'
|
||||
else:
|
||||
if hand[0] == 'K':
|
||||
action = 'raise'
|
||||
elif hand[0] == 'Q':
|
||||
action = 'check'
|
||||
else:
|
||||
action = 'fold'
|
||||
|
||||
#return action
|
||||
if action in legal_actions:
|
||||
return action
|
||||
else:
|
||||
if action == 'raise':
|
||||
return 'call'
|
||||
if action == 'check':
|
||||
return 'fold'
|
||||
if action == 'call':
|
||||
return 'raise'
|
||||
else:
|
||||
return action
|
||||
|
||||
def eval_step(self, state):
|
||||
return self.step(state), []
|
||||
|
||||
class LeducHoldemRuleModelV2(Model):
|
||||
''' Leduc holdem Rule Model version 2
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
''' Load pretrained model
|
||||
'''
|
||||
env = rlcard.make('leduc-holdem')
|
||||
rule_agent = LeducHoldemRuleAgentV2()
|
||||
self.rule_agents = [rule_agent for _ in range(env.player_num)]
|
||||
|
||||
@property
|
||||
def agents(self):
|
||||
''' Get a list of agents for each position in a the game
|
||||
|
||||
Returns:
|
||||
agents (list): A list of agents
|
||||
|
||||
Note: Each agent should be just like RL agent with step and eval_step
|
||||
functioning well.
|
||||
'''
|
||||
return self.rule_agents
|
|
@ -119,3 +119,5 @@ USE_TZ = True
|
|||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 2.2.12 on 2020-05-11 05:03
|
||||
# Generated by Django 2.2.12 on 2020-05-13 02:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
@ -34,4 +34,14 @@ class Migration(migrations.Migration):
|
|||
('payoff', models.FloatField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UploadedAgent',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('game', models.CharField(max_length=100)),
|
||||
('entry', models.CharField(max_length=100)),
|
||||
('f', models.FileField(upload_to='uploaded_agents')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
class Game(models.Model):
|
||||
# The name of the game
|
||||
|
@ -35,3 +36,16 @@ class Payoff(models.Model):
|
|||
# The average payoff of the first agent
|
||||
payoff = models.FloatField()
|
||||
|
||||
class UploadedAgent(models.Model):
|
||||
# The name of the agent
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
# The game of the agent
|
||||
game = models.CharField(max_length=100)
|
||||
|
||||
# The class name of the Model
|
||||
entry = models.CharField(max_length=100)
|
||||
|
||||
# File
|
||||
f = models.FileField(upload_to='uploaded_agents')
|
||||
|
||||
|
|
|
@ -22,3 +22,5 @@ MODEL_IDS['doudizhu'] = [
|
|||
'doudizhu-rule-v1',
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,4 +7,7 @@ urlpatterns = [
|
|||
path('launch', views.launch, name='launch'),
|
||||
path('query_payoff', views.query_payoff, name='query_payoff'),
|
||||
path('query_game', views.query_game, name='query_game'),
|
||||
path('upload_agent', views.upload_agent, name='upload_agent'),
|
||||
path('delete_agent', views.delete_agent, name='delete_agent'),
|
||||
path('list_agents', views.list_agents, name='list_agents'),
|
||||
]
|
||||
|
|
|
@ -1,13 +1,46 @@
|
|||
import json
|
||||
import os
|
||||
import importlib.util
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from django.db import transaction
|
||||
from django.core import serializers
|
||||
|
||||
from .models import Game, Payoff
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.dispatch import receiver
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from .rlcard_wrap import rlcard, MODEL_IDS
|
||||
from .models import Game, Payoff, UploadedAgent
|
||||
|
||||
from .tournament import Tournament
|
||||
|
||||
def reset_model_ids():
|
||||
from .rlcard_wrap import rlcard, MODEL_IDS
|
||||
agents = UploadedAgent.objects.all()
|
||||
for agent in agents:
|
||||
path = os.path.join(settings.MEDIA_ROOT, agent.f.name)
|
||||
name = agent.name
|
||||
game = agent.game
|
||||
entry = agent.entry
|
||||
module_name = path.split('/')[-1].split('.')[0]
|
||||
spec = importlib.util.spec_from_file_location(module_name, path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
M = getattr(module, entry)
|
||||
|
||||
class ModelSpec(object):
|
||||
def __init__(self):
|
||||
self.model_id = name
|
||||
self._entry_point = M
|
||||
|
||||
def load(self):
|
||||
model = self._entry_point()
|
||||
return model
|
||||
rlcard.models.registration.model_registry.model_specs[name] = ModelSpec()
|
||||
MODEL_IDS[game].append(name)
|
||||
|
||||
def replay(request):
|
||||
if request.method == 'GET':
|
||||
name = request.GET['name']
|
||||
|
@ -56,5 +89,41 @@ def launch(request):
|
|||
agent1=payoff_data['agent1'],
|
||||
payoff=payoff_data['payoff'])
|
||||
p.save()
|
||||
return HttpResponse(1)
|
||||
return HttpResponse(json.dumps({'value': 0, 'info': 'success'}))
|
||||
|
||||
@csrf_exempt
|
||||
def upload_agent(request):
|
||||
if request.method == 'POST':
|
||||
f = request.FILES['model']
|
||||
name = request.POST['name']
|
||||
game = request.POST['game']
|
||||
entry = request.POST['entry']
|
||||
if UploadedAgent.objects.filter(name=name).exists():
|
||||
return HttpResponse(json.dumps({'value': -1, 'info': 'name exists'}))
|
||||
|
||||
a = UploadedAgent(name=name, game=game, f=f, entry=entry)
|
||||
a.save()
|
||||
reset_model_ids()
|
||||
return HttpResponse(json.dumps({'value': 0, 'info': 'success'}))
|
||||
|
||||
def delete_agent(request):
|
||||
if request.method == 'GET':
|
||||
name = request.GET['name']
|
||||
if not UploadedAgent.objects.filter(name=name).exists():
|
||||
return HttpResponse(json.dumps({'value': -1, 'info': 'name not exists'}))
|
||||
|
||||
UploadedAgent.objects.filter(name=name).delete()
|
||||
reset_model_ids()
|
||||
return HttpResponse(json.dumps({'value': 0, 'info': 'success'}))
|
||||
|
||||
def list_agents(request):
|
||||
if request.method == 'GET':
|
||||
agents = UploadedAgent.objects.all()
|
||||
result = serializers.serialize('json', agents)
|
||||
return HttpResponse(result)
|
||||
|
||||
@receiver(models.signals.post_delete, sender=UploadedAgent)
|
||||
def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
if instance.f:
|
||||
if os.path.isfile(instance.f.path):
|
||||
os.remove(instance.f.path)
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
''' Leduc Hold 'em rule model
|
||||
'''
|
||||
import rlcard
|
||||
from rlcard.models.model import Model
|
||||
|
||||
class LeducHoldemRuleAgentV2(object):
|
||||
''' Leduc Hold 'em Rule agent version 2
|
||||
'''
|
||||
def __init__(self):
|
||||
self.use_raw = True
|
||||
|
||||
def step(self, state):
|
||||
''' Predict the action when given raw state. A simple rule-based AI.
|
||||
Args:
|
||||
state (dict): Raw state from the game
|
||||
|
||||
Returns:
|
||||
action (str): Predicted action
|
||||
'''
|
||||
legal_actions = state['raw_legal_actions']
|
||||
state = state['raw_obs']
|
||||
hand = state['hand']
|
||||
public_card = state['public_card']
|
||||
action = 'fold'
|
||||
'''
|
||||
When having only 2 hand cards at the game start, choose fold to drop terrible cards:
|
||||
Acceptable hand cards:
|
||||
Pairs
|
||||
AK, AQ, AJ, AT
|
||||
A9s, A8s, ... A2s(s means flush)
|
||||
KQ, KJ, QJ, JT
|
||||
Fold all hand types except those mentioned above to save money
|
||||
'''
|
||||
if public_card:
|
||||
if public_card[1] == hand[1]:
|
||||
action = 'raise'
|
||||
else:
|
||||
action = 'fold'
|
||||
else:
|
||||
if hand[0] == 'K':
|
||||
action = 'raise'
|
||||
elif hand[0] == 'Q':
|
||||
action = 'check'
|
||||
else:
|
||||
action = 'fold'
|
||||
|
||||
#return action
|
||||
if action in legal_actions:
|
||||
return action
|
||||
else:
|
||||
if action == 'raise':
|
||||
return 'call'
|
||||
if action == 'check':
|
||||
return 'fold'
|
||||
if action == 'call':
|
||||
return 'raise'
|
||||
else:
|
||||
return action
|
||||
|
||||
def eval_step(self, state):
|
||||
return self.step(state), []
|
||||
|
||||
class LeducHoldemRuleModelV2(Model):
|
||||
''' Leduc holdem Rule Model version 2
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
''' Load pretrained model
|
||||
'''
|
||||
env = rlcard.make('leduc-holdem')
|
||||
rule_agent = LeducHoldemRuleAgentV2()
|
||||
self.rule_agents = [rule_agent for _ in range(env.player_num)]
|
||||
|
||||
@property
|
||||
def agents(self):
|
||||
''' Get a list of agents for each position in a the game
|
||||
|
||||
Returns:
|
||||
agents (list): A list of agents
|
||||
|
||||
Note: Each agent should be just like RL agent with step and eval_step
|
||||
functioning well.
|
||||
'''
|
||||
return self.rule_agents
|
Loading…
Reference in New Issue