{"notes":[{"id":"action-recognition/st-gcn","category":"action-recognition","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"ST-GCN","subtitle":"Vers le centre, loin du centre","author":"Z. Yuan","paperDate":"2018-01-23","publishedOn":"2023-12-11","world":"external/st-gcn","paperTitle":"Spatial Temporal Graph Convolutional Networks for Skeleton-Based Action Recognition","paperUrl":"https://arxiv.org/abs/1801.07455","bibliography":{"title":"Spatial Temporal Graph Convolutional Networks for Skeleton-Based Action Recognition","authors":["Sijie Yan","Yuanjun Xiong","Dahua Lin"],"url":"https://arxiv.org/abs/1801.07455","pdfUrl":"https://arxiv.org/pdf/1801.07455v2","codeUrl":"https://github.com/yysijie/st-gcn","preprint":{"id":"1801.07455","submittedOn":"2018-01-23","url":"https://arxiv.org/abs/1801.07455"},"publication":{"venue":"AAAI","year":2018,"kind":"conference","url":"https://ojs.aaai.org/index.php/AAAI/article/view/12328"},"citation":"@misc{actionrecognitionstgcn2018,\n  title = {{Spatial Temporal Graph Convolutional Networks for Skeleton-Based Action Recognition}},\n  author = {Sijie Yan and Yuanjun Xiong and Dahua Lin},\n  year = {2018},\n  eprint = {1801.07455},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1801.07455}\n}\n","citationPath":"/content/papers/citations/action-recognition/st-gcn.d4a6b81c8471.bib"},"thumbnail":{"src":"/content/papers/assets/75fab9132b72202980c799f04d5fa51cf9749352d5b47ce0d19b571aa8a39acc.png","width":868,"height":292},"locale":"fr","path":"/content/papers/fr/action-recognition/st-gcn.386713bb786b.md","headings":[{"id":"poser-le-problème","text":"Poser le problème","depth":2},{"id":"résoudre-le-problème","text":"Résoudre le problème","depth":2},{"id":"le-graphe-spatio-temporel","text":"Le graphe spatio-temporel","depth":3},{"id":"à-qui-attribuer-les-poids-sur-le-graphe-","text":"À qui attribuer les poids sur le graphe ?","depth":3},{"id":"trois-regroupements","text":"Trois regroupements","depth":3},{"id":"une-implémentation-matricielle","text":"Une implémentation matricielle","depth":3},{"id":"limportance-des-arêtes","text":"L'importance des arêtes","depth":3},{"id":"le-réseau-entier","text":"Le réseau entier","depth":3},{"id":"discussion","text":"Discussion","depth":2},{"id":"les-jeux-de-données","text":"Les jeux de données","depth":3},{"id":"ablation-des-regroupements","text":"Ablation des regroupements","depth":3},{"id":"comparaison-aux-autres-méthodes","text":"Comparaison aux autres méthodes","depth":3},{"id":"conclusion","text":"Conclusion","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"graph-learning/gcn","relation":"referenced","topic":""}]},{"id":"graph-learning/gcn","category":"graph-learning","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"GCN","subtitle":"Un seul paramètre suffit-il ?","author":"Z. Yuan","paperDate":"2016-09-09","publishedOn":"2023-10-01","world":"external/gcn","paperTitle":"Semi-Supervised Classification with Graph Convolutional Networks","paperUrl":"https://arxiv.org/abs/1609.02907","bibliography":{"title":"Semi-Supervised Classification with Graph Convolutional Networks","authors":["Thomas N. Kipf","Max Welling"],"url":"https://arxiv.org/abs/1609.02907","pdfUrl":"https://arxiv.org/pdf/1609.02907v4","codeUrl":"https://github.com/tkipf/gcn","preprint":{"id":"1609.02907","submittedOn":"2016-09-09","url":"https://arxiv.org/abs/1609.02907"},"publication":{"venue":"ICLR","year":2017,"kind":"conference","url":"https://arxiv.org/abs/1609.02907"},"citation":"@misc{graphlearninggcn2016,\n  title = {{Semi-Supervised Classification with Graph Convolutional Networks}},\n  author = {Thomas N. Kipf and Max Welling},\n  year = {2016},\n  eprint = {1609.02907},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1609.02907}\n}\n","citationPath":"/content/papers/citations/graph-learning/gcn.43058ec3e77e.bib"},"thumbnail":{"src":"/content/papers/assets/ded600c9ca8f4eda09d39ffb16b3c9b0ec730780063e55948b29924d00f14794.png","width":1122,"height":400},"locale":"fr","path":"/content/papers/fr/graph-learning/gcn.92d7953d0185.md","headings":[{"id":"poser-le-problème","text":"Poser le problème","depth":2},{"id":"le-graphe-comme-terme-de-régularisation","text":"Le graphe comme terme de régularisation","depth":3},{"id":"résoudre-le-problème","text":"Résoudre le problème","depth":2},{"id":"simplifier-depuis-le-domaine-spectral","text":"Simplifier depuis le domaine spectral","depth":3},{"id":"une-couche-de-gcn","text":"Une couche de GCN","depth":3},{"id":"deux-couches-suffisent","text":"Deux couches suffisent","depth":3},{"id":"discussion","text":"Discussion","depth":2},{"id":"protocole-expérimental","text":"Protocole expérimental","depth":3},{"id":"résultats-principaux","text":"Résultats principaux","depth":3},{"id":"quelle-propagation-fonctionne-le-mieux-","text":"Quelle propagation fonctionne le mieux ?","depth":3},{"id":"que-se-passe-t-il-en-profondeur-","text":"Que se passe-t-il en profondeur ?","depth":3},{"id":"le-lien-avec-lalgorithme-wl","text":"Le lien avec l'algorithme WL","depth":3},{"id":"une-critique-quatre-jours-plus-tard","text":"Une critique, quatre jours plus tard","depth":3},{"id":"les-limites-relevées-par-larticle","text":"Les limites relevées par l'article","depth":3},{"id":"conclusion","text":"Conclusion","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"graph-learning/spectral-networks","relation":"referenced","topic":""},{"id":"graph-learning/chebnet","relation":"referenced","topic":""}]}],"text":"Pour reconnaître ce qu'une personne fait dans une vidéo, on peut regarder les images, ou seulement son squelette.\n\nUn squelette est une suite de coordonnées d'articulations. Un outil d'estimation de pose repère tête, épaules, coudes, poignets, hanches, genoux et chevilles à chaque image ; dix secondes deviennent quelques centaines d'images d'une dizaine de points ou un peu plus chacune. Les données sont légères et indépendantes du fond et de l'éclairage. Danser, saluer, tomber : le squelette renseigne déjà beaucoup sur ces mouvements du corps.\n\nLe squelette est naturellement un graphe : les articulations sont des nœuds, les os des arêtes. Sijie Yan, Yuanjun Xiong et Dahua Lin, de l'université chinoise de Hong Kong, y appliquent GCN pour traiter l'espace et le temps ensemble. Ils l'appellent ST-GCN.\n\n## Poser le problème\n\nLa reconnaissance d'actions à partir de squelettes suivait jusque-là deux grandes voies.\n\nLa première reposait sur des règles manuelles : découper le corps en parties, définir leurs relations, ou calculer des caractéristiques conçues à la main sur les trajectoires des articulations. Changer de données exigeait de réécrire les règles.\n\nLa seconde employait un RNN ou des convolutions temporelles, après concaténation de toutes les coordonnées d'une image en un long vecteur. On perdait ainsi la connectivité du squelette : au modèle de deviner dans les données que le coude droit rejoint le poignet droit, mais pas le genou gauche.\n\nLes auteurs cherchent un modèle qui exploite directement cette connectivité et apprenne des motifs spatiaux et temporels, sans découpage manuel. GCN offre justement un cadre de convolution sur graphes, conçu cependant pour des réseaux de citations. Son application au squelette demande encore de résoudre une difficulté.\n\n## Résoudre le problème\n\n### Le graphe spatio-temporel\n\nPour une séquence de $T$ images à $N$ articulations, les auteurs construisent un graphe spatio-temporel non orienté. Chaque articulation à chaque image devient un nœud, soit $T\\times N$ nœuds. Ses caractéristiques sont ses coordonnées et le score de confiance de l'estimation de pose.\n\nDeux types d'arêtes : dans une image, les articulations sont reliées selon l'anatomie ; entre images consécutives, la même articulation est reliée à elle-même. Kinetics utilise 18 articulations 2D estimées par OpenPose, NTU-RGB+D les 25 articulations 3D suivies par Kinect. La connectivité vient des données, sans découpage manuel en parties.\n\n[![Figure 1 de l'article : graphe spatio-temporel d'une séquence de squelettes. Les points bleus sont les articulations, reliées par les os dans chaque image. Les arêtes vertes relient la même articulation entre images consécutives ; la flèche en bas à droite donne le sens du temps.](/content/papers/assets/9e7851cb79bcf44e244d3b165ae301cb07adf86ffa6961d683bb9b743c4d2275.png)](/content/papers/assets/9e7851cb79bcf44e244d3b165ae301cb07adf86ffa6961d683bb9b743c4d2275.png)\n\n*Figure 1 de l'article (Yan et al.), extraite de la [**page 1 du PDF**](https://arxiv.org/pdf/1801.07455v2#page=1). Légende originale omise.*\n\nSur Kinetics, le tenseur d'une vidéo est $(3,T,18,2)$. Les 3 canaux sont $(x,y,\\text{confiance})$, 18 est le nombre d'articulations, et 2 limite chaque vidéo aux deux personnes les plus fiables. Les auteurs répètent la vidéo pour atteindre $T=300$ images.\n\n### À qui attribuer les poids sur le graphe ?\n\nRevenons d'abord à la convolution 2D ordinaire. Avec un noyau 3×3, la sortie à la position $x$ vaut :\n\n$$\nf_{out}(x)=\\sum_{h=1}^{3}\\sum_{w=1}^{3}f_{in}\\left(p(x,h,w)\\right)\\cdot w(h,w)\n$$\n\nLes auteurs séparent deux fonctions. La **fonction d'échantillonnage** $p$ choisit les positions regardées : les 9 pixels voisins d'une image. La **fonction de poids** $w$ attribue un jeu de poids à chaque position. La grille fixe associe ses 9 positions — haut gauche, haut, haut droite, etc. — à 9 jeux de poids, accessibles dans un tenseur $(c,3,3)$.\n\nSur un graphe, choisir les positions est simple : prendre les voisins à un saut au plus. Attribuer les poids est plus délicat, car les voisins n'ont pas de positions fixes « haut gauche » ou « haut ».\n\nLes auteurs répartissent les voisins en $K$ groupes fixes, donnent une étiquette à chaque groupe et partagent les poids à l'intérieur de celui-ci :\n\n$$\nf_{out}(v_{ti})=\\sum_{v_{tj}\\in B(v_{ti})}\\frac{1}{Z_{ti}(v_{tj})}\\,f_{in}(v_{tj})\\cdot w\\left(l_{ti}(v_{tj})\\right)\n$$\n\n$l_{ti}$ associe chaque voisin à son groupe ; $Z$ est le nombre de nœuds du groupe et équilibre leurs contributions. De ce point de vue, une convolution 3×3 répartit 9 pixels en 9 groupes d'un seul pixel.\n\nLe temps est plus simple, car son axe est ordonné. Numéroter les groupes spatiaux selon leur décalage temporel permet de définir la convolution sur le voisinage spatio-temporel. La portée temporelle $\\Gamma$ est la taille du noyau temporel, fixée à 9 dans l'article.\n\n### Trois regroupements\n\nLes groupes déterminent ce que le modèle peut distinguer. Les auteurs en testent trois :\n\n[![Figure 3 de l'article : quatre dessins. (a) Squelette d'entrée, dont le voisinage D=1 est entouré en rouge pointillé. (b) Groupe unique : tous les nœuds sont verts. (c) Selon la distance : soi-même en vert, voisins en bleu. (d) Selon la position spatiale : une croix noire marque le centre du squelette, soi-même est vert, les voisins plus proches du centre sont bleus et les plus éloignés jaunes.](/content/papers/assets/75fab9132b72202980c799f04d5fa51cf9749352d5b47ce0d19b571aa8a39acc.png)](/content/papers/assets/75fab9132b72202980c799f04d5fa51cf9749352d5b47ce0d19b571aa8a39acc.png)\n\n*Figure 3 de l'article (Yan et al.), extraite de la [**page 5 du PDF**](https://arxiv.org/pdf/1801.07455v2#page=5). Légende originale omise.*\n\n- **Groupe unique** (uni-labeling, figure b) : tout le voisinage dans un groupe, $K=1$. Les auteurs l'identifient à la propagation GCN de Kipf et Welling. Tous les voisins multiplient les mêmes poids : on moyenne leurs caractéristiques avant le produit scalaire et perd leurs relations relatives.\n- **Selon la distance** (figure c) : soi-même dans un groupe, les voisins à un saut dans l'autre, $K=2$. Deux jeux de poids permettent des différences locales comme « soi-même moins les voisins », par exemple les déplacements relatifs entre articulations.\n- **Selon la position spatiale** (figure d) : $K=3$. Un groupe pour soi-même ; un pour les voisins plus proches du centre du squelette, dits **centripètes** ; un pour les plus éloignés, dits **centrifuges**. Le centre est la moyenne des coordonnées de toutes les articulations de l'image ; $r_i$ est la distance moyenne de l'articulation $i$ à ce centre sur l'entraînement. L'idée est que les membres se replient vers l'intérieur ou s'étendent vers l'extérieur.\n\nPrenons un squelette simplifié à six articulations et appliquons ce regroupement spatial :\n\n```python\nimport numpy as np\nnp.set_printoptions(precision=2, suppress=True)\n\n# Squelette simplifié : 0 cou, 1 épaule droite, 2 coude droit, 3 épaule gauche, 4 coude gauche, 5 bassin\nnames = [\"cou\", \"épaule droite\", \"coude droit\", \"épaule gauche\", \"coude gauche\", \"bassin\"]\nxy = np.array([[0.0, 1.0], [-0.4, 0.9], [-0.6, 0.5], [0.4, 0.9], [0.6, 0.5], [0.0, 0.2]])\nbones = [(0, 1), (1, 2), (0, 3), (3, 4), (0, 5)]\nV = len(xy)\nA = np.zeros((V, V))\nfor i, j in bones:\n    A[i, j] = A[j, i] = 1\n\ncenter = xy.mean(0)                          # Centre du squelette : moyenne des coordonnées\nr = np.linalg.norm(xy - center, axis=1)      # Distance de chaque articulation au centre\n\nA_root, A_in, A_out = np.eye(V), np.zeros((V, V)), np.zeros((V, V))\nfor i in range(V):\n    for j in np.nonzero(A[i])[0]:\n        if r[j] < r[i]:\n            A_in[i, j] = 1                   # Centripète : voisin plus proche du centre\n        else:\n            A_out[i, j] = 1                  # Centrifuge : voisin plus éloigné\n\nprint(\"Distances au centre:\", r)\nfor i in (0, 1, 2):\n    print(f\"{names[i]} : centripètes {[names[j] for j in A_in[i].nonzero()[0]]}, \"\n          f\"centrifuges {[names[j] for j in A_out[i].nonzero()[0]]}\")\n```\n\n```text\nDistances au centre: [0.33 0.46 0.62 0.46 0.62 0.47]\ncou : centripètes [], centrifuges ['épaule droite', 'épaule gauche', 'bassin']\népaule droite : centripètes ['cou'], centrifuges ['coude droit']\ncoude droit : centripètes ['épaule droite'], centrifuges []\n```\n\nLa démonstration utilise une seule image ; l'article moyenne les distances sur tout l'entraînement. Les deux voisins de l'épaule droite vont dans des groupes différents : le cou du côté centripète, le coude du côté centrifuge. Un groupe unique les aurait moyennés ensemble.\n\n\n> [!TIP]\n> \n> Si vous lisez le code officiel, notez un écart avec l'article. La stratégie `spatial` de `net/utils/graph.py` compare les nombres de sauts jusqu'à une **articulation centrale désignée** : le cou pour les 18 points OpenPose, la colonne vertébrale pour NTU, plutôt que les distances au centre des coordonnées. Les voisins à même nombre de sauts sont regroupés avec le nœud lui-même.\n\n\n### Une implémentation matricielle\n\nL'implémentation reprend GCN. Avec un groupe unique, une couche s'écrit :\n\n$$\nf_{out}=\\Lambda^{-\\frac12}(A+I)\\Lambda^{-\\frac12}f_{in}W\n$$\n\nAvec plusieurs groupes, on décompose $A+I=\\sum_jA_j$ en $K$ matrices, chacune normalisée et dotée de ses poids, puis on somme :\n\n$$\nf_{out}=\\sum_j\\Lambda_j^{-\\frac12}A_j\\Lambda_j^{-\\frac12}f_{in}W_j\n$$\n\nPour le regroupement par distance, $A_0=I$ et $A_1=A$. Certains groupes peuvent avoir une ligne entièrement nulle, comme le cou sans voisin centripète ci-dessus ; la normalisation ajoute donc $\\alpha=0.001$ aux degrés.\n\nReprenons ce squelette, considérons l'entrée comme un tenseur $(C,T,V)$ et calculons une convolution spatiale sur graphe :\n\n```python\ndef normalize(Aj, alpha=0.001):\n    d = Aj.sum(1) + alpha                    # L'article ajoute α pour éviter les lignes nulles\n    return Aj / np.sqrt(np.outer(d, d))\n\nC_in, C_out, T = 3, 8, 4\nx = np.random.default_rng(0).random((C_in, T, V))      # (canaux, images, articulations)\nWs = [np.random.default_rng(k).normal(size=(C_out, C_in)) for k in range(3)]\n\nout = sum(np.einsum(\"oc,ctv,wv->otw\", Wk, x, normalize(Ak))   # Chaque groupe a sa normalisation et ses poids\n          for Wk, Ak in zip(Ws, [A_root, A_in, A_out]))\nprint(\"Entrée:\", x.shape, \"→ Sortie:\", out.shape)\n```\n\n```text\nEntrée: (3, 4, 6) → Sortie: (8, 4, 6)\n```\n\nUn véritable bloc ST-GCN ajoute ensuite une convolution $1\\times\\Gamma$ le long du temps, reliant la même articulation sur plusieurs images successives.\n\n### L'importance des arêtes\n\nUne articulation peut appartenir à plusieurs parties du corps, avec une importance différente dans chacune. Les auteurs multiplient donc chaque matrice d'adjacence de chaque couche, élément par élément, par un masque appris $M$, initialisé à 1 partout. Ils évoquent aussi une attention dépendante des données, laissée aux travaux futurs.\n\n### Le réseau entier\n\nUne BatchNorm d'entrée aligne les échelles des coordonnées des articulations : le partage des poids sur tous les nœuds rendrait les écarts d'échelle gênants. Suivent 9 blocs ST-GCN de 64, 64, 64, 128, 128, 128, 256, 256 et 256 canaux, avec noyau temporel 9, connexions résiduelles dans chaque bloc et dropout de 0.5 après celui-ci. Les blocs 4 et 7 ont un pas temporel de 2 pour le pooling. Un pooling global donne enfin un vecteur de 256 dimensions, suivi d'une classification softmax.\n\nL'entraînement utilise SGD à 0.01, multiplié par 0.1 toutes les 10 époques. Sur Kinetics, les auteurs remplacent le dropout par deux augmentations : des transformations affines aléatoires interpolées entre images pour simuler le mouvement de caméra, et des découpages temporels aléatoires à l'entraînement, la séquence entière étant conservée au test.\n\n## Discussion\n\n### Les jeux de données\n\n**Kinetics** compte environ 300,000 vidéos YouTube de 400 classes d'actions, d'environ 10 secondes chacune : 240,000 pour l'entraînement, 20,000 pour la validation. Les auteurs redimensionnent à 340×256 et 30 FPS, estiment les squelettes avec OpenPose et n'utilisent qu'eux en entrée.\n\n**NTU-RGB+D** est filmé en laboratoire : 40 sujets, trois caméras simultanées, environ 56,000 séquences et 60 classes. Kinect suit 25 articulations 3D par personne. X-Sub sépare les sujets entre entraînement et test ; X-View sépare les points de vue des caméras.\n\n### Ablation des regroupements\n\nSur Kinetics, comparaison des exactitudes top-1 et top-5 :\n\n| Configuration | Top-1 | Top-5 |\n| --- | ---: | ---: |\n| Référence à convolutions temporelles seules (TCN) | 20.3% | 40.0% |\n| Graphe de squelette creux, sans partage des poids | 22.0% | 43.2% |\n| Groupe unique | 19.3% | 37.4% |\n| Par distance, poids des deux groupes opposés | 23.9% | 44.9% |\n| Par distance | 29.1% | 51.3% |\n| Par position spatiale | 29.9% | 52.2% |\n| Par position spatiale + importance des arêtes | **30.7%** | **52.8%** |\n\nPlusieurs choses ressortent de ce tableau.\n\nD'abord, le groupe unique, de type GCN, fait moins bien que la référence temporelle sans structure de graphe. L'explication des auteurs reprend l'argument précédent : la moyenne efface les différences locales.\n\nEnsuite, séparer soi-même de ses voisins fait sauter l'exactitude de 19.3% à 29.1%. Même en liant les deux jeux de poids à un signe près, on dépasse le groupe unique : les auteurs y voient l'importance du regroupement lui-même.\n\nEnfin, trois groupes spatiaux font encore un peu mieux que deux ; l'importance des arêtes ajoute près d'un point.\n\nLa référence temporelle équivaut par ailleurs à une convolution spatio-temporelle sur un graphe d'articulations complet, sans partage des poids. ST-GCN s'en distingue par les connexions anatomiques creuses et les poids partagés.\n\n### Comparaison aux autres méthodes\n\n| Méthode | Kinetics Top-1 | NTU X-Sub | NTU X-View |\n| --- | ---: | ---: | ---: |\n| Deep LSTM | 16.4% | 60.7% | 67.3% |\n| Temporal ConvNet | 20.3% | 74.3% | 83.1% |\n| C-CNN + MTLN | — | 79.6% | 84.8% |\n| **ST-GCN** | **30.7%** | **81.5%** | **88.3%** |\n\nSur les deux jeux de données, ST-GCN est la meilleure méthode de l'époque fondée sur le squelette.\n\nSur Kinetics, regarder seulement le squelette reste toutefois loin des images : RGB atteint 57.0%, le flux optique 49.5%. Les auteurs rappellent que beaucoup d'actions exigent de voir les objets tenus et la scène. Sur un sous-ensemble de 30 classes liées aux mouvements du corps, l'exactitude moyenne par classe est de 72.4% pour ST-GCN, 70.4% pour RGB et 72.8% pour le flux optique, donc comparable.\n\nCombiner ST-GCN au modèle RGB à deux flux aide davantage qu'ajouter le flux optique. Sans préentraînement ImageNet, RGB seul atteint 70.3%, avec flux optique 71.1%, avec ST-GCN 71.2%, et avec les trois 71.7%.\n\n## Conclusion\n\nST-GCN transforme une séquence de squelettes en graphe spatio-temporel et y applique la forme de GCN. Son choix décisif est le regroupement des voisins : sans lui, le modèle perd même contre la référence sans graphe ; deux groupes apportent près de 10 points.\n\nC'est aussi une réponse pratique au noyau moyenneur auquel GCN se réduit sur une grille d'image. Sur un graphe spatial, pouvoir séparer les poids selon le rôle des voisins change beaucoup les choses.\n\n\n> [!TIP]\n> \n> Pour la propagation de GCN et la raison du partage d'un même jeu de poids par tous les voisins, voir notre note :\n> \n> - **[[16.09] GCN : Un seul paramètre suffit-il ?](/blog/papers/graph-learning/gcn)**\n\n\nDe nombreux modèles de reconnaissance d'actions sur squelettes partiront ensuite de ST-GCN ; [2s-AGCN](https://arxiv.org/abs/1805.07694) apprend par exemple l'adjacence depuis les données. Avant d'implémenter, vérifiez combien d'articulations produit votre estimateur et laquelle sert de centre : tout le regroupement en dépend.\n","imageSizes":{"/content/papers/assets/9e7851cb79bcf44e244d3b165ae301cb07adf86ffa6961d683bb9b743c4d2275.png":{"width":454,"height":364},"/content/papers/assets/75fab9132b72202980c799f04d5fa51cf9749352d5b47ce0d19b571aa8a39acc.png":{"width":868,"height":292}}}
