Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions Client/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

## Basic configuration of the Client. These timeouts can be changed at will

CLIENT_VERSION = 42 # Client version to send to the Server
CLIENT_VERSION = 43 # Client version to send to the Server
TIMEOUT_HTTP = 30 # Timeout in seconds for HTTP requests
TIMEOUT_ERROR = 10 # Timeout in seconds when any errors are thrown
TIMEOUT_WORKLOAD = 30 # Timeout in seconds between workload requests
Expand Down Expand Up @@ -331,32 +331,37 @@ def report_results(config, batches):
'crashes' : 0, # " disconnect" or "connection stalls"
'timelosses' : 0, # " loses on time "
'illegals' : 0, # " illegal move "

'spsa_delta' : '', # JSON dump of the delta vector for SPSA, otherwise empty
}

for batch in batches:
payload['trinomial' ] = [x+y for x,y in zip(payload['trinomial' ], batch['trinomial' ])]
payload['pentanomial'] = [x+y for x,y in zip(payload['pentanomial'], batch['pentanomial'])]
payload['crashes' ] += batch['crashes' ]
payload['timelosses' ] += batch['timelosses']
payload['illegals' ] += batch['illegals' ]

# Collapse into a JSON friendly format for Django
payload['trinomial' ] = ' '.join(map(str, payload['trinomial' ]))
payload['pentanomial'] = ' '.join(map(str, payload['pentanomial']))

payload['trinomial' ] = [x+y for x,y in zip(payload['trinomial' ], batch['trinomial' ])]
payload['pentanomial'] = [x+y for x,y in zip(payload['pentanomial'], batch['pentanomial'])]
if config.workload['test']['type'] == 'SPSA':

payload['crashes' ] += batch['crashes' ]
payload['timelosses'] += batch['timelosses']
payload['illegals' ] += batch['illegals' ]
# Server expects a delta vector, already ordered by Parameter index
ordered_parameters = sorted(config.workload['spsa'].items(), key=lambda kv: kv[1]['index'])
ordered_delta = [0] * len(ordered_parameters)

if config.workload['test']['type'] == 'SPSA':
for batch in batches:

# Pairs can be added one at a time, or in bulk
result = batch['trinomial'][2] - batch['trinomial'][0]

# For each param compute the update step for the Server
for name, param in config.workload['spsa'].items():
for index, (name, param) in enumerate(ordered_parameters):
delta = param['r'] * param['c'] * result * param['flip'][batch['runner_idx']]
payload['spsa_%s' % (name)] = payload.get('spsa_%s' % (name), 0.0) + delta

# Collapse into a JSON friendly format for Django
payload['trinomial' ] = ' '.join(map(str, payload['trinomial' ]))
payload['pentanomial'] = ' '.join(map(str, payload['pentanomial']))
ordered_delta[index] = ordered_delta[index] + delta

print (payload)
payload['spsa_delta'] = json.dumps(ordered_delta)

return ServerReporter.report(config, 'clientSubmitResults', payload)

Expand Down
2 changes: 1 addition & 1 deletion Config/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"client_version" : 42,
"client_version" : 43,
"client_repo_url" : "https://github.com/AndyGrant/OpenBench",
"client_repo_ref" : "master",

Expand Down
47 changes: 47 additions & 0 deletions OpenBench/migrations/0002_spsarun_spsaparameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 4.2.1 on 2025-06-10 23:37

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='SPSARun',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('reporting_type', models.CharField(choices=[('BULK', 'BULK'), ('BATCHED', 'BATCHED')], max_length=16)),
('distribution_type', models.CharField(choices=[('SINGLE', 'SINGLE'), ('MULTIPLE', 'MULTIPLE')], max_length=16)),
('alpha', models.FloatField()),
('gamma', models.FloatField()),
('iterations', models.IntegerField()),
('pairs_per', models.IntegerField()),
('a_ratio', models.FloatField()),
('a_value', models.FloatField()),
('tune', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='spsa_run', to='OpenBench.test')),
],
),
migrations.CreateModel(
name='SPSAParameter',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64)),
('value', models.FloatField()),
('is_float', models.BooleanField()),
('start', models.FloatField()),
('min_value', models.FloatField()),
('max_value', models.FloatField()),
('c_end', models.FloatField()),
('r_end', models.FloatField()),
('c_value', models.FloatField()),
('a_end', models.FloatField()),
('a_value', models.FloatField()),
('spsa_run', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='OpenBench.spsarun')),
],
),
]
19 changes: 19 additions & 0 deletions OpenBench/migrations/0003_alter_spsaparameter_spsa_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2025-06-10 23:48

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0002_spsarun_spsaparameter'),
]

operations = [
migrations.AlterField(
model_name='spsaparameter',
name='spsa_run',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='OpenBench.spsarun'),
),
]
19 changes: 19 additions & 0 deletions OpenBench/migrations/0004_spsaparameter_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2025-06-11 00:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0003_alter_spsaparameter_spsa_run'),
]

operations = [
migrations.AddField(
model_name='spsaparameter',
name='index',
field=models.IntegerField(default=0),
preserve_default=False,
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.1 on 2026-01-26 05:13

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0004_spsaparameter_index'),
]

operations = [
migrations.RemoveField(
model_name='spsaparameter',
name='a_end',
),
migrations.RemoveField(
model_name='spsarun',
name='a_value',
),
]
62 changes: 62 additions & 0 deletions OpenBench/migrations/0006_auto_20260126_0648.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 4.2.1 on 2026-01-26 06:48

from django.db import migrations

def forwards(apps, schema_editor):

Test = apps.get_model('OpenBench', 'Test')
SPSARun = apps.get_model('OpenBench', 'SPSARun')
SPSAParameter = apps.get_model('OpenBench', 'SPSAParameter')

for test in Test.objects.filter(test_mode='SPSA'):

if not test.spsa:
continue

try:
test.spsa_run
continue
except SPSARun.DoesNotExist:
pass # Need to create the SPSARun

spsa_run = SPSARun.objects.create(
tune = test,
reporting_type = test.spsa.get('reporting_type', 'BATCHED'),
distribution_type = test.spsa.get('distribution_type', 'SINGLE'),
alpha = test.spsa.get('Alpha'),
gamma = test.spsa.get('Gamma'),
iterations = test.spsa.get('iterations'),
pairs_per = test.spsa.get('pairs_per'),
a_ratio = test.spsa.get('A_ratio'),
)

for name, param in test.spsa.get('parameters', {}).items():
SPSAParameter.objects.create(
spsa_run = spsa_run,
name = name,
index = param.get('index'),
value = param.get('value'),
is_float = param.get('float'),
start = param.get('start'),
min_value = param.get('min'),
max_value = param.get('max'),
c_end = param.get('c_end'),
r_end = param.get('r_end'),
c_value = param.get('c'),
a_value = param.get('a'),
)


def backwards(apps, schema_editor):
SPSARun = apps.get_model('OpenBench', 'SPSARun')
SPSARun.objects.all().delete()

class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0005_remove_spsaparameter_a_end_remove_spsarun_a_value'),
]

operations = [
migrations.RunPython(forwards, backwards),
]
17 changes: 17 additions & 0 deletions OpenBench/migrations/0007_remove_test_spsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.1 on 2026-01-26 07:08

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('OpenBench', '0006_auto_20260126_0648'),
]

operations = [
migrations.RemoveField(
model_name='test',
name='spsa',
),
]
39 changes: 38 additions & 1 deletion OpenBench/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ class ScaleMethod(TextChoices):
currentllr = FloatField(default=0.0) # SPRT
upperllr = FloatField(default=0.0) # SPRT
max_games = IntegerField(default=0) # GAMES or DATAGEN
spsa = JSONField(default=dict, blank=True, null=True) # SPSA
genfens_args = CharField(max_length=256, default='', blank=True) # DATAGEN
play_reverses = BooleanField(default=False) # DATAGEN

Expand Down Expand Up @@ -234,3 +233,41 @@ def __str__(self):

def filename(self):
return '%s.%s.%s.pgn.bz2' % (self.test_id, self.result_id, self.book_index)

class SPSARun(Model):

class SPSAReportingType(TextChoices):
BULK = 'BULK' , 'BULK'
BATCHED = 'BATCHED', 'BATCHED'

class SPSADistributionType(TextChoices):
SINGLE = 'SINGLE' , 'SINGLE'
MULTIPLE = 'MULTIPLE', 'MULTIPLE'

tune = OneToOneField(Test, on_delete=CASCADE, related_name='spsa_run', null=True, blank=True)

reporting_type = CharField(max_length=16, choices=SPSAReportingType.choices)
distribution_type = CharField(max_length=16, choices=SPSADistributionType.choices)

alpha = FloatField() # Constants
gamma = FloatField()
iterations = IntegerField()
pairs_per = IntegerField()
a_ratio = FloatField()

class SPSAParameter(Model):

spsa_run = ForeignKey(SPSARun, on_delete=CASCADE, related_name='parameters')
name = CharField(max_length=64)
index = IntegerField()
value = FloatField() # Only field that changes

is_float = BooleanField() # Constants
start = FloatField()
min_value = FloatField()
max_value = FloatField()
c_end = FloatField()
r_end = FloatField()

c_value = FloatField() # Constants pre-computed for speed
a_value = FloatField()
Loading