{"id":3680,"date":"2026-06-26T17:11:39","date_gmt":"2026-06-26T16:11:39","guid":{"rendered":"https:\/\/www.macerobotics.com\/?p=3680"},"modified":"2026-06-26T17:16:23","modified_gmt":"2026-06-26T16:16:23","slug":"reseau-de-neurones-artificiel","status":"publish","type":"post","link":"http:\/\/www.macerobotics.com\/?p=3680","title":{"rendered":"R\u00e9seau de neurones artificiel"},"content":{"rendered":"<h2>Pr\u00e9sentation<\/h2>\n<p>Dans cet article nous allons apprendre au robot MR25 \u00e0 \u00e9viter les obstacles en utilisant un r\u00e9seau de neurones. Nous allons coder un r\u00e9seau \u00e0 2 couches, une seule couche (le perceptron) suffit quand le probl\u00e8me est <em>lin\u00e9airement s\u00e9parable<\/em>, c\u2019est-\u00e0-dire qu\u2019on peut tracer une ligne droite entre les cas \u00ab\u00a0oui\u00a0\u00bb et les cas \u00ab\u00a0non\u00a0\u00bb.<\/p>\n<p>\u00c9viter un obstacle unique devant soi, c\u2019est ce cas. Simple, rapide, mais tr\u00e8s limit\u00e9. Deux couches de neurones permet de r\u00e9soudre des probl\u00e8mes avec des fronti\u00e8res courbes ou des zones multiples. C\u2019est exactement notre cas : il faut distinguer 4 situations (libre, gauche, droite, obstacle) qui ne sont pas s\u00e9parables par une seule ligne dans l\u2019espace des 5 capteurs.<\/p>\n<p>La couche 1 construit des \u00ab\u00a0concepts interm\u00e9diaires\u00a0\u00bb (obstacle gauche, obstacle devant, obstacle droite), et la couche 2 combine ces concepts pour d\u00e9cider (action).<\/p>\n<p>Voici le r\u00e9seau de neurone utiliser avec le robot MR25 :<\/p>\n<p><a href=\"https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-4033\" src=\"https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216.png\" sizes=\"auto, (max-width: 966px) 100vw, 966px\" srcset=\"https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216.png 966w, https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216-300x175.png 300w, https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216-768x447.png 768w, https:\/\/fr.macerobotics.com\/wp-content\/uploads\/sites\/4\/2026\/06\/Capture-decran-2026-06-24-104216-600x349.png 600w\" alt=\"\" width=\"966\" height=\"562\" \/><\/a><\/p>\n<h2>Le Programme<\/h2>\n<p data-start=\"0\" data-end=\"173\">Ce programme impl\u00e9mente un petit r\u00e9seau de neurones \u00e0 deux couches (<strong>apprentissage supervis\u00e9<\/strong> ) qui apprend \u00e0 piloter un robot MR25 \u00e0 partir de ses 5 capteurs de proximit\u00e9. Il comporte deux phases :<\/p>\n<ol data-start=\"175\" data-end=\"375\">\n<li data-section-id=\"fd7l4f\" data-start=\"175\" data-end=\"266\"><strong data-start=\"178\" data-end=\"205\">Phase d\u2019apprentissage\u00a0<\/strong> : le r\u00e9seau apprend \u00e0 associer des situations \u00e0 des actions.<\/li>\n<li data-section-id=\"iqisee\" data-start=\"267\" data-end=\"375\"><strong data-start=\"270\" data-end=\"305\">Phase de pilotage en temps r\u00e9el\u00a0<\/strong> : le robot utilise le r\u00e9seau entra\u00een\u00e9 pour d\u00e9cider de ses mouvements.<\/li>\n<\/ol>\n<p>Les 5 capteurs sont regroup\u00e9s en 3 zones :<\/p>\n<ul>\n<li>Neurone gauche : il mesure l\u2019\u00e9tat de la zone gauche.<\/li>\n<li>Neurone devant : il repr\u00e9sente l\u2019\u00e9tat de la zone centrale.<\/li>\n<li>Neurone droit : il repr\u00e9sente l\u2019\u00e9tat de la zone droite.<\/li>\n<\/ul>\n<p>Le r\u00e9seau apprend gr\u00e2ce \u00e0 la r\u00e9tropropagation du gradient, puis pilote le robot en temps r\u00e9el en transformant les mesures des capteurs en actions de navigation et d\u2019\u00e9vitement d\u2019obstacles. La r\u00e9tropropagation du gradient (<em data-start=\"37\" data-end=\"54\">backpropagation<\/em> en anglais) est l\u2019algorithme qui permet \u00e0 un r\u00e9seau de neurones d\u2019apprendre de ses erreur, on commence par corriger la couche de sortie, puis on remonte vers la couche 1.<\/p>\n<p data-start=\"152\" data-end=\"171\"><em>L\u2019id\u00e9e est simple :<\/em><\/p>\n<ol data-start=\"173\" data-end=\"423\">\n<li data-section-id=\"ocl0ft\" data-start=\"173\" data-end=\"206\"><em>Le r\u00e9seau fait une pr\u00e9diction.<\/em><\/li>\n<li data-section-id=\"1f4nvj8\" data-start=\"207\" data-end=\"260\"><em>On compare cette pr\u00e9diction \u00e0 la r\u00e9ponse attendue.<\/em><\/li>\n<li data-section-id=\"mnombm\" data-start=\"261\" data-end=\"283\"><em>On mesure l\u2019erreur.<\/em><\/li>\n<li data-section-id=\"z32o2s\" data-start=\"284\" data-end=\"353\"><em>On remonte cette erreur de la sortie vers les couches pr\u00e9c\u00e9dentes.<\/em><\/li>\n<li data-section-id=\"1j1p9dd\" data-start=\"354\" data-end=\"423\"><em>On modifie les poids pour r\u00e9duire l\u2019erreur lors du prochain essai.<\/em><\/li>\n<\/ol>\n<p>Le gradient indique dans quelle direction modifier les poids pour diminuer l\u2019erreur le plus rapidement. Le gradient indique la pente. Le r\u00e9seau suit la pente descendante pour atteindre le minimum d\u2019erreur.<\/p>\n<div class=\"code-embed-wrapper\"> <pre class=\"language-python code-embed-pre line-numbers\"  data-start=\"1\" data-line-offset=\"0\"><code class=\"language-python code-embed-code\">#!\/usr\/bin\/python3<br\/>import MR25<br\/>import time<br\/>import math<br\/><br\/># =============================================================================<br\/># MR25 \u2014 R\u00e9seau de neurones \u00e0 deux couches<br\/># =============================================================================<br\/>#<br\/>#  Couche 1 : 3 neurones de perception (5 entr\u00e9es \u2192 3 sorties continues)<br\/>#<br\/>#    Neurone 1 (gauche)  : capteurs 1 et 2<br\/>#    Neurone 2 (devant)  : capteurs 2, 3 et 4<br\/>#    Neurone 3 (droite)  : capteurs 4 et 5<br\/>#<br\/>#  Couche 2 : 4 neurones de d\u00e9cision (3 entr\u00e9es \u2192 4 sorties)<br\/>#<br\/>#    Sortie 0 : AVANCE<br\/>#    Sortie 1 : TOURNE GAUCHE<br\/>#    Sortie 2 : TOURNE DROITE<br\/>#    Sortie 3 : STOP<br\/>#<br\/># =============================================================================<br\/><br\/># -----------------------------<br\/># Fonctions d&#039;activation<br\/># -----------------------------<br\/><br\/>def sigmoid(x):<br\/>    &quot;&quot;&quot;<br\/>    Fonction sigmo\u00efde \u2014 sortie continue dans ]0, 1[.<br\/>    Utilis\u00e9e dans la couche 1 pour produire un &#039;niveau d&#039;obstacle&#039; graduel.<br\/>    &quot;&quot;&quot;<br\/>    return 1.0 \/ (1.0 + math.exp(-x))<br\/><br\/>def softmax(vec):<br\/>    &quot;&quot;&quot;<br\/>    Softmax \u2014 transforme un vecteur en distribution de probabilit\u00e9s.<br\/>    Utilis\u00e9e dans la couche 2 : la somme des 4 sorties vaut 1.<br\/>    L&#039;action choisie est celle dont la probabilit\u00e9 est la plus haute.<br\/>    &quot;&quot;&quot;<br\/>    e = [math.exp(v) for v in vec]<br\/>    s = sum(e)<br\/>    return [v \/ s for v in e]<br\/><br\/># -----------------------------<br\/># Architecture du r\u00e9seau<br\/># -----------------------------<br\/>#<br\/># Couche 1 \u2014 poids W1[neurone][capteur] et biais B1[neurone]<br\/>#<br\/># Chaque neurone de perception combine les capteurs de son c\u00f4t\u00e9.<br\/># Valeurs initiales : chaque capteur p\u00e8se pareil, biais nul.<br\/>#<br\/>#  neurone 0 (gauche) \u2192 capteurs x1, x2<br\/>#  neurone 1 (devant) \u2192 capteurs x2, x3, x4  (x2 et x4 = flancs proches centre)<br\/>#  neurone 2 (droite) \u2192 capteurs x4, x5<br\/><br\/>W1 = [<br\/>    # x1    x2    x3    x4    x5<br\/>    [0.5,  0.5,  0.0,  0.0,  0.0],   # neurone 0 : gauche<br\/>    [0.0,  0.33, 0.33, 0.33, 0.0],   # neurone 1 : devant<br\/>    [0.0,  0.0,  0.0,  0.5,  0.5],   # neurone 2 : droite<br\/>]<br\/>B1 = [0.0, 0.0, 0.0]<br\/><br\/># Couche 2 \u2014 poids W2[action][neurone] et biais B2[action]<br\/>#<br\/>#  action 0 (AVANCE)         \u2192 r\u00e9compenser l&#039;ABSENCE d&#039;obstacle<br\/>#  action 1 (TOURNE GAUCHE)  \u2192 obstacle \u00e0 droite, pas \u00e0 gauche<br\/>#  action 2 (TOURNE DROITE)  \u2192 obstacle \u00e0 gauche, pas \u00e0 droite<br\/>#  action 3 (STOP)           \u2192 obstacle des deux c\u00f4t\u00e9s<br\/><br\/>W2 = [<br\/>    # n_gauche  n_devant  n_droite<br\/>    [-0.5,     -1.0,     -0.5],   # AVANCE       : mauvais score si obstacle<br\/>    [ 0.0,     -0.5,      1.0],   # TOURNE GAUCHE: obstacle \u00e0 droite<br\/>    [ 1.0,     -0.5,      0.0],   # TOURNE DROITE: obstacle \u00e0 gauche<br\/>    [ 0.5,      1.0,      0.5],   # STOP         : obstacles partout<br\/>]<br\/>B2 = [0.0, 0.0, 0.0, 0.0]<br\/><br\/># Taux d&#039;apprentissage<br\/>eta = 0.1<br\/><br\/># -----------------------------<br\/># Jeu d&#039;entra\u00eenement<br\/># -----------------------------<br\/>#<br\/># Entr\u00e9es : [x1, x2, x3, x4, x5] normalis\u00e9es dans [0, 1]<br\/>#   0 = obstacle tr\u00e8s proche   1 = voie libre<br\/>#<br\/># Cibles : indice de l&#039;action correcte<br\/>#   0 = AVANCE   1 = TOURNE GAUCHE   2 = TOURNE DROITE   3 = STOP<br\/>#<br\/># R\u00e9partition des capteurs sur le MR25 (vue de dessus) :<br\/>#<br\/>#        [1]  [2]  [3]  [4]  [5]<br\/>#         \\    |   (avant)   |    \/<br\/>#          gauche         droite<br\/><br\/>training_data = [<br\/>    # Voie compl\u00e8tement libre \u2192 AVANCE<br\/>    ([1.0, 1.0, 1.0, 1.0, 1.0], 0),<br\/><br\/>    # Obstacle devant uniquement \u2192 STOP (pas d&#039;info sur quel c\u00f4t\u00e9 \u00e9viter)<br\/>    ([0.9, 0.9, 0.1, 0.9, 0.9], 3),<br\/><br\/>    # Obstacle \u00e0 gauche (capteurs 1-2 faibles) \u2192 TOURNE DROITE<br\/>    ([0.1, 0.2, 0.8, 0.9, 0.9], 2),<br\/>    ([0.2, 0.1, 1.0, 1.0, 1.0], 2),<br\/><br\/>    # Obstacle \u00e0 droite (capteurs 4-5 faibles) \u2192 TOURNE GAUCHE<br\/>    ([0.9, 0.9, 0.8, 0.2, 0.1], 1),<br\/>    ([1.0, 1.0, 1.0, 0.1, 0.2], 1),<br\/><br\/>    # Obstacle sur toute la largeur \u2192 STOP<br\/>    ([0.1, 0.1, 0.1, 0.1, 0.1], 3),<br\/>    ([0.2, 0.3, 0.2, 0.3, 0.2], 3),<br\/><br\/>    # Obstacle l\u00e9ger devant-gauche, droite libre \u2192 TOURNE DROITE<br\/>    ([0.3, 0.4, 0.4, 0.8, 0.9], 2),<br\/><br\/>    # Obstacle l\u00e9ger devant-droite, gauche libre \u2192 TOURNE GAUCHE<br\/>    ([0.9, 0.8, 0.4, 0.4, 0.3], 1),<br\/>]<br\/><br\/># Noms des actions (pour les affichages)<br\/>ACTIONS = [&quot;AVANCE&quot;, &quot;TOURNE GAUCHE&quot;, &quot;TOURNE DROITE&quot;, &quot;STOP&quot;]<br\/><br\/># -----------------------------<br\/># Propagation avant (forward pass)<br\/># -----------------------------<br\/><br\/>def forward(inputs):<br\/>    &quot;&quot;&quot;<br\/>    Calcule la sortie compl\u00e8te du r\u00e9seau pour un vecteur d&#039;entr\u00e9es.<br\/><br\/>    Retourne :<br\/>      h      \u2014 sorties de la couche 1 (3 valeurs sigmo\u00efdes)<br\/>      probs  \u2014 distribution softmax de la couche 2 (4 probabilit\u00e9s)<br\/>      action \u2014 indice de l&#039;action ayant la probabilit\u00e9 la plus haute<br\/>    &quot;&quot;&quot;<br\/>    # --- Couche 1 : neurones de perception ---<br\/>    h = []<br\/>    for n in range(3):<br\/>        z = sum(W1[n][i] * inputs[i] for i in range(5)) + B1[n]<br\/>        h.append(sigmoid(z))<br\/><br\/>    # --- Couche 2 : neurones de d\u00e9cision ---<br\/>    logits = []<br\/>    for a in range(4):<br\/>        z = sum(W2[a][n] * h[n] for n in range(3)) + B2[a]<br\/>        logits.append(z)<br\/><br\/>    probs  = softmax(logits)<br\/>    action = probs.index(max(probs))<br\/>    return h, probs, action<br\/><br\/># -----------------------------<br\/># Mise \u00e0 jour des poids (r\u00e9tropropagation simplifi\u00e9e)<br\/># -----------------------------<br\/>#<br\/># On utilise une r\u00e8gle delta adapt\u00e9e au softmax + entropie crois\u00e9e :<br\/>#   delta_couche2[a] = probs[a] - (1 si a == cible, sinon 0)<br\/>#<br\/># Pour la couche 1, on r\u00e9tropropage le gradient \u00e0 travers la sigmo\u00efde :<br\/>#   delta_couche1[n] = sigmoid&#039;(h[n]) * somme_a(W2[a][n] * delta_c2[a])<br\/>#   avec sigmoid&#039;(h) = h * (1 - h)<br\/><br\/>def train_step(inputs, target, h, probs):<br\/>    &quot;&quot;&quot;<br\/>    Effectue une mise \u00e0 jour des poids W1, B1, W2, B2<br\/>    \u00e0 partir d&#039;un exemple (inputs, target).<br\/>    &quot;&quot;&quot;<br\/>    # --- Gradient couche 2 ---<br\/>    delta2 = [probs[a] - (1.0 if a == target else 0.0) for a in range(4)]<br\/><br\/>    # --- Mise \u00e0 jour W2, B2 ---<br\/>    for a in range(4):<br\/>        for n in range(3):<br\/>            W2[a][n] -= eta * delta2[a] * h[n]<br\/>        B2[a] -= eta * delta2[a]<br\/><br\/>    # --- Gradient couche 1 (r\u00e9tropropagation) ---<br\/>    delta1 = []<br\/>    for n in range(3):<br\/>        grad = sum(W2[a][n] * delta2[a] for a in range(4))<br\/>        delta1.append(h[n] * (1.0 - h[n]) * grad)<br\/><br\/>    # --- Mise \u00e0 jour W1, B1 ---<br\/>    for n in range(3):<br\/>        for i in range(5):<br\/>            W1[n][i] -= eta * delta1[n] * inputs[i]<br\/>        B1[n] -= eta * delta1[n]<br\/><br\/># -----------------------------<br\/># Phase d&#039;apprentissage<br\/># -----------------------------<br\/><br\/>print(&quot;=&quot; * 50)<br\/>print(&quot;   APPRENTISSAGE DU R\u00c9SEAU DE NEURONES&quot;)<br\/>print(&quot;=&quot; * 50)<br\/><br\/>for epoch in range(500):<br\/>    nb_erreurs = 0<br\/><br\/>    for inputs, target in training_data:<br\/>        h, probs, action = forward(inputs)<br\/>        if action != target:<br\/>            nb_erreurs += 1<br\/>        train_step(inputs, target, h, probs)<br\/><br\/>    # Affichage toutes les 50 \u00e9poques<br\/>    if (epoch + 1) % 50 == 0:<br\/>        print(f&quot;\u00c9poque {epoch + 1:4d} \u2014 erreurs : {nb_erreurs}\/{len(training_data)}&quot;)<br\/><br\/>    if nb_erreurs == 0:<br\/>        print(f&quot;\\nConvergence atteinte \u00e0 l&#039;\u00e9poque {epoch + 1}&quot;)<br\/>        break<br\/><br\/>print(&quot;\\nPoids finaux \u2014 couche 1 (perception) :&quot;)<br\/>for n, nom in enumerate([&quot;Gauche&quot;, &quot;Devant&quot;, &quot;Droite&quot;]):<br\/>    print(f&quot;  Neurone {nom} : w={[f&#039;{v:.3f}&#039; for v in W1[n]]}  b={B1[n]:.3f}&quot;)<br\/><br\/>print(&quot;\\nPoids finaux \u2014 couche 2 (d\u00e9cision) :&quot;)<br\/>for a, nom in enumerate(ACTIONS):<br\/>    print(f&quot;  {nom:15s} : w={[f&#039;{v:.3f}&#039; for v in W2[a]]}  b={B2[a]:.3f}&quot;)<br\/><br\/># V\u00e9rification finale sur le jeu d&#039;entra\u00eenement<br\/>print(&quot;\\nV\u00e9rification sur les donn\u00e9es d&#039;entra\u00eenement :&quot;)<br\/>for inputs, target in training_data:<br\/>    _, probs, action = forward(inputs)<br\/>    statut = &quot;\u2713&quot; if action == target else &quot;\u2717&quot;<br\/>    print(f&quot;  {statut} capteurs={inputs}  attendu={ACTIONS[target]:15s}  obtenu={ACTIONS[action]}&quot;)<br\/><br\/>print(&quot;\\nD\u00e9marrage du robot dans 5 secondes\u2026&quot;)<br\/>time.sleep(5)<br\/><br\/># -----------------------------<br\/># Pilotage en temps r\u00e9el<br\/># -----------------------------<br\/><br\/>SEUIL_MAX = 80.0  # mm \u2014 distance au-del\u00e0 de laquelle la voie est consid\u00e9r\u00e9e libre<br\/><br\/>print(&quot;\\n&quot; + &quot;=&quot; * 50)<br\/>print(&quot;   PILOTAGE EN COURS  (Ctrl+C pour stopper)&quot;)<br\/>print(&quot;=&quot; * 50)<br\/><br\/>try:<br\/>    while True:<br\/>        # --- Lecture et normalisation des 5 capteurs ---<br\/>        raw = [MR25.proxSensor(i) for i in range(1, 6)]<br\/>        inputs = [min(v, SEUIL_MAX) \/ SEUIL_MAX for v in raw]<br\/><br\/>        # --- Inf\u00e9rence ---<br\/>        h, probs, action = forward(inputs)<br\/><br\/>        # --- Affichage diagnostique ---<br\/>        obstacle = [&quot;\u2b1b&quot; if v &lt; 0.5 else &quot;\u2b1c&quot; for v in inputs]<br\/>        print(<br\/>            f&quot;Capteurs {&#039;&#039;.join(obstacle)}  &quot;<br\/>            f&quot;G={h[0]:.2f} D={h[1]:.2f} Dr={h[2]:.2f}  &quot;<br\/>            f&quot;\u2192 {ACTIONS[action]}&quot;<br\/>        )<br\/><br\/>        # --- Commande moteur ---<br\/>        if action == 0:<br\/>            MR25.forward(40)<br\/>        elif action == 1:<br\/>            MR25.turnLeft(30)<br\/>        elif action == 2:<br\/>            MR25.turnRight(30)<br\/>        else:<br\/>            MR25.stop()<br\/><br\/>        time.sleep(0.1)  # 10 Hz<br\/><br\/>except KeyboardInterrupt:<br\/>    MR25.stop()<br\/>    print(&quot;\\nArr\u00eat propre.&quot;)<br\/><br\/># end of file<\/code><\/pre> <div class=\"code-embed-infos\"> <\/div> <\/div>\n<div class=\"code-embed-wrapper\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Pr\u00e9sentation Dans cet article nous allons apprendre au robot MR25 \u00e0 \u00e9viter les obstacles en utilisant un r\u00e9seau de neurones. Nous allons coder un r\u00e9seau \u00e0 2 couches, une seule couche (le perceptron) suffit quand le probl\u00e8me est lin\u00e9airement s\u00e9parable, c\u2019est-\u00e0-dire qu\u2019on peut tracer une ligne droite entre les cas \u00ab\u00a0oui\u00a0\u00bb et les cas \u00ab\u00a0non\u00a0\u00bb. &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3680","post","type-post","status-publish","format-standard","hentry","category-non-classe"],"_links":{"self":[{"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/posts\/3680","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3680"}],"version-history":[{"count":5,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/posts\/3680\/revisions"}],"predecessor-version":[{"id":3685,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=\/wp\/v2\/posts\/3680\/revisions\/3685"}],"wp:attachment":[{"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3680"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.macerobotics.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}