Cette solution a été développée pour le concours LMSYS - Chatbot Arena Human Preference Predictions sur Kaggle, où les participants ont été mis au défi de prédire les préférences des utilisateurs dans des conversations en tête-à-tête entre chatbots alimentés par de grands modèles de langage (LLM). La tâche impliquait l'utilisation d'un ensemble de données de Chatbot Arena , dans lequel les utilisateurs interagissent avec deux LLM anonymes et choisissent leur réponse préférée. En créant un modèle d'apprentissage automatique qui prédit avec précision ces préférences, nous visions à contribuer à améliorer l'alignement des réponses des chatbots sur les préférences humaines.
Notre équipe s'est classée 4e sur 1 849 équipes , remportant une médaille d'or pour notre solution et un prix de 20 000 $ ! ?
Tout d'abord, nous avons utilisé l'ensemble de données officiel (55 000) ainsi que 33 000 données dédupliquées, en utilisant une validation croisée 20 fois (n_splits = 20), mais nous nous sommes entraînés uniquement sur un seul pli pour maximiser la quantité de données d'entraînement. De plus, nous avons créé des pseudo-étiquettes pour 30 000 entrées de l’ensemble de données ultrafeedback afin de compléter davantage l’ensemble de données.
Nous avons conçu une invite unique, ce qui est bénéfique car lorsque la longueur du dialogue dépasse la longueur maximale du jeton ( max_length
), elle permet une troncature raisonnable du dernier tour de conversation. Cela garantit que l'invite, la réponse A et la réponse B peuvent toutes être affichées de manière adéquate, évitant ainsi les situations dans lesquelles seule l'invite ou la réponse A est tronquée. Si le nombre de jetons restants lors du tour final est inférieur à 80, le tour de conversation entier (et les suivants) sera rejeté. Ces seuils et proportions ont été déterminés par l'observation de l'ensemble de formation.
def tokenize_cls_p3 ( example , tokenizer , max_length , is_train ):
input_ids = []
attention_mask = []
dot_tokens = tokenizer ( "......" , add_special_tokens = False )[ "input_ids" ]
final_p_tokens = tokenizer ( " n n --- n Which response is better? [A or B or tie] n Answer: " , add_special_tokens = False )[ "input_ids" ]
for ps , ras , rbs in zip ( example [ 'prompt' ], example [ 'response_a' ], example [ 'response_b' ]):
one_input_ids = [ tokenizer . bos_token_id ]
prev_tokens_num = 2 + len ( final_p_tokens ) # 2 for bos_token and eos_token
for idx , ( p , ra , rb ) in enumerate ( zip ( ps , ras , rbs )):
r_tokens = tokenizer ( f' n n ## Round { idx + 1 } :' if idx else f'## Round { idx + 1 } :' , add_special_tokens = False )[ "input_ids" ]
p_tokens = tokenizer ( f' n ### Prompt: n { p } ' , add_special_tokens = False )[ "input_ids" ]
ra_tokens = tokenizer ( f' n n ### Response A: n { ra } ' , add_special_tokens = False )[ "input_ids" ]
rb_tokens = tokenizer ( f' n n ### Response B: n { rb } ' , add_special_tokens = False )[ "input_ids" ]
all_tokens_num = prev_tokens_num + len ( r_tokens ) + len ( p_tokens ) + len ( ra_tokens ) + len ( rb_tokens
if all_tokens_num > max_length :
remain_tokens_num = max_length - prev_tokens_num - len ( r_tokens ) - 3 * len ( dot_tokens )
if remain_tokens_num >= 80 :
p_tokens = p_tokens [: int ( remain_tokens_num * 0.2 )] + dot_tokens if len ( p_tokens ) > int ( remain_tokens_num * 0.2 ) else p_tokens
ra_tokens = ra_tokens [: int ( remain_tokens_num * 0.4 )] + dot_tokens if len ( ra_tokens ) > int ( remain_tokens_num * 0.4 ) else ra_tokens
rb_tokens = rb_tokens [: int ( remain_tokens_num * 0.4 )] + dot_tokens if len ( rb_tokens ) > int ( remain_tokens_num * 0.4 ) else rb_tokens
one_input_ids += r_tokens + p_tokens + ra_tokens + rb_tokens
break
else :
prev_tokens_num = all_tokens_num
one_input_ids += r_tokens + p_tokens + ra_tokens + rb_tokens
one_input_ids += final_p_tokens + [ tokenizer . eos_token_id ]
one_attention_mask = [ 1 ] * len ( one_input_ids )
input_ids . append ( one_input_ids )
attention_mask . append ( one_attention_mask )
if is_train :
labels = [ 0 if a_win else 1 if b_win else 2 for a_win , b_win , tie in zip ( example [ 'winner_model_a' ], example [ 'winner_model_b' ], example [ 'winner_tie' ])]
return {
"input_ids" : input_ids ,
"attention_mask" : attention_mask ,
"labels" : labels ,
}
else :
return {
"input_ids" : input_ids ,
"attention_mask" : attention_mask ,
}
Nous avons sélectionné gemma-2-9b-it comme modèle de départ, qui surpasse considérablement d'autres modèles tels que Llama3 8b et Llama3.1 8b . Nous avons utilisé Gemma2ForSequenceClassification pour une tâche de classification en trois classes et affiné le modèle à l'aide de lora avec une précision bf16 . Les meilleurs résultats expérimentaux ont été obtenus sur quatre GPU A100.
Chaque expérience a duré environ 10 heures pour la première phase et 15 heures pour la deuxième phase sur un système doté de 4 GPU A100 (40G).
La phase d'inférence utilise une structure de code similaire à celle de la phase de formation, avec quelques différences clés : la max_length
est augmentée à 3 072, et réponse_a et réponse_b sont échangées dans le cadre d'une stratégie d'augmentation du temps de test (TTA). Le résultat final est le rendement moyen des deux.
Le post-traitement a été appliqué pour deux scénarios spécifiques (qui peuvent se chevaucher) :
df2 = pd . read_csv ( '/kaggle/input/lmsys-chatbot-arena/test.csv' )
df2 [ 'id' ] = df2 [ 'id' ]. astype ( str )
a_null_df = df2 [( df2 [ "response_a" ] == '[null]' ) | ( df2 [ "response_a" ] == '[]' ) | ( df2 [ "response_a" ] == '[ ]' ) | ( df2 [ "response_a" ] == '[ ]' ) | ( df2 [ "response_a" ] == '[""]' ) | ( df2 [ "response_a" ] == '["",""]' )]
a_null_id_list = a_null_df [ "id" ]. tolist ()
submission_df . loc [ submission_df [ 'id' ]. isin ( a_null_id_list ), [ 'winner_model_a' , 'winner_model_b' , 'winner_tie' ]] = [ 0.04 , 0.88 , 0.08 ]
b_null_df = df2 [( df2 [ "response_b" ] == '[null]' ) | ( df2 [ "response_b" ] == '[]' ) | ( df2 [ "response_b" ] == '[ ]' ) | ( df2 [ "response_b" ] == '[ ]' ) | ( df2 [ "response_b" ] == '[""]' ) | ( df2 [ "response_b" ] == '["",""]' )]
b_null_id_list = b_null_df [ "id" ]. tolist ()
submission_df . loc [ submission_df [ 'id' ]. isin ( b_null_id_list ), [ 'winner_model_a' , 'winner_model_b' , 'winner_tie' ]] = [ 0.88 , 0.04 , 0.08 ]
same_a_b_df2 = df2 [( df2 [ "response_a" ] == df2 [ "response_b" ])]
same_a_b_id_list = same_a_b_df2 [ "id" ]. tolist ()
submission_df . loc [ submission_df [ 'id' ]. isin ( same_a_b_id_list ), [ 'winner_model_a' , 'winner_model_b' , 'winner_tie' ]] = [ 0.06 , 0.06 , 0.88 ]
Présentation : Développement et optimisation d'un modèle de prédiction des préférences humaines pour les systèmes de dialogue basé sur le modèle gemma-2-9b-it, améliorant la précision de la prédiction des réponses aux préférences des utilisateurs dans le système de dialogue.
Techniques clés :
Daoyuan Li - Profil Kaggle
Pour toute question, veuillez contacter Daoyuan Li à [email protected].