L’auto-cohérence (self-consistency) est peut-être l’une des techniques les plus avancées pour une ingénierie rapide. Proposé par Wang et al. (2022), l’autocohérence vise « à remplacer le décodage naïf et gourmand utilisé dans l’incitation à la chaîne de pensée ». L’idée est d’échantillonner plusieurs chemins de raisonnement divers à travers un CoT en quelques coups et d’utiliser les générations pour sélectionner la réponse la plus cohérente. Cela contribue à améliorer les performances des invites CoT sur les tâches impliquant un raisonnement arithmétique et de bon sens.

Pour les tâches de raisonnement complexes comportant plusieurs chemins valides, l’auto-cohérence génère diverses chaînes de raisonnement par échantillonnage à partir du décodeur du modèle de langage. Il identifie ensuite la réponse finale la plus cohérente en marginalisant ces chaînes échantillonnées. Cette approche capitalise sur l’observation selon laquelle les problèmes nécessitant une analyse réfléchie entraînent souvent une plus grande diversité de raisonnement, conduisant à une solution.

La combinaison de l’auto-cohérence et de la chaîne de pensée entraîne des améliorations significatives de la précision sur divers benchmarks, tels que 17,9 % sur GSM8K, 11,0 % sur SVAMP, 12,2 % sur AQuA, 6,4 % sur StrategyQA et 3 à 9 % sur Défi ARC par rapport à l’incitation à la chaîne de pensée de base.

self-consistency

Plusieurs réponses pour faire un cas général

L’auto-cohérence est une approche qui demande simplement à un modèle la même invite plusieurs fois et prend le résultat majoritaire comme réponse finale. Il s’agit d’un suivi des invites CoT et est plus puissant lorsqu’il est utilisé conjointement avec celui-ci.

Prenons un exemple simple d’analyse d’e-mails. Supposons que vous soyez un éditeur de logiciels et que vous recevez des centaines d’e-mails par jour. Vous souhaitez utiliser un modèle pour classer les e-mails comme importants ou non, afin de pouvoir prioriser ceux qui peuvent avoir un impact majeur sur votre entreprise.

Voici un exemple d’e-mail que vous pourriez recevoir. Mettons cela dans une invite :

self consistency prompting

self consistency prompting

En générant de nombreuses chaînes de pensée et en prenant la réponse la plus courante (IMPORTANTE), nous pouvons obtenir une réponse correcte de manière plus cohérente.

Il a été démontré que l’autocohérence améliore les résultats dans les tâches d’arithmétique, de bon sens et de raisonnement symbolique. Même lorsque le CoT régulier s’avérait inefficace, l’auto-cohérence restait en mesure d’améliorer les résultats.

Code pour le Self-Consistency

Voici un récap du fonctionnement :

self consistency prompting

Pour utiliser l’autocohérence, il est recommandé d’utiliser un script car les LLM avec interface ne permettent pas cette option. Vous trouverez le code Python pour utiliser l’autocohérence :

import logging
from typing import List, Dict
from difflib import SequenceMatcher

logger = logging.getLogger(__name__)

class AdvancedSelfConsistency:
    def __init__(self, client, model: str,  num_samples: int = 5, similarity_threshold: float = 0.8):
        self.client = client
        self.model = model
        self.num_samples = num_samples
        self.similarity_threshold = similarity_threshold
        self.self_consistency_completion_tokens = 0

    def generate_responses(self, system_prompt: str, user_prompt: str) -> List[str]:
        responses = []
        for _ in range(self.num_samples):
            response = self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {"role": "system", "content": system_prompt},
                    {"role": "user", "content": user_prompt}
                ],
                temperature=1,
                max_tokens=4096
            )
            self.self_consistency_completion_tokens += response.usage.completion_tokens
            responses.append(response.choices[0].message.content)
        return responses

    def calculate_similarity(self, a: str, b: str) -> float:
        return SequenceMatcher(None, a, b).ratio()

    def cluster_similar_responses(self, responses: List[str]) -> List[List[str]]:
        clusters = []
        for response in responses:
            added_to_cluster = False
            for cluster in clusters:
                if self.calculate_similarity(response, cluster[0]) >= self.similarity_threshold:
                    cluster.append(response)
                    added_to_cluster = True
                    break
            if not added_to_cluster:
                clusters.append([response])
        return clusters

    def aggregate_results(self, responses: List[str]) -> Dict[str, any]:
        final_answers = responses
        clusters = self.cluster_similar_responses(final_answers)
        
        cluster_info = []
        for cluster in clusters:
            cluster_info.append({
                "answer": cluster[0],
                "frequency": len(cluster),
                "variants": cluster
            })
        
        cluster_info.sort(key=lambda x: x['frequency'], reverse=True)
        
        return {
            "clusters": cluster_info,
            "total_responses": len(responses),
            "num_unique_clusters": len(clusters)
        }

    def evaluate(self, system_prompt: str, user_prompt: str) -> Dict[str, any]:
        responses = self.generate_responses(system_prompt, user_prompt)
        aggregated_result = self.aggregate_results(responses)
        
        return {
            "individual_responses": responses,
            "aggregated_result": aggregated_result
        }

def advanced_self_consistency_approach(system_prompt: str, initial_query: str, client, model: str) -> str:
    self_consistency = AdvancedSelfConsistency(client, model)
    result = self_consistency.evaluate(system_prompt, initial_query)
    
    logger.info("Advanced Self-Consistency Results:")
    logger.info(f"Total responses: {result['aggregated_result']['total_responses']}")
    logger.info(f"Number of unique clusters: {result['aggregated_result']['num_unique_clusters']}")
    for i, cluster in enumerate(result['aggregated_result']['clusters'], 1):
        logger.debug(f"\nCluster {i}:")
        logger.debug(f"  Representative answer: {cluster['answer']}")
        logger.debug(f"  Frequency: {cluster['frequency']}")
        logger.debug(f"  Variants: {cluster['variants']}")
    
    if result['aggregated_result']['clusters']:
        return result['aggregated_result']['clusters'][0]['answer'], self_consistency.self_consistency_completion_tokens
    else:
        return "No consistent answer found.", self_consistency.self_consistency_completion_tokens

Self-consistency sur multiLLM

Étant donné une chaîne de réflexion, plusieurs LLM peuvent être utilisés pour assurer la cohérence entre les différents LLM, améliorant ainsi la précision du résultat final. Initialement, la même chaîne de réflexion est transmise à plusieurs LLM différents (GPT4, PaLM2, etc.). Ensuite, le quorum est déterminé, dans cet exemple via GPT4 en tant qu’évaluateur de quorum, mais peut être programmé à l’aide d’autres méthodologies.

self consistency prompting

Le code est disponible sur ce GitHub.

Self-consistency meilleure pratique

La méthode d’auto-cohérence comprend trois étapes. Tout d’abord, incitez un modèle de langage à l’aide de l’invite CoT, puis remplacez le « décodage gourmand » (1-Best) dans l’invite CoT par un échantillonnage à partir du décodeur du modèle de langage pour générer un ensemble diversifié de chemins de raisonnement, et enfin, marginalisez les chemins de raisonnement et agréger en choisissant la réponse la plus cohérente dans l’ensemble de réponses final.

Il est à noter que l’autocohérence peut être harmonieusement intégrée à la plupart des algorithmes d’échantillonnage, y compris, sans toutefois s’y limiter, l’échantillonnage de température, l’échantillonnage top-k et l’échantillonnage de noyau.

Néanmoins, une telle opération peut nécessiter l’invocation de l’API du modèle pour affiner ces hyperparamètres. À la lumière de cela, une approche alternative pourrait consister à permettre au modèle de générer des résultats en utilisant diverses voies de raisonnement, puis à générer un ensemble diversifié de voies de raisonnement candidates.

La réponse démontrant le plus haut degré de cohérence entre les différentes trajectoires de raisonnement est alors plus encline à représenter la solution exacte. L’auto-cohérence améliore les résultats dans les tâches de raisonnement arithmétique, de bon sens et symbolique. De plus, en pratique, l’autocohérence peut être combinée avec d’autres techniques pour améliorer encore les performances du modèle. Il a été constaté que la combinaison de l’autocohérence avec une approche de raisonnement en plusieurs étapes guidée par un discriminateur améliorait considérablement les capacités de raisonnement du modèle.

fr_FRFR