训练+评估流程

  • 1、要求
  • 2、训练+评估(PyTorch + TensorBoard )
    • 完整代码(单文件示例)
    • 运行方法
    • 功能对应表
  • 3、pytorch自定义评估要继承哪个类?
  • 4、HF Trainer和SB3
  • 5、 汇总
    • 1. PyTorch Lightning + TensorBoard + ModelCheckpoint + EarlyStopping
      • 核心代码示例:
    • 2. TensorFlow / Keras + TensorBoard + ModelCheckpoint + EarlyStopping
    • 3. Stable Baselines3 (强化学习)
    • 4. Huggingface Trainer(NLP)
    • 5. 结合Weights & Biases(W\&B)
    • 总结推荐

1、要求

训练:
- 可视化
- 回调
- 自定义loss
- 自定义metric评估:
- 可视化
- 自定义数据:
- 自定义模型:
- 自定义

训练:训练可视化,自定义回调,评估指标
评估:评估可视化,自定义评估指标

数据:自定义数据
https://lightning.ai/docs/pytorch/stable/data/datamodule.html

模型:自定义模型

回调集合:参考sb3
稳定基线为您提供了一组常见的回调:
定期保存模型(CheckpointCallback)
定期评估模型并保存最佳模型(EvalCallback)
链接回调 (CallbackList)
触发事件回调(事件回调、EveryNTimesteps)
每 N 个时间步长记录数据 (LogEveryNTimesteps)
根据奖励阈值提前停止训练 (StopTrainingOnRewardThreshold)

2、训练+评估(PyTorch + TensorBoard )

官方api,https://docs.pytorch.ac.cn/docs/stable/tensorboard.html
https://blog.csdn.net/Python_Ai_Road/article/details/107704530
https://github.com/haoxizhong/pytorch-worker
https://github.com/onepanelio/onepanel

提问:

pytorch tensorboard实现下面要求:
训练:
- 可视化
- 回调
- 自定义metric评估:
- 可视化
- 自定义数据:
- 自定义模型:
- 自定义

好的,我帮你写一个PyTorch + TensorBoard 完整可运行的示例,
满足你所有要求:

  • 训练
    ✅ 可视化(loss/accuracy/自定义metric曲线)
    ✅ 回调(EarlyStopping)
    ✅ 自定义 metric(比如 F1-score)

  • 评估
    ✅ 可视化(混淆矩阵、曲线)
    ✅ 自定义指标(precision、recall、F1等)

  • 数据
    ✅ 自定义 Dataset / DataLoader

  • 模型
    ✅ 自定义 nn.Module


完整代码(单文件示例)

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from sklearn.metrics import precision_score, recall_score, f1_score, confusion_matrix
import matplotlib.pyplot as plt
import time# ===================== 1. 自定义数据集 =====================
class MyDataset(Dataset):def __init__(self, size=500):np.random.seed(0)self.x = np.random.rand(size, 10).astype(np.float32)self.y = (self.x.sum(axis=1) > 5).astype(np.int64)  # 二分类def __len__(self):return len(self.x)def __getitem__(self, idx):return self.x[idx], self.y[idx]# ===================== 2. 自定义模型 =====================
class MyModel(nn.Module):def __init__(self, input_dim=10, hidden_dim=32, num_classes=2):super().__init__()self.net = nn.Sequential(nn.Linear(input_dim, hidden_dim),nn.ReLU(),nn.Linear(hidden_dim, num_classes))def forward(self, x):return self.net(x)# ===================== 3. 回调(早停) =====================
class EarlyStopping:def __init__(self, patience=5, save_path="best_model.pth"):self.patience = patienceself.counter = 0self.best_loss = float("inf")self.save_path = save_pathself.early_stop = Falsedef __call__(self, val_loss, model):if val_loss < self.best_loss:self.best_loss = val_lossself.counter = 0torch.save(model.state_dict(), self.save_path)else:self.counter += 1if self.counter >= self.patience:self.early_stop = True# ===================== 4. 自定义 metric =====================
def compute_metrics(y_true, y_pred):precision = precision_score(y_true, y_pred, zero_division=0)recall = recall_score(y_true, y_pred, zero_division=0)f1 = f1_score(y_true, y_pred, zero_division=0)return precision, recall, f1# ===================== 5. 训练(可视化 + 回调 + 自定义metric) =====================
def train_model():train_set = MyDataset(500)val_set = MyDataset(100)train_loader = DataLoader(train_set, batch_size=32, shuffle=True)val_loader = DataLoader(val_set, batch_size=32)device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = MyModel().to(device)criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(), lr=0.001)log_dir = f"runs/train_{time.strftime('%Y%m%d-%H%M%S')}"writer = SummaryWriter(log_dir=log_dir)early_stopping = EarlyStopping(patience=5)for epoch in range(50):# ===== 训练 =====model.train()total_loss, y_true_train, y_pred_train = 0, [], []for x, y in train_loader:x, y = x.to(device), y.to(device)optimizer.zero_grad()outputs = model(x)loss = criterion(outputs, y)loss.backward()optimizer.step()total_loss += loss.item()preds = outputs.argmax(1)y_true_train.extend(y.cpu().numpy())y_pred_train.extend(preds.cpu().numpy())train_loss = total_loss / len(train_loader)train_precision, train_recall, train_f1 = compute_metrics(y_true_train, y_pred_train)train_acc = np.mean(np.array(y_true_train) == np.array(y_pred_train))# ===== 验证 =====model.eval()val_loss, y_true_val, y_pred_val = 0, [], []with torch.no_grad():for x, y in val_loader:x, y = x.to(device), y.to(device)outputs = model(x)loss = criterion(outputs, y)val_loss += loss.item()preds = outputs.argmax(1)y_true_val.extend(y.cpu().numpy())y_pred_val.extend(preds.cpu().numpy())val_loss /= len(val_loader)val_precision, val_recall, val_f1 = compute_metrics(y_true_val, y_pred_val)val_acc = np.mean(np.array(y_true_val) == np.array(y_pred_val))# ===== 写入 TensorBoard =====writer.add_scalar("Loss/train", train_loss, epoch)writer.add_scalar("Loss/val", val_loss, epoch)writer.add_scalar("Accuracy/train", train_acc, epoch)writer.add_scalar("Accuracy/val", val_acc, epoch)writer.add_scalar("F1/train", train_f1, epoch)writer.add_scalar("F1/val", val_f1, epoch)print(f"Epoch {epoch+1} | "f"Train Loss: {train_loss:.4f} Acc: {train_acc:.4f} F1: {train_f1:.4f} | "f"Val Loss: {val_loss:.4f} Acc: {val_acc:.4f} F1: {val_f1:.4f}")# 回调early_stopping(val_loss, model)if early_stopping.early_stop:print("Early stopping!")breakwriter.close()print(f"训练日志保存在 {log_dir}")# ===================== 6. 评估(可视化 + 自定义metric) =====================
def evaluate_model():device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = MyModel().to(device)model.load_state_dict(torch.load("best_model.pth"))model.eval()test_set = MyDataset(100)test_loader = DataLoader(test_set, batch_size=32)y_true, y_pred = [], []with torch.no_grad():for x, y in test_loader:x, y = x.to(device), y.to(device)outputs = model(x)preds = outputs.argmax(1)y_true.extend(y.cpu().numpy())y_pred.extend(preds.cpu().numpy())acc = np.mean(np.array(y_true) == np.array(y_pred))precision, recall, f1 = compute_metrics(y_true, y_pred)print(f"Test Accuracy: {acc:.4f}")print(f"Test Precision: {precision:.4f} Recall: {recall:.4f} F1: {f1:.4f}")# ===== 混淆矩阵可视化 =====cm = confusion_matrix(y_true, y_pred)fig, ax = plt.subplots()ax.matshow(cm, cmap=plt.cm.Blues)for i in range(cm.shape[0]):for j in range(cm.shape[1]):ax.text(j, i, cm[i, j], va='center', ha='center')plt.xlabel("Predicted")plt.ylabel("True")plt.title("Confusion Matrix")plt.show()if __name__ == "__main__":train_model()evaluate_model()

运行方法

# 安装依赖
pip install torch tensorboard scikit-learn matplotlib# 运行
python demo.py# 查看TensorBoard
tensorboard --logdir runs

功能对应表

模块功能实现方式
训练可视化 loss / acc / F1SummaryWriter.add_scalar()
回调 EarlyStoppingEarlyStopping
自定义 metric(precision/recall/F1)compute_metrics()
评估可视化混淆矩阵matplotlib + confusion_matrix
自定义 metric(precision/recall/F1)compute_metrics()
数据自定义 DatasetMyDataset
模型自定义 nn.ModuleMyModel

我建议你如果后面项目要长期用,可以帮你改成模块化结构(dataset.py、model.py、train.py、evaluate.py 分开),
这样扩展性更好。

你要我下一步帮你拆成模块化版本吗?这样更适合大型项目维护。

3、pytorch自定义评估要继承哪个类?

pytorch自定义评估要继承哪个类

PyTorch 里,如果你是纯用 torch(而不是 PyTorch Lightning、Hugging Face Trainer 等封装框架),自定义评估其实不用继承任何固定的类,因为 PyTorch 本身没有“评估器”这一内置抽象,评估通常就是自己写一个函数:

def evaluate(model, dataloader, criterion):model.eval()total_loss = 0.0correct = 0total = 0with torch.no_grad():for inputs, targets in dataloader:outputs = model(inputs)loss = criterion(outputs, targets)total_loss += loss.item()# 分类任务示例_, predicted = outputs.max(1)total += targets.size(0)correct += predicted.eq(targets).sum().item()avg_loss = total_loss / len(dataloader)accuracy = 100. * correct / totalreturn avg_loss, accuracy

但是,如果你是在 某个训练框架 里做自定义评估,就会有对应的基类:

框架自定义评估类要继承的基类
PyTorch Lightningpl.Callbackpl.LightningModule(重写 validation_step
Hugging Face TransformersTrainerCallback 或直接在 Trainer 里传 compute_metrics
TorchMetricstorchmetrics.Metric
Catalystcatalyst.metrics.MetricCallback
Igniteignite.metrics.Metric

所以我需要确认一下,你的“自定义评估”是:

  • 纯 PyTorch 写的训练循环
  • 还是基于 Lightning / Transformers / 其他训练框架

我猜你可能是想在 PPO 或 RL 里加自定义评估指标,如果是那种情况,类继承方式又不一样。
你要我帮你按 RL + PPO 场景写一个自定义评估类吗?这样就直接能接到你现有环境里。

4、HF Trainer和SB3

详细参考下面笔记:
https://blog.csdn.net/weixin_44986037/article/details/151153156?spm=1001.2014.3001.5502
https://blog.csdn.net/weixin_44986037/article/details/151225587?spm=1001.2014.3001.5502
https://blog.csdn.net/weixin_44986037/article/details/150427299?spm=1001.2014.3001.5502
https://blog.csdn.net/weixin_44986037/article/details/148544185?spm=1001.2014.3001.5501

建议用针对性框架:
Stable Baselines3 : 强化学习
Huggingface Trainer :NLP及Transformer模型
PyTorch Lightning:不追求训练速度,建议用tensorboard,PyTorch Lightning坑有点多

5、 汇总

提问:现成的ai模型训练评估框架,包括tersorboard查看训练数据、筛选模型、评估效果

提问:

简单概述主流现成的AI模型训练+评估框架,包含:训练过程中的数据监控(比如通过 TensorBoard 可视化损失、指标)模型筛选(如自动保存最优模型、早停)评估效果(自动计算指标,方便比较模型)

你想要的是一个现成的AI模型训练+评估框架,包含:

  • 训练过程中的数据监控(比如通过 TensorBoard 可视化损失、指标)
  • 模型筛选(如自动保存最优模型、早停)
  • 评估效果(自动计算指标,方便比较模型)

下面给你推荐几个主流且功能完整的框架/工具组合,覆盖你需求的这几个点:


1. PyTorch Lightning + TensorBoard + ModelCheckpoint + EarlyStopping

  • 训练监控:Lightning内置对TensorBoard的支持,训练时自动记录loss、metric到TensorBoard。
  • 模型筛选:内置 ModelCheckpoint,可自动保存指标最优模型(如val_loss最小、准确率最高)。
  • 早停:内置 EarlyStopping,当验证指标不再提升时自动停止训练。
  • 评估效果:支持训练、验证、测试阶段指标计算和记录。

核心代码示例:

import pytorch_lightning as pl
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStoppingcheckpoint_callback = ModelCheckpoint(monitor='val_loss',    # 监控验证损失mode='min',           # 取最小值对应模型save_top_k=1,verbose=True,
)early_stop_callback = EarlyStopping(monitor='val_loss',patience=5,verbose=True,mode='min'
)trainer = pl.Trainer(max_epochs=50,callbacks=[checkpoint_callback, early_stop_callback],logger=pl.loggers.TensorBoardLogger('tb_logs/')
)trainer.fit(model, train_dataloader, val_dataloader)

启动后,在终端运行 tensorboard --logdir=tb_logs/ 即可实时查看训练过程。


2. TensorFlow / Keras + TensorBoard + ModelCheckpoint + EarlyStopping

  • TensorFlow内置支持TensorBoard,训练时会自动写入日志。
  • ModelCheckpoint可保存验证指标最优模型。
  • EarlyStopping自动停止训练避免过拟合。

示例:

callbacks = [tf.keras.callbacks.TensorBoard(log_dir='./logs'),tf.keras.callbacks.ModelCheckpoint('best_model.h5', monitor='val_loss', save_best_only=True),tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5)
]model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=50, callbacks=callbacks)

3. Stable Baselines3 (强化学习)

  • 自带 EvalCallback 用于训练过程中自动评估模型表现。
  • CheckpointCallback 用于保存模型。
  • 训练日志可通过 TensorBoard 监控。

示例:

from stable_baselines3.common.callbacks import EvalCallback, CheckpointCallbackeval_callback = EvalCallback(eval_env, best_model_save_path='./logs/',log_path='./logs/', eval_freq=10000, deterministic=True)
checkpoint_callback = CheckpointCallback(save_freq=5000, save_path='./logs/')model.learn(total_timesteps=100000, callback=[eval_callback, checkpoint_callback])

运行 tensorboard --logdir=./logs 可查看指标变化。


4. Huggingface Trainer(NLP)

  • 内置日志记录(支持TensorBoard、WandB等)
  • 自动保存最优模型和早停(EarlyStoppingCallback)
  • 评估指标自动计算和记录

示例:

from transformers import Trainer, TrainingArguments, EarlyStoppingCallbacktraining_args = TrainingArguments(output_dir='./results',evaluation_strategy='epoch',save_strategy='epoch',logging_dir='./logs',logging_steps=10,load_best_model_at_end=True,
)trainer = Trainer(model=model,args=training_args,train_dataset=train_dataset,eval_dataset=eval_dataset,callbacks=[EarlyStoppingCallback(early_stopping_patience=3)],
)trainer.train()

然后使用TensorBoard查看 ./logs 文件夹。


5. 结合Weights & Biases(W&B)

(即WandB)

  • 支持各种框架(PyTorch、TensorFlow、Lightning、SB3、HF等)
  • 自动记录训练日志、模型、超参
  • 支持在线实时可视化和对比多个实验
  • 支持模型版本管理和筛选

官网:https://wandb.ai/site


总结推荐

框架/工具训练监控(TensorBoard)自动保存最优模型早停评估指标简单易用适用范围
PyTorch LightningPyTorch通用
TensorFlow / KerasTensorFlow/Keras
Stable Baselines3部分强化学习
Huggingface TrainerNLP及Transformer模型
Weights & Biases ((WandB))各类深度学习框架

如果你告诉我你用的是哪种框架,我可以帮你写具体的训练+评估+TensorBoard配置示例,或者帮你搭建完整的训练流水线。你看?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921546.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921546.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921546.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【开题答辩全过程】以 基于Android的点餐系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

【音视频】Http-FLV 介绍

一、Http-FLV 原理 HTTP-FLV 是基于 HTTP 协议的 FLV&#xff08;Flash Video&#xff09;流媒体传输方式。它使用 HTTP 协议而不是传统的 RTMP 协议来传输 FLV 格式的视频流。HTTP-FLV 在 Web 视频直播场景中得到了广泛应用&#xff0c;尤其是在不支持或不希望使用 RTMP 协议的…

uniapp vue页面传参到webview.nvue页面的html或者另一vue中

在app内部使用 uni.$emit(collectiones, { data: gx });传到webview.nvue页面 在webview.nvue页面接受 uni.$on(collectiones, (data) > {console.log(接收到的数据:, data.data);});使用evalJS方法 nvue webview通信示例 这块使用receiveMessageFromNvue方法这样传入的 u…

美团大模型“龙猫”登场,能否重塑本地生活新战局?

美团大模型“龙猫”登场&#xff0c;能否重塑本地生活新战局&#xff1f; 美团大模型登场&#xff1a;行业投下重磅炸弹 在大模型技术迅猛发展的当下&#xff0c;每一次新模型的发布都如投入湖面的石子&#xff0c;激起层层涟漪。美团推出的龙猫大模型 LongCat-Flash&#xff0…

shell(十三)参数代换

shell参数代换xargs. 产生命令的参数1. cut -d : -f 1 /etc/passwd | head -n 3 | xargs finger2. 执行前询问用户cut -d : -f 1 /etc/passwd | head -n 3 | xargs -p finger如果直接按回车就退出3. 指定查阅参数个数cut -d : -f 1 /etc/passwd | xargs -p -n 5 finger4. 指定遇…

Proteus 仿真 + STM32CubeMX 协同开发全教程:从配置到仿真一步到位

为帮助你精准掌握「Proteus 仿真 STM32CubeMXSTM32F103R6」的协同开发流程&#xff0c;本文将聚焦该芯片的特性&#xff0c;从工具适配、分步实操到进阶案例&#xff0c;用富文本格式清晰呈现细节&#xff0c;尤其适合新手入门 32 位单片机开发&#xff1a;ProteusSTM32CubeMX…

WIN10+ubuntu22.04.05双系统装机教程

最近DIY了一台5070TI显卡主机&#xff0c;目的是跑IsaacSim5.0仿真&#xff0c;记录双系统装机过程。 1.Ubuntu22.04.05系统盘制作 参考教程&#xff1a;01_【U盘制作ubuntu22.04启动盘并为电脑安装系统记录】_制作ubuntu22.04安装u盘-CSDN博客 U盘因为是64G的&#xff0c;而…

构建高可用二级缓存系统

二级缓存机制原理详解1. 整体架构MyBatis-Plus二级缓存采用装饰器模式实现&#xff0c;核心组件包括&#xff1a;‌Cache接口‌&#xff1a;定义缓存基本操作‌PerpetualCache‌&#xff1a;基础缓存实现&#xff08;HashMap&#xff09;‌装饰器‌&#xff1a;如LruCache、Fif…

MacOS微信双开,亲测有效

本机配置打开终端运行以下命令 第一步&#xff1a;sudo cp -R /Applications/WeChat.app /Applications/WeChat2.app第二步&#xff1a;sudo /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.tencent.xinWeChat2" /Applications/WeChat2.app/Contents/Info…

Drupal XSS漏洞复现:原理详解+环境搭建+渗透实践(CVE-2019-6341)

目录 一、Drupal XSS漏洞 二、环境搭建 1、确保系统已安装 Docker 和 Docker-Compose 2、下载 Vulhub 3、进入漏洞环境 4、启动漏洞环境 5、查看环境状态 6、初始化Drupal环境 &#xff08;1&#xff09;访问 Drupal 安装页面 &#xff08;2&#xff09;完成图形化安…

Redis复制延迟全解析:从毫秒到秒级的优化实战指南

Redis主从延迟飙升导致数据不一致&#xff1f;订单丢失、缓存穿透频发&#xff1f;本文深入剖析8大复制延迟元凶&#xff0c;并提供解决方案&#xff0c;让你的复制延迟从秒级降到毫秒级&#xff01; 一、复制延迟:分布式系统的隐形杀手 ⚠️ 什么是复制延迟&#xff1f; 当主…

数据预处理与特征工程全流程指南:数据清洗、缺失值填补、类别特征编码、特征缩放归一化、特征选择与降维(PCA/LDA)实战解析

1. 数据预处理与特征工程 “数据清洗、缺失值填补、类别特征编码、特征缩放/归一化、特征选择与降维&#xff08;PCA、LDA&#xff09;” 等流程&#xff0c;虽然被反复提到&#xff0c;但要在复杂的实际数据集中一步步落实&#xff0c;难度很大。 摘要 在机器学习与深度学习…

小迪安全v2023学习笔记(七十九讲)—— 中间件安全IISApacheTomcatNginxCVE

文章目录前记服务攻防——第七十九天中间件安全&IIS&Apache&Tomcat&Nginx&弱口令&不安全配置&CVE中间件 - IIS-短文件&解析&蓝屏等中间件 - Nginx-文件解析&命令执行等常见漏洞介绍漏洞复现中间件 - Apache-RCE&目录遍历&文件…

《云原生微服务治理进阶:隐性风险根除与全链路能力构建》

云原生微服务架构已成为企业支撑业务快速迭代的核心载体&#xff0c;但治理能力的滞后却常常成为制约发展的短板。许多企业在完成服务容器化、部署自动化后&#xff0c;便陷入了“架构先进但治理粗放”的困境—服务数量激增导致依赖关系失控&#xff0c;流量波动加剧引发资源配…

因泰立科技:用激光雷达重塑智能工厂物流生态

应对AGV碰撞困局——激光雷达如何重塑智能工厂物流在现代化工厂中&#xff0c;AGV&#xff08;自动引导车&#xff09;与移动机器人已成为提升生产效率的重要设备。然而&#xff0c;这些智能设备在忙碌的工厂环境中&#xff0c;却时常面临碰撞的困扰。这不仅影响了生产效率&…

Remove.bg:精准自动抠图工具,高效解决图片去背景需求

有没有做设计时被 “抠图去背景” 搞到崩溃的朋友&#xff1f;上次小索奇帮同事做活动海报&#xff0c;要把人物图从复杂背景里抠出来&#xff0c;用 PS 选了半天钢笔工具&#xff0c;头发丝还是漏一块缺一块&#xff0c;折腾半小时都没弄好 —— 后来被设计圈的朋友安利了 Rem…

功率器件固晶挑战:抗高温翘曲治具提升IGBT焊接强度30%

功率器件封装新突破&#xff1a;耐高温防变形工装助力IGBT模块焊接强度提升30%在功率半导体封装领域&#xff0c;IGBT模块的芯片贴装工艺正面临严峻挑战。随着功率密度不断提升&#xff0c;传统固晶工装在高温环境下易发生形变&#xff0c;导致焊接层产生空洞、裂纹等缺陷。最新…

MATLAB可以实现的各种智能算法

MATLAB可以实现的各种智能算法(包括但不限于)中文名称英文全称缩写出现年份算法来由&#xff08;灵感来源&#xff09;遗传算法Genetic AlgorithmGA1975模拟达尔文生物进化论的自然选择和遗传学机理&#xff08;选择、交叉、变异&#xff09;粒子群优化算法Particle Swarm Opti…

【iOS】push,pop和present,dismiss

文章目录前言push和poppresent和dismiss基本方法属性说明常见的用法运行演示push和present区别前言 在之前的学习中&#xff0c;我们发现iOS有两种用于推出新界面的常用方法&#xff0c;分别是push和present&#xff0c;但是二者存在很多区别 present只能返回自己的上一级视图…

编写后端JAR包蓝绿发布脚本

前端发布脚本的功能 保留每一个发布版本&#xff0c;防止新版本异常&#xff0c;方便回撤用户无感知&#xff0c;防止发布过程中的宕机 原理&#xff1a; 发布的JAR包只是一个软连接&#xff0c;新的JAR启动正常后&#xff0c;切换软连接指向即可。蓝绿JAR包绑定端口不同&…