Février 2016

Volume 31, numéro 2

Cet article a fait l'objet d'une traduction automatique.

Microsoft Azure - Azure Service Fabric, Q-Learning et Morpion (Tic-Tac-Toe)

Par Jesus Aguilar

Innovations en matière de cloud computing réduisent les barrières à l'entrée pour l'informatique distribuée et des applications à partir de technologies spécialisées nécessitant une infrastructure spécialisé et cher à un produit offre disponible pour n'importe quel développeur ou une solution architecte d'apprentissage. Dans cet article, je décrirai l'implémentation d'un renforcement de formation technique qui tire parti des capacités de calcul et de stockage distribuées d'Azure Service Fabric, l'itération suivante de l'offre Azure Platform-as-a-Service. Pour illustrer le potentiel de cette approche, je montrerai comment vous pouvez vous servir de l'infrastructure de Service et son modèle de programmation acteurs fiables pour créer un serveur principal intelligent capable de prédire la prochaine déplacer dans un jeu de morpion. Jeux de guerre, tout le monde ?

Entrez Q-formation

Aujourd'hui, nous allons voir des solutions innovantes piloté par les données telles que des recommandations, sont confrontés à la reconnaissance et détection des fraudes partout. Équipes d'ingénierie logicielle permet de mettre en œuvre ces solutions techniques d'apprentissage supervisé et non supervisé. Malgré les fonctions complètes de ces approches, il existe les cas où elles sont difficiles à appliquer.

Apprentissage de renforcement est une méthode qui gère les scénarios que vous pouvez représenter comme une séquence d'états et transitions. Contrairement aux autres d'apprentissage approches, apprentissage de renforcement ne tente pas de généraliser des modèles à l'apprentissage d'un modèle à partir des informations étiquetées (supervisé) ou à partir des données sans étiquette (apprentissage). Au lieu de cela, il se concentre sur les problèmes que vous pouvez modéliser comme une séquence d'états et transitions.

Prenons un scénario, que vous pouvez représenter comme une séquence d'États qui mènent à l'état final (appelée l'absorption état). Considérez un robot pour prendre des décisions afin d'éviter des obstacles ou intelligence artificielle (IA) dans un jeu conçu pour battre un adversaire. Dans de nombreux cas, la séquence des États qui mènent à une situation particulière est l'élément qui détermine l'étape suivante meilleures pour le caractère de l'agent/robot/AI.

Q-learning est un renforcement de formation technique qui utilise un mécanisme de récompense itérative pour trouver les voies de transition optimales dans un modèle de machine d'état ; il fonctionne particulièrement bien lorsque le nombre d'états et les transitions est fixes. Dans cet article, je vais présenter comment j'ai utilisé le Service Fabric pour créer une solution de Q-learning de bout en bout et montrent comment vous pouvez créer un serveur principal intelligent qui « détecte » comment lire morpion. (Notez que les scénarios de machine d'état sont également appelés processus de décision de Markov [fournisseurs MDP]).

Tout d'abord, certaines base théorie sur Q-learning. Tenez compte des États et transitions mentionnées dans les Figure 1. Imaginons que vous voulez rechercher, à tous les États, quel est l'état un agent doit passer à la suivante pour arriver à l'état gold, tout en réduisant le nombre de transitions. Permet de résoudre ce problème consiste à attribuer une valeur de récompense à chaque état. La récompense suggère la valeur de la transition vers un état pour atteindre votre objectif : mise en route de l'or.

Une séquence d'états, ce qui conduit à l'état de l'or
Séquence figure 1 des États conduisant à l'état de l'or

C'est simple, non ? Le défi devient comment identifier la récompense pour chaque état. L'algorithme d'apprentissage-Q identifie les récompenses par itération et l'affectation des récompenses aux États qui entraînent l'absorption état (gold) de manière récursive. L'algorithme calcule les primes d'un état dans l'actualisation de la valeur de récompense à partir d'un état suivant. Si un état comporte deux récompenses, ce qui est possible si un état existe dans plusieurs parcours — prévaut le plus élevé. La remise a une incidence importante sur le système. Dans l'actualisation de la récompense, l'algorithme réduit la valeur de la prime pour les États qui sont loin d'être or et affecte un poids plus à l'état le plus proche de l'or.

Par exemple comment algorithme calcule la récompense, examinez le diagramme d'état dans Figure 1. Comme vous pouvez le voir, il existe trois voies à or :

1 -> 5 -> 4 -> G

1 -> 5 -> 3 -> 4 -> G

1 -> 5 -> 3 -> 2 -> 4 -> G

Après avoir exécuté l'algorithme en utilisant des attaques en force transition (itération dans tous les chemins d'accès possibles dans le graphique), l'algorithme calcule et affecte les récompenses pour les voies valides. Récompenses sont calculées par le facteur de réduction de 0,9.

1(R=72) -> 5(R=81) -> 4(R=90) -> G (R = 100)

1(R=64) -> 5(R=72) -> 3(R=81) -> 4(R=90) -> G(R=100)

1(R=58) -> 5(R=64) -> 3(R=72) -> 2(R=81) -> 4(R=90) -> G(R=100)

Étant donné que certains États ont plusieurs récompense, la valeur la plus élevée est prioritaires. Figure 2 illustre l'affectation de récompense finale.

Récompenses finales
Figure 2 les récompenses finale

Avec ces informations, un agent peut identifier le chemin d'accès optimal à or dans n'importe quel état lors du passage à l'état avec la récompense la plus élevée. Par exemple, si l'agent est en état 5, il a le choix de la transition à 3 ou 4, les États et 4 devient le choix car la récompense est plus élevée.

Azure Service Fabric

Service Fabric, l'itération suivante de l'offre Azure Platform-as-a-Service, permet aux développeurs de créer des applications distribuées à l'aide de deux modèles de programmation niveau supérieur différents : Acteurs fiables et Services fiables. Ces modèles de programmation permettent d'optimiser les ressources d'infrastructure d'une plate-forme distribuée. La plate-forme gère les tâches les plus difficiles associés à la maintenance et l'exécution d'une application distribuée, la récupération des défaillances, la distribution des services pour garantir l'utilisation efficace des ressources, déploiement des mises à jour et le versioning côte à côte, de mentionner quelques exemples.

Service Fabric vous fournit un cluster, ce qui vous donne un niveau supérieur d'abstraction à utiliser, plutôt que d'avoir à vous soucier de l'infrastructure sous-jacente. Votre code s'exécute sur les nœuds d'un cluster Service Fabric, et vous pouvez héberger des clusters à plusieurs nœuds sur un seul ordinateur à des fins de développement ou sur plusieurs serveurs (ordinateurs virtuels ou physiques) pour les charges de production. La plateforme gère le cycle de vie de vos intervenants et les Services et la récupération des défaillances de l'infrastructure.

Service Fabric introduit des acteurs fiables et Services avec la sémantique avec état. Cette fonctionnalité se traduit par une expérience de développement entièrement intégré dans lequel vous pouvez développer des applications qui conservent les données de manière distribuée et par conséquent hautement disponible sans avoir à inclure une couche de stockage externe (par exemple, prendre des dépendances sur un stockage externe ou couche de mise en cache) dans votre architecture.

En implémentant l'algorithme d'apprentissage de Q en tant que service dans Service Fabric, vous pouvez tirer parti de l'utilisation de capacités de stockage état informatique et à faible latence, distribuées vous permettant d'exécuter l'algorithme, conserver les résultats et exposer l'intégralité comme fiable des points de terminaison pour les clients à accéder. Toutes ces fonctionnalités sont réunies dans une solution unique avec une programmation unifiée et de la pile de gestion. Il est inutile d'ajouter des composants supplémentaires dans votre architecture, tel qu'un stockage externe, le cache ou le système de messagerie. En bref, vous avez une solution dans laquelle votre calcul, les données et les services se trouvent dans la même plate-forme intégrée. C'est une solution élégante dans mon livre !

Acteurs fiables et de Q-formation

Le modèle d'acteur simplifie la conception d'applications simultanées massivement. Dans le modèle d'acteur, les acteurs sont l'unité fondamentale de calcul. Un acteur représente une limite de fonctionnalité et d'état. Vous pouvez considérer un acteur en tant qu'objet entité vivant dans un système distribué. Service Fabric gère le cycle de vie de l'acteur. En cas de défaillance, Service Fabric ré-permet d'instancier l'acteur dans un nœud intègre automatiquement. Par exemple, si un acteur avec état tombe en panne pour une raison quelconque ou sur le nœud (pensez à machine virtuelle), il est en cours d'exécution sur échoue, l'acteur est automatiquement recréé sur un autre ordinateur avec l'intégralité de son état (données) intact.

Service Fabric gère également l'accès à une instance d'un acteur. La plate-forme garantit que, à tout moment, qu'une seule méthode sur un acteur particulier s'exécute à la fois. S'il existe deux appels simultanés pour le même acteur, Service Fabric est une file d'attente et laissez les autres passez. La conséquence est qu'à l'intérieur d'un acteur votre code ne contient pas à vous soucier de la synchronisation, des verrous ou des conditions de concurrence.

Comme décrit précédemment, l'algorithme d'apprentissage-Q effectue une itération dans les États dans le but de trouver l'absorption des États et des États avec des récompenses. Une fois que l'algorithme identifie un état absorption avec une récompense, il calcule les récompenses pour tous les États qui entraînent l'absorption état.

À l'aide du modèle d'acteur, je peux modèle cette fonctionnalité en tant qu'acteur qui représente un état dans le contexte de l'algorithme d'apprentissage-Q (pensez à des étapes dans le graphique global). Dans mon implémentation, le type d'acteur qui représente ces États est QState. Lorsqu'une transition vers un acteur QState contenant une récompense, l'acteur QState créera une autre instance d'acteur d'un type différent (QTrainedState) pour chacun des acteurs QState dans le chemin d'accès. Les acteurs QTrainedState conservent la valeur maximale de récompense et une liste des états suivants qui génèrent la récompense. La liste contient les jetons d'état (qui identifie de façon unique un état dans le graphique) des états suivants.

Dans Figure 3, j'ai décrit la logique de l'algorithme à l'aide des acteurs, pour un scénario très simple où un état avec le jeton de l'état 3 est dans un état absorption contient une prime de 100 et a qu'un seul chemin d'accès avec deux États précédents (jeton état 1 et 2). Chaque cercle représente une instance d'un acteur, QStates en bleu et QTrainedStates en orange. Une fois le processus de transition atteint le QState avec jeton état 3, l'acteur QState créera deux QTrainedStates, de la QStates précédente. Pour l'acteur QTrainedState qui représente le jeton de l'état 2, la transition suggérée (pour une récompense de 90) est à l'état 3 de jeton et de l'acteur QTrainedState qui représente le jeton de l'état 1, la transition suggérée (pour une récompense de 81) est à l'état du jeton 2.

Détermination et la persistance des récompenses
Figure 3 Détermination et la persistance de récompenser

Il est possible que plusieurs États génère la même prime, donc l'acteur QTrainedState persiste une collection de jetons de l'état en tant qu'états enfants.

Le code suivant illustre l'implémentation des interfaces pour les acteurs QState et QTrainedState, appelée IQState et IQTrainedState. QStates ont deux comportements : transition vers d'autres QStates et le démarrage de la transition traitement lorsqu'aucune transition précédente n'existe :

public interface IQState : IActor
{
  Task StartTrainingAsync(int initialTransitionValue);
  Task TransitionAsync(int? previousStateToken, int transitionValue);
}
public interface IQTrainedState:IActor
{
 .Task AddChildQTrainedStateAsync(int stateToken, double reward);
 .Task<List<int>> GetChildrenQTrainedStatesAsync();
}

Notez que l'implémentation de IQTrainedState expose la méthode GetChildrenQTrainedStatesAsync. Cette méthode est l'acteur QTrainedState expose comment les données d'apprentissage contenant les États avec la valeur la plus élevée de la récompense des États dans le système. (Notez que tous les acteurs dans l'infrastructure de Service doivent implémenter une interface dérivée de IActor).

QState acteur

Après avoir défini les interfaces, je peux pour l'implémentation des acteurs. Je vais commencer par l'acteur QState et la méthode TransitionAsync, qui est la pierre angulaire de l'algorithme et où réside l'essentiel du travail. TransitionAsync effectue la transition vers un autre état en créant une nouvelle instance d'un acteur QState et en appelant de nouveau la même méthode.

Vous vous demandez peut-être si vous vous éviterez la surcharge d'un appel de la méthode par une autre instance d'acteur en appelant la méthode de manière récursive. Un appel de méthode récursive est une opération de calcul intensif dans un nœud unique. En revanche, en instanciant un autre acteur, vous prenez des advantange des fonctionnalités de Service Fabric en laissant la plateforme de répartir le traitement sur les ressources informatiques horizontales.

Pour gérer l'attribution de la récompense, je vais enregistrer un rappel. Les rappels sont nouvelles constructions qui vous permettent de planifier le travail asynchrone sans bloquer l'exécution d'une méthode introduites dans le modèle de programmation d'acteur.

Les rappels sont uniquement disponibles pour les acteurs avec état. Pour les acteurs avec et sans état, la plate-forme fournit des minuteries qui permettent à un modèle similaire. Il est important que lorsque l'acteur est utilisé, le processus de nettoyage est retardé ; Néanmoins, la plate-forme ne considère pas les rappels timer en tant qu'activité. Si le garbage collector entre en action, les minuteurs seront arrêtés. Les acteurs ne sont pas le garbage collecté lorsqu'une méthode est exécutée. Pour garantir l'exécution périodique, utiliser les rappels. Vous trouverez plus d'informations sur bit.ly/1RmzKfr.

L'objectif, par rapport à l'algorithme, consiste à effectuer l'affectation de récompense sans bloquer le processus de transition. En règle générale, la planification d'un élément de travail dans le pool de threads à un rappel est suffisante ; Toutefois, dans le modèle de programmation d'acteur, cette approche n'est pas une bonne idée que vous allez perdre les avantages de concurrence de la plateforme.

La plate-forme garantit qu'une seule méthode est exécutée à tout moment. Cette fonctionnalité vous permet d'écrire votre code sans tenir compte d'accès concurrentiel ; Autrement dit, sans avoir à vous soucier de sécurité des threads. Évidemment, il existe un compromis : Vous devez éviter de créer des tâches ou threads pour encapsuler des opérations dans les méthodes d'acteur. Les rappels permettent de mettre en œuvre des scénarios de traitement en arrière-plan avec les garanties d'accès concurrentiel de la plate-forme, comme indiqué dans Figure 4.

TransitionAsync figure 4 dans la classe QState

public abstract class QState : StatefulActor, IQState, IRemindable
{
  // ...
  public Task TransitionAsync(int? previousStateToken, int transitionValue)
  {
    var rwd = GetReward(previousStateToken, transitionValue);
    var stateToken = transitionValue;
    if (previousStateToken != null)
        stateToken = int.Parse(previousStateToken.Value + stateToken.ToString());
    var ts = new List<Task>();
    if (rwd == null || !rwd.IsAbsorbent)
      ts.AddRange(GetTransitions(stateToken).Select(p =>
        ActorProxy.Create<IQState>(ActorId.NewId(),
        "fabric:/QLearningServiceFab").TransitionAsync(stateToken, p)));
    if (rwd != null)
      ts.Add(RegisterReminderAsync("SetReward",
        Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(rwd))
        , TimeSpan.FromMilliseconds(0)
        , TimeSpan.FromMilliseconds(-1), ActorReminderAttributes.Readonly));
      return Task.WhenAll(ts);
  }
  // ...
}

(Notez que dueTime à TimeSpan.FromMilliseconds(0)) indique une exécution immédiate).

Pour terminer l'implémentation de IQState, le code suivant implémente la méthode StartTransitionAsync, où j'utilise un rappel pour éviter un blocage appel longue :

public Task StartTrainingAsync(int initialTransitionValue)
  {
    return RegisterReminderAsync("StartTransition",
      Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { TransitionValue =
      initialTransitionValue })), TimeSpan.FromMilliseconds(0),
      TimeSpan.FromMilliseconds(-1),
      ActorReminderAttributes.Readonly);
  }

Pour finaliser l'implémentation de la classe QState, je vais décrire l'implémentation de la SetRewardAsync et les méthodes ReceiveReminderAsync, illustrés Figure 5. La méthode SetReward crée ou met à jour un acteur avec état (l'implémentation de IQTrainedState). Pour localiser l'acteur dans les appels suivants, j'utilise le jeton de l'état en tant que l'id d'acteur : acteurs sont adressables.

Figure 5 méthodes ReceiveReminderAsync et le SetRewardAsync

public Task SetRewardAsync(int stateToken, double stateReward, double discount)
  {
    var t = new List<Task>();
    var reward = stateReward;
    foreach (var pastState in GetRewardingQStates(stateToken))
    {
      t.Add(ActorProxy
        .Create<IQTrainedState>(new ActorId(pastState.StateToken),
          "fabric:/QLearningServiceFab")
        .AddChildQTrainedStateAsync(pastState.NextStateToken, reward));
      reward = reward * discount;
    }
    return Task.WhenAll(t);
  }
public async Task ReceiveReminderAsync(string reminderName,
  byte[] context, TimeSpan dueTime, TimeSpan period)
  {
    await UnregisterReminderAsync(GetReminder(reminderName));
    var state = JsonConvert.DeserializeObject<JObject>(
      Encoding.UTF8.GetString(context));
    if (reminderName == "SetReward")
    {
      await SetRewardAsync(state["StateToken"].ToObject<int>(),
        state["Value"].ToObject<double>(),
        state["Discount"].ToObject<double>());
    }
    if (reminderName == "StartTransition")
    {
      await TransitionAsync(null, state["TransitionValue"].ToObject<int>());
    }
  }

QTrainedState acteur

Le deuxième intervenant dans la solution est QTrainedState. Les données de QTrainedState acteur doivent être fiables, donc j'ai implémenté cet acteur comme un acteur avec état.

Dans Service Fabric, vous implémentez un acteur avec état en dérivant de votre classe StatefulActor ou les classes de base StatefulActor < T > et qui implémente une interface dérivée de IActor. T est le type de l'instance d'état, qui doit être sérialisable et un type de référence. Lorsque vous appelez une méthode d'une classe dérivée de StatefulActor < T >, la plateforme charge de l'état du fournisseur d'état et une fois l'appel terminé, la plate-forme enregistre automatiquement. Dans le cas de la QTrainedState, j'ai modélisé l'état (données durables) à l'aide de la classe suivante :

[DataContract]
public class QTrainedStateState
{
  [DataMember]
  public double MaximumReward { get; set; }
  [DataMember]
  public HashSet<int> ChildrenQTrainedStates { get; set; }
}

Figure 6 présente l'implémentation complète de la classe QTrainedState, qui implémente les deux méthodes de l'interface IQTrainedState.

Figure 6 la classe QTrainedState

public class QTrainedState : StatefulActor<QTrainedStateState>, IQTrainedState
{
  protected async override Task OnActivateAsync()
  {
    this.State =
      await ActorService.StateProvider.LoadStateAsync<QTrainedStateState>(
      Id, "qts") ??
      new QTrainedStateState() { ChildrenQTrainedStates = new HashSet<int>() };
    await base.OnActivateAsync();
  }
  protected async override Task OnDeactivateAsync()
  {
    await ActorService.StateProvider.SaveStateAsync(Id, "qts", State);
    await base.OnDeactivateAsync();
  }
  [Readonly]
  public  Task AddChildQTrainedStateAsync(int stateToken, double reward)
  {
    if (reward < State.MaximumReward)
    {
      return Task.FromResult(true);
    }
    if (Math.Abs(reward - State.MaximumReward) < 0.10)
    {
      State.ChildrenQTrainedStates.Add(stateToken);
      return Task.FromResult(true);
    }
      State.MaximumReward = reward;
      State.ChildrenQTrainedStates.Clear();
      State.ChildrenQTrainedStates.Add(stateToken);
      return Task.FromResult(true);
  }
  [Readonly]
  public Task<List<int>> GetChildrenQTrainedStatesAsync()
  {
    return Task.FromResult(State.ChildrenQTrainedStates.ToList());
  }
}

En exposant les acteurs

À ce stade, la solution a tous les éléments nécessaires pour démarrer le processus d'apprentissage et rendre persistantes les données. Mais je n'ai pas encore traité de manière dont les clients interagissent avec ces acteurs. À un niveau élevé, cette interaction se compose de démarrage du processus d'apprentissage et d'interrogation des données persistantes. Chacun de ces interactions corrélation parfaitement avec une opération d'API et une implémentation RESTful facilite l'intégration avec les clients.

Outre les deux modèles de programmation, Service Fabric est une orchestration complète et une plate-forme de gestion des processus. L'échec de la récupération et gestion des ressources qui existent pour les acteurs et les services est également disponible pour les autres processus. Par exemple, vous pouvez exécuter des processus de Node.js ou ASP.NET 5, gérés par le Service Fabric, ils bénéficient de ces fonctionnalités sans effort supplémentaire. Je peux simplement utiliser une application API ASP.NET 5 Web standard et créer un contrôleur d'API qui expose les fonctionnalités de l'acteur pertinentes, comme indiqué dans Figure 7.

Figure 7 le contrôleur d'API

[Route("api/[controller]")]
public class QTrainerController : Controller
{
  [HttpGet()]
  [Route("[action]/{startTrans:int}")]
  public  async Task<IActionResult>  Start(int startTrans)
  {
    var actor = ActorProxy.Create<IQState>(ActorId.NewId(),
      "fabric:/QLearningServiceFab/");
    await actor.StartTrainingAsync(startTrans);
    return Ok(startTrans); 
  }
  [HttpGet()]
  [Route("[action]/{stateToken}")]
  public async Task<int> NextValue(int stateToken)
  {
    var actor = ActorProxy.Create<IQTrainedState>(new ActorId(stateToken),
      "fabric:/QLearningServiceFab");
    var qs = await actor.GetChildrenQTrainedStatesAsync();
    return qs.Count == 0 ? 0 : qs[new Random().Next(0, qs.Count)];
  }
}

Et morpion ?

Reste est maintenant faire utiliser la solution avec un scénario concret. Pour ce faire, je vais utiliser un jeu simple : morpion.

L'objectif est de former un ensemble de QTrainedStates que vous pouvez interroger pour prédire le déplacement suivant dans un jeu de morpion. Une façon d'envisager cela est que l'ordinateur est agissant en tant que les deux lecteurs et les résultats de formation.

Pour revenir à l'implémentation, notez que QState est une classe abstraite. L'idée consiste à encapsuler les aspects de l'algorithme de base et la logique du scénario spécifique dans une classe dérivée. Un scénario définit trois parties de l'algorithme : comment la transition entre les États produit (stratégie) ; les États sont absorption et ont une récompense initiale ; et les États de l'algorithme affecte une récompense avec une remise. Pour chacune de ces parties, la classe QState possède une méthode dans laquelle vous pouvez implémenter ces sémantiques pour résoudre un scénario spécifique. Ces méthodes sont GetTransitions, GetReward et GetRewardingQStates.

Par conséquent, la question devient : Comment vous modéliser un jeu de morpion comme une séquence d'états et transitions ?

Considérez le jeu illustré Figure 8, où chaque cellule a un numéro affecté. Vous pouvez considérer chaque tour comme une transition d'un état à un autre dans lequel la valeur de la transition est la cellule où le lecteur effectue une lecture. Chaque jeton état devient une combinaison de l'activer précédentes (cellules) et la valeur de la transition. Par exemple, dans Figure 8, une transition à partir de 1 à 14, puis à 142 et ainsi de suite, modélise les étapes du jeu dans lequel le joueur lu la première activer wins. Et, dans ce cas, tous les États qui mènent à 14273 (l'état gagnante et absorption) doivent être affectées une récompense : 1 et 142.

Le scénario du morpion
Figure 8 le scénario morpion

Pour revenir à Q-formation, ce que je dois fournir tous les États sont les finales (absorption), chacun avec une récompense initiale. De morpion, trois types d'états produira une récompense : un avantage, un lien ou un bloc (qui fait référence à un point lorsque votre adversaire va gagner, donc vous êtes obligé d'utiliser votre tour bloquer lui). Un avantage et égalité sont absorption, ce qui signifie que la partie se termine ; un bloc n'est pas le cas, toutefois, et la partie se poursuit. Figure 9 illustre l'implémentation de la méthode GetReward pour le jeu de morpion.

Figure 9 la méthode GetReward

internal override IReward GetReward(int? previousStateToken, int transitionValue)
{
  var game = new TicTacToeGame(previousStateToken,transitionValue);
  IReward rwd = null;
  if (game.IsBlock)
  {
    rwd = new TicTacToeReward() { Discount = .5, Value = 95, IsAbsorbent = false,
      StateToken = game.StateToken};
  }
  if (game.IsWin)
  {
    rwd = new TicTacToeReward() { Discount = .9, Value = 100, IsAbsorbent = true,
      StateToken = game.StateToken };
  }
  if (game.IsTie)
  {
    rwd = new TicTacToeReward() { Discount = .9, Value = 50, IsAbsorbent = true,
      StateToken = game.StateToken };
  }
  return rwd;
}

Ensuite, une fois qu'un état est identifié avec une récompense, je dois fournir à l'algorithme avec les États qui ont conduit à l'état avec une récompense initiale donc une récompense à prix réduit peut être affectée. Pour les scénarios Windows ou un bloc, ces États sont tous les États précédents (lecture) du lecteur gagnant ou de blocage. Pour les liens, tous les États (lecture) des deux joueurs doivent être attribuées à une récompense :

internal override IEnumerable<IPastState> GetRewardingQStates(int stateToken)
{
  var game = new TicTacToeGame(stateToken);
  if (game.IsTie)           
    return game.GetAllStateSequence();           
  return game.GetLastPlayersStateSequence();
}

Enfin, je dois implémenter une stratégie de transition qui détermine la façon dont l'algorithme effectue une itération via les États. Pour le jeu, je vais implémenter une stratégie de transition dans laquelle toutes les combinaisons possibles sont abordées :

internal override IEnumerable<int> GetTransitions(int stateToken)
{
  var game = new TicTacToeGame(stateToken);
  return game.GetPossiblePlays();
}

Lecture sur l'ordinateur

À ce stade, je peux publier la solution et commencer à la formation en appelant l'API REST et en fournissant les transitions initiales : 1 à 9.

Une fois la formation terminée, vous pouvez utiliser l'API pour créer une application qui peut simplement passer un jeton d'état et recevoir la valeur suggérée. Le code source pour cet article contient une application de plateforme Windows universelle qui utilise ce serveur principal. Figure 10 illustre le jeu.

Un jeu de morpion
Figure 10 les jeu du morpion

Synthèse

À l'aide de Q-learning et le Service Fabric, j'ai pu créer une infrastructure de bout en bout qui s'appuie sur une plateforme distribuée pour calculer et conserver les données. Pour illustrer cette approche, j'ai utilisé le jeu du morpion pour créer un serveur principal qui vous apprend à jouer et ce à un niveau acceptable en indiquant quand un avantage, un lien ou un bloc se produit uniquement et en permettant à l'ordinateur d'apprendre le jeu.


Jesus Aguilarest architecte de cloud senior chez Microsoft dans l'équipe de promotion technique et de développement dans lequel il collabore avec des entreprises awesome sont nés dans le cloud et leur permet de créer des expériences incroyables à grande échelle. Il est passionné par l'ingénierie logicielle et la conception de la solution, et vous interceptera son attention à l'aide de termes tels que « Analyse prédictive, » « Évolutivité », « Concurrence », « Design Patterns » et « < choisir n'importe quelle lettre > aaS. » Vous pouvez le suivre sur Twitter : @giventocode et consulter son blog à l'adresse giventocode.com.

Remercie les experts techniques Microsoft suivants pour avoir relu cet article : Rob Bagby, Mike Lanzetta et Matthew Snider
Rob est un responsable Architecte de cloud de Microsoft. Dans ce rôle, Rob fonctionne avec influence les éditeurs de logiciels, les aider à implémenter leurs logiciels dans Azure. Avant de ce rôle, Rob a travaillé comme un consultant à développer faiblement couplés, gérables et évolutives des systèmes.

Mike Lanzetta est développeur dans l'équipe de catalyseur de partenaire de Microsoft, mettant l'accent sur l'apprentissage automatique, les données volumineuses et les systèmes de programmation. Il a une MS dans l'extension côté client de l'Université de Washington et a été dans l'industrie pour plus de 20 ans à des sociétés allant de démarrages à Amazon et Microsoft.

Matt Snider rejoint Microsoft en 2008, travaille sur une petite partie de .NET. Après la livraison de .NET 4, il a rejoint l'équipe de Service Fabric le premier PM technique, travaille sur tous les domaines de fonctionnalités différentes et a été avec l'équipe depuis. Ces jours principalement travaille sur le Gestionnaire de ressources de Cluster (Orchestrator), les Collections fiables et les parties de basculement/réplication de la pile. Lorsque vous ne travaillez pas dans les systèmes distribués, il aime bière, randonnée et la musique.