Esta solución se desarrolló para la competencia LMSYS - Chatbot Arena Human Preference Predictions en Kaggle, donde los participantes tuvieron el desafío de predecir las preferencias de los usuarios en conversaciones cara a cara entre chatbots impulsados por grandes modelos de lenguaje (LLM). La tarea implicó utilizar un conjunto de datos de Chatbot Arena , en el que los usuarios interactúan con dos LLM anónimos y eligen su respuesta preferida. Al crear un modelo de aprendizaje automático que predice con precisión estas preferencias, nuestro objetivo era contribuir a mejorar la alineación de las respuestas del chatbot con las preferencias humanas.
Nuestro equipo obtuvo con éxito el cuarto lugar entre 1849 equipos , obteniendo una medalla de oro por nuestra solución y un premio de $20 000. ?
Primero, utilizamos el conjunto de datos oficial (55k) junto con 33k datos deduplicados, empleando una validación cruzada de 20 veces (n_splits=20), pero solo entrenamos en una parte para maximizar la cantidad de datos de entrenamiento. Además, creamos pseudoetiquetas para 30.000 entradas del conjunto de datos de ultrafeedback para complementar aún más el conjunto de datos.
Diseñamos un mensaje único, que es beneficioso porque cuando la longitud del diálogo excede la longitud máxima del token ( max_length
), permite un truncamiento razonable de la ronda final de conversación. Esto garantiza que el mensaje, la respuesta A y la respuesta B se puedan mostrar adecuadamente, evitando situaciones en las que solo se trunca el mensaje o la respuesta A. Si el recuento de fichas restantes en la ronda final es inferior a 80, se descartará toda la ronda de conversación (y las siguientes). Estos umbrales y proporciones se determinaron mediante la observación del conjunto de entrenamiento.
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 ,
}
Seleccionamos gemma-2-9b-it como modelo inicial, que supera significativamente a otros modelos como Llama3 8b y Llama3.1 8b . Usamos Gemma2ForSequenceClassification para una tarea de clasificación de tres clases y ajustamos el modelo usando lora con precisión bf16 . Los mejores resultados experimentales se lograron con cuatro GPU A100.
Cada experimento tomó aproximadamente 10 horas para la primera fase y 15 horas para la segunda fase en un sistema con 4 GPU A100 (40G).
La fase de inferencia utiliza una estructura de código similar a la fase de entrenamiento, con algunas diferencias clave: max_length
se incrementa a 3072 y la respuesta_a y la respuesta_b se intercambian como parte de una estrategia de aumento del tiempo de prueba (TTA). El resultado final es la producción promedio de ambos.
El posprocesamiento se aplicó para dos escenarios específicos (que pueden superponerse):
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 ]
Descripción general : Desarrollé y optimicé un modelo de predicción de preferencias humanas para sistemas de diálogo basado en el modelo gemma-2-9b-it, mejorando la precisión de la predicción de las respuestas de preferencias del usuario en el sistema de diálogo.
Técnicas clave :
Daoyuan Li - Perfil de Kaggle
Si tiene alguna pregunta, comuníquese con Daoyuan Li en [email protected].