在 Pytorch 中使用 TensorBoard
- 机器学习的训练过程中会产生各类数据,包括 “标量scalar”、“图像image”、“统计图diagram”、“视频video”、“音频audio”、“文本text”、“嵌入Embedding” 等等。为了更好地追踪和分析这些数据,许多可视化工具应运而生,比如之前介绍的 wandb
- 本文介绍另一种更加常用的数据追踪工具 TensorBoard,参考见 Pytorch 官方文档
文章目录
- 1. Tensorboard 简介
- 2. 快速入门
- 2.1 运行方法
- 2.2 常用 API
- 3. 使用 TensorBoard 记录 PPO 运行情况
- 4. 其他
1. Tensorboard 简介
- TensorBoard 是Google开发的一个机器学习可视化工具,它原本是TensorFlow中的模块,不过现在已经集成到了Pytorch中。它的功能主要包括
- 跟踪和可视化损失及准确率等指标
- 可视化模型图(操作和层)
- 查看权重、偏差或其他张量随时间变化的直方图
- 将嵌入投射到较低的维度空间
- 显示图片、文字和音频数据
- 剖析 TensorFlow 程序
- TensorBoard 的工作原理和 Wandb 基本相同,本质也是一个网页服务,分成前端和后台两部分,两部分间是异步I/O的
- 后台程序将数据写入到本地文件中
- 前端程序读取本地文件中的数据来进行显示
- 由于 TensorBoard 已经集成到 Pytorch,无需再单独安装,直接
torch.utils.tensorboard
即可找到
2. 快速入门
2.1 运行方法
- 可以把 Tensorboard 的运行分成两步
- 记录数据:使用
SummaryWriter
类实例数据要追踪的数据。每次运行时,该类对象首先会在给定目录log_dir中创建 “事件文件”(本次运行的数据仓库),然后在训练过程中我们可以利用其提供的一系列高级 API 向事件文件中异步地添加数据,从而实时地追踪数据变化。该类的定义如下torch.utils.tensorboard.writer.SummaryWriter(log_dir=None, comment='', purge_step=None, max_queue=10, flush_secs=120, filename_suffix='')
log_dir
(str) – 事件文件保存的目录位置。默认为runs / CURRENT_DATETIME_HOSTNAME,每次运行后都会更改。推挤使用分层文件夹结构,例如对于每个新实验,可以传递“runs / exp1”,“runs / exp2”等来进行比较。comment
(str) –在默认的log_dir后缀中的注释。如果已设置log_dir,则此参数无效。purge_step
(int) – 若在运行到第 T + X T + X T+X 个 step 的时候由于各种原因(内存溢出)发生崩溃,那么当服务重启之后,就回退 X X X 个 step,从 T T T 时刻重新开始将数据写入文件。purge_step 参数就是设置的 X X X,这一段数据将被重新写入。注意,崩溃和恢复的实验应该具有相同的log_dirmax_queue
(int) – 记录事件和摘要时在内存中开的队列的长度,当队列慢了之后就会把数据写入磁盘(文件)中。flush_secs
(int) – 将待处理事件和摘要刷新到磁盘的频率,以秒为单位,默认为每两分钟一次。filename_suffix
(str) – 添加到log_dir目录中所有事件文件名的后缀。有关文件名构造的更多详细信息,请参阅tensorboard.summary.writer.event_file_writer.EventFileWriter。
- 启动网页服务显示数据:使用
tensorboard --logdir 数据文件夹
命令运行网页服务,其中 “数据文件夹” 应设置为之前实验时设置的 log_dir。若看到了如下输出TensorBoard 2.8.0 at http://localhost:6006/ (Press CTRL+C to quit)
则说明启动成功,在浏览器打开相应 url 就能进入TensorBoard界面看到数据显示了。注意默认端口是 6006,如果想进一步指定网页服务端口,可以用tensorboard --logdir=数据文件夹 --port=端口
命令
- 记录数据:使用
2.2 常用 API
-
我们使用
SummaryWriter
类提供的一系列 API 记录数据,比较常用的包括- add_hparams:以表格形式添加一组要比较的超参数
- add_scalar:将标量数据添加到摘要中,用来画一条折线
- add_scalars:将一组标量数据添加到摘要中,可以在同一张图内画多条折线
- add_histogram:绘制直方图
- add_image:将一张图片添加到摘要,需要
pillow
包 - add_images:将一组图片添加到摘要,需要
pillow
包 - add_figure:将matplotlib图形渲染到图像中,并将其添加到摘要中,需要
matplotlib
包 - add_video:将视频数据添加到摘要中,需要
moviepy
包 - add_audio:将音频数据添加到摘要中
- add_text:将文本数据添加到摘要中
- add_graph:将图表数据添加到摘要中,这个常用来显示模型结构
- add_embedding:将词嵌入向量数据添加到摘要中,这个可以交互式显示一组词向量在三维空间的投影
- add_pr_curve:添加精确召回曲线。绘制精确召回曲线可让您了解模型在不同阈值设置下的性能。此函数可以为每个目标提供真实标签(T/F)和预测置信度(通常是模型的输出)。利用 TensorBoard UI 可以交互式地选择阈值
- add_custom_scalars:通过在 “scalar” 中收集的图表
tag
来创建特殊图表。注意对于每个SummaryWriter
对象该函数只能调用一次,因为它只向tensorboard提供元数据,所以可以在训练循环之前或之后调用该函数 - add_mesh:向TensorBoard添加网格或3D点云。可视化基于Three.js,因此它允许用户与呈现的对象进行交互。除了顶点、面等基本定义外,用户还可以提供相机参数、光照条件等
-
综合测试代码参考这里,运行效果可以参考这里:
# 引入SummaryWriter import numpy as np import torch from torch.utils.tensorboard import SummaryWriter import torchvision from PIL import Image import matplotlib import matplotlib.pyplot as plt matplotlib.use('Agg')##### 1、add_scalar实例 def add_scalar_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_scalar")# 绘制 y = 2x 实例x = range(100)for i in x:writer.add_scalar('add_scalar实例:y=2x', i * 2, i)# 关闭writer.close() add_scalar_demo()##### 2、add_scalars 实例 def add_scalars_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_scalars")r = 5for i in range(100):writer.add_scalars('add_scalars实例', {'xsinx':i*np.sin(i/r),'xcosx':i*np.cos(i/r),'tanx': np.tan(i/r)}, i)# 关闭writer.close()add_scalars_demo()##### 3、add_text 实例 def add_text_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_text")writer.add_text('lstm', 'This is an lstm', 0)writer.add_text('rnn', 'This is an rnn', 10)# 关闭writer.close()add_text_demo()##### 4、add_graph 实例def add_graph_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_graph")img = torch.rand([1, 3, 64, 64], dtype=torch.float32)model = torchvision.models.AlexNet(num_classes=10)# print(model)writer.add_graph(model, input_to_model=img)# 关闭writer.close()add_graph_demo()##### 5、add_image 实例def add_image_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_image")img1 = np.random.randn(1, 100, 100)writer.add_image('add_image 实例:/imag1', img1)img2 = np.random.randn(100, 100, 3)writer.add_image('add_image 实例:/imag2', img2, dataformats='HWC')img = Image.open('../imgs/1.png')img_array = np.array(img)writer.add_image('add_image 实例:/cartoon', img_array, dataformats='HWC')# 关闭writer.close()add_image_demo()##### 6、add_images 实例def add_images_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_images")imgs1 = np.random.randn(8, 100, 100, 1)writer.add_images('add_images 实例/imgs1', imgs1, dataformats='NHWC')imgs2 = np.zeros((16, 3, 100, 100))for i in range(16):imgs2[i, 0] = np.arange(0, 10000).reshape(100, 100) / 10000 / 16 * iimgs2[i, 1] = (1 - np.arange(0, 10000).reshape(100, 100) / 10000) / 16 * iwriter.add_images('add_images 实例/imgs2', imgs2) # Default is :math:`(N, 3, H, W)`img = Image.open('../imgs/1.jpg')img3 = np.array(img)imgs4= np.zeros((5, img3.shape[0], img3.shape[1], img3.shape[2]))for i in range(5):imgs4[i] = img3//(i+1)writer.add_images('add_images 实例/imgs4', imgs4, dataformats='NHWC') # Default is :math:`(N, 3, H, W)`# 关闭writer.close()add_images_demo()##### 7、add_figure 实例def add_figure_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_figure")# First create some toy data:x = np.linspace(0, 2 * np.pi, 400)y = np.sin(x ** 2)# Create just a figure and only one subplotfig, ax = plt.subplots()ax.plot(x, y)ax.set_title('Simple plot')writer.add_figure("add_figure 实例:figure", fig)# 关闭writer.close()add_figure_demo()##### 8、add_pr_curve 实例def add_pr_curve_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_pr_curve")labels = np.random.randint(2, size=100) # binary labelpredictions = np.random.rand(100)writer.add_pr_curve('add_pr_curve 实例:pr_curve', labels, predictions, 0)# 关闭writer.close()add_pr_curve_demo()##### 9、add_embedding 实例def add_embedding_demo():# 将信息写入logs文件夹,可以供TensorBoard消费,来可视化writer = SummaryWriter("logs/add_embedding")import tensorflow as tfimport tensorboard as tbtf.io.gfile = tb.compat.tensorflow_stub.io.gfileimport keywordimport torchmeta = []while len(meta) < 100:meta = meta + keyword.kwlist # get some stringsmeta = meta[:100]for i, v in enumerate(meta):meta[i] = v + str(i)label_img = torch.rand(100, 3, 10, 32)for i in range(100):label_img[i] *= i / 100.0writer.add_embedding(torch.randn(100, 5), metadata=meta, label_img=label_img)# 关闭writer.close()add_embedding_demo()
3. 使用 TensorBoard 记录 PPO 运行情况
- 将 TensorBoard 相关代码添加到前文 RL 实践(7)—— CartPole【TPRO & PPO】 的 PPO 代码中,观察 RL 的收敛过程
这里使用了两个 API,import gym import torch import random import torch.nn.functional as F import numpy as np import matplotlib.pyplot as plt from tqdm import tqdm from gym.utils.env_checker import check_env from gym.wrappers import TimeLimit from datetime import datetime from torch.utils.tensorboard import SummaryWriterclass PolicyNet(torch.nn.Module):''' 策略网络是一个两层 MLP '''def __init__(self, input_dim, hidden_dim, output_dim):super(PolicyNet, self).__init__()self.fc1 = torch.nn.Linear(input_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, output_dim)def forward(self, x):x = F.relu(self.fc1(x)) # (1, hidden_dim)x = F.softmax(self.fc2(x), dim=1) # (1, output_dim)return xclass VNet(torch.nn.Module):''' 价值网络是一个两层 MLP '''def __init__(self, input_dim, hidden_dim):super(VNet, self).__init__()self.fc1 = torch.nn.Linear(input_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, 1)def forward(self, x):x = F.relu(self.fc1(x))x = self.fc2(x)return xclass PPO(torch.nn.Module):def __init__(self, state_dim, hidden_dim, action_range, actor_lr, critic_lr, lmbda, epochs, eps, gamma, device):super().__init__()self.actor = PolicyNet(state_dim, hidden_dim, action_range).to(device)self.critic = VNet(state_dim, hidden_dim).to(device) self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=actor_lr)self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=critic_lr)self.device = deviceself.gamma = gammaself.lmbda = lmbda # GAE 参数self.epochs = epochs # 一条轨迹数据用来训练的轮数self.eps = eps # PPO 中截断范围的参数self.device = device def take_action(self, state):state = torch.tensor(state, dtype=torch.float).to(self.device)state = state.unsqueeze(0)probs = self.actor(state)action_dist = torch.distributions.Categorical(probs)action = action_dist.sample()return action.item()def compute_advantage(self, gamma, lmbda, td_delta):''' 广义优势估计 GAE '''td_delta = td_delta.detach().numpy()advantage_list = []advantage = 0.0for delta in td_delta[::-1]:advantage = gamma * lmbda * advantage + deltaadvantage_list.append(advantage)advantage_list.reverse()return torch.tensor(np.array(advantage_list), dtype=torch.float)def update(self, transition_dict):states = torch.tensor(np.array(transition_dict['states']), dtype=torch.float).to(self.device)actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(self.device)rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).view(-1, 1).to(self.device)next_states = torch.tensor(np.array(transition_dict['next_states']), dtype=torch.float).to(self.device)dones = torch.tensor(transition_dict['dones'], dtype=torch.float).view(-1, 1).to(self.device)td_target = rewards + self.gamma * self.critic(next_states) * (1-dones)td_delta = td_target - self.critic(states)advantage = self.compute_advantage(self.gamma, self.lmbda, td_delta.cpu()).to(self.device)old_log_probs = torch.log(self.actor(states).gather(1, actions)).detach()# 用刚采集的一条轨迹数据训练 epochs 轮for _ in range(self.epochs):log_probs = torch.log(self.actor(states).gather(1, actions))ratio = torch.exp(log_probs - old_log_probs)surr1 = ratio * advantagesurr2 = torch.clamp(ratio, 1 - self.eps, 1 + self.eps) * advantage # 截断actor_loss = torch.mean(-torch.min(surr1, surr2)) # PPO损失函数critic_loss = torch.mean(F.mse_loss(self.critic(states), td_target.detach()))# 更新网络参数self.actor_optimizer.zero_grad()self.critic_optimizer.zero_grad()actor_loss.backward()critic_loss.backward()self.actor_optimizer.step()self.critic_optimizer.step()if __name__ == "__main__":def moving_average(a, window_size):''' 生成序列 a 的滑动平均序列 '''cumulative_sum = np.cumsum(np.insert(a, 0, 0)) middle = (cumulative_sum[window_size:] - cumulative_sum[:-window_size]) / window_sizer = np.arange(1, window_size-1, 2)begin = np.cumsum(a[:window_size-1])[::2] / rend = (np.cumsum(a[:-window_size:-1])[::2] / r)[::-1]return np.concatenate((begin, middle, end))def set_seed(env, seed=42):''' 设置随机种子 '''env.action_space.seed(seed)env.reset(seed=seed)random.seed(seed)np.random.seed(seed)torch.manual_seed(seed)state_dim = 4 # 环境观测维度action_range = 2 # 环境动作空间大小actor_lr = 1e-3critic_lr = 1e-2num_episodes = 200hidden_dim = 64gamma = 0.98lmbda = 0.95epochs = 10eps = 0.2device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")# build environmentenv_name = 'CartPole-v0'env = gym.make(env_name, render_mode='rgb_array')check_env(env.unwrapped) # 检查环境是否符合 gym 规范set_seed(env, 0)# build agentagent = PPO(state_dim, hidden_dim, action_range, actor_lr, critic_lr, lmbda, epochs, eps, gamma, device)# TensorBoard writerTIMESTAMP = "{0:%Y-%m-%dT%H-%M-%S/}".format(datetime.now())writer = SummaryWriter(f"logs/PPO")#writer = SummaryWriter(f"logs/PPO/{TIMESTAMP}")# start trainingreturn_list = []for i in range(10):with tqdm(total=int(num_episodes / 10), desc='Iteration %d' % i) as pbar:for i_episode in range(int(num_episodes / 10)):episode_return = 0transition_dict = {'states': [],'actions': [],'next_states': [],'next_actions': [],'rewards': [],'dones': []}state, _ = env.reset()# 以当前策略交互得到一条轨迹while True:action = agent.take_action(state)next_state, reward, terminated, truncated, _ = env.step(action)next_action = agent.take_action(next_state)transition_dict['states'].append(state)transition_dict['actions'].append(action)transition_dict['next_states'].append(next_state)transition_dict['next_actions'].append(next_action)transition_dict['rewards'].append(reward)transition_dict['dones'].append(terminated or truncated)state = next_stateepisode_return += rewardif terminated or truncated:break#env.render()# 用当前策略收集的数据进行 on-policy 更新agent.update(transition_dict)# 更新进度条return_list.append(episode_return)pbar.set_postfix({'episode':'%d' % (num_episodes / 10 * i + i_episode + 1),'return':'%.3f' % episode_return,'ave return':'%.3f' % np.mean(return_list[-10:])})pbar.update(1)writer.add_scalars(main_tag='return', tag_scalar_dict={f'hidden{hidden_dim}':episode_return}, global_step=i*int(num_episodes / 10) + i_episode)writer.add_hparams(hparam_dict={'actor_lr': actor_lr, 'critic_lr': critic_lr,'hidden_dim': hidden_dim,'gamma': gamma,'lmbda': lmbda,'eps': eps,'num_episodes': num_episodes},metric_dict={'hparam/ave return': np.mean(return_list), })writer.close()# show policy performencemv_return_list = moving_average(return_list, 29)episodes_list = list(range(len(return_list)))plt.figure(figsize=(12,8))plt.plot(episodes_list, return_list, label='raw', alpha=0.5)plt.plot(episodes_list, mv_return_list, label='moving ave')plt.xlabel('Episodes')plt.ylabel('Returns')plt.title(f'{agent._get_name()} on CartPole-V0')plt.legend()plt.savefig(f'./result/{agent._get_name()}.png')plt.show()
add_hparams
用来记录实验的超参数和结果,add_scalars
用来记录收敛过程(用这个是为了方便把多条曲线绘制到一张图中),结果如下
这里测试了两种隐藏层尺寸,发现 hidden_size=64 时收敛比 128 快一点
4. 其他
- 关于 TensorBoard UI 的说明可以参考:TensorBoard最全使用教程:看这篇就够了
- 关于多次实验数据混合显示互相干扰的问题可以参考:tensorboard多个events文件显示紊乱的解决办法
- 总之感觉不如 Wandb 好用,就简单记录一下
相关文章:
在 Pytorch 中使用 TensorBoard
机器学习的训练过程中会产生各类数据,包括 “标量scalar”、“图像image”、“统计图diagram”、“视频video”、“音频audio”、“文本text”、“嵌入Embedding” 等等。为了更好地追踪和分析这些数据,许多可视化工具应运而生,比如之前介绍的…...
Grafana Dashboard 备份方案
文章目录 Grafana Dashboard 备份方案引言工具简介支持的组件要求配置备份安装使用 pypi 安装grafana备份工具配置环境变量使用Grafana Backup Tool 进行备份恢复备份 Grafana Dashboard恢复 Grafana Dashboard结论Grafana Dashboard 备份方案 引言 每个使用 Grafana 的同学都…...
opencv-疲劳检测-眨眼检测
#导入工具包 from scipy.spatial import distance as dist from collections import OrderedDict import numpy as np import argparse import time import dlib import cv2FACIAL_LANDMARKS_68_IDXS OrderedDict([("mouth", (48, 68)),("right_eyebrow",…...
2023-08-24力扣每日一题
链接: 1267. 统计参与通信的服务器 题意: 同行同列可以发生通信,求能发生通信的机器数量 解: 标记每行/每列的机器个数即可 实际代码: #include<bits/stdc.h> using namespace std; class Solution { pub…...
蚂蚁数科持续发力PaaS领域,SOFAStack布局全栈软件供应链安全产品
8月18日,记者了解到,蚂蚁数科再度加码云原生PaaS领域,SOFAStack率先完成全栈软件供应链安全产品及解决方案的布局,包括静态代码扫描Pinpoint、软件成分分析SCA、交互式安全测试IAST、运行时防护RASP、安全洞察Appinsight等&#x…...
Java后端开发面试题——消息中间篇
RabbitMQ-如何保证消息不丢失 交换机持久化: Bean public DirectExchange simpleExchange(){// 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除 return new DirectExchange("simple.direct", true, false); }队列持久化…...
C++ Windows API IsDebuggerPresent的作用
IsDebuggerPresent 是 Windows API 中的一个函数,它用于检测当前运行的程序是否正在被调试。当程序被如 Visual Studio 这样的调试器附加时,此函数会返回 TRUE;否则,它会返回 FALSE。 这个函数经常被用在一些安全相关的场景或是防…...
【JVM 内存结构 | 程序计数器】
内存结构 前言简介程序计数器定义作用特点示例应用场景 主页传送门:📀 传送 前言 Java 虚拟机的内存空间由 堆、栈、方法区、程序计数器和本地方法栈五部分组成。 简介 JVM(Java Virtual Machine)内存结构包括以下几个部分&#…...
华为云Stack的学习(一)
一、华为云Stack架构 1.HCS 物理分散、逻辑统一、业务驱动、运管协同、业务感知 2.华为云Stack的特点 可靠性 包括整体可靠性、数据可靠性和单一设备可靠性。通过云平台的分布式架构,从整体系统上提高可靠性,降低系统对单设备可靠性的要求。 可用性…...
人类反馈强化学习RLHF;微软应用商店推出AI摘要功能
🦉 AI新闻 🚀 微软应用商店推出AI摘要功能,快速总结用户对App的评价 摘要:微软应用商店正式推出了AI摘要功能,该功能能够将数千条在线评论总结成一段精练的文字,为用户选择和下载新应用和游戏提供参考。该…...
day1:前端缓存问题
❝ 「目标」: 持续输出!每日分享关于web前端常见知识、面试题、性能优化、新技术等方面的内容。篇幅不会过长,方便理解和记忆。 ❞ ❝ 「主要面向群体:」前端开发工程师(初、中、高级)、应届、转行、培训等同学 ❞ Day…...
学习网络编程No.4【socket编程实战】
引言 北京时间:2023/8/19/23:01,耍了好几天,主要归咎于《我欲封天》这本小说,听了几个晚上之后逐渐入门,在闲暇时间又看了一下,小高潮直接来临,最终在三个昼夜下追完了,哈哈哈&…...
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 四)
Observed装饰器和ObjectLink装饰器:嵌套类对象属性变化 上文所述的装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数…...
arcgis--坐标系
1、arcgis中,投影坐标系的y坐标一定是7位数,X坐标有两种:6位和8位。 6位:省略带号,这是中央经线形式的投影坐标,一般投影坐标中会带CM字样;8位:包括带号,一般投影坐标中…...
LFS学习系列 第5章. 编译交叉工具链(1)
5.1 介绍 本章介绍如何构建交叉编译器及其相关工具。尽管这里的交叉编译是“伪造”、“假装”的,但其原理与真正的交叉工具链相同。 本章中编译的程序将安装在$LFS/tools目录下,以使它们与以下章节中安装的文件分离。而另一方面,库被安装到…...
网络互联与互联网 - TCP 协议详解
文章目录 1 概述2 TCP 传输控制协议2.1 报文格式2.2 三次握手,建立连接2.3 四次挥手,释放连接 3 扩展3.1 实验演示3.2 网工软考 1 概述 在 TCP/IP 协议簇 中有两个传输协议 TCP:Transmission Control Protocol,传输控制协议&…...
开源在线图片设计器,支持PSD解析、AI抠图等,基于Puppeteer生成图片
Github 开源地址: palxiao/poster-design 项目速览 git clone https://github.com/palxiao/poster-design.git cd poster-design npm run prepared # 快捷安装依赖指令 npm run serve # 本地运行将同时运行前端界面与图片生成服务(3000与7001端口),合成图片时…...
在Linux系统上安装和配置Redis数据库,无需公网IP即可实现远程连接的详细解析
文章目录 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址连接 Redis作为一款高速缓存的key value键值对的数据库,在…...
跨平台图表:ChartDirector for .NET 7.1 Crack
什么是新的 ChartDirector for .NET 7.0 支持跨平台使用,但仅限于 .NET 6。这是因为在 .NET 7 中,Microsoft 停止了用于非 Windows 使用的 .NET 图形库 System.Drawing.Common。由于 ChartDirector for .NET 7.0 依赖于该库,因此它不再支持 .…...
【unity数据持久化】XML数据管理器知识点
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:Uni…...
Linux——Shell常用运算符
运算符说明举例-eq检测两个数是否相等,相等返回 true。[ $a -eq $b ] 返回 false。-ne检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 true。-gt检测左边的数是否大于右边的,如果是,则返回 true。[ $a -gt $b ] 返回 …...
C++(4)C++内存管理和命名空间
内存管理 new/delete C语言 malloc free完成对堆内存的申请和释放。 C new delete 类 new:动态申请存储空间的运算符,返回值为申请空间的对应数据类型的地址 int *p new int(10); 申请了一个初始值为10的整型数据 int *p new int[10]; 申…...
一网打尽java注解-克隆-面向对象设计原则-设计模式
文章目录 注解内置注解元注解 对象克隆为什么要克隆?如何克隆浅克隆深克隆 Java设计模式什么是设计模式?为什么要学习设计模式? 建模语言类接口类之间的关系依赖关系关联关系聚合关系组合关系继承关系实现关系 面向对象设计原则单一职责开闭原…...
k8s-statefulset部署myql-Nodeport方式
目录 1、部署openebs(Elastic Block Store) 1.下载镜像(针对k8s1.19) 2.加载镜像(所有节点包括master) 3.下载yaml文件并部署 4.设置默认storageclass 2、编写相关yaml文件 1.编写secret 2.编写state…...
MySQL双主架构、主从架构
为什么要对数据库做优化? MySQL官方说法: 单表2000万数据就达到瓶颈了。所以为了保证查询效率,要让每张表的大小得到控制。 MySQL主主架构 主数据库都负责增删改查。 比如有1000W的数据,有两个主数据库,就将数据分流给…...
基于微信小程序的物流管理系统3txar
在此基础上,结合现有物流管理体系的特点,运用新技术,构建了以 springboot为基础的物流信息化管理体系。首先,以需求为依据,对目前传统物流管理基础业务进行了较为详尽的了解和分析。根据需求分析结果进行了系统的设计&…...
Maven 一键部署到 SSH 服务器
简介 利用 Maven Mojo 功能一键部署 jar 包或 war 包到远程服务器上。 配置 在 maven 的setting.xml 配置服务器 SSH 账号密码。虽然可以在工程的 pom.xml 直接配置,但那样不太安全。 <servers><server><id>iq</id><configuration&…...
docker搭建owncloud,Harbor,构建镜像
1、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。 拉取镜像 docker pull owncloud docker pull mysql:5.6 2、安装搭建私有仓库 Harbor 1.下载docker-compose 2.安装harbor 3.编辑 harbor.yml文件 使用./intall.sh安装 4.登录 3、编写Dockerfile制作Web应用系…...
RISC-V(1)——RISC-V是什么,有什么用
目录 1. RISC-V是什么 2. RISC-V指令集 3. RISC-V特权架构 4. RiscV的寄存器描述 5. 指令 5.1 算数运算—add/sub/addi/mul/div/rem 5.2 逻辑运算—and/andi/or/ori/xor/xori 5.3 位移运算—sll/slli/srl/srli/sra/srai 5.4 数据传输—lb/lh/lw/lbu/lhu/lwu/sb/sh/sw …...
基于黄金正弦算法优化的BP神经网络(预测应用) - 附代码
基于黄金正弦算法优化的BP神经网络(预测应用) - 附代码 文章目录 基于黄金正弦算法优化的BP神经网络(预测应用) - 附代码1.数据介绍2.黄金正弦优化BP神经网络2.1 BP神经网络参数设置2.2 黄金正弦算法应用 4.测试结果:5…...
深圳考试培训网站建设/站长工具是什么
欢迎关注”生信修炼手册”!miRNA是一类长度在18到36bp的非编码RNA, 其功能属于转后后修饰调控,主要通过和mRNA的3’UTR区进行结合,结合区域称之为seed,当结合区域的序列完全配对时,诱导mRNA降解, 当只有部分序列配对时…...
苏州教育网站建设/推广计划书范文
某日某站某博水民甲:我要买股票赚大钱,放消息啊方消息啊,我要更多消息水民乙:顶……n日后仍然没有消息水民甲:博主是一XXX,为什么不放消息?水民乙:博主高人啊,应该有内线…...
网站建设的概念/网站建设技术托管
展开全部回答不能插入代码格式,比较乱。e68a843231313335323631343130323136353331333433633433我截图给你看吧。package com.test;import javax.swing.*;import java.awt.*;public class DrawTest extends JFrame {public static void main(String[] args) {DrawTe…...
怎么做打鱼网站/唯尚广告联盟app下载
前言本文从函数定义的语法规则开始,简要介绍 PHP 解释器如何 "编译" 函数定义函数对应的 AST 节点为了看起来清楚一些,我们将 语法规则定义 与 语法动作分开:// zend_language_parser.ytop_statement: function_declaration_statem…...
常州外贸网站建设公司/百度手机关键词排名工具
这段时间一直在研究hdmi-servers,因为友善对这个在是闭源的,所以由于兴趣的关系和工作的关系,决定自己写一个hdmi-servers。 在hdmi中,最关键的是弄清楚了Hdmi显示数据的怎么来的,怎么输出的。 在s5pv210数据手册上,在…...
营销型网站建设 价格/适合小学生的最新新闻
起因 最近临近双十一,你们也知道,电商类公司到双十一的时候有多忙。压测、稳定性、实时大屏,一堆事情要在双十一之前完成。加上我们最近在做数据平台相关的事情,简直忙到爆炸。就在这么忙的时候,还踩到了Flink中Topn的…...