5.2-流水线并行与微批次调度(2)


文档摘要

通信缓冲区 self.inputbuffers = [None] self.numstages self.outputbuffers = [None] self.numstages self.commevents = [None] self.numstages 异步操作队列 self.forwardqueue = asyncio.Queue() self.backwardqueue = asyncio.Queue() self.resultqueue = asyncio.Queue() 启动异步任务 self.loop = asyncio.geteventloop() self.tasks = [] async def forwardasync(self, inputids: torch.

通信缓冲区

self.input_buffers = [None] * self.num_stages self.output_buffers = [None] * self.num_stages self.comm_events = [None] * self.num_stages # 异步操作队列 self.forward_queue = asyncio.Queue() self.backward_queue = asyncio.Queue() self.result_queue = asyncio.Queue() # 启动异步任务 self.loop = asyncio.get_event_loop() self.tasks = [] async def forward_async(self, input_ids: torch.Tensor) -> torch.Tensor: """异步前向传播""" batch_size = input_ids.shape[0] num_microbatches = (batch_size + self.microbatch_size - 1) // self.microbatch_size # 分割微批次 microbatches = [] for i in range(num_microbatches): start_idx = i * self.microbatch_size end_idx = min((i + 1) * self.microbatch_size, batch_size) microbatch = input_ids[start_idx:end_idx] microbatches.append(microbatch) # 启动异步任务 results = [] for microbatch in microbatches: # 将微批次加入队列 await self.forward_queue.put(microbatch) # 等待所有结果 for _ in range(num_microbatches): result = await self.result_queue.get() results.append(result) # 合并结果 final_output = torch.cat(results, dim=0) return final_output async def process_pipeline(self): """处理流水线操作""" while True: # 获取下一个微批次 microbatch = await self.forward_queue.get() # 初始化输入缓冲区 if self.input_buffers[0] is None: self.input_buffers[0] = microbatch else: self.input_buffers[0] = torch.cat([self.input_buffers[0], microbatch], dim=0) # 处理流水线 outputs = [] for i in range(self.num_stages): if self.input_buffers[i] is not None: # 处理当前阶段的输入 stage = self.stages[i] output = stage(self.input_buffers[i]) if i < self.num_stages - 1: # 通信到下一个阶段 if self.overlap_communication: # 异步通信 asyncio.create_task(self._async_send_to_stage(i + 1, output)) else: # 同步通信 self.input_buffers[i + 1] = output.to(self.stages[i + 1].device) outputs.append(output) # 将最终输出加入结果队列 if len(outputs) > 0: await self.result_queue.put(outputs[-1]) # 清理缓冲区 for i in range(self.num_stages): if self.input_buffers[i] is not None: # 检查是否完成了微批次处理 if self.input_buffers[i].shape[0] >= self.microbatch_size: # 只保留部分数据用于下一个微批次 remaining = self.input_buffers[i].shape[0] - self.microbatch_size if remaining > 0: self.input_buffers[i] = self.input_buffers[i][-remaining:] else: self.input_buffers[i] = None async def _async_send_to_stage(self, stage_idx: int, tensor: torch.Tensor): """异步发送到指定阶段""" # 这里应该使用实际的异步通信机制 # 简化处理,直接设置缓冲区 self.input_buffers[stage_idx] = tensor.to(self.stages[stage_idx].device) def start_processing(self): """启动处理任务""" # 启动流水线处理任务 task = self.loop.create_task(self.process_pipeline()) self.tasks.append(task) def stop_processing(self): """停止处理任务""" for task in self.tasks: task.cancel()

class OptimizedCommunication:
"""优化的通信管理"""

def __init__(self, num_stages: int, devices: List[torch.device]): self.num_stages = num_stages self.devices = devices self.communication_overhead = 0.0 self.comm_count = 0 # 通信缓存 self.cache_enabled = True self.communication_cache = {} self.cache_hits = 0 self.cache_misses = 0 def async_send(self, source_device: torch.device, target_device: torch.device, tensor: torch.Tensor, priority: str = 'normal') -> torch.Tensor: """异步发送张量""" start_time = time.time() # 检查通信缓存 cache_key = (tensor.data_ptr(), str(target_device)) if self.cache_enabled and cache_key in self.communication_cache: self.cache_hits += 1 cached_tensor = self.communication_cache[cache_key] return cached_tensor # 模拟异步通信 if source_device == target_device: # 本地传输,无通信开销 result = tensor.to(target_device) else: # 跨设备通信 # 简化处理,实际应该使用NCCL或其他通信库 time.sleep(0.001) # 模拟通信延迟 result = tensor.to(target_device) # 更新通信统计 self.communication_overhead += time.time() - start_time self.comm_count += 1 # 缓存结果 if self.cache_enabled: self.communication_cache[cache_key] = result self.cache_misses += 1 return result def batch_communication(self, tensors: List[Tuple[torch.device, torch.device, torch.Tensor]]) -> List[torch.Tensor]: """批量通信优化""" # 按目标设备分组 grouped_comm = {} for source_device, target_device, tensor in tensors: if target_device not in grouped_comm: grouped_comm[target_device] = [] grouped_comm[target_device].append((source_device, tensor)) # 批量处理 results = [] for target_device, comm_list in grouped_comm.items(): # 这里应该实现真正的批量通信 # 简化处理,逐个处理 for source_device, tensor in comm_list: result = self.async_send(source_device, target_device, tensor) results.append(result) return results def get_statistics(self) -> Dict: """获取通信统计信息""" avg_comm_time = self.communication_overhead / max(self.comm_count, 1) cache_hit_rate = self.cache_hits / (self.cache_hits + self.cache_misses) if (self.cache_hits + self.cache_misses) > 0 else 0 return { 'communication_overhead': self.communication_overhead, 'comm_count': self.comm_count, 'avg_communication_time': avg_comm_time, 'cache_enabled': self.cache_enabled, 'cache_hits': self.cache_hits, 'cache_misses': self.cache_misses, 'cache_hit_rate': cache_hit_rate, 'num_stages': self.num_stages }

演示异步流水线通信

async def demonstrate_async_pipeline():
"""演示异步流水线通信"""
print("\n异步流水线通信演示")
print("-" * 50)

# 创建设备 devices = [torch.device(f'cuda:{i}') for i in range(4)] # 创建测试层 layers = [] d_model = 256 for i in range(12): if i % 4 == 0: layers.append(nn.MultiheadAttention(d_model, 4)) else: layers.append(nn.Linear(d_model, d_model)) # 创建流水线模型 pipeline_model = PipelineParallelModel(layers, 4, devices) # 创建异步流水线 async_pipeline = AsyncPipeline(pipeline_model, microbatch_size=4, overlap_communication=True) # 启动处理 async_pipeline.start_processing() # 创建输入 batch_size = 16 seq_len = 32 input_ids = torch.randint(0, 10000, (batch_size, seq_len)) # 异步前向传播 start_time = time.time() output = await async_pipeline.forward_async(input_ids) async_time = time.time() - start_time print(f"输入形状: {input_ids.shape}") print(f"输出形状: {output.shape}") print(f"异步流水线时间: {async_time:.4f}s") # 停止处理 async_pipeline.stop_processing() # 通信统计 comm_stats = async_pipeline.comm_manager.get_statistics() print(f"\n通信统计:") print(f"通信开销: {comm_stats['communication_overhead']:.4f}s") print(f"平均通信时间: {comm_stats['avg_communication_time']:.4f}s") print(f"缓存命中率: {comm_stats['cache_hit_rate']:.2%}")

运行异步演示

asyncio.run(demonstrate_async_pipeline())

## 2. 微批次调度策略 ### 2.1 智能微批次管理 **动态微批次调整算法** ```python class MicrobatchScheduler: """微批次调度器""" def __init__(self, base_batch_size: int, max_batch_size: int, min_batch_size: int = 1, adaptive_scaling: bool = True): self.base_batch_size = base_batch_size self.max_batch_size = max_batch_size self.min_batch_size = min_batch_size self.adaptive_scaling = adaptive_scaling # 性能监控 self.performance_history = [] self.batch_size_history = [] self.latency_history = [] self.throughput_history = [] # 自适应参数 self.current_batch_size = base_batch_size self.performance_threshold = 0.95 # 性能阈值 self.scaling_factor = 1.5 self.shrink_factor = 0.7 def schedule_microbatches(self, total_batch_size: int, gpu_memory_info: Dict) -> List[int]: """调度微批次大小""" if not self.adaptive_scaling: # 固定微批次大小 return self._fixed_microbatch_schedule(total_batch_size) else: # 自适应微批次大小 return self._adaptive_microbatch_schedule(total_batch_size, gpu_memory_info) def _fixed_microbatch_schedule(self, total_batch_size: int) -> List[int]: """固定微批次调度""" num_microbatches = (total_batch_size + self.current_batch_size - 1) // self.current_batch_size microbatch_sizes = [] remaining = total_batch_size for i in range(num_microbatches): size = min(self.current_batch_size, remaining) microbatch_sizes.append(size) remaining -= size return microbatch_sizes def _adaptive_microbatch_schedule(self, total_batch_size: int, gpu_memory_info: Dict) -> List[int]: """自适应微批次调度""" # 获取GPU内存信息 available_memory = gpu_memory_info.get('available_memory', 0) used_memory = gpu_memory_info.get('used_memory', 0) # 计算最大可用的微批次大小 memory_per_token = 0.001 # GB per token (简化估计) max_tokens = available_memory / memory_per_token max_microbatch_size = min(int(max_tokens), self.max_batch_size) # 根据历史性能调整微批次大小 if len(self.performance_history) > 10: recent_performance = sum(self.performance_history[-10:]) / 10 if recent_performance > self.performance_threshold: # 性能良好,可以增加微批次大小 self.current_batch_size = min( int(self.current_batch_size * self.scaling_factor), max_microbatch_size ) else: # 性能不佳,减少微批次大小 self.current_batch_size = max( int(self.current_batch_size * self.shrink_factor), self.min_batch_size ) # 确保微批次大小在合理范围内 self.current_batch_size = max( self.min_batch_size, min(self.current_batch_size, max_microbatch_size) ) # 生成微批次调度 return self._fixed_microbatch_schedule(total_batch_size) def update_performance_metrics(self, batch_size: int, latency: float, throughput: float): """更新性能指标""" self.batch_size_history.append(batch_size) self.latency_history.append(latency) self.throughput_history.append(throughput) # 计算性能分数(吞吐量与延迟的比值) performance_score = throughput / latency if latency > 0 else 0 self.performance_history.append(performance_score) # 保持历史记录长度 max_history = 100 if len(self.performance_history) > max_history: self.performance_history = self.performance_history[-max_history:] if len(self.batch_size_history) > max_history: self.batch_size_history = self.batch_size_history[-max_history:] if len(self.latency_history) > max_history: self.latency_history = self.latency_history[-max_history:] if len(self.throughput_history) > max_history: self.throughput_history = self.throughput_history[-max_history:] def get_optimal_batch_size(self, target_latency: float = None) -> int: """获取最优批次大小""" if target_latency is None: # 使用历史数据预测最优批次大小 if len(self.performance_history) > 0: best_performance = max(self.performance_history) best_batch_size = self.batch_size_history[ self.performance_history.index(best_performance) ] return best_batch_size else: return self.base_batch_size else: # 根据延迟目标调整批次大小 if len(self.latency_history) > 0: # 找到满足延迟条件的最大批次大小 for i in range(len(self.latency_history) - 1, -1, -1): if self.latency_history[i] <= target_latency: return self.batch_size_history[i] return self.min_batch_size def get_statistics(self) -> Dict: """获取调度器统计信息""" return { 'current_batch_size': self.current_batch_size, 'base_batch_size': self.base_batch_size, 'max_batch_size': self.max_batch_size, 'min_batch_size': self.min_batch_size, 'adaptive_scaling': self.adaptive_scaling, 'performance_history': self.performance_history[-10:], # 最近10个 'batch_size_history': self.batch_size_history[-10:], 'latency_history': self.latency_history[-10:], 'throughput_history': self.throughput_history[-10:], 'average_performance': sum(self.performance_history) / len(self.performance_history) if self.performance_history else 0, 'average_latency': sum(self.latency_history) / len(self.latency_history) if self.latency_history else 0, 'average_throughput': sum(self.throughput_history) / len(self.throughput_history) if self.throughput_history else 0 } class DynamicMicrobatchManager: """动态微批次管理器""" def __init__(self, model: nn.Module, devices: List[torch.device], base_batch_size: int = 8, max_batch_size: int = 32): self.model = model self.devices = devices self.schedulers = [MicrobatchScheduler(base_batch_size, max_batch_size) for _ in devices] # GPU监控 self.gpu_monitors = {} for device in devices: self.gpu_monitors[device] = self._create_gpu_monitor(device) def _create_gpu_monitor(self, device: torch.device) -> Dict: """创建GPU监控器""" return { 'device': device, 'memory_info': None, 'utilization': 0.0, 'temperature': 0.0, 'power_usage': 0.0 } def update_gpu_status(self): """更新GPU状态""" for device, monitor in self.gpu_monitors.items(): try: # 获取GPU内存信息 memory_info = torch.cuda.memory_allocated(device) memory_total = torch.cuda.get_device_properties(device).total_memory memory_free = memory_total - memory_info monitor['memory_info'] = { 'used_memory': memory_info, 'free_memory': memory_free, 'total_memory': memory_total, 'utilization': memory_info / memory_total } # 模拟获取其他信息(实际应该使用nvidia-ml-py) monitor['utilization'] = min(1.0, memory_info / (memory_total * 0.9))

发布者: 作者: 转发
评论区 (0)
U