AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


基于DSPy和微调,提升Chat模型解决国际象棋难题的能力
发布日期:2024-08-26 07:24:19 浏览次数: 1594


研究表明,GPT完成模型在国际象棋领域的表现相当出色,例如gpt-3.5-turbo-instruct的Elo评级大约为1800。

然而,聊天模型的表现通常较差。已有研究表明,结合微调和提示优化能够显著提升模型性能。

为探讨能否将聊天模型的表现提升至与完成模型竞争的水平,进行了多次实验。

本文采用DSPy进行提示优化,并通过微调gpt-4o-mini,以增强大型语言模型(LLM)在国际象棋难题中的解决能力。

名词解释

  • • 微调Finetuning:在特定数据集上进一步训练预训练的语言模型,以提高其在特定任务上的表现。

  • • 提示优化Prompt optimization:通过改进输入提示来引导 AI 模型,以获得更好和更准确的响应。

  • • 少样本提示Few shot prompting:一种方法,其中语言模型在提示中提供少量示例(通常是 2-5 个),以帮助其理解和执行特定任务。

  • • 思维链 (Chain of thought,CoT):一种鼓励 AI 模型将复杂问题分解为逐步推理的策略,通常在提示或训练数据中包含中间步骤。

  • • DSPy:用于算法优化 LM 提示和权重的高级框架。

  • • Completion Models :适用于明确、单一的任务,能够快速生成所需内容。它们适合于任务导向的应用,如问答系统和代码生成。比如GPT-3.5-turbo-instruct,Codex等

  • • Chat Models :设计用于与用户进行长时间的对话,能够处理多轮对话并维持上下文。它们适合于需要连续互动和自然对话的场景,如虚拟助理和客服系统,GPT-4、GPT-3.5-turbo等

数据集

为了创建评估模型的数据集,我使用了 Lichess 数据库中的国际象棋难题集,该数据库提供了 400 万个带有元数据的国际象棋难题。

对于每个难题,我通过 API 获取了每个难题的 PGN 格式的完整走棋列表,每个走棋都有一个示例。

PGN: 1. e3 e5 2. Ne2 d5 3. Ng3 Nf6 4. Nh5 Bd6 5. d3 Bg4 6.
Answer: ?

处理后的数据集可在 Hugging Face 上获取。

完成模型能解决国际象棋难题吗?

GPT 完成模型提供了一个强有力的基准,babbage 和 davinci 分别在评估集中达到了 61.23% 和 74.45% 的准确率。

模型准确率
babbage-00261.23%
davinci-00274.45%

提示优化

在没有向 LLM 展示任何示例的情况下,聊天模型的表现相当差,gpt-4o-mini 仅解决了 17.4% 的难题,而 gpt-4o 解决了 28.44%。

DSPy 程序

DSPy:一个用于编程(而不是提示)基础模型的框架

为了使用DSPy优化程序,可以通过LLM签名和模块来表达它。这个简单的签名将被优化为高质量的少样本提示。

仅通过这种方法,gpt-4o-mini的准确率提高到了25.99%,比零样本基线提高了50%。

当结合非法走棋的自我修正步骤和2次重试时,准确率进一步提高到了 31.72%。

class ChessSolver(dspy.Signature):
    """Given a series of chess moves in Portable Game Notation (PGN) format, your task is to determine and return the correct next move in Standard Algebraic Notation (SAN) format."""
    pgn = dspy.InputField(desc="The chess position")
    answer = dspy.OutputField(desc="The correct next move in SAN format")

class ChessEngine(dspy.Module):
    def __init__(self):
        super().__init__()
        self.generate_move = dspy.ChainOfThought(ChessSolver)

    def forward(self,pgn):
        gen_pred = self.generate_move(pgn=pgn)
        gen_move = gen_pred.answer
        gen_move = gen_move.split(" ")[-1]
        valid, reason = validate_pgn_move(pgn, gen_move)
        dspy.Suggest(valid, reason)
        if valid:
            print(f"valid:\n{pgn} *{gen_move}")
        if not valid:
            print(f"invalid:\n{pgn} *{gen_move}*\n{reason}")

        return dspy.Prediction(pgn=pgn, answer=gen_move, rationale=gen_pred.rationale)

检查走棋是否有效:

def validate_pgn_move(pgn_board, san_move):
    # Create a board from the PGN
    board = chess.Board()
    pgn = io.StringIO(pgn_board)
    game = chess.pgn.read_game(pgn)
    
    # Apply all moves from the PGN to get the current board state
    for move in game.mainline_moves():
        board.push(move)
    
    # Parse the new move
    try:
        print(str(san_move))
        chess_move = board.parse_san(str(san_move))
    except chess.InvalidMoveError:
        return False"Invalid move notation"
    except chess.IllegalMoveError:
        return False"Illegal move"
    except chess.AmbiguousMoveError:
        return False"SAN is ambigious"
    
    # Check if the move is legal
    if chess_move in board.legal_moves:
        return True"Move is valid"
    else:
        return False"Move is not legal in the current position"

通过使用DSPy对少样本提示进行优化,gpt-4o-mini的性能提升到了 31.72%。

使用新优化的少样本思维链提示结合gpt-4o,准确率提高到了 63.88%。

编译

# 定义超参数:
N = 20 # The number of instructions and fewshot examples that we will generate and optimize over
batches = 50 # The number of optimization trials to be run (we will test out a new combination of instructions and fewshot examples in each trial)
temperature = 1.0 # The temperature configured for generating new instructions

# 设置评估指标
NUM_THREADS = 64

# 评估
metric = dspy.evaluate.answer_exact_match
kwargs = dict(num_threads=NUM_THREADS, display_progress=True)
evaluate = Evaluate(devset=val, metric=metric, **kwargs)

# 基线
baseline_val_score = evaluate(program_with_assertions, devset=val)
print(f"Baseline val: {baseline_val_score}")

# 编译
eval_kwargs = dict(num_threads=NUM_THREADS, display_progress=True, display_table=0)
teleprompter = MIPROv2(prompt_model=prompt_model, task_model=task_model, metric=metric, num_candidates=N, init_temperature=temperature, verbose=True)
compiled_program = teleprompter.compile(program_with_assertions, trainset=train, valset=val, num_batches=batches, max_bootstrapped_demos=3,max_labeled_demos=5, eval_kwargs=eval_kwargs)
compiled_program.save("compiled_chess_cot_ft_student.dspy")

# 编译得分
fs_val_score, fs_outputs = evaluate(compiled_program, devset=val, return_outputs=True)
print(f"Few shot compiled val: {fs_val_score}")

消耗数百万个Token后...

编译后的提示

DSPy优化后的少样本思维链提示,包含 5 个示例:

{
  "generate_move": {
    "lm": null,
    "traces": [],
    "train": [],
    "demos": [
      {
        "augmented": true,
        "pgn": "1. e4 e5 2. Ne2 Bc5 3. Ng3 d6 4. Bc4 h6 5. O-O Nf6 6. d3 O-O 7. Nh5 Bg4 8. Nxf6+ Qxf6 9. ",
        "rationale": "Pgn: 1. e4 e5 2. Ne2 Bc5 3. Ng3 d6 4. Bc4 h6 5. O-O Nf6 6. d3 O-O 7. Nh5 Bg4 8. Nxf6+ Qxf6 9.\nReasoning: Let's think step by step in order to determine the best move for White. After 8...Qxf6, Black has captured the knight on f6, and now White needs to respond. The most logical move for White is to play 9. Qxg4, capturing the bishop on g4. This move not only gains material but also puts pressure on Black's position.",
        "move": "Qxg4"
      },
      {
        "augmented": true,
        "pgn": "1. e4 d5 2. exd5 Qxd5 3. Nc3 Qd8 4. Nf3 Nf6 5. h3 Bf5 6. Bc4 e6 7. d3 Be7 8. Qe2 O-O 9. Bd2 a6 10. g4 Bg6 11. Ne5 b5 12. Bb3 c5 13. h4 h6 14. Nxg6 fxg6 15. g5 Nd5 16. Nxd5 exd5 17. Qe6+ Kh7 18. Bxd5 Bxg5 19. O-O-O Bxd2+ 20. Rxd2 Rf6 21. Qe4 Ra7 22. h5 Re7 23. hxg6+ Kh8 24. Qg2 Qd6 25. Re2 Rxe2 26. Rxh6+ gxh6 27. g7+ Kh7 28. ",
        "rationale": "determine the best move for White. The position after 28. is critical as White has a strong initiative and is threatening to deliver checkmate or win material. The last move played by Black was 27...Kh7, which puts the Black king in a precarious position. \n\nWhite has several options to consider, but the most effective move is to play 29. g8=Q+. This move promotes the pawn on g7 to a queen, delivering check to the Black king. The newly promoted queen will also create a significant threat, as it can potentially lead to checkmate on the next move if Black does not respond adequately.",
        "move": "g8=Q+"
      },
      {
        "pgn": "1. e4 e5 2. Nf3 Nc6 3. Bc4 Bc5 4. c3 Nf6 5. d4 exd4 6. cxd4 Bb4+ 7. Nc3 Nxe4 8. O-O Bxc3 9. d5 Bf6 10. Re1 Ne7 11. Rxe4 d6 12. Bg5 Bxg5 13. Nxg5 h6 14. Nf3 O-O 15. Qe2 Ng6 16. Re1 Bf5 17. Rd4 a6 18. Bd3 Bxd3 19. Qxd3 Qd7 20. h4 Rae8 21. Rxe8 Rxe8 22. h5 Ne5 23. Nxe5 Rxe5 24. g4 Qe7 25. Kg2 Re1 26. Qf5 g6 27. hxg6 fxg6 28. Qxg6+ Qg7 29. Qxg7+ Kxg7 30. Rd2 Kf6 31. f4 Re4 32. Kf3 Rc4 33. b3 Rc5 34. Ke4 Ra5 35. a4 Rc5 36. Rd3 Rc1 37. Rh3 Kg6 38. f5+ Kg5 39. Kf3 Rc3+ 40. Kg2",
        "answer": "Rxh3"
      },
      {
        "pgn": "1. e4 e5 2. f4 exf4 3. Bc4 d6 4. Nc3 h6 5. d4 g5 6. h4 Bg7 7. hxg5 hxg5 8. Rxh8 Bxh8 9. Qh5 Qf6 10. Nd5 Qxd4 11. Nxc7+ Kd8 12. Nf3 Qxe4+ 13. Be2 Kxc7 14. Qxh8 Ne7 15. Nxg5 Qxg2 16. Bxf4 Bg4 17. O-O-O Qxe2 18. Bxd6+ Kb6 19. Qd4+ Kc6 20.",
        "answer": "Qc3+"
      },
      {
        "pgn": "1. e4 e5 2. d3 Nc6 3. Be2 d5 4. exd5 Qxd5 5. Bf3 Qd8 6. Bxc6+ bxc6 7. Nf3 Bd6 8. O-O h6 9. Qe2 Qf6 10. d4 Bg4 11. dxe5 Bxf3 12. exf6+ Bxe2 13. Re1 Nxf6 14. Rxe2+ Be7 15. b3 O-O-O 16. Rxe7",
        "answer": "Rd1+"
      }
    ],
    "signature_instructions": "Given a sequence of chess moves in Portable Game Notation (PGN) format, critically analyze the current board position to determine the next optimal move in Standard Algebraic Notation (SAN) format. Your answer should include a detailed step-by-step reasoning to justify why this move is the best choice, considering the current threats, opportunities for material gain, and positional advantages. Ensure that your rationale explains how your chosen move aligns with an overall strategic plan to improve your position and counter your opponent's threats.",
    "signature_prefix": "Move:"
  }
}

有趣的是,第一个示例中的基本原理存在错误,并重复了说明中的 PGN。删除它实际上会显着降低性能。

DSPy 编译结果

模型准确率
gpt-4o-mini [zero shot]17.4%
gpt-4o-mini25.99%
gpt-4o-mini [SELF CORRECT 3 tries max]31.72%
gpt-4o [zero shot]28.44%
gpt-4o55.07%
gpt-4o [SELF CORRECT 3 tries max]63.88%

微调

可以在这些数据上微调一个模型,而不是构建提示词。GPT-3.5-turbo-16k通常在LLM数据上表现良好,因此使用了gpt-4o-mini进行微调。

构建良好示例

为了微调,需要创建高质量的训练示例。尽管原始Lichess数据库中有许多国际象棋难题,但并不是所有难题都适合用来训练模型。因此,手动选择了最适合微调的难题,并确保它们代表了各种不同的情况。这些例子包含了不同类型的局面,如开局、中局和残局。

每个示例都包括完整的棋局(PGN 格式)和正确的下一步(SAN 格式),并增加了详细的推理步骤,以帮助模型理解为什么这是最优解。

gpt-4o-mini

gpt-4o-mini 是一个相对较小的模型,在微调前的基线性能仅为 17.4%。在进行微调后,模型的表现显著提升,达到了 45.21%。虽然这仍不如提示优化后的 gpt-4o,但已经展示了微调对模型性能的有效性。

gpt-4o

gpt-4o 是一个更大的模型,在未微调时的基线性能为 28.44%。通过 DSPy 编译的少样本提示优化,该模型的性能提升至 63.88%。在微调之后,gpt-4o 的性能进一步提升,达到了 70.32%,显示出微调的巨大潜力。

davinci

为了比较,还尝试微调了 davinci-002,这是一个更强大的模型。davinci-002 在基线上的性能为 74.45%。经过微调后,模型的准确率达到了 80.12%。尽管 davinci-002 的基线性能已经很高,但微调仍然能够进一步提升其表现。

微调结果

完成模型

模型微调前准确率微调后准确率
gpt-4o-mini17.4%45.21%
gpt-4o28.44%70.32%
davinci-00274.45%80.12%

聊天模型 + DSPy

模型准确度
gpt-4o-mini [zero shot]17.4%
gpt-4o-mini25.99%
gpt-4o-mini [SELF CORRECT 3 tries max]31.72%
gpt-4o-mini finetune57.71%
gpt-4o-mini finetune [SELF CORRECT 3 tries max]65.64%
gpt-4o [zero shot]28.44%
gpt-4o55.07%
gpt-4o [SELF CORRECT 3 tries max]63.88%
gpt-4o finetune58.59%
gpt-4o finetune [SELF CORRECT 3 tries max]71.37%

注意事项

尽管实验结果表明,DSPy 编译的少样本提示和微调可以显著提升聊天模型的国际象棋难题解决能力

但仍有一些注意事项:

1、微调过程需要大量的数据和计算资源。

2、不同类型的国际象棋难题可能需要不同的优化策略,这意味着我们可能需要针对特定类型的难题进行额外的优化。

总结

本研究展示了通过DSPy提示优化和微调,可以显著提升聊天模型解决国际象棋难题的能力。

在最好的情况下,gpt-4o在经过DSPy提示优化和微调后,达到了70.32%的准确率,接近于完成模型的表现。

然而,仍有一些差距需要弥补,未来的工作将继续探索如何进一步优化这些模型,以提高其在各种复杂局面中的表现。


53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询