我们初期可以从规则开始,那么是否可以通过yolo输出的各个目标类型和位置预测信息,作为模型的输入,并将当前从人的角度应该进行的方式比如攻击、防御、移动作为输出标签,进行模型搭建进行训练
您提出的这个思路非常棒!这确实是实现游戏AI智能决策的一个非常经典且高效的入门方法,在学术上被称为行为克隆或模仿学习。您已经抓住了从“感知”到“决策”的关键:将YOLO的检测结果作为状态特征,将人类专家的操作作为学习目标。
下面,我用一个清晰的流程和代码示例,为您展示如何将这一想法落地。
您的想法本质是让AI模仿人类专家的行为。整个过程可以分解为以下几个关键步骤,其核心流程如下:
flowchart TD
A[人类专家演示] --> B[数据采集<br>记录画面与对应操作]
B --> C[特征提取<br>使用YOLO解析画面生成状态特征]
C --> D[标签生成<br>将人类操作编码为动作标签]
D --> E{模型训练<br>训练决策模型拟合专家行为}
E --> F[智能体部署<br>新画面由YOLO+决策模型自动决策]
F --> G[执行动作]
G --> H[游戏环境]
H -- 新画面 --> A
H -- 新画面 --> F
下面,我们详细拆解图中的每一个环节。
首先,我们需要记录人类高手玩游戏的数据。每一条数据都是一个 “状态-动作”对。
示例代码:记录数据点
pythonimport cv2
from ultralytics import YOLO
import keyboard # 用于监听按键
import pandas as pd
from collections import deque
# 初始化YOLO模型(假设已训练好)
detection_model = YOLO('best.pt')
# 创建一个列表来存储数据
data_buffer = []
# 假设我们关心的目标类别和按键
interest_classes = ['enemy', 'health_pack', 'boss'] # 您自定义的类别
action_keys = ['w', 'a', 's', 'd', 'j', 'k'] # 例如: 上下左右、攻击、跳跃
# 开始录制数据
print("开始录制专家数据... 按 'q' 停止录制。")
cap = cv2.VideoCapture(0) # 或获取游戏窗口
while True:
ret, frame = cap.read()
if not ret:
break
# 1. 状态获取:使用YOLO分析当前帧
results = detection_model(frame)[0]
current_state = []
# 提取关键信息,例如:最近敌人的位置、是否存在血包等
for box in results.boxes:
class_id = int(box.cls)
class_name = results.names[class_id]
if class_name in interest_classes:
# 获取边界框坐标(归一化)
x_center, y_center, width, height = box.xywhn[0].tolist()
# 将信息加入当前状态向量
current_state.extend([class_id, x_center, y_center, width, height])
# 2. 动作标签获取:监听当前时刻的按键
current_action = 0 # 默认动作为“无操作”
for i, key in enumerate(action_keys):
if keyboard.is_pressed(key): # 检测某个键是否被按下
current_action = i + 1 # 动作标签,例如1代表'w',2代表'a'...
break # 假设同一时刻只执行一个主要动作
# 3. 将“状态-动作”对存入缓冲区
# 注意:状态可能长度不固定,需要处理
data_buffer.append({'state': current_state, 'action': current_action})
cv2.imshow('Recoding', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# 将数据保存到CSV文件(需要将状态列表转换为固定格式)
df = pd.DataFrame(data_buffer)
df.to_csv('expert_data.csv', index=False)
print(f“录制完成,共保存 {len(data_buffer)} 条数据。”)
YOLO每帧检测到的目标数量不固定,但神经网络需要固定长度的输入。我们需要设计一个特征提取器,将YOLO的原始输出转化为有意义的、固定维度的特征向量。下表展示了几种常见的特征设计方法:
| 特征设计方法 | 核心思想 | 示例特征(假设游戏为2D射击) | 适用场景 |
|---|---|---|---|
| 关键目标统计 | 关注对决策最重要的单一目标 | 1. 最近敌人的相对方位(x方向差值,y方向差值) 2. 自身与敌人的距离 3. 最近敌人的类型(One-Hot编码) | 动作决策强烈依赖于单一主要目标(如格斗、射击游戏) |
| 全局统计摘要 | 统计画面中各类目标的整体情况 | 1. 敌人总数 2. 平均敌人距离 3. 血包是否存在(0或1) 4. 最近血包的距离和方位 | 需要宏观态势感知的游戏(如MOBA、RTS) |
| 空间网格划分 | 将屏幕划分为网格,统计每个网格内的目标 | 将屏幕分为3x3网格,统计每个格子中是否存在敌人,生成一个9维的0/1向量。 | 决策与目标的屏幕位置强相关(如需要绕行、占据特定地形的游戏) |
示例代码:特征提取器
pythonimport numpy as np
def extract_features(yolo_detection_results, frame_width, frame_height):
"""
从YOLO结果中提取固定长度的特征向量
"""
features = []
boxes = yolo_detection_results.boxes
if boxes is None:
# 如果没有检测到任何目标,返回零向量
return np.zeros(5) # 根据特征维度调整
# 假设我们采用“关键目标统计”法:只关心最近的敌人
enemy_boxes = []
for box in boxes:
class_id = int(box.cls)
if class_id == 0: # 假设 class_id=0 是 'enemy'
# 获取框的中心点坐标
x_center, y_center = box.xywhn[0][0].item(), box.xywhn[0][1].item()
# 计算到屏幕中心(玩家位置)的距离
distance = np.sqrt((x_center - 0.5)**2 + (y_center - 0.5)**2)
enemy_boxes.append((distance, x_center, y_center))
if enemy_boxes:
# 找到最近的敌人
enemy_boxes.sort(key=lambda x: x[0])
closest_dist, closest_x, closest_y = enemy_boxes[0]
# 特征:最近敌人的相对位置和距离
features.extend([closest_x - 0.5, closest_y - 0.5, closest_dist])
else:
# 没有敌人,用零填充
features.extend([0, 0, 999])
# 可以继续添加其他特征,如自身血量(需从游戏内存或UI识别获取)
# features.append(current_health)
return np.array(features)
接下来,我们搭建一个简单的神经网络,学习从“状态特征”到“动作”的映射。这是一个典型的分类问题。
示例代码:决策模型
pythonimport torch
import torch.nn as nn
import torch.optim as optim
class DecisionNN(nn.Module):
"""
简单的决策神经网络
输入:游戏状态特征(固定长度)
输出:执行每个动作的概率
"""
def __init__(self, input_size, output_size):
super(DecisionNN, self).__init__()
self.network = nn.Sequential(
nn.Linear(input_size, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, output_size)
)
def forward(self, x):
return self.network(x)
# 假设特征向量长度为3,动作空间为6(5个动作+1个“无操作”)
INPUT_SIZE = 3
OUTPUT_SIZE = len(['no_op', 'up', 'left', 'down', 'right', 'attack']) # 6
policy_model = DecisionNN(INPUT_SIZE, OUTPUT_SIZE)
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数,用于分类
optimizer = optim.Adam(policy_model.parameters(), lr=0.001)
最后,我们将所有环节串联起来,进行模型训练和部署。
示例代码:训练与部署循环
python# 训练循环
df = pd.read_csv('expert_data.csv')
# ... (需要将之前保存的state字符串解析为特征向量)
for epoch in range(100):
for i, row in df.iterrows():
# 假设已经将特征向量处理好
state = torch.FloatTensor(eval(row['state'])) # 将字符串列表转为Tensor
action_label = torch.LongTensor([row['action']]) # 真实动作标签
optimizer.zero_grad()
action_scores = policy_model(state) # 模型预测
loss = criterion(action_scores, action_label) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新权重
# 部署智能体
while True:
frame = get_game_frame()
results = detection_model(frame)
state_features = extract_features(results[0], frame.width, frame.height)
with torch.no_grad():
action_probs = torch.softmax(policy_model(torch.FloatTensor(state_features)), dim=0)
chosen_action = torch.argmax(action_probs).item()
# 执行动作
execute_action(action_keys[chosen_action])
您提出的路径是完全可行的,是连接计算机视觉(CV)与决策智能(AI)非常漂亮的桥梁。希望这个详细的方案能帮助您启动项目!
本文作者:君逍遥
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!