{"id":663,"date":"2026-10-09T16:35:33","date_gmt":"2026-10-09T14:35:33","guid":{"rendered":"https:\/\/www.ranksignal.fr\/blog\/?p=663"},"modified":"2026-10-14T17:16:07","modified_gmt":"2026-10-14T15:16:07","slug":"le-modele-bert","status":"publish","type":"post","link":"https:\/\/www.ranksignal.fr\/blog\/deep-learning\/le-modele-bert\/","title":{"rendered":"Le mod\u00e8le BERT : un lecteur qui regarde des deux c\u00f4t\u00e9s"},"content":{"rendered":"<p><\/p>\n<p>Compl\u00e8te cette phrase : \u00ab Le chat dort sur le ___ depuis ce matin. \u00bb Pour deviner le mot manquant, tu as pris appui sur ce qui pr\u00e9c\u00e8de le trou, mais aussi sur \u00ab depuis ce matin \u00bb, qui vient apr\u00e8s. Un mod\u00e8le de langage classique lit de gauche \u00e0 droite et se prive de ce second indice. BERT a \u00e9t\u00e9 con\u00e7u pour exploiter les deux. Tu vas voir ce que son nom veut dire, comment on lui apprend \u00e0 lire, comment on l&#8217;emploie pour classer des documents et pourquoi il a c\u00e9d\u00e9 du terrain.<\/p>\n<p><strong>Sommaire<\/strong><\/p>\n<ul>\n<li><a href=\"#l-essentiel-en-30-secondes\">L&rsquo;essentiel en 30 secondes<\/a><\/li>\n<li><a href=\"#un-nom-qui-dit-tout-b-e-r-t\">Un nom qui dit tout : B, E, R, T<\/a><\/li>\n<li><a href=\"#apprendre-a-lire-avec-un-texte-a-trous\">Apprendre \u00e0 lire avec un texte \u00e0 trous<\/a><\/li>\n<li><a href=\"#classer-des-documents-pour-une-question-deux-montages\">Classer des documents pour une question : deux montages<\/a><\/li>\n<li><a href=\"#reclasser-des-resultats-le-code\">Reclasser des r\u00e9sultats : le code<\/a><\/li>\n<li><a href=\"#la-famille-bert-variantes-et-allegements\">La famille BERT : variantes et all\u00e8gements<\/a><\/li>\n<li><a href=\"#bert-face-aux-modeles-qui-generent\">BERT face aux mod\u00e8les qui g\u00e9n\u00e8rent<\/a><\/li>\n<li><a href=\"#quatre-idees-recues-sur-bert\">Quatre id\u00e9es re\u00e7ues sur BERT<\/a><\/li>\n<\/ul>\n<h2 id=\"l-essentiel-en-30-secondes\">L&rsquo;essentiel en 30 secondes<\/h2>\n<ul>\n<li>BERT est <strong>un encodeur de <a href=\"\/blog\/deep-learning\/qu-est-ce-qu-un-transformer\/\" title=\"Transformer\">Transformer<\/a> bidirectionnel<\/strong> : chaque mot est lu avec ce qui le pr\u00e9c\u00e8de et ce qui le suit.<\/li>\n<li>Il apprend en <strong>retrouvant des mots masqu\u00e9s<\/strong>, et en jugeant si deux phrases sont li\u00e9es.<\/li>\n<li>Il ne r\u00e9dige pas : il fournit <strong>des repr\u00e9sentations r\u00e9utilisables<\/strong> pour classer, r\u00e9pondre ou comparer.<\/li>\n<li>Pour chercher dans des documents, on le monte en <strong>encodeur unique ou en bi-encodeur<\/strong>, l&rsquo;un pr\u00e9cis, l&rsquo;autre rapide.<\/li>\n<li>Face aux mod\u00e8les qui g\u00e9n\u00e8rent du texte, il garde <strong>un r\u00f4le sur les t\u00e2ches rapides<\/strong>, avec une fen\u00eatre de 512 jetons.<\/li>\n<\/ul>\n<h2 id=\"un-nom-qui-dit-tout-b-e-r-t\">Un nom qui dit tout : B, E, R, T<\/h2>\n<p>BERT est l&rsquo;abr\u00e9viation de <em>Bidirectional Encoder Representations from Transformers<\/em>. Chaque mot de ce nom correspond \u00e0 un choix de conception : en les prenant un \u00e0 un, tu obtiens la d\u00e9finition compl\u00e8te du mod\u00e8le.<\/p>\n<h3>T : une variante du Transformer<\/h3>\n<p>Le Transformer a \u00e9t\u00e9 une r\u00e9volution, mais BERT a beaucoup fait pour le populariser : cette variante a montr\u00e9 ce dont ce type de mod\u00e8le est capable. Elle a \u00e9t\u00e9 pens\u00e9e d\u00e8s le d\u00e9part pour des applications comme les questions-r\u00e9ponses, le r\u00e9sum\u00e9 ou la traduction.<\/p>\n<h3>B : bidirectionnel<\/h3>\n<p>Le Transformer d&rsquo;origine lit la s\u00e9quence de gauche \u00e0 droite. Quand il rencontre une entit\u00e9, il ne peut pas la relier \u00e0 ce qui se trouve \u00e0 sa droite, alors que pour r\u00e9pondre \u00e0 une question ou r\u00e9sumer, <strong>le contexte des deux directions<\/strong> compte. Un encodeur bidirectionnel l\u00e8ve cette limite : chaque jeton peut chercher des relations sur toute la s\u00e9quence.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef46f11987&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef46f11987\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2119\" height=\"1117\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel.png\" alt=\"Deux matrices de visibilit\u00e9 entre cinq jetons : \u00e0 gauche, un escalier o\u00f9 les positions futures sont barr\u00e9es (\u00ab -\u221e \u00bb) ; \u00e0 droite, une matrice enti\u00e8rement remplie\" class=\"wp-image-287\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel.png 2119w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel-300x158.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel-1024x540.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel-768x405.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel-1536x810.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch02_masque_causal_bidirectionnel-2048x1080.png 2048w\" sizes=\"auto, (max-width: 2119px) 100vw, 2119px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Prends la ligne d&rsquo;un jeton du milieu. \u00c0 gauche, le motif d&rsquo;un mod\u00e8le comme GPT, les cases situ\u00e9es \u00e0 sa droite sont barr\u00e9es : il ne voit que lui-m\u00eame et son pass\u00e9. \u00c0 droite, le motif de BERT, aucune case n&rsquo;est barr\u00e9e : tout le reste de la phrase lui est accessible.<\/figcaption><\/figure>\n\n\n<h3>E : un encodeur, rien d&rsquo;autre<\/h3>\n<p>Dans un montage encodeur-d\u00e9codeur, l&rsquo;encodeur fabrique une repr\u00e9sentation interne enrichie d&rsquo;informations et de sens, puis le d\u00e9codeur s&rsquo;en sert pour g\u00e9n\u00e9rer la sortie. BERT s&rsquo;arr\u00eate \u00e0 la premi\u00e8re moiti\u00e9 : <strong>il n&rsquo;est compos\u00e9 que de l&rsquo;encodeur<\/strong> et lit la s\u00e9quence enti\u00e8re d&rsquo;un seul coup. Le reste de la cha\u00eene est familier : embedding, encodage de position, blocs, projection lin\u00e9aire, softmax.<\/p>\n<p>Le mod\u00e8le d&rsquo;origine existe en deux tailles, qui diff\u00e8rent par la profondeur et par la largeur des vecteurs qui circulent entre les couches :<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>BERT-BASE<\/th>\n<th>BERT-LARGE<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Couches<\/td>\n<td>12<\/td>\n<td>24<\/td>\n<\/tr>\n<tr>\n<td>Dimension des vecteurs internes<\/td>\n<td>768<\/td>\n<td>1 024<\/td>\n<\/tr>\n<tr>\n<td>T\u00eates d&rsquo;attention par couche<\/td>\n<td>12<\/td>\n<td>24<\/td>\n<\/tr>\n<tr>\n<td>Param\u00e8tres<\/td>\n<td>110 millions<\/td>\n<td>340 millions<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>R : des repr\u00e9sentations<\/h3>\n<p>Le dernier mot du nom annonce ce que BERT fournit : non pas du texte, mais <strong>une repr\u00e9sentation du texte<\/strong> que d&rsquo;autres composants exploitent. C&rsquo;est elle qui sert ensuite aux t\u00e2ches pour lesquelles il a \u00e9t\u00e9 pens\u00e9, du r\u00e9sum\u00e9 \u00e0 la comparaison de documents.<\/p>\n<h2 id=\"apprendre-a-lire-avec-un-texte-a-trous\">Apprendre \u00e0 lire avec un texte \u00e0 trous<\/h2>\n<p>Pour qu&rsquo;un mod\u00e8le apprenne une langue sans qu&rsquo;on lui fournisse d&rsquo;exemples annot\u00e9s, il faut une t\u00e2che dont la r\u00e9ponse est d\u00e9j\u00e0 dans le texte. Deux grandes familles existent. Dans la premi\u00e8re, le <em>causal language modeling<\/em>, le mod\u00e8le \u00e9crit la suite sans jamais voir autre chose que le pass\u00e9. Dans la seconde, le <em>masked language modeling<\/em> (MLM), on perce des trous dans le texte et le mod\u00e8le les comble en regardant avant comme apr\u00e8s.<\/p>\n<p>BERT rel\u00e8ve de la seconde famille, exactement comme dans ton exercice d&rsquo;ouverture : un jeton est remplac\u00e9 par un jeton sp\u00e9cial <code>&lt;MASK&gt;<\/code>, et le mod\u00e8le doit retrouver le mot cach\u00e9. \u00c0 l&rsquo;origine, <strong>15 % des jetons<\/strong> \u00e9taient masqu\u00e9s au hasard. On ne cache pas le futur comme chez un mod\u00e8le causal, puisque l&rsquo;on veut que le mod\u00e8le ait conscience de tout le contexte. La perte se calcule comme pour la pr\u00e9diction du mot suivant, avec le jeton masqu\u00e9 \u00e0 la place.<\/p>\n<blockquote>\n<p><strong>\ud83d\udca1 Intuition<\/strong> Un mod\u00e8le causal lit comme on \u00e9coute une phrase au fil de la parole. BERT lit comme on corrige une copie, stylo en main, avec toute la page sous les yeux.<\/p>\n<\/blockquote>\n<p>Cette t\u00e2che est plus souple qu&rsquo;il n&rsquo;y para\u00eet : le principe g\u00e9n\u00e9ral consiste \u00e0 corrompre l&rsquo;entr\u00e9e puis \u00e0 demander au mod\u00e8le de la reconstruire. Masquer n&rsquo;est qu&rsquo;une fa\u00e7on de la corrompre ; on peut aussi r\u00e9ordonner les \u00e9l\u00e9ments ou appliquer d&rsquo;autres transformations. Cette souplesse se paie : seuls 15 % des jetons servent \u00e0 apprendre \u00e0 chaque passage, ce qui rend le mod\u00e8le <strong>peu efficace<\/strong>.<\/p>\n<p>Le syst\u00e8me a un second exercice. On peut en effet l&rsquo;\u00e9tendre \u00e0 la pr\u00e9diction de la phrase suivante, qui consiste \u00e0 deviner si deux phrases sont li\u00e9es (paraphrase, coh\u00e9rence, implication). BERT a \u00e9t\u00e9 entra\u00een\u00e9 avec des paires de phrases reli\u00e9es positivement et non reli\u00e9es, un jeton <code>[SEP]<\/code> plac\u00e9 entre elles et une softmax finale pour la classification. Cela montre \u00e0 quel point le dispositif s&rsquo;adapte \u00e0 des t\u00e2ches diff\u00e9rentes.<\/p>\n<h2 id=\"classer-des-documents-pour-une-question-deux-montages\">Classer des documents pour une question : deux montages<\/h2>\n<p>Imagine une collection de documents et une question. Un moteur de recherche doit apparier la question aux documents pertinents, puis les renvoyer par ordre de pertinence. La recherche par mots-cl\u00e9s comme BM25 y trouve ses limites : elle <strong>comprend mal la s\u00e9mantique<\/strong>, ne capte pas le contexte des termes polys\u00e9miques et souffre de l&rsquo;inad\u00e9quation de vocabulaire, quand la question et les documents ne se recouvrent pas.<\/p>\n<p>La parade consiste \u00e0 utiliser des vecteurs denses qui contiennent de l&rsquo;information contextuelle, et un encodeur bidirectionnel comme BERT sait en produire. Pour cela, deux strat\u00e9gies existent.<\/p>\n<h3>Premier montage : un encodeur unique<\/h3>\n<p>On donne au mod\u00e8le la question et le document <strong>en m\u00eame temps<\/strong>, au format <code>[CLS]<\/code> question <code>[SEP]<\/code> document. L&rsquo;auto-attention bidirectionnelle circule alors sur tous les jetons : la repr\u00e9sentation du document tient compte de la question, et inversement. La repr\u00e9sentation du jeton <code>[CLS]<\/code> passe ensuite dans une couche lin\u00e9aire qui produit le score de similarit\u00e9 ; c&rsquo;est cette couche que l&rsquo;on ajuste.<\/p>\n<p>Deux contraintes p\u00e8sent sur ce montage. D&rsquo;abord, la taille : pour BERT, le contexte est de <strong>512 jetons<\/strong>, question et document compris, donc on traite des fragments qui ne se recouvrent pas plut\u00f4t que des documents entiers. Ensuite, le co\u00fbt : il faut repasser la question avec chaque document du corpus.<\/p>\n<h3>Second montage : le bi-encodeur<\/h3>\n<p>Pour r\u00e9duire ce co\u00fbt, on a con\u00e7u le bi-encodeur. Un encodeur extrait la repr\u00e9sentation de la question, not\u00e9e <code>[CLS]q<\/code>, et un autre celle de chaque document ou fragment, not\u00e9e <code>[CLS]d<\/code>. Les repr\u00e9sentations des documents se calculent une fois pour toutes et se rangent dans une base ; \u00e0 l&rsquo;arriv\u00e9e d&rsquo;une question, il suffit de la comparer \u00e0 tous les vecteurs de la base.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef46f11fa8&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef46f11fa8\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1378\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-scaled.png\" alt=\"Deux architectures de recherche : \u00e0 gauche, un encodeur unique re\u00e7oit la question et le document coll\u00e9s bout \u00e0 bout et sort un score par une couche lin\u00e9aire ; \u00e0 droite, deux encodeurs s\u00e9par\u00e9s produisent deux vecteurs compar\u00e9s par cosinus\" class=\"wp-image-661\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-300x162.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-1024x551.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-768x414.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-1536x827.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_bi_encodeur-2048x1103.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Compare les deux moiti\u00e9s du sch\u00e9ma : en A, un seul BERT voit la question et le document c\u00f4te \u00e0 c\u00f4te ; en B, ils ne se rencontrent qu&rsquo;\u00e0 la fin, au moment du calcul de similarit\u00e9. La comparaison se fait par le cosinus de l&rsquo;angle entre les deux vecteurs :<\/figcaption><\/figure>\n\n\n<p><p class=\"ql-center-displayed-equation\" style=\"line-height: 41px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-56e337dadde0b44d30dd18ee9a81fd3b_l3.png\" height=\"41\" width=\"135\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#91; &#92;&#99;&#111;&#115;&#40;&#113;&#44;&#100;&#41;&#61;&#92;&#102;&#114;&#97;&#99;&#123;&#113;&#92;&#99;&#100;&#111;&#116;&#32;&#100;&#125;&#123;&#124;&#113;&#124;&#92;&#44;&#124;&#100;&#124;&#125;&#46;&#92;&#93;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p><\/p>\n<p>Ici <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-ac7da57d7f507262338bb5168feb3e06_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#113;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"8\" style=\"vertical-align: -4px;\"\/> est le vecteur de la question, <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-4e8716946f6a868f015e0d62f28bc540_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#100;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"10\" style=\"vertical-align: 0px;\"\/> celui du document, <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-6e2658b72bd6f173b7cad9a2711b25c8_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#113;&#92;&#99;&#100;&#111;&#116;&#32;&#100;\" title=\"Rendered by QuickLaTeX.com\" height=\"16\" width=\"31\" style=\"vertical-align: -4px;\"\/> leur produit scalaire et <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-3b299991d0a1e490980a5cf738fd1fa5_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#124;&#113;&#124;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"14\" style=\"vertical-align: -5px;\"\/>, <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-34541aff80970010fc6807bc553ca7bc_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#124;&#100;&#124;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"15\" style=\"vertical-align: -5px;\"\/> leurs longueurs. Le r\u00e9sultat ne d\u00e9pend que de l&rsquo;angle : plus il est proche de 1, plus les deux textes se ressemblent.<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Encodeur unique<\/th>\n<th>Bi-encodeur<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Ce que re\u00e7oit BERT<\/td>\n<td>question et document ensemble<\/td>\n<td>question d&rsquo;un c\u00f4t\u00e9, document de l&rsquo;autre<\/td>\n<\/tr>\n<tr>\n<td>Interactions entre les mots<\/td>\n<td>toutes conserv\u00e9es<\/td>\n<td><strong>en partie perdues<\/strong><\/td>\n<\/tr>\n<tr>\n<td>Documents<\/td>\n<td>repass\u00e9s \u00e0 chaque question<\/td>\n<td>vecteurs calcul\u00e9s d&rsquo;avance, rang\u00e9s en base<\/td>\n<\/tr>\n<tr>\n<td>Vitesse<\/td>\n<td>lent<\/td>\n<td>rapide<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"reclasser-des-resultats-le-code\">Reclasser des r\u00e9sultats : le code<\/h2>\n<p>Voici le premier montage au travail. Une recherche a d\u00e9j\u00e0 ramen\u00e9 des documents ; il s&rsquo;agit de les remettre dans l&rsquo;ordre de leur pertinence pour la question, avec un BERT pr\u00e9entra\u00een\u00e9.<\/p>\n<pre><code>def rerank_documents(query, documents):\n    &quot;&quot;&quot;\n    Reranks the retrieved documents based on their relevance to the\nquery using a pre-trained\n    BERT model.\n    Args:\n        query (str): The user's query.\n        documents (list): A list of documents retrieved from the\nsearch.\n    Returns:\n        list: A list of reranked documents, sorted by relevance.\n    &quot;&quot;&quot;\n    inputs = [rerank_tokenizer.encode_plus(query, doc, return_\ntensors='pt', truncation=True, padding=True) for doc in documents]\n    scores = []\n    for input in inputs:\n        outputs = rerank_model(**input)\n        logits = outputs.logits\n        probabilities = F.softmax(logits, dim=1)\n        positive_class_probability = probabilities[:, 1].item()\n        scores.append(positive_class_probability)\n    ranked_docs = sorted(zip(documents, scores), key=lambda x: x[1],\nreverse=True)\n    return [doc for doc, score in ranked_docs]\n<\/code><\/pre>\n<p>Ce code suppose d\u00e9j\u00e0 charg\u00e9s <code>rerank_tokenizer<\/code> (le d\u00e9coupeur de texte en jetons) et <code>rerank_model<\/code> (le mod\u00e8le BERT), ainsi que <code>F<\/code>, les fonctions de PyTorch.<\/p>\n<p>Lis-le en trois temps. Pour chaque document, <code>encode_plus(query, doc, ...)<\/code> pr\u00e9pare <strong>la question et le document ensemble<\/strong>, exactement comme dans le montage \u00e0 encodeur unique. Le mod\u00e8le rend alors des scores bruts (<code>logits<\/code>), que <code>F.softmax<\/code> convertit en probabilit\u00e9s. Enfin, <code>probabilities[:, 1]<\/code> isole la probabilit\u00e9 de la classe positive, qui sert de note au document.<\/p>\n<p>La derni\u00e8re ligne trie les documents par note d\u00e9croissante. Comme ce montage repasse la question avec chaque document, il est logique de ne l&rsquo;appliquer qu&rsquo;\u00e0 une courte liste d\u00e9j\u00e0 retrouv\u00e9e plut\u00f4t qu&rsquo;\u00e0 tout un corpus.<\/p>\n<h2 id=\"la-famille-bert-variantes-et-allegements\">La famille BERT : variantes et all\u00e8gements<\/h2>\n<p>BERT a fait \u00e9cole, et plusieurs variantes en sont n\u00e9es. RoBERTa en est une. SpanBERT <strong>masque un segment entier<\/strong> plut\u00f4t qu&rsquo;un seul jeton, avec de meilleurs r\u00e9sultats : le trou de l&rsquo;exercice d&rsquo;ouverture devient plus large, et la devinette change. SciBERT, lui, est adapt\u00e9 \u00e0 un domaine.<\/p>\n<p>Pour all\u00e9ger, on distille : DistilBERT est une version distill\u00e9e de BERT. Un mod\u00e8le distill\u00e9 capte les connaissances d&rsquo;un mod\u00e8le bien plus grand sans perte notable de performance, tout en \u00e9tant beaucoup plus maniable.<\/p>\n<p>Une autre voie ne touche presque pas au mod\u00e8le. Les adaptateurs sont de petites couches ajustables, gliss\u00e9es \u00e0 l&rsquo;int\u00e9rieur des blocs et construites comme un autoencodeur. Si les couches du mod\u00e8le ont 1 024 dimensions, un adaptateur projette vers 24 puis reprojette vers 1 024, ce qui repr\u00e9sente <strong>moins de 50 000 param\u00e8tres<\/strong> par adaptateur. Lors de leurs d\u00e9buts, ils ont rattrap\u00e9 l&rsquo;ajustement complet de BERT pour seulement 3,6 % de param\u00e8tres suppl\u00e9mentaires \u00e0 entra\u00eener, l\u00e0 o\u00f9 la m\u00e9thode classique les entra\u00eene tous.<\/p>\n<blockquote>\n<p><strong>\ud83d\udccc \u00c0 retenir<\/strong> La famille BERT d\u00e9cline une m\u00eame id\u00e9e dans trois directions : changer l&rsquo;exercice de masquage (SpanBERT), changer le domaine (SciBERT), r\u00e9duire le co\u00fbt (DistilBERT, adaptateurs).<\/p>\n<\/blockquote>\n<h2 id=\"bert-face-aux-modeles-qui-generent\">BERT face aux mod\u00e8les qui g\u00e9n\u00e8rent<\/h2>\n<p>Les mod\u00e8les de type GPT font le choix inverse : ils sont causaux, chaque jeton ne voit que son pass\u00e9, et ils produisent le texte un jeton \u00e0 la fois. Les <a href=\"\/blog\/inference\/qu-est-ce-qu-un-llm\/\" title=\"grands mod\u00e8les de langage\">grands mod\u00e8les de langage<\/a> actuels sont, pour la plupart, des d\u00e9codeurs seuls. Les mod\u00e8les \u00e0 encodeur seul, dont la famille BERT pour l&#8217;embedding de texte \u00e0 l&rsquo;ancienne, <strong>sont devenus rares<\/strong>.<\/p>\n<p>L&rsquo;architecture encodeur-d\u00e9codeur n&rsquo;a pas disparu pour autant : elle sert de nombreux mod\u00e8les d&rsquo;autres modalit\u00e9s. Whisper, populaire pour la transcription audio, emploie un encodeur pour traiter le son et un d\u00e9codeur pour g\u00e9n\u00e9rer les jetons de texte.<\/p>\n<p>C\u00f4t\u00e9 <a href=\"\/blog\/rag\/que-sont-les-embeddings\/\" title=\"embeddings\">embeddings<\/a>, le paysage se divise en deux. D&rsquo;un c\u00f4t\u00e9, des mod\u00e8les b\u00e2tis comme BERT, sous le milliard de param\u00e8tres ; de l&rsquo;autre, des mod\u00e8les d\u00e9riv\u00e9s de grands mod\u00e8les de langage, qui montent jusqu&rsquo;\u00e0 huit milliards et affichent des capacit\u00e9s nettement sup\u00e9rieures.<\/p>\n<h2 id=\"quatre-idees-recues-sur-bert\">Quatre id\u00e9es re\u00e7ues sur BERT<\/h2>\n<h3>\u00ab Il comprend si bien qu&rsquo;il r\u00e9dige aussi bien \u00bb<\/h3>\n<p>Non : un encodeur dress\u00e9 par masquage se pr\u00eate mal \u00e0 la g\u00e9n\u00e9ration, contrairement aux d\u00e9codeurs. Lire dans les deux sens et \u00e9crire de gauche \u00e0 droite sont deux m\u00e9tiers diff\u00e9rents.<\/p>\n<h3>\u00ab Il lit n&rsquo;importe quel document en entier \u00bb<\/h3>\n<p>Sa fen\u00eatre est de 512 jetons, question comprise. Au-del\u00e0, il faut d\u00e9couper les documents en fragments avant de les lui pr\u00e9senter.<\/p>\n<h3>\u00ab Il apprend sur tout le texte \u00e0 chaque passage \u00bb<\/h3>\n<p>Pas tout \u00e0 fait : avec le masquage, <strong>seuls 15 % des jetons<\/strong> nourrissent l&rsquo;apprentissage. C&rsquo;est le prix \u00e0 payer pour que le mod\u00e8le voie les deux c\u00f4t\u00e9s du trou.<\/p>\n<h3>\u00ab Puisqu&rsquo;il est devenu rare, il ne sert plus \u00e0 rien \u00bb<\/h3>\n<p>Ce serait aller trop vite. Les mod\u00e8les de type BERT servent encore \u00e0 des t\u00e2ches simples et sensibles \u00e0 la latence, comme la classification, l\u00e0 o\u00f9 la rapidit\u00e9 de r\u00e9ponse compte.<\/p>\n<blockquote>\n<p><strong>\u26a0\ufe0f Pi\u00e8ge<\/strong> \u00ab Bidirectionnel \u00bb ne veut pas dire \u00ab meilleur partout \u00bb. C&rsquo;est un outil pour comprendre un texte d\u00e9j\u00e0 \u00e9crit : pour en produire un, on prend l&rsquo;architecture inverse.<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>BERT lit chaque mot avec ce qui le pr\u00e9c\u00e8de et ce qui le suit. Son nom d\u00e9cod\u00e9, son entra\u00eenement \u00e0 trous, ses usages en recherche de documents et ses limites.<\/p>\n","protected":false},"author":1,"featured_media":662,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-663","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deep-learning"],"_links":{"self":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/663","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/comments?post=663"}],"version-history":[{"count":3,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/663\/revisions"}],"predecessor-version":[{"id":782,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/663\/revisions\/782"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media\/662"}],"wp:attachment":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media?parent=663"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/categories?post=663"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/tags?post=663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}