146 lines
6.4 KiB
Markdown
146 lines
6.4 KiB
Markdown
# 奖励模型
|
|
|
|
默认情况下,奖励模型是指具有分类头数值输出的模型,通常称为输出奖励模型(ORM)。这些模型会对其他模型的输出进行评分,从而生成一个标量值,表示模型响应的质量。
|
|
|
|
我们可以通过使用参数 `reward_models` 来加载具有分类头的奖励模型,或者加载经过[奖励建模](../../RLHF.md#rm)训练的奖励模型,进而使用模型的logits作为奖励。
|
|
|
|
## 自定义奖励模型
|
|
对于生成式奖励模型,有两种常见的调用方式:一种是在 Trainer 内部直接使用 reward_model_plugin 定义奖励模型的逻辑,可以使用TransformersEngine对奖励模型进行推理,另一种是通过外部部署的模型服务进行调用。
|
|
|
|
- 使用 reward_model_plugin 调用奖励模型时,模型会被内嵌在 Trainer 内部,无需额外占用计算资源。该方式优点是方便集成,但生成速度相对较慢,更适合参数量较小的奖励模型场景。
|
|
|
|
- 外部部署奖励模型时,可以通过诸如 swift deploy 或 vllm serve 等命令将模型服务部署于独立设备,大幅提升推理速度,适合参数量较大的模型。但这样需要预留额外的硬件资源。
|
|
|
|
### 内部插件
|
|
|
|
我们可以在 reward_model_plugin 中灵活地自定义奖励模型的处理逻辑。这使得实现诸如生成式奖励模型等技术成为可能,包括:
|
|
|
|
- 自定义模型的系统提示:定义特定的指令和上下文以指导评估过程。
|
|
- 处理模型交互历史:管理对话上下文,以提供有意义且具有上下文感知的评估。
|
|
- 定义自定义评估标准:设置独特的标准和度量,用于评估模型的响应,超越默认的准确性和相关性衡量标准。
|
|
|
|
通过reward_model_plugin,开发者可以针对其应用的特定需求定制奖励评估过程。这种灵活性允许更细致和有效的基于奖励的训练策略。
|
|
|
|
奖励模型通过plugin的`__call__`方法进行调用,该方法接受 `inputs` 作为参数,包含了模型输入输出的 messages 和数据集中的其他列
|
|
|
|
```python
|
|
def __call__(self, inputs):
|
|
print(inputs)
|
|
"""
|
|
[
|
|
{
|
|
'messages': [
|
|
{'role': 'system', 'content': 'system prompt'},
|
|
{'role': 'query', 'content': 'query'},
|
|
{'role': 'user', 'content': 'completions1'},
|
|
],
|
|
'solution': "abc",
|
|
},
|
|
{
|
|
'messages': [
|
|
{'role': 'system', 'content': 'system prompt'},
|
|
{'role': 'query', 'content': 'query'},
|
|
{'role': 'user', 'content': 'completions2'},
|
|
],
|
|
'solution': "abc",
|
|
}
|
|
]
|
|
|
|
```
|
|
|
|
在插件中使用 TransformersEngine 进行奖励模型的推理, 我们只需构造 messages ,并通过 infer 接口调用:
|
|
```python
|
|
class RMPlugin(DefaultRMPlugin):
|
|
|
|
def __init__(self, model, template):
|
|
|
|
super().__init__(model, template)
|
|
# initilize TransformersEngine to infer
|
|
self.engine = TransformersEngine(self.model, template=self.template, max_batch_size=0)
|
|
|
|
def __call__(self, inputs):
|
|
system_prompt = ...
|
|
query = ...
|
|
messages = [{'role': 'system', 'content': system_prompt}, {'role': 'query', 'content': query}]
|
|
result = self.engine.infer([messages], self.request_config, use_tqdm=False)
|
|
rewards = ...
|
|
return rewards
|
|
```
|
|
|
|
我们在 [rm_plugin.py](https://github.com/modelscope/ms-swift/blob/main/swift/rewards/rm_plugin.py) 中提供了一个简单的生成式奖励模型示例(GenRMPlugin)。
|
|
|
|
在 [plugin.py](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo/plugin/plugin.py) 中自定义奖励模型插件,并使用 `external_plugins` 参数进行注册。
|
|
|
|
|
|
注意:
|
|
1. 在 GRPOTrainer 中,reward_model 会依次append到 reward_funcs 中。因此,reward_weights 的顺序对应 [reward_funcs, reward_model]。
|
|
2. reward_model_plugin 默认为 default,即使用 ORM 处理逻辑。
|
|
3. 对于参数量较大的模型,TransformersEngine 生成速度较慢,请使用[外部部署](#外部部署)方法
|
|
|
|
对于 BERT 这类无法通过 reward_model 加载的模型,我们可以内置在 reward_function 中进行加载,参考[issue](https://github.com/modelscope/ms-swift/issues/4580)
|
|
|
|
### 外部部署
|
|
|
|
**示例 2:使用 swift deploy 部署奖励模型并进行远程调用**
|
|
|
|
这类方法则不需要使用 reward_model_plugin , 而是直接在奖励函数中进行调用即可
|
|
|
|
首先用如下命令启动模型服务:
|
|
|
|
```bash
|
|
# 注意部署的设备不要与训练设备重叠
|
|
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
|
swift deploy \
|
|
--model Qwen/Qwen2.5-72B-Instruct \
|
|
--vllm_tensor_parallel_size 4
|
|
|
|
# [INFO:swift] model_list: ['Qwen2.5-72B-Instruct']
|
|
# INFO: Started server process [xxxxxx]
|
|
# INFO: Waiting for application startup.
|
|
# INFO: Application startup complete.
|
|
# INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
|
```
|
|
在奖励函数中通过 OpenAI 库初始化客户端,指定模型服务的地址和端口,示例代码如下:
|
|
|
|
```python
|
|
from openai import OpenAI
|
|
|
|
class RMReward(ORM):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
try:
|
|
self.client = OpenAI(
|
|
api_key='EMPTY',
|
|
base_url='http://127.0.0.1:8000/v1', # 若在本地部署则为 127.0.0.1
|
|
)
|
|
self.verify_model_name = self.client.models.list().data[0].id
|
|
except Exception as e:
|
|
raise RuntimeError('Failed to connect to the model service. Please deploy the model '
|
|
"using 'swift deploy' or 'vllm serve'.") from e
|
|
|
|
|
|
def __call__(self, completions, messages, **kwargs) -> List[float]:
|
|
rewards = []
|
|
for completion, message in zip(completions, messages):
|
|
rm_prompt = ... # 构建 reward model 的prompt
|
|
chat_response = self.client.chat.completions.create(
|
|
model=self.verify_model_name,
|
|
messages=[
|
|
{
|
|
'role': 'system',
|
|
'content': 'You are a helpful assistant.'
|
|
},
|
|
{
|
|
'role': 'user',
|
|
'content': rm_prompt
|
|
},
|
|
],
|
|
)
|
|
response = chat_response.choices[0].message.content.strip()
|
|
reward = ... # 根据奖励模型生成结果提取奖励值
|
|
rewards.append(reward)
|
|
return rewards
|
|
|
|
```
|