Palabra clave: Mask
Las máscaras de acción restringen el conjunto de acciones que un concepto aprendido puede seleccionar, en función del estado actual. El enmascaramiento es útil en las aplicaciones en las que el conjunto de acciones válidas no siempre es el mismo. Por ejemplo, el cerebro no debe permitirse enrutar el trabajo a un equipo que está inactivo para el mantenimiento.
Las máscaras de acción se admiten para tipos de acción nominales, como type Action {cmd: number<Up=0, Down=1, Left=2, Right=3>}.
Uso
Para especificar una máscara, escriba una función mask y haga referencia a ella con la mask palabra clave dentro del plan de estudios para un concepto. Por ejemplo:
function MaskFunction(s: ObservableState) {
# The mask function takes the input to the concept graph
# and returns a dynamic constraint on the Action type for a concept.
return constraint Action <Dynamic Type Expression>
}
graph(input: ObservableState): ActionType {
concept AConcept(input): ActionType {
curriculum {
mask MaskFunction
... # other curriculum elements here
}
}
}
Funciones mask
Las funciones mask reciben la misma entrada que el cerebro, como se especifica con la graph palabra clave . La función debe devolver una restricción de tipo dinámico que limite el tipo de acción base para el concepto.
function MaskFunction(s: ObservableState) {
# Mask functions can use control flow, variables, etc.
# Here, we'll restrict the bin in which to place an object based on its size
if s.object_size < SmallSizeThreshold {
return constraint Action {bin: number<in s.available_small_bins>}
} else if s.object_size > LargeSizeThreshold {
return constraint Action {bin: number<in s.available_large_bins>}
} else {
# No constraint
return constraint Action {}
}
}
El tipo de valor devuelto de una función mask se parametriza mediante el tipo estático que se restringe: Type.DynamicType<Action>. El compilador de Inkling normalmente puede deducir el tipo necesario, por lo que no es necesario definir explícitamente el tipo.
Todas las rutas de acceso de devolución deben devolver el mismo tipo con parámetros.
Restricciones de tipo dinámico
Las expresiones de restricción dinámica comienzan con la palabra clave constraint y van seguidas de dos expresiones de tipo:
- el tipo estático (sin restricciones) y
- una restricción dinámica aplicada al primer tipo.
Una expresión de tipo dinámico usa la sintaxis de expresión de tipo existente, pero permite que algunas subexpresiones sean dinámicas en lugar de estáticas. Por ejemplo, {choice: number<in s.valid_choices>}, o {fruit: number<mask observable_state.fruit_mask>}
Hay dos tipos de restricciones dinámicas en enumeraciones nominales in y mask:
| Restricción | Descripción | Ejemplo | Detalles |
|---|---|---|---|
in |
Incluir valores especificados de la enumeración | number<in obs.allowedValues> |
Los valores que no están en la enumeración se omiten. |
mask |
Valor booleano para cada elemento de enumeración | number<mask obs.actionMask> |
El tamaño de la matriz debe coincidir con el tamaño de la enumeración. |
Sugerencia
Para aplicar ninguna restricción, use {}.
En el caso de los tipos de acción multidimensionales, las restricciones se aplican por campo. Por ejemplo, si el tipo de acción es:
type Action {
a: number<A=1,B=2,C=3>,
b: number<X=1,Y=2>
}
y la restricción es:
constraint Action {a: number<in [1,2]>, b: number<in [2]>}
las acciones válidas serán {a: 1, b: 2} y {a:2, b:2}.
Importante
La restricción Mask siempre debe dar lugar a una enumeración que no sea NULL. Si todas las opciones están enmascaradas, el cerebro devolverá un error en tiempo de ejecución.
Ejemplos
Restricción mediante mask palabra clave
type Action {cmd: number<Up=0, Down=1, Left=2, Right=3>}
type ObservableState {
x: number,
y: number,
# Booleans. If there's a wall, can't move in that direction
wallAbove: number<0,1,>,
wallBelow: number<0,1,>,
wallLeft: number<0,1,>
wallRight: number<0,1,>,
}
function MaskFunction(s: ObservableState) {
# Only move in allowed directions.
# Note: simulator (and real world) need to ensure that at least one direction is available.
# 1 means that action is allowed. Enumeration order in Action type is Up, Down, Left, Right.
return constraint Action {cmd: number<mask [not s.wallAbove, not s.wallBelow, not s.wallLeft, not s.wallRight]>}
}
Restricción mediante in
type Action {cmd: number<Up=0, Down=1, Left=2, Right=3>}
type ObservableState {
x: number,
y: number,
# Array of allowed directions, with -1 for unused entries
allowedDirections: number<0..3 step 1>[4]
}
function MaskFunction(s: ObservableState) {
# Only move in allowed directions.
# Note: simulator (and real world) need to ensure that at least one direction is available.
var UpOk = 1-wallAbove
# s.allowedDirections should be an array of valid action values or placeholders
# e.g.
# [0,1,2,3,4] -- all allowed
# [0,1, -1, -1] -- only Up (0) and Down (1) allowed
return constraint Action {cmd: number<in s.allowedDirections>}
}
Uso de variables de estado en la máscara, pero no para el aprendizaje
A veces, la información necesaria para la máscara no es relevante para el aprendizaje. Por ejemplo, considere una decisión de enrutamiento que envía trabajo a una de varias máquinas de una fábrica. Si una máquina está inactiva, no se debe enviar ningún trabajo a ella, pero no es necesario aprender a evitar máquinas fuera de servicio como un concepto explícito. En su lugar, el cerebro puede aprender a seleccionar qué máquinas serían mejores y la máscara garantizará que solo se elijan las máquinas de trabajo.
type Action {
machine: number<A=1,B=2,C=3,D=4>
}
# Mask isn't needed for learning, so leave it out
type LearningState {
# info about the job to be done by one of the machines
job_property_a: number,
job_property_b: number
# machine properties that should be used to decide which is best to use
machine_speeds: number<1..100 step 1>[4],
machine_costs: number<0..1>[4],
}
# Add the mask info to get the full state that will be passed to the brain
type ObservableState extends LearningState {
# array of 4 bools: 1 if machine is available, 0 otherwise
available_machine_mask: number<0,1,>[4],
}
graph (input: ObservableState) {
concept RemoveMask(input): LearningState {
programmed function(s: ObservableState): LearningState {
# use cast to avoid writing out all the fields one by one -- works if LearningState is a subset of ObservableState
return LearningState(s)
}
}
output concept ChooseMachine(RemoveMask): Action {
mask function(s: ObservableState) {
return constraint Action {machine: number<mask s.available_machine_mask>}
}
... # rest of curriculum definition
}
}