Esplorare ChatGPT rispetto ai modelli open source su attività leggermente più difficili

May 13 2023
Gli LLM open source come Vicuna e MPT-7B-Chat stanno spuntando ovunque, il che ha portato a molte discussioni su come questi modelli si confrontano con gli LLM commerciali (come ChatGPT o Bard). La maggior parte del confronto è stata sulle risposte a semplici domande/istruzioni a un giro.
Tutte le immagini sono state generate da Marco e Scott.

Gli LLM open source come Vicuna e MPT-7B-Chat stanno spuntando ovunque, il che ha portato a molte discussioni su come questi modelli si confrontano con gli LLM commerciali (come ChatGPT o Bard).

La maggior parte del confronto è stata sulle risposte a semplici domande/istruzioni a un giro. Ad esempio, i ragazzi di LMSYSOrg hanno svolto un'analisi interessante (+1 per essere automatizzati e riproducibili) confrontando Vicuna-13B con ChatGPT su varie brevi domande, il che è ottimo come confronto tra i modelli come semplici chatbot. Tuttavia, molti modi interessanti di utilizzare gli LLM in genere richiedono istruzioni complesse e/o conversazioni a più turni e un po' di ingegneria tempestiva. Riteniamo che nel "mondo reale", la maggior parte delle persone vorrà confrontare diverse offerte LLM sul proprio problema, con una varietà di suggerimenti diversi.

Questo post sul blog (scritto insieme a Scott Lundberg ) è un esempio di come potrebbe essere una tale esplorazione con guidance, un progetto open source che aiuta gli utenti a controllare gli LLM. Confrontiamo due modelli open source (Vicuna-13B, MPT-7b-Chat) con ChatGPT (3.5) su attività di varia complessità.

Riscaldamento: risoluzione di equazioni

A titolo di riscaldamento, iniziamo con il compito giocattolo di risolvere semplici equazioni polinomiali, in cui possiamo verificare la correttezza dell'output e non dovrebbe essere necessario un intervento ingegneristico molto rapido. Questo sarà simile alla categoria Matematica qui , con la differenza che valutiamo i modelli come corretti/errati sulla base della verità, piuttosto che utilizzare GPT-4 per valutare l'output.

Breve digressione sulla sintassi della chat : ciascuno di questi modelli ha la propria sintassi della chat, con token speciali che separano le espressioni. Ecco come apparirebbe la stessa conversazione in Vicuna e MPT (dove [generated response]è dove il modello genererebbe il suo output):

Vigogna:

A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.  
USER: Can you please solve the following equation? x^2 + 2x + 1 = 0  
ASSISTANT: [generated response] </s>

<|im_start|>system
- You are a helpful assistant chatbot trained by MosaicML.  
- You answer questions.
- You are excited to be able to help the user, but will refuse to do anything that could be considered harmful to the user.
- You are more than just an information source, you are also able to write poetry, short stories, and make jokes.
<|im_end|>
<|im_start|>user Can you please solve the following equation? x^2 + 2x + 1 = 0<|im_end|>
<|im_start|>assistant [generated response]<|im_end|>

find_roots = guidance('''
{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
Please find the roots of the following equation: {{equation}}
Think step by step, find the roots, and then say:
ROOTS = [root1, root2...]
For example, if the roots are 1.3 and 2.2, say ROOTS = [1.3, 2.2].
Make sure to use real numbers, not fractions.
{{~/user}}

{{#assistant~}}
{{gen 'answer'}}
{{~/assistant~}}''')

import guidance

mpt = guidance.llms.transformers.MPTChat('mosaicml/mpt-7b-chat', device=1)
vicuna = guidance.llms.transformers.Vicuna('yourpath/vicuna-13b', device_map='auto')
chatgpt = guidance.llms.OpenAI("gpt-3.5-turbo")

equation = 'x^2 + 3.0x = 0'
roots = [0, -3]
answer_gpt = find_roots(llm=chatgpt, equation=equation)

      
                

answer_vicuna = find_roots(llm=vicuna, equation=equation)

      
                

answer_mpt = find_roots(llm=mpt, equation=equation)

      
                

Nel taccuino che accompagna questo post, scriviamo una funzione per generare equazioni quadratiche casuali con radici intere comprese tra -20 e 20 ed eseguiamo il prompt 20 volte con ciascun modello. I risultati sono stati i seguenti:

╔═══════════╦══════════╦
║   Model   ║ Accuracy ║     
╠═══════════╬══════════╬
║ ChatGPT   ║   80%    ║
║ Vicuna    ║    0%    ║ 
║ MPT       ║    0%    ║
╚═══════════╩══════════╩

ChatGPT commette un errore di calcolo nell'ultimo passaggio, dove (13 +- 25) /2dovrebbe restituire [19, -6]anziché [19.5, -6.5].
Ora, poiché Vicuna e MPT hanno fallito con le equazioni quadratiche, esaminiamo anche equazioni più semplici, come x - 10 = 0. Per queste equazioni, otteniamo questi numeri:

╔═══════════╦══════════╦
║   Model   ║ Accuracy ║     
╠═══════════╬══════════╬
║ ChatGPT   ║   100%   ║
║ Vicuna    ║    85%   ║ 
║ MPT       ║    30%   ║
╚═══════════╩══════════╩

Discussione

Questa è stata un'attività molto giocattolo, ma è servita come esempio di come confrontare modelli con sintassi di chat diversa utilizzando lo stesso prompt. Per questa particolare combinazione attività / richiesta, ChatGPT supera di gran lunga Vicuna e MPT in termini di accuratezza (misurata sulla base della verità).

Attività: estrazione di frammenti + risposta alle domande sulle riunioni

Passiamo ora a un compito più realistico, in cui valutare l'accuratezza non è così semplice. Diciamo che vogliamo che il nostro LLM risponda alle domande (con i relativi segmenti di conversazione per il grounding) sulle trascrizioni delle riunioni.
Questa è un'applicazione in cui alcuni utenti potrebbero preferire utilizzare LLM open source piuttosto che commerciali, per motivi di privacy (ad esempio, alcune aziende potrebbero non voler inviare i dati delle proprie riunioni a OpenAI).

Ecco una trascrizione di una riunione di giocattoli per iniziare:

Trascrizione della riunione:
John
: Bene, siamo tutti qui per discutere dell'offerta che abbiamo ricevuto da Microsoft per l'acquisto della nostra startup. Quali sono i tuoi pensieri su questo?
Lucy : Beh, penso che sia una grande opportunità per noi. Microsoft è una grande azienda con molte risorse e potrebbe davvero aiutarci a portare il nostro prodotto al livello successivo.
Steven : Sono d'accordo con Lucy. Microsoft ha molta esperienza nel settore tecnologico e potrebbe fornirci il supporto di cui abbiamo bisogno per far crescere la nostra attività.
John : Capisco il tuo punto di vista, ma sono un po' titubante nel vendere la nostra startup. Abbiamo dedicato molto tempo e impegno alla costruzione di questa azienda e non sono sicuro di essere ancora pronto a lasciarla andare.
Lucia: Capisco da dove vieni, John, ma dobbiamo pensare al futuro della nostra azienda. Se vendiamo a Microsoft, avremo accesso alle loro risorse e competenze, che potrebbero aiutarci a far crescere ancora di più la nostra attività.
Steven : Giusto, e non dimentichiamoci dei benefici finanziari. Microsoft ci sta offrendo molti soldi per la nostra startup, che potrebbero aiutarci a investire in nuovi progetti e ad espandere il nostro team.
John : Capisco il tuo punto di vista, ma ho ancora delle riserve. Cosa succede se Microsoft cambia il nostro prodotto o la nostra cultura aziendale? E se perdiamo il controllo sulla nostra attività?
Steven : Sai una cosa, non ci avevo pensato prima, ma forse John ha ragione. Sarebbe un peccato se la nostra cultura cambiasse.
Lucia: Queste sono preoccupazioni valide, ma possiamo negoziare i termini dell'accordo per assicurarci di mantenere un certo controllo sulla nostra azienda. E per quanto riguarda il prodotto e la cultura, possiamo lavorare con Microsoft per assicurarci che la nostra visione sia ancora intatta.
John : Ma non cambieremo solo in virtù dell'essere assorbiti in una grande azienda? Voglio dire, siamo una piccola startup con una cultura molto specifica. Microsoft è una grande azienda con una cultura molto diversa. Non sono sicuro che i due possano coesistere.
Steven : Ma John, non abbiamo sempre pensato di essere acquisiti? Non sarà un problema ogni volta?
Lucy : Giusto
John : Non voglio perdere quello che abbiamo costruito qui.
Steven : Anch'io condivido questa preoccupazione

Cominciamo semplicemente cercando di ottenere ChatGPT per risolvere il compito per noi. Verificheremo la domanda "Come si sente Steven riguardo alla vendita?". Ecco un primo tentativo di prompt

qa_attempt1 = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
You will read a meeting transcript, then extract the relevant segments to answer the following question:
Question: {{query}}
Here is a meeting transcript:
----
{{transcript}}
----
Please answer the following question:
Question: {{query}}
Extract from the transcript the most relevant segments for the answer, and then answer the question.
{{/user}}

{{#assistant~}}
{{gen 'answer'}}
{{~/assistant~}}''')

      
                

qa_attempt3 = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
You will read a meeting transcript, then extract the relevant segments to answer the following question:
Question: {{query}}
Here is a meeting transcript:
----
{{transcript}}
----
Based on the above, please answer the following question:
Question: {{query}}
Please extract from the transcript whichever conversation segments are most relevant for the answer, and then answer the question.
Note that conversation segments can be of any length, e.g. including multiple conversation turns.
Please extract at most 3 segments. If you need less than three segments, you can leave the rest blank.

As an example of output format, here is a fictitious answer to a question about another meeting transcript.
CONVERSATION SEGMENTS:
Segment 1: Peter and John discuss the weather.
Peter: John, how is the weather today?
John: It's raining.
Segment 2: Peter insults John
Peter: John, you are a bad person.
Segment 3: Blank
ANSWER: Peter and John discussed the weather and Peter insulted John.
{{/user}}

{{#assistant~}}
{{gen 'answer'}}
{{~/assistant~}}''')

      
                

qa_attempt5 = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
You will read a meeting transcript, then extract the relevant segments to answer the following question:
Question: What were the main things that happened in the meeting?
Here is a meeting transcript:
----
Peter: Hey
John: Hey
Peter: John, how is the weather today?
John: It's raining.
Peter: That's too bad. I was hoping to go for a walk later.
John: Yeah, it's a shame.
Peter: John, you are a bad person.
----
Based on the above, please answer the following question:
Question: {{query}}
Please extract from the transcript whichever conversation segments are most relevant for the answer, and then answer the question.
Note that conversation segments can be of any length, e.g. including multiple conversation turns.
Please extract at most 3 segments. If you need less than three segments, you can leave the rest blank.
{{/user}}
{{#assistant~}}
CONVERSATION SEGMENTS:
Segment 1: Peter and John discuss the weather.
Peter: John, how is the weather today?
John: It's raining.
Segment 2: Peter insults John
Peter: John, you are a bad person.
Segment 3: Blank
ANSWER: Peter and John discussed the weather and Peter insulted John.
{{~/assistant~}}
{{#user~}}
You will read a meeting transcript, then extract the relevant segments to answer the following question:
Question: {{query}}
Here is a meeting transcript:
----
{{transcript}}
----
Based on the above, please answer the following question:
Question: {{query}}
Please extract from the transcript whichever conversation segments are most relevant for the answer, and then answer the question.
Note that conversation segments can be of any length, e.g. including multiple conversation turns.
Please extract at most 3 segments. If you need less than three segments, you can leave the rest blank.
{{~/user}}

{{#assistant~}}
{{gen 'answer'}}
{{~/assistant~}}''')
qa_attempt5(llm=chatgpt, transcript=meeting_transcript, query=query1)

      
                

qa_guided = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
You will read a meeting transcript, then extract the relevant segments to answer the following question:
Question: {{query}}
----
{{transcript}}
----
Based on the above, please answer the following question:
Question: {{query}}
Please extract the three segment from the transcript that are the most relevant for the answer, and then answer the question.
Note that conversation segments can be of any length, e.g. including multiple conversation turns. If you need less than three segments, you can leave the rest blank.

As an example of output format, here is a fictitious answer to a question about another meeting transcript:
CONVERSATION SEGMENTS:
Segment 1: Peter and John discuss the weather.
Peter: John, how is the weather today?
John: It's raining.
Segment 2: Peter insults John
Peter: John, you are a bad person.
Segment 3: Blank
ANSWER: Peter and John discussed the weather and Peter insulted John.
{{/user}}

{{#assistant~}}
CONVERSATION SEGMENTS:
Segment 1: {{gen 'segment1'}}
Segment 2: {{gen 'segment2'}}
Segment 3: {{gen 'segment3'}}
ANSWER: {{gen 'answer'}}
{{~/assistant~}}''')

Possiamo, ovviamente, eseguire lo stesso prompt con MPT:

Mentre MPT segue il formato, ignora la domanda e prende frammenti dall'esempio di formato piuttosto che dalla vera trascrizione.
D'ora in poi, confronteremo solo ChatGPT e Vicuna.

Proviamo con un'altra domanda: "Chi vuole vendere l'azienda?"

Ecco ChatGPT:

Vigogna:

Entrambi sembrano funzionare davvero bene. Spostiamo la trascrizione della riunione ai primi minuti di un'intervista con Elon Musk. La parte rilevante per la domanda che faremo è

Elon Musk : Allora dico, signore, che lei non sa di cosa sta parlando.
Intervistatore : Davvero?
Elon Musk : Sì. Perché non puoi fornire un solo esempio di contenuto odioso. Nemmeno un tweet. Eppure hai affermato che il contenuto odioso era alto. È falso.
Intervistatore : No. Quello che ho affermato-
Elon Musk : Hai appena mentito.

Quindi poniamo la seguente domanda:
"Elon Musk insulta l'intervistatore?"

Chat GPT:

Vigogna:

Vicuna, ha il formato giusto e anche i segmenti giusti, ma genera sorprendentemente una risposta completamente sbagliata, quando dice “Elon musk non lo accusa di mentire né lo insulta in alcun modo”.

Abbiamo provato una varietà di altre domande e conversazioni e lo schema generale era che Vicuna era paragonabile a ChatGPT sulla maggior parte delle domande, ma sbagliava la risposta più spesso di ChatGPT.

Compito: fare cose con bash

Ora proviamo a fare in modo che questi LLM utilizzino in modo iterativo una shell bash per risolvere i singoli problemi. Ogni volta che emettono un comando, lo eseguiamo e reinseriamo l'output nel prompt, finché l'attività non viene risolta.

Ecco il prompt di ChatGPT (si noti che shell this.commandchiama una funzione definita dall'utente con this.commandcome argomento):

terminal = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
Please complete the following task:
Task: list the files in the current directory
You can give me one bash command to run at a time, using the syntax:
COMMAND: command
I will run the commands on my terminal, and paste the output back to you. Once you are done with the task, please type DONE.
{{/user}}

{{#assistant~}}
COMMAND: ls
{{~/assistant~}}

{{#user~}}
Output: guidance project
{{/user}}

{{#assistant~}}
The files or folders in the current directory are:
- guidance
- project
DONE
{{~/assistant~}}

{{#user~}}
Please complete the following task:
Task: {{task}}
You can give me one bash command to run at a time, using the syntax:
COMMAND: command
I will run the commands on my terminal, and paste the output back to you. Once you are done with the task, please type DONE.
{{/user}}

{{#geneach 'commands' stop=False}}
{{#assistant~}}
{{gen 'this.command'}}
{{~/assistant~}}

{{~#user~}}
Output: {{shell this.command)}}
{{~/user~}}
{{/geneach}}''')

In effetti, ChatGPT segue una sequenza molto naturale e risolve il compito. Non segue la nostra istruzione per dire FATTO, ma siamo in grado di interrompere automaticamente l'iterazione perché non emette alcun COMANDO.

Per i modelli open source, scriviamo un prompt (guidato) più semplice in cui è presente una sequenza di output di comando:

guided_terminal = guidance('''{{#system~}}
{{llm.default_system_prompt}}
{{~/system}}

{{#user~}}
Please complete the following task:
Task: list the files in the current directory
You can run bash commands using the syntax:
COMMAND: command
OUTPUT: output
Once you are done with the task, use the COMMAND: DONE.
{{/user}}

{{#assistant~}}
COMMAND: ls
OUTPUT: guidance project
COMMAND: DONE 
{{~/assistant~}}

{{#user~}}
Please complete the following task:
Task: {{task}}
You can run bash commands using the syntax:
COMMAND: command
OUTPUT: output
Once you are done with the task, use the COMMAND: DONE.
{{~/user}}

{{#assistant~}}
{{#geneach 'commands' stop=False ~}}
COMMAND: {{gen 'this.command' stop='\\n'}}
OUTPUT: {{shell this.command)}}{{~/geneach}}
{{~/assistant~}}''')

Ecco MPT:

In un'interessante svolta degli eventi, Vicuna non è in grado di risolvere il compito, ma MPT riesce. Oltre alla privacy (non stiamo inviando la trascrizione della sessione a OpenAI), i modelli open source hanno un vantaggio significativo qui: l'intero prompt è una singola esecuzione LLM (e lo acceleriamo persino non facendogli generare i token della struttura di output come COMMAND:) .
Al contrario, dobbiamo effettuare una nuova chiamata a ChatGPT per ogni comando, che è più lento e più costoso.

Ora proviamo un comando diverso: "Trova tutti i file jupyter notebook in ~/work/guidance attualmente non tracciati da git".

Ecco ChatGPT:

Ancora una volta, ci imbattiamo in un problema con ChatGPT che non segue la nostra struttura di output specificata (rendendoci quindi impossibile l'utilizzo all'interno di un programma, senza un essere umano nel ciclo). Il nostro programma ha appena eseguito i comandi e quindi si è fermato dopo l'ultimo messaggio ChatGPT sopra.

Sospettavamo che l'output vuoto avesse disattivato ChatGPT, quindi abbiamo risolto questo particolare problema modificando il messaggio quando non c'è output. Tuttavia, non possiamo risolvere il problema generale di non essere in grado di forzare ChatGPT a seguire la nostra struttura di output specificata.

ChatGPT è riuscito a risolvere il problema dopo questa piccola modifica. Vediamo come fa Vicuna:

Vicuna segue la nostra struttura di output, ma sfortunatamente esegue il comando sbagliato per eseguire l'operazione. MPT (non mostrato) chiama git status ripetutamente, quindi anche questo fallisce.

Abbiamo eseguito questi programmi per varie altre istruzioni e abbiamo scoperto che ChatGPT produce quasi sempre la corretta sequenza di comandi, mentre a volte non segue il formato specificato (e quindi necessita dell'intervento umano). I modelli open source non hanno funzionato così bene (probabilmente possiamo migliorarli con un'ingegneria più rapida, ma hanno fallito con le istruzioni più difficili).

Asporto

Oltre agli esempi precedenti, abbiamo provato vari input per entrambi i compiti (risposta alle domande e bash). Abbiamo anche provato una serie di altre attività che coinvolgono il riepilogo, la risposta a domande, la generazione "creativa" e attività di manipolazione di stringhe di giocattoli in cui possiamo valutare automaticamente l'accuratezza.
Ecco una sintesi dei nostri risultati:

  • Qualità sull'attività : per ogni attività che abbiamo provato, ChatGPT (3.5) è ancora più forte di Vicuna sull'attività stessa. MPT si è comportato male su quasi tutte le attività (forse lo stiamo usando male?), mentre Vicuna era spesso vicino a ChatGPT (a volte molto vicino, a volte molto peggio come nell'ultimo compito di esempio sopra).
  • Facilità d'uso : è molto più doloroso far sì che ChatGPT segua un formato di output specificato, e quindi è più difficile usarlo all'interno di un programma (senza un essere umano nel ciclo). Inoltre, dobbiamo sempre scrivere parser regex per l'output (al contrario di Vicuna, dove l'analisi di un prompt con una sintassi chiara è banale).
    In genere siamo in grado di risolvere il problema della struttura aggiungendo più esempi di poche riprese, ma è noioso scriverli e talvolta ChatGPT va comunque fuori copione. Finiamo anche con suggerimenti più lunghi, goffi e brutti, il che è insoddisfacente.
    Essere in grado di specificare la struttura dell'output è un vantaggio significativo dei modelli open source, al punto che a volte potremmo preferire Vicuna a ChatGPT anche quando è un po' peggio per il compito stesso.
  • Efficienza : avere il modello localmente significa che possiamo risolvere le attività in una singola esecuzione LLM ( guidancemantiene lo stato LLM mentre il programma è in esecuzione), che è più veloce ed economico. Ciò è particolarmente vero quando qualsiasi passaggio secondario comporta la chiamata di altre API o funzioni (ad es. ricerca, terminale, ecc.), che richiede sempre una nuova chiamata all'API OpenAI. guidanceaccelera anche la generazione non facendo in modo che il modello generi i token della struttura di output, il che a volte fa una grande differenza.

Dovremmo riconoscere che siamo prevenuti per aver utilizzato molto i modelli OpenAI negli ultimi anni, aver scritto vari documenti che dipendono da GPT-3 (ad esempio qui , qui ) e un documento che sostanzialmente dice "GPT-4 è fantastico , ecco un mucchio di begli esempi”.
A proposito, mentre Vicuna è in qualche modo paragonabile a ChatGPT (3.5), riteniamo che GPT-4 sia un modello molto più forte e siamo entusiasti di vedere se i modelli open source possono avvicinarsi a questo . Sebbene guidancefunzioni abbastanza bene con i modelli OpenAI, brilla davvero quando puoi specificare la struttura di output e accelerare la generazione.

Ancora una volta, siamo chiaramente di parte, ma pensiamo che guidancesia un ottimo modo per utilizzare questi modelli, sia con le API (OpenAI, Azure) che localmente (huggingface). Ecco un collegamento al taccuino jupyter con il codice per tutti gli esempi sopra (e altro).

Disclaimer : questo post è stato scritto congiuntamente da Marco Tulio Ribeiro e Scott Lundberg. Rappresenta rigorosamente le nostre opinioni personali e non quelle del nostro datore di lavoro (Microsoft).

Ringraziamenti: siamo davvero grati a Harsha Nori per i commenti penetranti su questo post