Pytorhc Lightning進階:一篇實例玩轉Pytorhc Lightning 讓訓練更高效

Pytorhc Lightning進階:一篇實例玩轉Pytorhc Lightning 讓訓練更高效

Pytorhc Lightning 主要包含以下幾大類,主要圍繞以下講解:

  • 模型,PyTorch Lightning 的核心是繼承 pl.LightningModule
  • 數據,數據模塊繼承pl.LightningDataModule
  • 回調函數的構造和使用,以及自定義
  • 鉤子函數使用,模型中、數據類中、回調函數中調用先后
  • 日志記錄,一般用Pytorhc Lightning自帶的tensorboard

1. 定義模型類

1.1 如下模型的基本結構

import torch  
from torch import nn  
from torch.utils.data import DataLoader, random_split  
from torchvision.datasets import MNIST  
from torchvision.transforms import ToTensor  
import pytorch_lightning as pl  class LitModel(pl.LightningModule):  def __init__(self, imgsize=28, hidden=128, num_class=10):  super().__init__()  self.flatten = nn.Flatten()  self.net = nn.Sequential(  nn.Linear(imgsize * imgsize, hidden),  nn.ReLU(),  nn.Linear(hidden, num_class)  )  self.loss_fn = nn.CrossEntropyLoss()  def forward(self, x):  x = self.flatten(x)  return self.net(x)  def training_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("train_loss", loss)  # 自動記錄訓練損失  return loss  def validation_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("val_loss", loss)  # 自動記錄驗證損失  return loss  def test_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("test_loss", loss)  # 自動記錄測試損失  return loss  def configure_optimizers(self):  return torch.optim.Adam(self.parameters(), lr=1e-3)

1.2 方法validation_step training_step test_step

傳入兩個必須參數是batch,batch_idx,名字不能改。當然還有其他的,但是基本不怎么用。

  • batch 就是從dataloader 中返回的結果
  • batch_idx 記錄當前epoch數據批次的索引,比如我想每隔100step去記錄日志,可以if batch_idx % 100 == 0:
  • training_step 需要返回進行反向傳播的loss,其他兩個可以不用,多個優化器需要手動實現反向傳播(高版本)
  • validation_step training_step 訓練時一定要有; test_step是模型測試的時候調用,訓練時可以不要

1.3 優化器和調度定義方法configure_optimizers

該方法不需要額外傳參,如果有多個優化器則按照return [optimizer1, optimizer1...],[scheduler1, scheduler2,...] 當然還可以按照字典形式返回,這里拿以列表返回舉例。


1.4 多個優化器手動實現反向傳播

我們改寫一下1.1 的模型來看看怎么實現多個優化器情況。這里假設有多個優化器

class LitModel(pl.LightningModule):  def __init__(self, imgsize=28, hidden=128, num_class=10):  super().__init__()  self.flatten = nn.Flatten()  ####################  # 1. 修改模型為兩部分方便應用不同的優化器  self.feature_extractor = nn.Sequential(  nn.Linear(imgsize * imgsize, hidden),  nn.ReLU()  )  self.classifier = nn.Sequential(  nn.Linear(hidden, num_class)  )  #關閉自動優化  self.automatic_optimization = False  ####################  self.loss_fn = nn.CrossEntropyLoss()  # 增加保存參數  self.save_hyperparameters()  def forward(self, x):  x = self.flatten(x)  features = self.feature_extractor(x)  return self.classifier(features)  def training_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  opt1, opt2 = self.optimizers()  #3,手動優化  if batch_idx % 2 != 0:  opt1.zero_grad()  self.manual_backward(loss)  opt1.step()  # 每2步更新一次分類器  if batch_idx % 2 == 0:  opt2.zero_grad()  self.manual_backward(loss)  opt2.step()  self.log("train_loss", loss)  # 自動記錄訓練損失  # 不在返回loss,因為已經手動實現  return None  def validation_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("val_loss", loss)  # 自動記錄驗證損失  return loss  def test_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("test_loss", loss)  # 自動記錄測試損失  return loss  def configure_optimizers(self):  #2. 這里對不同參數應用不同優化和調度,  optimizer1 = torch.optim.Adam(  self.feature_extractor.parameters(),  lr=1e-3,  weight_decay=1e-4  )  optimizer2 = torch.optim.SGD(  self.classifier.parameters(),  lr=1e-2,  momentum=0.9  )  # 假如這里只需對第二個優化器進行學習率調度  scheduler2 = torch.optim.lr_scheduler.MultiStepLR(  optimizer2,  milestones=[1,3,5],  gamma=0.5,  last_epoch=-1)  # 返回值return [optimizer1, optimizer2], scheduler2  # 4. 增加鉤子函數,每個batch后手動更新學習率  def on_train_batch_end(self, outputs, batch, batch_idx):  # 獲取調度器  scheduler2 = self.lr_schedulers()  # 更新調度器(按批次)  scheduler2.step()  # 記錄學習率  lr = scheduler2.get_last_lr()[0]  self.log("lr", lr, prog_bar=True)  # 5. 增加鉤子函數,模型中保存參數配置  def on_save_checkpoint(self, checkpoint: dict) -> None:  checkpoint["save_data"] = self.hparams

2 數據

class MNISTDataModule(pl.LightningDataModule):  def __init__(self, batch_size=32):  super().__init__()  self.batch_size = batch_size  # 數據處理部分,只會加載一次  def prepare_data(self):  # 下載數據集  MNIST(root="data", train=True, download=True)  MNIST(root="data", train=False, download=True)  # 在分布式訓練的時候,每個進程都會加載  def setup(self, stage=None):  # 數據預處理和劃分  transform = ToTensor()  mnist_full = MNIST(root="data", train=True, transform=transform)  self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000])  self.mnist_test = MNIST(root="data", train=False, transform=transform)  def train_dataloader(self):  return DataLoader(self.mnist_train, batch_size=self.batch_size, shuffle=True)  def val_dataloader(self):  return DataLoader(self.mnist_val, batch_size=self.batch_size)  def test_dataloader(self):  # 當然如果沒有test,只需要返回None  return DataLoader(self.mnist_test, batch_size=self.batch_size)

以上是數據模塊的基本結構

3 回調函數定義

下面是一個定義的例子,作用是保存config

import torch  
from torch import nn  
from torch.utils.data import DataLoader, random_split  
from torchvision.datasets import MNIST  
from torchvision.transforms import ToTensor  
import pytorch_lightning as pl  
from typing import Dict, Any  
import os  
from pytorch_lightning.callbacks import ModelCheckpoint, Callback, LearningRateMonitor  
from omegaconf import OmegaConfclass SetupCallback(Callback):  def __init__(self, now, cfgdir, config):  super().__init__()  self.now = now  self.cfgdir = cfgdir  self.config = config  def on_train_start(self, trainer, pl_module):  # 只在主進程保留  if trainer.global_rank == 0:  print("Project config")  OmegaConf.save(self.config,  os.path.join(self.cfgdir, "{}-project.yaml".format(self.now)))  # 把config 也存到模型中  def on_save_checkpoint(  self, trainer: "pl.Trainer", pl_module: "pl.LightningModule", checkpoint: Dict[str, Any]  ) -> None:  checkpoint["cfg_project"] = self.config

這里on_train_start``on_save_checkpoint 就是定義在回調函數中的鉤子函數,下面介紹這幾個鉤子函數使用方法

4 幾個常見的鉤子函數使用

以下是三個鉤子函數在模型類和回調函數中使用方法及調用順序的簡明對比表格:

鉤子函數位置方法簽名典型用途調用順序執行頻率
on_fit_start模型類def on_fit_start(self)全局初始化、分布式設置先執行整個訓練過程一次
回調函數def on_fit_start(self, trainer, pl_module)準備日志系統、設置全局狀態后執行整個訓練過程一次
on_train_start模型類def on_train_start(self)初始化訓練指標、計時器先執行每個訓練循環一次
回調函數def on_train_start(self, trainer, pl_module)重置回調狀態、訓練前準備后執行每個訓練循環一次
on_save_checkpoint模型類def on_save_checkpoint(self, checkpoint)保存模型額外狀態后執行每次保存檢查點時
回調函數def on_save_checkpoint(self, trainer, pl_module, checkpoint)保存回調狀態、添加元數據先執行每次保存檢查點時

調用順序示意圖

訓練開始
├── on_fit_start
│   ├── 模型類.on_fit_start (1)
│   └── 回調函數.on_fit_start (2)
│
├── on_train_start
│   ├── 模型類.on_train_start (3)
│   └── 回調函數.on_train_start (4)
│
├── 訓練周期...
│
└── 保存檢查點├── 回調函數.on_save_checkpoint (5)└── 模型類.on_save_checkpoint (6)

5 完整代碼

simple.yaml

trainer:accelerator: gpudevices: [1]max_epochs: 100
call_back:modelckpt:filename: "{epoch:03}-{train_loss:.2f}-{val_loss:.2f}"save_top_k: -1save_step: trueevery_n_epochs: 10verbose: truesave_last: true
model:target: main_pl.LitModelparams:imgsize: 28hidden: 128num_class: 10
data:target: main_pl.MNISTDataModuleparams:batch_size: 32

main_pl.py

import torch  
from torch import nn  
from torch.utils.data import DataLoader, random_split  
from torchvision.datasets import MNIST  
from torchvision.transforms import ToTensor  
import pytorch_lightning as pl  
from typing import Dict, Any  
from pytorch_lightning.callbacks import ModelCheckpoint, Callback, LearningRateMonitor  
from omegaconf import OmegaConf  
import argparse, os, datetime, importlib, glob  
from pytorch_lightning import Trainer  def get_obj_from_str(string, reload=False):  module, cls = string.rsplit(".", 1)  if reload:  module_imp = importlib.import_module(module)  importlib.reload(module_imp)  return getattr(importlib.import_module(module, package=None), cls)  def instantiate_from_config(config):  if not "target" in config:  raise KeyError("Expected key `target` to instantiate.")  return get_obj_from_str(config["target"])(**config.get("params", dict()))  # 1. 定義 LightningModule 子類  
class LitModel(pl.LightningModule):  def __init__(self, imgsize=28, hidden=128, num_class=10):  super().__init__()  self.flatten = nn.Flatten()  ####################  # 1. 修改模型為兩部分方便應用不同的優化器  self.feature_extractor = nn.Sequential(  nn.Linear(imgsize * imgsize, hidden),  nn.ReLU()  )  self.classifier = nn.Sequential(  nn.Linear(hidden, num_class)  )  #關閉自動優化  self.automatic_optimization = False  ####################  self.loss_fn = nn.CrossEntropyLoss()  # 增加保存參數  self.save_hyperparameters()  def forward(self, x):  x = self.flatten(x)  features = self.feature_extractor(x)  return self.classifier(features)  def training_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  opt1, opt2 = self.optimizers()  #3,手動優化  if batch_idx % 2 != 0:  opt1.zero_grad()  self.manual_backward(loss)  opt1.step()  # 每2步更新一次分類器  if batch_idx % 2 == 0:  opt2.zero_grad()  self.manual_backward(loss)  opt2.step()  self.log("train_loss", loss)  # 自動記錄訓練損失  # 不在返回loss,因為已經手動實現  return None  def validation_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("val_loss", loss)  # 自動記錄驗證損失  return loss  def test_step(self, batch, batch_idx):  x, y = batch  pred = self(x)  loss = self.loss_fn(pred, y)  self.log("test_loss", loss)  # 自動記錄測試損失  return loss  def configure_optimizers(self):  #2. 這里對不同參數應用不同優化和調度,  optimizer1 = torch.optim.Adam(  self.feature_extractor.parameters(),  lr=1e-3,  weight_decay=1e-4  )  optimizer2 = torch.optim.SGD(  self.classifier.parameters(),  lr=1e-2,  momentum=0.9  )  # 假如這里只需對第二個優化器進行學習率調度  scheduler2 = torch.optim.lr_scheduler.MultiStepLR(  optimizer2,  milestones=[1,3,5],  gamma=0.5,  last_epoch=-1)  # 返回值return [optimizer1, optimizer2], scheduler2  # 4. 增加鉤子函數,每個batch后手動更新學習率  def on_train_batch_end(self, outputs, batch, batch_idx):  # 獲取調度器  scheduler2 = self.lr_schedulers()  # 更新調度器(按批次)  scheduler2.step()  # 記錄學習率  lr = scheduler2.get_last_lr()[0]  self.log("lr", lr, prog_bar=True)  def on_save_checkpoint(self, checkpoint: dict) -> None:  checkpoint["save_data"] = self.hparams  # 2. 準備數據模塊  
class MNISTDataModule(pl.LightningDataModule):  def __init__(self, batch_size=32):  super().__init__()  self.batch_size = batch_size  # 數據處理部分,只會加載一次  def prepare_data(self):  # 下載數據集  MNIST(root="data", train=True, download=True)  MNIST(root="data", train=False, download=True)  # 在分布式訓練的時候,每個進程都會加載  def setup(self, stage=None):  # 數據預處理和劃分  transform = ToTensor()  mnist_full = MNIST(root="data", train=True, transform=transform)  self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000])  self.mnist_test = MNIST(root="data", train=False, transform=transform)  def train_dataloader(self):  return DataLoader(self.mnist_train, batch_size=self.batch_size, shuffle=True)  def val_dataloader(self):  return DataLoader(self.mnist_val, batch_size=self.batch_size)  def test_dataloader(self):  # 當然如果沒有test,只需要返回None  return DataLoader(self.mnist_test, batch_size=self.batch_size)  class SetupCallback(Callback):  def __init__(self, now, cfgdir, config):  super().__init__()  self.now = now  self.cfgdir = cfgdir  self.config = config  def on_train_start(self, trainer, pl_module):  # 只在主進程保留  if trainer.global_rank == 0:  print("Project config")  OmegaConf.save(self.config,  os.path.join(self.cfgdir, "{}-project.yaml".format(self.now)))  # 把config 也存到模型中  def on_save_checkpoint(  self, trainer: "pl.Trainer", pl_module: "pl.LightningModule", checkpoint: Dict[str, Any]  ) -> None:  checkpoint["cfg_project"] = self.config  if __name__ == '__main__':  now = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")  configs_path = 'simple.yaml'  logdir = os.path.join("logs", now)  config = OmegaConf.load(configs_path)  #0. 從config中讀取 trainer 基本參數  accelerator: gpu devices: [0] max_epochs: 100    trainer_kwargs = dict(config.trainer)  #1, 定義loss loger trainer_kwargs  logger_cfg =  {  "target": "pytorch_lightning.loggers.TensorBoardLogger",  "params": {  "name": "tensorboard",  "save_dir": logdir,  }  }  logger_cfg = OmegaConf.create(logger_cfg)  trainer_kwargs["logger"] = instantiate_from_config(logger_cfg)  #2. callback  modelckpt_params =  config.call_back.modelckpt  callbacks_cfg = {  "setup_callback": {  "target": "main_pl.SetupCallback",  "params": {  "now": now,  "cfgdir": logdir,  "config": config,  }  },  "learning_rate_logger": {  "target": "main_pl.LearningRateMonitor",  "params": {  "logging_interval": "step",  }  },  "checkpoint_callback":{  "target": "pytorch_lightning.callbacks.ModelCheckpoint",  "params": {  "dirpath": logdir,  "filename": modelckpt_params.filename,  "save_top_k": modelckpt_params.save_top_k,  "verbose": modelckpt_params.verbose,  "save_last": modelckpt_params.save_last,  "every_n_epochs": modelckpt_params.every_n_epochs,  }  }  }  callbacks = [instantiate_from_config(callbacks_cfg[k]) for k in callbacks_cfg]  trainer_kwargs["callbacks"] = callbacks  print(trainer_kwargs)  #3. 構建trainer  trainer = Trainer(**trainer_kwargs)  #4. 構建data 和 model    # build data and model    data = instantiate_from_config(config.data)  model = instantiate_from_config(config.model)  #5. 訓練  try:  trainer.fit(model, data)  except Exception:  raise

運行結果:
logs中會保存我們的配置和tensorboard的日志以及模型
在這里插入圖片描述

5 總結

PyTorch Lightning 是一個輕量級的 PyTorch 封裝庫,它通過結構化代碼和自動化工程細節,顯著提升深度學習研究和開發的效率。以下是其主要優勢總結:


1. 代碼結構化與可讀性

  • 關注科研而非工程:將模型定義、訓練邏輯、工程代碼解耦
  • 標準化接口:強制使用 LightningModule 方法(training_step, configure_optimizers 等)
  • 減少樣板代碼:訓練循環代碼量減少 80%+
# 傳統 PyTorch vs Lightning
# ---------------------------
# PyTorch: 需手動編寫訓練循環
for epoch in epochs:for batch in data:optimizer.zero_grad()loss = model(batch)loss.backward()optimizer.step()# Lightning: 只需定義邏輯
class LitModel(pl.LightningModule):def training_step(self, batch, batch_idx):x, y = batchy_hat = self(x)loss = F.cross_entropy(y_hat, y)return loss

2. 自動化工程細節

功能實現方式優勢
分布式訓練Trainer(accelerator="gpu", devices=4)單行代碼啟用多GPU/TPU
混合精度訓練Trainer(precision="16-mixed")顯存節省+速度提升
梯度累積Trainer(accumulate_grad_batches=4)模擬更大batch_size
早停機制callbacks=[EarlyStopping(...)]自動防止過擬合

3. 可復現性與實驗管理

  • 版本控制:自動保存超參數 (self.save_hyperparameters())
  • 實驗跟蹤:內置支持 TensorBoard/W&B/MLFlow
  • 完整檢查點:一鍵保存模型+優化器+超參數狀態
# 自動記錄所有實驗
trainer = Trainer(logger=TensorBoardLogger("logs/"))

4. 硬件無關性

單行切換硬件環境:

# CPU → GPU → TPU → 多節點分布式
trainer = Trainer(accelerator="auto",      # 自動檢測硬件devices="auto",          # 使用所有可用設備strategy="ddp_find_unused_parameters_true"  # 分布式策略
)

5. 調試與開發效率

# 快速驗證代碼
trainer = Trainer(fast_dev_run=True)  # 只跑1個batch# 性能分析
trainer = Trainer(profiler="advanced")  # 識別瓶頸

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87146.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87146.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87146.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型算法面試筆記——注意力Transformer流程/面試題篇

學習資料來源于字母站大學 1 Transformer架構 基于編碼器-解碼器的架構來處理序列對。跟使用注意力的seq2seq不同,Transformer是基于純注意力。 2 注意力 2.1 自注意力機制 使用注意力:需要根據整個序列進行預測,對于同一input&#xf…

Rust 定義與實例化結構體

文章目錄 Rust 定義與實例化結構體5.1 結構體的定義與意義5.2 結構體實例化5.2.1 基本實例化5.2.2 可變性規則5.2.3 字段初始化簡寫5.2.4 結構體更新語法 5.3 特殊結構體類型5.3.1 元組結構體(Tuple Struct)5.3.2 類單元結構體(Unit-Like Str…

ELK日志分析系統(filebeat+logstash+elasticsearch+kibana)

一、ELK 平臺介紹 1、ELK 概述 日志主要包括系統日志、應用程序日志和安全日志。系統運維和開發人員可以通過日志了解服務器軟硬件信息、檢查配置過程中的錯誤及錯誤發生的原因。經常分析日志可以了解服務器的負荷,性能安全性,從而及時采取措施糾正錯誤。…

JS基礎4—jQuery

jQuery常用內容 jQuery 介紹jQuery 獲取方式基本選擇器 (最常用)層級選擇器 (基于元素間關系)過濾選擇器 (基于特定條件) jQuery事件綁定jQuery 方法調用jQuery遍歷jQuery 獲取與設置jQuery 添加與刪除jQuery CSS 類jQuery - AJAX 總結 jQuery 介紹 jQuery 是一個輕量級、快速…

時鐘周期是什么?

時鐘周期(Clock Cycle)是什么? 時鐘周期(Clock Cycle)是計算機系統中一個最基礎的時間單位,也稱為時鐘節拍或時鐘周期時間(Clock Period)。它由系統時鐘發生器產生的一個周期性脈沖…

如何用SEO優化長尾關鍵詞?

內容概要 在SEO優化領域,長尾關鍵詞扮演著至關重要的角色,它們能有效提升網站在搜索引擎中的可見度和流量轉化率。本文將全面解析如何通過系統方法優化長尾關鍵詞,涵蓋從基礎理論到實戰應用的完整流程。核心內容包括利用專業工具進行關鍵詞挖…

電子面單系統開發全解析

一、如果要做電子面單系統,怎么做? 開發電子面單系統是一項復雜且涉及多方面考量的工程,涵蓋需求分析、系統架構設計、技術選型、接口對接、安全性保障、第三方服務選擇以及部署與維護等關鍵環節。 電子面單系統開發步驟 需求分析&#xf…

UE5 - 制作《塞爾達傳說》中林克的技能 - 18 - 磁力抓取器

讓我們繼續《塞爾達傳說》中林克技能的制作!!! UE版本:5.6.0 VS版本:2022 本章節的核心目標:磁力抓取器 先讓我們看一下完成后的效果: 18_磁力抓取器 大綱如下: 引言功能架構與核心邏輯物理材質與場景配置代碼實現:從識別到操控操作說明1.引言 在《塞爾達傳說》中,林…

基于ApachePOI實現百度POI分類快速導入PostgreSQL數據庫實戰

目錄 前言 一、百度POI分類簡介 1、數據表格 2、分類結構 二、從Excel導入到PG數據庫 1、Excel解析流程 2、數據入庫 3、入庫成果及檢索 三、總結 前言 在上一篇博文中,我們對高德POI分類進行了深入剖析 并對Excel 中 POI 分類數據的存儲結構特點進行了詳細介…

學習經驗分享【41】YOLOv13:基于超圖增強自適應視覺感知的實時目標檢測

YOLO算法更新速度很快,已經出到V13版本,后續大家有想發論文或者搞項目可更新自己的baseline了。 摘要:YOLO 系列模型憑借其卓越的精度和計算效率,在實時目標檢測領域占據主導地位。然而,YOLOv11 及早期版本的卷積架構&…

Handling outliers in non-blind image deconvolution論文閱讀

Handling outliers in non-blind image deconvolution 1. 研究目標與實際意義2. 創新方法:基于EM的異常值建模2.1 新模糊模型2.1.1 目標函數2.2 EM框架:迭代優化二元掩碼2.2.1 E步:計算后驗權重 E [ m x ] E[m_x] E[mx?]2.2.2 M步:加權正則化反卷積2.3 優化加速技術2.3.1…

Redis 功能擴展:Lua 腳本對 Redis 的擴展

Redis 是一個高性能的內存數據庫,支持多種數據結構,如字符串、哈希、列表、集合和有序集合。為了增強其功能,Redis 引入了 Lua 腳本支持,使開發者可以編寫自定義的腳本,確保操作的原子性并提高復雜操作的性能。本文將詳…

七天學完十大機器學習經典算法-06.支持向量機(SVM):分類邊界的藝術——深入淺出指南

接上一篇《七天學完十大機器學習經典算法-05.從投票到分類:K近鄰(KNN)算法完全指南》 想象你要在操場上為兩個班級劃活動區域,如何畫出一條最公平的分界線?這條線不僅要分開兩班學生,還要讓兩個班都離分界線盡可能遠——這就是支持…

python如何安裝PyQt6-stubs依賴包

PyQt6-stubs 是為 PyQt6 提供類型提示(Type Hints)和 IDE 智能補全支持的第三方補丁包,特別適用于 PyCharm、VS Code 等現代 IDE。它對開發者在編碼時幫助極大。 一、安裝方法 需要提前安裝好git,然后克隆PyQt6-stubs源碼&#xf…

創宇智腦 MCP 賦能 AiPy,IP 風險調查效率實現 10 倍飛躍,威脅分析一鍵生成

還記得上個月那個焦頭爛額的凌晨三點嗎?監控大屏突然瘋狂閃爍,500 多個 IP 地址同時出現異常訪問,密密麻麻的數據流在屏幕上跳動,像極了一張讓人窒息的大網。我和團隊成員瞪著布滿血絲的眼睛,手動排查每一個 IP&#x…

使用SRS+ffmpeg實現https推流flv

1修改SRS的live.conf配置如下: # Live streaming config for SRS. # see full.conf for detail config.listen 1935; max_connections 1000; srs_log_tank console; daemon off;http_api {enabled on;listen …

力扣網編程題:合并兩個有序數組(雙指針解法)

一. 簡介 上一篇文章對"合并兩個有序數組"題目,使用了暴力解法,算法時間復雜度比較高。文章如下: 力扣網編程題:合并兩個有序數組(直接解法)-CSDN博客 本文滿足進階要求,算法時間復…

數據結構之 【樹的簡介】(樹的(相關)概念、二叉樹的概念、部分性質、滿二叉樹、完全二叉樹)

目錄 1.樹的概念及結構 1.1樹的概念 1.2樹的相關概念 1.3樹的表示 1.4樹在實際中的應用 2.二叉樹概念及結構 2.1二叉樹的概念 2.2特殊的二叉樹 2.3二叉樹的性質 2.4應用題 1.樹的概念及結構 1.1樹的概念 樹是一種非線性的數據結構,由 n(n…

Redis-7.4.3-Windows-x64下載安裝使用

Redis軟件包下載地址鏈接:https://github.com/redis-windows/redis-windows/releases 檢查或者修改配置文件redis.conf: #如果允許外部其他主機訪問本機redis,設置成:bind 0.0.0.0 bind 127.0.0.1 protected-mode yes #設置端口…

Educational Codeforces Round 180 (Rated for Div. 2)

AB 略 C 對于axayaz>max(2*az,an),枚舉y z 二分x D 首先,長度為1的邊的已經有n-1條,那么構造的圖中只能存在一條長度為2的好邊。我們先構造出一個圖只存在n-1條好邊,我們發現對于一個點所有連接它的邊要不均指向它要不均背…