您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
112 行
4.4 KiB
112 行
4.4 KiB
import os
|
|
import json
|
|
import math
|
|
|
|
from .exception import CurriculumError
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger('mlagents.trainers')
|
|
|
|
|
|
class Curriculum(object):
|
|
def __init__(self, location, default_reset_parameters):
|
|
"""
|
|
Initializes a Curriculum object.
|
|
:param location: Path to JSON defining curriculum.
|
|
:param default_reset_parameters: Set of reset parameters for
|
|
environment.
|
|
"""
|
|
self.max_lesson_num = 0
|
|
self.measure = None
|
|
self._lesson_num = 0
|
|
# The name of the brain should be the basename of the file without the
|
|
# extension.
|
|
self._brain_name = os.path.basename(location).split('.')[0]
|
|
|
|
try:
|
|
with open(location) as data_file:
|
|
self.data = json.load(data_file)
|
|
except IOError:
|
|
raise CurriculumError(
|
|
'The file {0} could not be found.'.format(location))
|
|
except UnicodeDecodeError:
|
|
raise CurriculumError('There was an error decoding {}'
|
|
.format(location))
|
|
self.smoothing_value = 0
|
|
for key in ['parameters', 'measure', 'thresholds',
|
|
'min_lesson_length', 'signal_smoothing']:
|
|
if key not in self.data:
|
|
raise CurriculumError("{0} does not contain a "
|
|
"{1} field."
|
|
.format(location, key))
|
|
self.smoothing_value = 0
|
|
self.measure = self.data['measure']
|
|
self.min_lesson_length = self.data['min_lesson_length']
|
|
self.max_lesson_num = len(self.data['thresholds'])
|
|
|
|
parameters = self.data['parameters']
|
|
for key in parameters:
|
|
if key not in default_reset_parameters:
|
|
raise CurriculumError(
|
|
'The parameter {0} in Curriculum {1} is not present in '
|
|
'the Environment'.format(key, location))
|
|
if len(parameters[key]) != self.max_lesson_num + 1:
|
|
raise CurriculumError(
|
|
'The parameter {0} in Curriculum {1} must have {2} values '
|
|
'but {3} were found'.format(key, location,
|
|
self.max_lesson_num + 1,
|
|
len(parameters[key])))
|
|
|
|
@property
|
|
def lesson_num(self):
|
|
return self._lesson_num
|
|
|
|
@lesson_num.setter
|
|
def lesson_num(self, lesson_num):
|
|
self._lesson_num = max(0, min(lesson_num, self.max_lesson_num))
|
|
|
|
def increment_lesson(self, measure_val):
|
|
"""
|
|
Increments the lesson number depending on the progress given.
|
|
:param measure_val: Measure of progress (either reward or percentage
|
|
steps completed).
|
|
:return Whether the lesson was incremented.
|
|
"""
|
|
if not self.data or not measure_val or math.isnan(measure_val):
|
|
return False
|
|
if self.data['signal_smoothing']:
|
|
measure_val = self.smoothing_value * 0.25 + 0.75 * measure_val
|
|
self.smoothing_value = measure_val
|
|
if self.lesson_num < self.max_lesson_num:
|
|
if measure_val > self.data['thresholds'][self.lesson_num]:
|
|
self.lesson_num += 1
|
|
config = {}
|
|
parameters = self.data['parameters']
|
|
for key in parameters:
|
|
config[key] = parameters[key][self.lesson_num]
|
|
logger.info('{0} lesson changed. Now in lesson {1}: {2}'
|
|
.format(self._brain_name,
|
|
self.lesson_num,
|
|
', '.join([str(x) + ' -> ' + str(config[x])
|
|
for x in config])))
|
|
return True
|
|
return False
|
|
|
|
def get_config(self, lesson=None):
|
|
"""
|
|
Returns reset parameters which correspond to the lesson.
|
|
:param lesson: The lesson you want to get the config of. If None, the
|
|
current lesson is returned.
|
|
:return: The configuration of the reset parameters.
|
|
"""
|
|
if not self.data:
|
|
return {}
|
|
if lesson is None:
|
|
lesson = self.lesson_num
|
|
lesson = max(0, min(lesson, self.max_lesson_num))
|
|
config = {}
|
|
parameters = self.data['parameters']
|
|
for key in parameters:
|
|
config[key] = parameters[key][lesson]
|
|
return config
|