当前位置: 首页 > news >正文

【TVM 学习资料】用 Schedule 模板和 AutoTVM 优化算子

完整 TVM 中文文档,访问→TVM 中文站
作者:Lianmin Zheng,Chris Hoge

本教程将展示如何用 TVM 张量表达式(TE)语言编写 schedule 模板,并通过 AutoTVM 对模板进行搜索,从而找到最佳 schedule。这个自动优化张量计算的过程被称为 Auto-Tuning。

本教程基于前面的 TE 编写矩阵乘法教程 设立。

auto-tuning 包括两个步骤:

第一步:定义搜索空间。
第二步:运行搜索算法来探索这个空间。
通过本教程可以了解如何在 TVM 中执行这两个步骤。整个工作流程由一个矩阵乘法示例来说明。

备注
注意,本教程不会在 Windows 或最新版本的 macOS 上运行。如需运行,请将本教程的主体放在 if name == “main”: 代码块中。

安装依赖

要在 TVM 中使用 autotvm 包,需安装一些额外的依赖。

pip3 install --user psutil xgboost cloudpickle

为了让 TVM 在调优过程中运行更快,建议使用 Cython 作为 TVM 的 FFI。在 TVM 的根目录下,执行:

pip3 install --user cython
sudo make cython3

现在我们一起来看如何用 Python 代码实现。首先导入所需的包:

import logging
import sysimport numpy as np
import tvm
from tvm import te
import tvm.testing# 模块名叫 `autotvm`
from tvm import autotvm

TE 的基本矩阵乘法

回想一下用 TE 进行矩阵乘法的基本实现,下面做一些改变。将矩阵乘法放在 Python 函数定义中。简单起见,重点关注拆分的优化,将重新排序的块大小设为固定值。

def matmul_basic(N, L, M, dtype):A = te.placeholder((N, L), name="A", dtype=dtype)B = te.placeholder((L, M), name="B", dtype=dtype)k = te.reduce_axis((0, L), name="k")C = te.compute((N, M), lambda i, j: te.sum(A[i, k] * B[k, j], axis=k), name="C")s = te.create_schedule(C.op)# 调度y, x = s[C].op.axisk = s[C].op.reduce_axis[0]yo, yi = s[C].split(y, 8)xo, xi = s[C].split(x, 8)s[C].reorder(yo, xo, k, yi, xi)return s, [A, B, C]

用 AutoTVM 进行矩阵乘法

前面的调度代码用常量“8”作为循环切分因子,但是它可能不是最佳的。因为最佳的循环切分因子取决于真实的硬件环境和输入 shape。

如果希望调度代码能够在更广泛的输入 shape 和目标硬件上可移植,最好定义一组候选值,并根据目标硬件上的评估结果选择最佳值。

autotvm 中可以为这种值定义一个可调参数,或者一个 “knob”。

基本矩阵乘法模板

以下示例将演示,如何为 split 调度操作的 block 大小创建一个可调的参数集。

# Matmul V1: 列出候选值
@autotvm.template("tutorial/matmul_v1")  # 1. 使用装饰器
def matmul_v1(N, L, M, dtype):A = te.placeholder((N, L), name="A", dtype=dtype)B = te.placeholder((L, M), name="B", dtype=dtype)k = te.reduce_axis((0, L), name="k")C = te.compute((N, M), lambda i, j: te.sum(A[i, k] * B[k, j], axis=k), name="C")s = te.create_schedule(C.op)# 调度y, x = s[C].op.axisk = s[C].op.reduce_axis[0]# 2. 获取 config 对象cfg = autotvm.get_config()# 3. 定义搜索空间cfg.define_knob("tile_y", [1, 2, 4, 8, 16])cfg.define_knob("tile_x", [1, 2, 4, 8, 16])# 4. 根据 config 进行调度yo, yi = s[C].split(y, cfg["tile_y"].val)xo, xi = s[C].split(x, cfg["tile_x"].val)s[C].reorder(yo, xo, k, yi, xi)return s, [A, B, C]

下面将对前面的调度代码作出四个修改,然后得到一个可调的“模板”。一一解释这些修改:

  1. 使用装饰器将此函数标记为简单模板。

  2. 获取 config 对象:将 cfg 视为此函数的参数,但我们以另外的方式获取它。cfg 参数使得这个函数不再是一个确定的 schedule。将不同的配置传递给这个函数,可以得到不同的 schedule。这种使用配置对象的函数称为“模板”。

为使模板函数更精炼,可在单个函数中定义参数搜索空间:

  • 用一组值来定义搜索空间。将 cfg 转为 ConfigSpace 对象,收集此函数中的所有可调 knob,然后从中构建一个搜索空间。
  • 根据空间中的实体进行调度。将 cfg 转为 ConfigEntity 对象,当它被转为 ConfigEntity 后,会忽略所有空间定义
    API(即 cfg.define_XXXXX(…)),但会存储所有可调 knob 的确定值,并根据这些值进行调度。

在 auto-tuning 的过程中,首先用 ConfigSpace 对象调用这个模板来构建搜索空间,然后在构建的空间中用不同的 ConfigEntity 调用这个模板,来得到不同的 schedule。最后,我们将评估由不同 schedule 生成的代码,然后选择最佳的 schedule。

  1. 定义两个可调 knob。第一个是 tile_y,它有 5 个可能值。第二个是 tile_x,它和前者具有相同的可能值。这两个 knob 是独立的,所以它们跨越大小为 25 = 5x5 的搜索空间。

  2. 配置 knob 被传递给 split 调度操作,然后可以根据之前在 cfg 中定义的 5x5 确定值进行调度。

带有高级参数 API 的矩阵乘法模板

前面的模板手动列出了 konb 的所有可能值,它是用来定义空间的最底层 API,显示列出了要搜索的参数空间。这里推荐使用另一组更高级的 API,它可以更简单、更智能地定义搜索空间。

下面的示例用 ConfigSpace.define_split 来定义拆分 knob。它列举了所有可能的拆分 axis 和构造空间的方法。

同时,ConfigSpace.define_reorder 用于对 knob 重新排序,ConfigSpace.define_annotate 用于对展开、向量化、线程绑定等进行注释 。当高级 API 无法满足你的需求时,可以回退使用底层 API。

@autotvm.template("tutorial/matmul")
def matmul(N, L, M, dtype):A = te.placeholder((N, L), name="A", dtype=dtype)B = te.placeholder((L, M), name="B", dtype=dtype)k = te.reduce_axis((0, L), name="k")C = te.compute((N, M), lambda i, j: te.sum(A[i, k] * B[k, j], axis=k), name="C")s = te.create_schedule(C.op)# 调度y, x = s[C].op.axisk = s[C].op.reduce_axis[0]##### 开始定义空间 #####cfg = autotvm.get_config()cfg.define_split("tile_y", y, num_outputs=2)cfg.define_split("tile_x", x, num_outputs=2)##### 结束定义空间 ###### 根据 config 进行调度yo, yi = cfg["tile_y"].apply(s, C, y)xo, xi = cfg["tile_x"].apply(s, C, x)s[C].reorder(yo, xo, k, yi, xi)return s, [A, B, C]

关于 cfg.define_split 的更多解释 在此模板中,cfg.define_split(“tile_y”, y,
num_outputs=2) 枚举了所有可能的组合(以 y 的长度为因子,将 y 轴分成两个轴)。例如,如果 y 的长度为 32 并且想以
32 为因子将它拆分为两个轴,那么(外轴长度,内轴长度)有 6 个可能的值,即 (32, 1),(16, 2),(8, 4),(4,
8),(2, 16) 或 (1, 32)。这些也是 tile_y 的 6 个可能值。

调度过程中,cfg[“tile_y”] 是一个 SplitEntity 对象。我们将外轴和内轴的长度存储在
cfg[‘tile_y’].size (有两个元素的元组)中。这个模板使用 yo, yi = cfg[‘tile_y’].apply(s,
C, y) 来应用它。其实等价于 yo, yi = s[C].split(y, cfg[“tile_y”].size[1]) 或 yo,
yi = s[C].split(y, nparts=cfg['tile_y"].size[0])。

cfg.apply API 的优点是它使多级拆分(即当 num_outputs >= 3 时)变得更加简单。

第 2 步:使用 AutoTVM 优化矩阵乘法

第 1 步编写的矩阵乘法模板,可对拆分的 schedule 中的块大小进行参数化。通过第 1 步,可以实现对这个参数空间进行搜索。下一步是选择一个调优器来指导如何对空间进行探索。

TVM 的自动调优器

调优器的任务可用以下伪代码来描述:

ct = 0
while ct < max_number_of_trials:propose a batch of configsmeasure this batch of configs on real hardware and get resultsct += batch_size

调优器可采取不同的策略来计划下一批配置,包括:

  • tvm.autotvm.tuner.RandomTuner :以随机顺序枚举空间

  • tvm.autotvm.tuner.GridSearchTuner :以网格搜索顺序枚举空间

  • tvm.autotvm.tuner.GATuner :使用遗传算法搜索空间

  • tvm.autotvm.tuner.XGBTuner :用基于模型的方法训练一个 XGBoost 模型,来预测降级 IR
    的速度,并根据预测值选择下一批配置。

可根据空间大小、时间预算和其他因素来选择调优器。例如,如果你的空间非常小(小于 1000),则网格搜索调优器或随机调优器就够了。如果你的空间在 10^9 级别(CUDA GPU 上的 conv2d 算子的空间大小),XGBoostTuner 可以更有效地探索并找到更好的配置。

开始调优

下面继续矩阵乘法的示例。首先创建一个调优任务,然后检查初始的搜索空间。下面示例中是 512x512 的矩阵乘法,空间大小为 10x10=100。注意,任务和搜索空间与选择的调优器无关。

N, L, M = 512, 512, 512
task = autotvm.task.create("tutorial/matmul", args=(N, L, M, "float32"), target="llvm")
print(task.config_space)

输出结果:

ConfigSpace (len=100, space_map=0 tile_y: Split(policy=factors, product=512, num_outputs=2) len=101 tile_x: Split(policy=factors, product=512, num_outputs=2) len=10
)

然后定义如何评估生成的代码,并且选择一个调优器。由于我们的空间很小,所以随机调优器就可以。

本教程只做 10 次试验进行演示。实际上可以根据自己的时间预算进行更多试验。调优结果会记录到日志文件中。这个文件可用于选择之后发现的调优器的最佳配置。

# 记录 config(为了将 tuning 日志打印到屏幕)
logging.getLogger("autotvm").setLevel(logging.DEBUG)
logging.getLogger("autotvm").addHandler(logging.StreamHandler(sys.stdout))

评估配置有两个步骤:构建和运行。默认用所有 CPU core 来编译程序。然后依次进行评估。为了减少方差,对 5 次评估结果取平均值。

measure_option = autotvm.measure_option(builder="local", runner=autotvm.LocalRunner(number=5))# 用 RandomTuner 开始调优, 日志记录到 `matmul.log` 文件中
# 可用 XGBTuner 来替代.
tuner = autotvm.tuner.RandomTuner(task)
tuner.tune(n_trial=10,measure_option=measure_option,callbacks=[autotvm.callback.log_to_file("matmul.log")],
)

输出结果:

waiting for device...
device available
Get devices for measurement successfully!
No: 1   GFLOPS: 8.48/8.48       result: MeasureResult(costs=(0.0316434228,), error_no=MeasureErrorNo.NO_ERROR, all_cost=0.638512134552002, timestamp=1657225928.6342561)        [('tile_y', [-1, 1]), ('tile_x', [-1, 256])],None,80
No: 2   GFLOPS: 2.30/8.48       result: MeasureResult(costs=(0.1165478966,), error_no=MeasureErrorNo.NO_ERROR, all_cost=2.0105199813842773, timestamp=1657225930.6636436)       [('tile_y', [-1, 4]), ('tile_x', [-1, 8])],None,32
No: 3   GFLOPS: 11.82/11.82     result: MeasureResult(costs=(0.0227097348,), error_no=MeasureErrorNo.NO_ERROR, all_cost=0.5589795112609863, timestamp=1657225931.7059512)       [('tile_y', [-1, 64]), ('tile_x', [-1, 32])],None,56
No: 4   GFLOPS: 1.66/11.82      result: MeasureResult(costs=(0.1616202114,), error_no=MeasureErrorNo.NO_ERROR, all_cost=2.6911513805389404, timestamp=1657225934.9635096)       [('tile_y', [-1, 1]), ('tile_x', [-1, 4])],None,20
No: 5   GFLOPS: 3.65/11.82      result: MeasureResult(costs=(0.073561817,), error_no=MeasureErrorNo.NO_ERROR, all_cost=1.3051848411560059, timestamp=1657225936.3988533)        [('tile_y', [-1, 256]), ('tile_x', [-1, 16])],None,48
No: 6   GFLOPS: 1.85/11.82      result: MeasureResult(costs=(0.1452834464,), error_no=MeasureErrorNo.NO_ERROR, all_cost=2.5179028511047363, timestamp=1657225938.961955)        [('tile_y', [-1, 512]), ('tile_x', [-1, 4])],None,29
No: 7   GFLOPS: 0.87/11.82      result: MeasureResult(costs=(0.30933780240000003,), error_no=MeasureErrorNo.NO_ERROR, all_cost=5.067087888717651, timestamp=1657225944.589149)  [('tile_y', [-1, 512]), ('tile_x', [-1, 2])],None,19
No: 8   GFLOPS: 10.53/11.82     result: MeasureResult(costs=(0.025489421,), error_no=MeasureErrorNo.NO_ERROR, all_cost=0.5452830791473389, timestamp=1657225945.1592515)        [('tile_y', [-1, 4]), ('tile_x', [-1, 64])],None,62
No: 9   GFLOPS: 1.58/11.82      result: MeasureResult(costs=(0.16960762680000002,), error_no=MeasureErrorNo.NO_ERROR, all_cost=2.8109781742095947, timestamp=1657225948.0900776)        [('tile_y', [-1, 2]), ('tile_x', [-1, 2])],None,11
No: 10  GFLOPS: 2.42/11.82      result: MeasureResult(costs=(0.11083148779999999,), error_no=MeasureErrorNo.NO_ERROR, all_cost=1.8757600784301758, timestamp=1657225950.0266354)        [('tile_y', [-1, 4]), ('tile_x', [-1, 4])],None,22

调优完成后,可从日志文件中选择具有最佳评估性能的配置,并用相应参数来编译 schedule。快速验证 schedule 是否产生了正确的结果,可直接在 autotvm.apply_history_best 上下文中调用 matmul 函数,它会用参数查询调度上下文,然后可用相同的参数获取最优配置。

# 从日志文件中应用历史最佳
with autotvm.apply_history_best("matmul.log"):with tvm.target.Target("llvm"):s, arg_bufs = matmul(N, L, M, "float32")func = tvm.build(s, arg_bufs)# 验证正确性
a_np = np.random.uniform(size=(N, L)).astype(np.float32)
b_np = np.random.uniform(size=(L, M)).astype(np.float32)
c_np = a_np.dot(b_np)c_tvm = tvm.nd.empty(c_np.shape)
func(tvm.nd.array(a_np), tvm.nd.array(b_np), c_tvm)tvm.testing.assert_allclose(c_np, c_tvm.numpy(), rtol=1e-4)

输出结果:

Finish loading 10 records

总结

本教程展示了如何构建算子模板,使得 TVM 能够搜索参数空间,并选择优化的调度配置。为了更深入地了解其工作原理,推荐基于 :ref: 张量表达式入门 <tensorexpr_get_started> 教程中演示的调度操作,向调度添加新的搜索参数。接下来的章节将演示 AutoScheduler,它是TVM 中一种优化常用算子的方法,同时无需用户提供自定义的模板。

相关文章:

【TVM 学习资料】用 Schedule 模板和 AutoTVM 优化算子

完整 TVM 中文文档&#xff0c;访问→TVM 中文站 作者&#xff1a;Lianmin Zheng&#xff0c;Chris Hoge 本教程将展示如何用 TVM 张量表达式&#xff08;TE&#xff09;语言编写 schedule 模板&#xff0c;并通过 AutoTVM 对模板进行搜索&#xff0c;从而找到最佳 schedule。…...

蓝牙Mesh学习笔记(一)

Mesh系统结构1 Mesh网络分层1.1 模型层(Model layer)1.2 基础模型层(Foundation Model layer)1.3 接入层(Access layer)1.4 上层传输层(Upper transport layer)1.5 下层传输层(Lower transport layer)1.6 网络层(Network layer)1.7 承载层(Bearer layer)1.8 BLE内核规范(BLE Co…...

【1234. 替换子串得到平衡字符串】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 有一个只含有 Q, W, E, R 四种字符&#xff0c;且长度为 n 的字符串。 假如在该字符串中&#xff0c;这四个字符都恰好出现 n/4 次&#xff0c;那么它就是一个「平衡字符串」。 给你一个这样的字符…...

独自开:提供创业机会、享受平台分红、推出新颖赚钱副业

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 前言 独自开&#xff1a;一款聚焦软件定制开发&#xff0c;独立、自主、开放平台 独创分层标准化平台架构,满足系统不断生长的个性化需求多端一键部署前端业务交互与展…...

C++【二叉树进阶(二叉搜索树)】

文章目录前言1、二叉搜索树1-1、 二叉搜索树概念2、二叉搜索树操作2-1、树和节点的基本框架2-2、二叉搜索树的查找2-3、中序遍历2-4、二叉搜索树的插入2-5、二叉搜索树的删除3、二叉搜索树的模拟实现3-1、循环版本3-2、递归版本4、二叉搜索树的应用4-1、K模型4-2、KV模型4-3、K…...

【C++初阶】vector的使用

大家好我是沐曦希&#x1f495; 文章目录一.vector介绍二、构造函数三、遍历1.[]2.迭代器3.范围for四、容量操作1.扩容机制五、增删查改六、迭代器失效问题一.vector介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。…...

OPenPCDet windows流程及其问题

首先的首先极其不推荐将OPenPCDet运行在Windows上,过程非常复杂,适配也不是很好,不推荐在windows下载并训练,本人做这个主要是方便再笔记本电脑上对实验结果进行整理,处理一些简单的推理评估等任务。如有必要请继续阅读: 以下是正文: 常规的安装流程不再赘述,请参考官方…...

【自学Python】Python字符大小写判断

大纲 Python字符串是否是小写 Python字符串是否是小写教程 在开发过程中&#xff0c;有时候我们需要判断一个 字符串 是否是小写形式&#xff08;即&#xff0c;所有的字符都是小写字母&#xff0c;不是英文字符的忽略不做判断&#xff09;&#xff0c;在 Python 中&#xff…...

设计模式之美总结(开源实战篇)

title: 设计模式之美总结&#xff08;开源实战篇&#xff09; date: 2023-01-10 17:13:05 tags: 设计模式 categories:设计模式 cover: https://cover.png feature: false 文章目录1. Java JDK 应用到的设计模式1.1 工厂模式在 Calendar 类中的应用1.2 建造者模式在 Calendar …...

两个月,测试转岗产品经理,我是怎么规划的?

​本期同学依旧来自深圳 测试到产品转变&#xff0c;用了两个月 本周&#xff0c;为大家介绍M同学的佛系转岗经历 学员档 学员档案 原岗位&#xff1a;测试 转岗级别&#xff1a;中级产品经理 转岗特点&#xff1a; 1.未接触产品工作 2.对岗位地点要求严格 先看结果 …...

三数之和-力扣15-java排序+双指针

一、题目描述给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意&#xff1a;答案中不可以包含重复的三元组。…...

【编程基础之Python】3、创建Python虚拟环境

【编程基础之Python】3、创建Python虚拟环境创建Python虚拟环境为什么需要虚拟环境Windows上的Anaconda创建虚拟环境conda 命令conda env 命令创建虚拟环境切换虚拟环境验证虚拟环境Linux上的Anaconda创建虚拟环境创建虚拟环境切换虚拟环境验证虚拟环境总结创建Python虚拟环境 …...

kettle开发-Day36-循环驱动作业

前言&#xff1a;在日常数据处理时&#xff0c;我们通过变量传参来完成某个日期的数据转换。但可能因程序或者网络原因导致某个时间段的数据抽取失败。常见导致kettle作业失败的原因大概分为三大类&#xff0c;数据源异常、数据库异常、程序异常。因此面对这些异常时&#xff0…...

2023秋招 新凯来 算法工程师 面经分享

本专栏分享 计算机小伙伴秋招春招找工作的面试经验和面试的详情知识点 专栏首页:秋招算法类面经分享 主要分享计算机算法类在面试互联网公司时候一些真实的经验 一面 技术面 30分钟左右 1.主要是问项目和论文上的东西,问的不深,中间还介绍他们是做缺陷检测的,大概问了16分钟…...

Web3CN|Damus刷频背后,大众在期待什么样的去中心化社交?

刚过去的一周&#xff0c;许多人的朋友圈包括Twitter、Faceboo在内都在被一串公钥字母刷屏&#xff0c;其重要起因就是 Twitter 前首席执行官 Jack Dorsey 发推称&#xff0c;&#xff08;2月1日&#xff09;基于去中心化社交协议 Nostr 的社交产品 Damus 和 Amethyst 已分别在…...

Jenkins自动发布到WindowsServer,在WindowsServer执行的命令

echo off set apppoolname"6.usegitee" set websitename"6.usegitee" set webfolder"usegitee" echo 停止站点的应用程序池 C:\Windows\System32\inetsrv\appcmd.exe stop apppool %apppoolname% echo 停止站点 c:\Windows\System32\inetsrv\a…...

【Git学习】Git如何Clone带有Submodule的仓库?

文章目录一、问题描述二、解决问题三、参考链接四、解决问题4.1 下载主模块4.2 查看主模块的配置4.2 子模块的添加4.3 查看子模块的配置4.4 查看子模块的检出状态4.5 检出submodule4.6 再次查看.git/config4.7 重新打开Android Studio运行代码一、问题描述 在GitHub上下载了一…...

C语言进阶——通讯录模拟实现

&#x1f307;个人主页&#xff1a;_麦麦_ &#x1f4da;今日名言&#xff1a;只有走在路上&#xff0c;才能摆脱局限&#xff0c;摆脱执着&#xff0c;让所有的选择&#xff0c;探寻&#xff0c;猜测&#xff0c;想象都生机勃勃。——余秋雨《文化苦旅》 目录 一、前言 二、正…...

【C#基础】C# 变量和常量的使用

序号系列文章1【C#基础】C# 程序通用结构总结2【C#基础】C# 程序基础语法解析3【C#基础】C# 数据类型总结文章目录前言一. 变量&#xff08;variable&#xff09;1&#xff0c;变量定义及初始化2&#xff0c;变量的类别3&#xff0c;接收输出变量二. 常量&#xff08;constant&…...

nvm安装后出现‘node‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件

出现这个问题多半是path地址不对。 打开系统环境变量。看看path里面有没有&#xff1f;没有的话&#xff0c;加上就行&#xff01; 我的报错原因就是因为path里没有自动加上nvm的相关路径。 注意项&#xff1a; 1&#xff0c;在安装nvm之前&#xff0c;提前要把本机以前安装…...

张驰咨询:关于六西格玛,有一些常见的疑惑!

​ 很多想要学习六西格玛的学员&#xff0c;经常会有这些困惑&#xff1a; 以前没有接触过六西格玛&#xff0c;需要什么基础吗&#xff1f;自学还是培训&#xff1f;哪些行业会用到六西格玛呢&#xff1f;学习六西格玛对以后的工作有哪些帮助&#xff1f;如何选择六西格玛培…...

【Vercel】教你部署imsyy/home个人主页

本篇博客教你如何部署一个自己的个人主页 项目地址&#xff1a;https://github.com/imsyy/home 本文首发于 慕雪的寒舍 1.fork仓库vercel部署 首先我们点击fork&#xff0c;将仓库复刻到自己的账户 随后进入vercel&#xff0c;点击dashboard-add new-project 选择你复刻的仓库…...

GeekChallenge

2.GeekChallenge 1.web 1.朋友的学妹 url&#xff1a;http://49.234.224.119:7413/ 右键点击查看源码&#xff0c;找到flagU1lDe0YxQF80c19oNExwZnVsbGxsbGx9 然后base64解码得到SYC{F1_4s_h4Lpfullllll} 2.EZwww url&#xff1a;http://47.100.46.169:3901/ 根据网站提示…...

Java文件IO

文章目录Java中的文件操作File常用构造方法方法文件内容的读写——数据流InputStreamFileInputStream利用Scanner进行字符读取OutputStreamPrintWriter按字符读取文件(FileReader)练习代码实例如何按字节进行数据读如何按字节进行数据写如何按字符进行数据读如何按字符进行数据…...

useSSL使用安全套接字协议(史上最全最详细)

useSSL使用安全套接字协议&#xff08;史上最全最详细&#xff09; SSL即为&#xff1a;Secure Sockets Layer 安全套接字协议。 useSSLfalse和useSSLtrue的区别&#xff1a; 在MySQL进行连接时&#xff1a; 如果MySQL的版本是5.7之后的版本必须要加上useSSLfalse&#xff0c…...

面向对象复习(2)

面向对象(2) 对象与引用 java语言中除基本类型之外的变量都称之为引用类型 java中的对象时通过引用对其操作的 Car bm new Car(); 右边的new Car是以Car类为模板,调用无参构造函数,在堆空间中创建一个Car对象 左边的Car bm 在栈中创建了一个Car类型的引用变量,所谓Car的…...

python中使用numpy包的向量矩阵相乘

一直对np的线性运算不太清晰&#xff0c;正好上课讲到了&#xff0c;做一个笔记整个理解一下 1.向量和矩阵 在numpy中&#xff0c;一重方括号表示的是向量vector&#xff0c;vector没有行列的概念。二重方括号表示矩阵matrix&#xff0c;有行列。 代码显示如下&#xff1a; …...

ElasticSearch 学习(一)

目录一、Elasticsearch 简介二、Elasticsearch 发展史三、Elasticsearch 功能四、Elasticsearch 特点五、Elasticsearch 应用场景一、Elasticsearch 简介 Elasticsearch 是一个实时的分布式搜索分析引擎&#xff0c;它能让你以前所未有的速度和规模&#xff0c;去探索你的数据…...

【新】华为OD机试 - 交换字符(Python)| 刷完获取OD招聘渠道

交换字符 题目 给定一个字符串 S 变化规则: 交换字符串中任意两个不同位置的字符 M S 都是小写字符组成 1 <= S.length <= 1000 输入 一串小写字母组成的字符串 输出 按照要求变换得到最小字符串 示例一 输入 abcdef输出 abcdef示例二 输入 bcdefa输出 acde…...

手把手教你解决传说中的NPE空指针异常

1. 前言最近有好几个初学java的小伙伴&#xff0c;甚至是学习到了JavaWeb、框架阶段的小伙伴也跑来问壹哥&#xff0c;该如何解决Java中的NullPointerException空指针异常。因为NPE是初学者特别常见的典型异常&#xff0c;所以壹哥在这里专门写一篇文章&#xff0c;来手把手地教…...

双语 网站 数据怎么做/qq营销软件

1.为什么无法定义1px左右高度的容器 解决办法&#xff1a;IE6下这个问题是因为默认的行高造成的&#xff0c;解决的方法也有很多&#xff0c;例如&#xff1a;overflow:hidden | zoom:0.08 | line-height:1px 2.通用的加入收藏代码 <script type"text/javascript"…...

主题网站设计模板/百度模拟搜索点击软件

准备好滚滚的JOE – Java on Everything吗&#xff1f; Java on Everything掌握了如何在几乎所有内容上运行Java的关键。 没有操作系统&#xff1f; 没问题。 JOE无需操作系统即可工作。 放弃操作系统的好处是什么&#xff1f; Java on Everything是由约瑟夫库里格&#xff08…...

2008 iis asp配置网站/seo站长网

在plsql开发中&#xff0c;会涉及到一些大数据量表的数据处理&#xff0c;如将某记录数超亿的表的记录经过处理转换插入到另外一张或几张表。常规的操作方法固然可以实现&#xff0c;但时间、磁盘IO、redo日志等等都非常大。Oracle 提供了一种高级函数&#xff0c;可以将这种数…...

长沙做网站的/电商平台怎么加入

XP系统下,双网卡共享上网,绝对可行,无须专业知识 XP下的双机互连 随着时代的发展&#xff0c;电脑在现在的家庭中的普及程度越来越高&#xff0c;而且已经有很多的家庭拥有了两台甚至两台以上的电脑。对于这些用户来说&#xff0c;如何把两台电脑连接在一起&#xff0c;组成一个…...

天津电商网站建设/市场营销网络

在此示例中&#xff0c;您可以获取网页上所有出现的电子邮件地址。 如果您必须更改站点的特定页面或子部分的电子邮件地址&#xff0c;则很有用。 也可能对从网页上筛选爬网电子邮件地址有用&#xff0c;尽管这不是我在这里要实现的目标。 查看更多jQuery .each示例 。 i 不敏感…...

品牌创意网站建设/互联网媒体广告公司

知识点:CSS3 transform 属性、transition属性 实现效果: 效果说明:一排图片大小一致,当鼠标放在任一图片上时,图片放大并且旋转。 制作思路: 1、给图片添加<a>标签,利用伪类选择器实现 2、设置鼠标悬浮在a标签上时,添加动画属性。 3、主要用到属性:transf…...