国产av一区二区三区传媒移动/宁波seo外包推广平台
一、 Arm架构寄存器体系熟悉
基于arm neon 实现的代码有 intrinsic 和inline assembly 两种实现。
1.1 通用寄存器
arm v7 有 16 个 32-bit 通用寄存器,用 r0-r15 表示。
arm v8 有 31 个 64-bit 通用寄存器,用 x0-x30 表示,和 v7 不一样的是,这 31 个寄存器也可以作为 32-bit 寄存器来用,用 w0-w30 表示,其中 wn 是 xn 的低 32 位,如下图所示:
函数前四个参数,会按顺序被放入寄存器 r0-r3(w0-w3), 剩下会采用压栈的方式保存
寄存器寄存器 | 别名 | 用途 |
r0 | a1 | 第一个函数参数: Scratch 寄存器 |
r1 | a2 | 第二个函数参数: Scratch 寄存器 |
r2 | a3 | 第三个函数参数: Scratch 寄存器 |
r3 | a4 | 第四个函数参数: Scratch 寄存器 |
r4 | v1 | 寄存器变量 |
r5 | v2 | 寄存器变量 |
r6 | v3 | 寄存器变量 |
r7 | v4 | 寄存器变量 |
r8 | v5 | 寄存器变量 |
r9 | v6 rfp | 寄存器变量 实际的帧指针 |
r10 | sl | 栈接线 |
r11 | fp | 参数指针 |
r12 | ip | 临时 |
r13 | sp | 栈指针 |
r14 | lr | 连接寄存器 |
r15 | pc | 程序计数 |
1.2 向量寄存器
armv7 包含 16 个 128-bit 向量寄存器,用 q0-q15 表示,其中每个 q 寄存器又可以拆分成两个 64-bit 向量寄存器来用,用 d0-d31 来表示。
armv8 则有更多的向量寄存器,32 个 128-bit 向量寄存器,用 v0-v31 来表示。
每个 128-bit 向量寄存器可以当做:
-
包含 2 个 64-bit 元素的向量寄存器来用,表达形式是 vn.2d;
-
包含 4 个 32-bit 元素的向量寄存器来用,表达形式是 vn.4s;
-
包含 8 个 16-bit 元素的向量寄存器来用,表达形式是 vn.8h;
-
包含 16 个 8-bit 元素的向量寄存器来用,表达形式是 vn.16b;
或者每个向量寄存器也可以只用低 64-bit:
-
1 个 64-bit 元素的向量寄存器来用,表达形式是 vn.1d;
-
2 个 32-bit 元素的向量寄存器来用,表达形式是 vn.2s;
-
4 个 16-bit 元素的向量寄存器来用,表达形式是 vn.4h;
-
8 个 8-bit 元素的向量寄存器来用,表达形式是 vn.8b;
利用指令集加速,无一例外地要利用专用寄存器这种在 CPU 上稀少、宝贵的资源。专用寄存器用少了 CPU 的性能不能充分发挥,用多了则会产生寄存器溢出 (Register Spilling)(https://blog.csdn.net/qq_41112170/article/details/90286091) 这种对性能有明显负面影响的问题。因此,我们至少需要了解在编写 Neon 代码时,有多少个专用寄存器可供利用。
二、内联汇编
2.1 基础写法
__asm__ qualifiers ( // 汇编代码部分
: OutputOperands //在内联汇编代码中被修改的变量列表
: InputOperands //在内联汇编代码中用到的变量列表
: Clobbers //在内联汇编代码中用到的寄存器列表 );
qualifiers
:一般是用 volatile
修饰词 ,关键字__volatile__:也可以写“volatile”,理由同上;__volatile__是可选的,作用是禁止编译器对后面汇编指令再进行优化。一般自己写的汇编,考虑性能,已经做过优化,编译器再优化的话,可能效果反而更差,所以通常还是带上这个关键字;
括号里:是真正的汇编代码,主要有四部分组成,第一部分是具体的汇编代码,是必须的;其他三个为辅助参数,可选;各部分之间用冒号“:”分割,即使参数为空,也要加冒号;
-
OutputOperands
:在内联汇编中会被修改的变量列表,变量之间用','隔开, 每个变量的格式是:[asmSymbolicName] "constraint"(cvariablename)
cvariablename
:表示变量原来的名字;asmSymbolicName
:表示变量在内联汇编代码中的别名,一般和 cvariablename 一样,在汇编代码中就可以通过%[asmSymbolicName]
去使用该变量;constraint
: 一般填=r
,具体解释见文档[6
] -
InputOperands
:在内联汇编中用到的所有变量列表,变量之间用','隔开, 每个变量的格式是:[asmSymbolicName] "constraint"(cexpression)
和输出不一样地方是,首先要按OutputOperands
列表的顺序再列一遍,但是constraint
用数字代替从0
开始,然后才是写其他只读变量,只读变量constraint
填r
。 -
Clobbers
: 一般是"cc", "memory"
开头,然后接着填内联汇编中用到的通用寄存器和向量寄存器"cc"
表示内联汇编代码修改了标志寄存器;"memory"
表示汇编代码对输入和输出操作数执行内存读取或写入操作(读写参数列表之一的变量指向的内存); -
输入列表 (
"r" (some_input)
): 这表明some_input
是一个输入操作数,它的值在汇编执行前被读取。"r"
约束表示some_input
被存储在某个寄存器中,具体哪个寄存器由编译器决定。 -
输出列表 (
"+r" (result)
): 这表明result
是一个输出操作数,它的值在汇编执行后被写回。"+"
约束表示result
既可以作为输入也可以作为输出,汇编代码可以读取它的初始值,并在执行过程中更新它的值。
约束说明:
-
"r"
:将值放入任意一个可用的寄存器中。 -
"+r"
:将值放入任意一个可用的寄存器中,并且该寄存器在操作后还会被写回,即它既可以作为输入也可以作为输出。 -
"+w"
:类似于"+r"
,但表示该值在汇编代码中可能会被修改,并且修改后的值需要写回原始变量。 -
"m"
:表示该值应该被加载到内存地址中,通常与指针一起使用。
asm("mov %0,%1":"+r"(val1):"r"(val2):);
由上面对指令语法的描述进行分析:
-
输出操作数为 val1,属性为 "=r"。
-
输入操作数为 val2,属性为 "r"
-
code 部分为 mov %1,%0,
-
%0 表示输入输出列表中的第一个操作数,
-
%1 表示操作数列表中提供的第二个操作数,以此类推,这条汇编指令很明显就是将第二个操作数(val2)赋值给第一个操作数(val1),所以最后的结果为 val1 = 222. 。
int x=10, y; __asm__ ("mov %[in],%[out]": [out]"=r"(y): [in]"r"(x): );
如果指定了别名的话,那在汇编模板中,引用该变量,就可以使用别名,增加可读性,
2.2 操作符含义
-
"=" 表示只写,通常用于所有输出操作数的属性
-
"+" 表示读写,只能被列为输出操作数的属性,否则编译会报错。
-
& :只能用作输出
限定符 | ARM指令集含义 |
r | 通用寄存器 |
f | 浮点寄存器 |
m | 内存地址 |
为保持寄存器,内存数据一致性,提供三个类型
类型 | 作用 |
r0…r15 | 告诉编译器汇编代码中修改了寄存器r0…r15 (v8 是x, v) |
cc | 告诉编译器汇编代码会导致CPU状态位的改变 |
memory | 告诉编译器汇编代码会读取或修改内存中某个地址存放的值 |
三、样例分析
对于刚入门优化的同学,改写汇编最好先从 C++ 改写 intrinsic 开始,然后再根据 intrinsic 的代码去改写汇编,一般 intrinsic 的指令和汇编指令都能对应的上,当然高手可以直接跳过去写汇编,但是对于新手建议还是一步步来。
而且比较重要的一点是,我认为 算法上的改进更为重要,假设你 C++ 算法层面代码已经定下来了,对于性能还想有更进一步的提升,那么可以尝试去写 neon 汇编(内联或者纯汇编),但不是说汇编是万能的,这个和你的优化经验还有算法本身的复杂度有很大关系,可能你吭哧坑次改完,发现还做了负优化,因为编译器本身也会做向量化。
3.1 两个数组加权和
第一个例子是两个数组对应元素加权和,例子足够简单,方便讲解改写汇编的一些思路。 下面代码为了可读性会相应的作简.
3.1.1 c++ 实现
bool arrWeightedAvg(const float *arr1,const float arr1Weight,const float *arr2,const float arr2Weight,const int len,float *resultArr) {for (int i = 0; i < len; ++i) {resultArr[i] = arr1[i] * arr1Weight + arr2[i] * arr2Weight;}return true;
}
3.1.2 改 intrinsic
对于 intrinsic 代码是兼容 armv7 和 v8 的,所以不同架构之间迁移也方便,不需要改代码:
bool arrWeightedAvgIntrinsic(const float *arr1,const float arr1Weight,const float *arr2,const float arr2Weight,const int len,float *resultArr) {int neonLen = len >> 2;int remain = len - (neonLen << 2);// 这里向量化主要思路是循环内每次// 处理4个元素的加权和// 所以neonLen是数组长度len除4// 而剩下的尾部元素按正常处理float *resultArrPtr = resultArr;const float *arr1Ptr = arr1;const float *arr2Ptr = arr2;// 因为一次处理4个元素// 所以权值要拷贝4份放到// 一个float32x4_t类型变量中// 也相当于是128-bit向量寄存器float32x4_t arr1Wf4 = vdupq_n_f32(arr1Weight);float32x4_t arr2Wf4 = vdupq_n_f32(arr2Weight);for (int i = 0; i < neonLen; ++i) {// 分别读4个数组元素float32x4_t arr1f4 = vld1q_f32(arr1Ptr);float32x4_t arr2f4 = vld1q_f32(arr2Ptr);// eltwise乘法arr1f4 = vmulq_f32(arr1f4, arr1Wf4);arr2f4 = vmulq_f32(arr2f4, arr2Wf4);// eltwise加法float32x4_t resultf4 = vaddq_f32(arr1f4, arr2f4);// 写结果vst1q_f32(resultArrPtr, resultf4);arr1Ptr += 4;arr2Ptr += 4;resultArrPtr += 4;}// 处理尾部元素for (; remain > 0; remain --) {*resultArrPtr = (*arr1Ptr) * arr1Weight + (*arr2Ptr) * arr2Weight;resultArrPtr ++;arr1Ptr ++;arr2Ptr ++;}return true;
}
3.1.3 arm v7 内联汇编
bool arrWeightedAvgIntrinsic(const float *arr1,const float arr1Weight,const float *arr2,const float arr2Weight,const int len,float *resultArr) {int neonLen = len >> 2;int remain = len - (neonLen << 2);// 这里向量化主要思路是循环内每次// 处理4个元素的加权和// 所以neonLen是数组长度len除4// 而剩下的尾部元素按正常处理float *resultArrPtr = resultArr;const float *arr1Ptr = arr1;const float *arr2Ptr = arr2;// 因为一次处理4个元素// 所以权值要拷贝4份放到// 一个float32x4_t类型变量中// 也相当于是128-bit向量寄存器float32x4_t arr1Wf4 = vdupq_n_f32(arr1Weight);float32x4_t arr2Wf4 = vdupq_n_f32(arr2Weight);for (int i = 0; i < neonLen; ++i) {// 分别读4个数组元素float32x4_t arr1f4 = vld1q_f32(arr1Ptr);float32x4_t arr2f4 = vld1q_f32(arr2Ptr);// eltwise乘法arr1f4 = vmulq_f32(arr1f4, arr1Wf4);arr2f4 = vmulq_f32(arr2f4, arr2Wf4);// eltwise加法float32x4_t resultf4 = vaddq_f32(arr1f4, arr2f4);// 写结果vst1q_f32(resultArrPtr, resultf4);arr1Ptr += 4;arr2Ptr += 4;resultArrPtr += 4;}// 处理尾部元素for (; remain > 0; remain --) {*resultArrPtr = (*arr1Ptr) * arr1Weight + (*arr2Ptr) * arr2Weight;resultArrPtr ++;arr1Ptr ++;arr2Ptr ++;}return true;
}
3.1.4 armv8 内联汇编
#ifdef __aarch64__ // armv8__asm__ volatile("mov x0, %[arr1Weight] \n" // 将weight1的值移动到通用寄存器x0中。"dup v0.4s, w0 \n" //w0是x0的低32位, 复制值到向量寄存器v0中,当成4*32来使用。"mov x1, %[arr2Weight] \n""dup v1.4s, w1 \n""0: \n" //循环结束条件,小于0."prfm pldl1keep, [%[arr1Ptr], #128] \n" //预读取arr1地址开始的128bit 数据,就是4个32bit的数据。"ld1 {v2.4s}, [%[arr1Ptr]], #16 \n" // 将数据加载到v2 向量寄存器中, 并且地址自增16个字节。"prfm pldl1keep, [%[arr2Ptr], #128] \n""ld1 {v3.4s}, [%[arr2Ptr]], #16 \n""fmul v4.4s, v2.4s, v0.4s \n" //数组1和权重相乘。保存在v4 寄存器中。"fmul v5.4s, v3.4s, v1.4s \n" // 数据2和权重相乘,保存在v5 寄存器中。"fadd v6.4s, v4.4s, v5.4s \n" //将寄存器v4, v5的值相加, 保存在v6寄存器中。"subs %[neonLen], %[neonLen], #1 \n" // 对应 neonLen-- sub指令后面加个s表示会更新条件flag"st1 {v6.4s}, [%[resultArrPtr]], #16 \n" //将寄存器v6的结果写入到目的地址resultarrptr, 地址自增16字节。(4个数,一个数四字节)"bgt 0b \n" //b跳转指令, gt 判断是不是大于0条件判断, 大于0, 跳转到0的位置。:[arr1Ptr] "+r"(arr1Ptr),[arr2Ptr] "+r"(arr2Ptr),[resultArrPtr] "+r"(resultArrPtr),[neonLen] "+r"(neonLen):[arr1Weight] "r"(arr1Weight),[arr2Weight] "r"(arr2Weight):"cc", "memory", "x0", "x1", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
反编译系统的编译文件,进行汇编代码对比,学习。
./llvm-objdump -d /home/lsq/wind/wind_develop_my/wind/build_android/src/backend/cpu/CMakeFiles/Wi
ndCPU.dir/kernel/neon/matmul_quant_test.cc.o
内联汇编的目的是进行汇编指令的优化,尽可能的直接操作寄存器,利用新特性,进行代码的加速。更多的指令需要查找官方文档进行学习。
3.2 汇编指令对应的机器码生成
.inst 0x4e80a4d8
是一个汇编指令,用于在 ARM 架构中直接插入机器码。这个指令的格式是 .inst <机器码>
,其中 <机器码>
是一个 32 位或 64 位的十六进制值,表示一条机器指令。
具体来说,0x4e80a4d8
是一个 32 位的机器码。为了理解这个机器码是如何编码的,我们需要查看 ARMv8 指令集的文档,特别是 NEON 指令集的文档。
3.2.1 使用 LLVM 工具
可以安装 llvm
工具链,然后运行如下命令:、
echo "smmla v16.4s, v4.16b, v0.16b" | llvm-mc -arch=aarch64 -mattr=+neon,+i8mm -show-encoding
这将会输出汇编指令对应的机器码。如果没有安装 llvm-mc
工具,可以参考以下汇编器指令来生成机器码。
3.2.2 使用 GNU 汇编器
你可以使用 arm-none-eabi-as
工具来编译汇编代码并生成机器码。下面是一个示例:
echo ".arch armv8-a; smmla v16.4s, v4.16b, v0.16b" | arm-none-eabi-as -o - -a -
3.2.3 在线工具
https://armconverter.com/
3.2.4 反编译编译产物
./llvm-objdump -d /home/lsq/wind/wind_develop_my/wind/build_android/src/backend/cpu/CMakeFiles/WindCPU.dir/kernel/neon/matmul_quant_test.cc.o 反汇编结果:
".inst 0x4e80a490 \n" // smmla v16.4s, v4.16b, v0.16b //v0_01s// *y0_0".inst 0x4e81a4b5 \n" // smmla v21.4s, v5.16b, v1.16b //v0_0hs// *y0_1".inst 0x4e82a4da \n" // smmla v26.4s, v6.16b, v2.16b //v0_1ls// *y0_2".inst 0x4e83a4ff \n" // smmla v31.4s, v7.16b, v3.16b// v0_1hs
四、附录
https://medium.com/@warmap_/%E8%BD%AC-%E5%A6%82%E4%BD%95%E5%9C%A8c%E6%88%96c-%E4%BB%A3%E7%A0%81%E4%B8%AD%E5%B5%8C%E5%85%A5arm%E6%B1%87%E7%BC%96%E4%BB%A3%E7%A0%81-a3704e164de8
http://giantpandacv.com/project/%E9%83%A8%E7%BD%B2%E4%BC%98%E5%8C%96/AI%20%E7%A7%BB%E5%8A%A8%E7%AB%AF%E7%AE%97%E6%B3%95%E4%BC%98%E5%8C%96/%E7%A7%BB%E5%8A%A8%E7%AB%AFarm%20cpu%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%A7%BB%E5%8A%A8%E7%AB%AFarm%20cpu%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E7%AC%AC4%E5%BC%B9--%E5%86%85%E8%81%94%E6%B1%87%E7%BC%96%E5%85%A5%E9%97%A8/
相关文章:

arm 内联汇编基础
一、 Arm架构寄存器体系熟悉 基于arm neon 实现的代码有 intrinsic 和inline assembly 两种实现。 1.1 通用寄存器 arm v7 有 16 个 32-bit 通用寄存器,用 r0-r15 表示。 arm v8 有 31 个 64-bit 通用寄存器,用 x0-x30 表示,和 v7 不一样…...

Java语言程序设计——篇五(1)
数组 概述数组定义实例展示实战演练 二维数组定义数组元素的使用数组初始化器实战演练:矩阵计算 💫不规则二维数组实战演练:杨辉三角形 概述 ⚡️数组是相同数据类型的元素集合。各元素是有先后顺序的,它们在内存中按照这个先后顺…...

【香橙派开发板测试】:在黑科技Orange Pi AIpro部署YOLOv8深度学习纤维分割检测模型
文章目录 🚀🚀🚀前言一、1️⃣ Orange Pi AIpro开发板相关介绍1.1 🎓 核心配置1.2 ✨开发板接口详情图1.3 ⭐️开箱展示 二、2️⃣配置开发板详细教程2.1 🎓 烧录镜像系统2.2 ✨配置网络2.3 ⭐️使用SSH连接主板 三、…...

集成学习在数学建模中的应用
集成学习在数学建模中的应用 一、集成学习概述(一)基知(二)相关术语(三)集成学习为何能提高性能?(四)集成学习方法 二、Bagging方法(一)装袋&…...

WebKit 的 Web SQL 数据库:现代浏览器的本地存储解决方案
WebKit 的 Web SQL 数据库:现代浏览器的本地存储解决方案 随着Web应用的不断发展,对本地存储的需求也日益增加。WebKit作为许多现代浏览器的核心引擎,提供了一种强大的本地存储解决方案:Web SQL 数据库。本文将详细探讨Web SQL 数…...

Yolo-World网络模型结构及原理分析(三)——RepVL-PAN
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1. 网络结构2. 特征融合3. 文本引导(Text-guided)4. 图像池化注意力(Image-Pooling Attention)5. 区域文本匹配&…...

代码随想录——一和零(Leetcode474)
题目链接 0-1背包 class Solution {public int findMaxForm(String[] strs, int m, int n) {// 本题m,n为背包两个维度// dp[i][j]:最多右i个0和j个1的strs的最大子集大小int[][] dp new int[m 1][n 1];// 遍历strs中字符串for(String str : strs){int num0 …...

力扣题解(组合总和IV)
377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 思路: 本题实质上是给一些数字,让他们在满足和是targ…...

Postgresql主键自增的方法
Postgresql主键自增的方法 一.方法(一) 使用 serial PRIMARY KEY 插入数据 二.方法(二) 🎈边走、边悟🎈迟早会好 一.方法(一) 使用 serial PRIMARY KEY 建表语句如下…...

【源码阅读】Sony的go breaker熔断器源码探究
文章目录 背景源码分析总结 背景 在微服务时代,服务和服务之间调用、跨部门调用都是很常见的事,但这些调用都存在很多不确定因素,如核心服务A依赖的部门B服务挂掉了,那么A本身的功能将会受到直接的影响,而这些都会影响…...

LeetCode题(66,69,35,88)--《c++》
66.加一 // // Created by wxj05 on 2024/7/20. // //法一 class Solution { public:vector<int> plusOne(vector<int>& digits) {bool carry true; // 进位标志for (int i digits.size() - 1; i > 0 && carry; --i) {digits[i] 1;carry digit…...

来参与“向日葵杯”全国教育仿真技术大赛~
可点击进行了解:“向日葵杯”全国教育仿真技术大赛 (sunmooc.cn) 本次大赛共分为四个赛道:自主命题赛道、教育知识图谱设计赛道、FPGA硬件扑克牌对抗赛道、EasyAR元宇宙空间设计赛道。 参赛对象 : 具有正式学籍的在校研究生,本科…...

SQL每日一题:删除重复电子邮箱
题干 表: Person -------------------- | Column Name | Type | -------------------- | id | int | | email | varchar | -------------------- id 是该表的主键列(具有唯一值的列)。 该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。 编写解决方案 删除 所有重复…...

3、宠物商店智能合约实战(truffle智能合约项目实战)
3、宠物商店智能合约实战(truffle智能合约项目实战) 1-宠物商店环境搭建、运行2-webjs与宠物逻辑实现3-领养智能合约初始化4-宠物领养实现5-更新宠物领养状态 1-宠物商店环境搭建、运行 https://www.trufflesuite.com/boxes/pet-shop 这个还是不行 或者…...

数据库系列
目录 一、数据库的概念和作用 1.数据库的特点 2.数据模型 二、数据库系统 1.数据库管理系统 2.数据库的基本操作 一、数据库的概念和作用 数据库是指长期存储在计算机内,有组织的、可共享的数据集合。它可视为一个电子化的文件柜,用来存储电子文件…...

极狐GitLab如何启用和配置PlantUML?
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...

Shell 构建flutter + Android 生成Apk
具体步骤 #shell 具体实现和说明如下: echo "build_start_apk!" echo "编译此脚本的前提条件如下:" #在Android 项目的主工程下,进入主工程文件夹,创建build-android 文件夹,在其文件夹下有build-android.sh文件,此文件就是整个文章的脚本内容(…...

如何用手机压缩视频?手机压缩视频方法来了
高清视频的大文件大小常常成为分享和存储的障碍,尤其是在数据流量有限或存储空间紧张的情况下。幸运的是,无论是智能手机还是个人电脑,都有多种方法可以帮助我们轻松压缩视频文件,以适应不同的需求和情境。本文将介绍如何在手机上…...

Linux下如何安装配置Elastic Stack日志收集系统
安装和配置Elastic Stack日志收集系统,包括Elasticsearch、Logstash和Kibana,是一个相对复杂的过程。本篇文章将逐步引导您完成整个过程。 安装Java Elasticsearch、Logstash和Kibana都需要Java运行环境。首先,您需要在Linux系统上安装Java…...

【深入C++】map和set的使用
文章目录 C 中的容器分类1. 顺序容器2. 关联容器3. 无序容器4. 容器适配器5. 字符串容器6. 特殊容器 set1.构造函数2.迭代器3.容量相关的成员函数4.修改器类的成员函数5.容器相关操作的成员函数 multiset1.equal_range map1.初始化相关的函数2.迭代器3.容量相关的成员函数4.访问…...

跟代码执行流程,读Megatron源码(二)训练入口pretrain_gpt.py
Megatron-LM默认支持GPT、T5、BERT等多个常见模型的预训练,当下大模型流行,故以pretrain_gpt.py为例做源码的走读。 一. 启动pretrain_gpt.py pretrain_gpt.py为GPT类模型的训练入口,它通过命令行形式被调用,其精确执行路径位于M…...
MATLAB练习题——矩阵(2)
逻辑运算 a [5 0.2 0 -8 -0.7 ],在进行逻辑运算时,a 相当于什么样的逻辑量。 相当于 a[1 1 0 1 1] 角度运算 在 sin(x)运算中,x 是角度还是弧度? 在 sin(x)运算中,x 是弧度,MATLAB 规定所有…...

arm、AArch64、x86、amd64、x86_64 的区别
arm vs AArch64 vs amd64 vs x86_64 vs x86 的区别 当涉及到 CPU 的时候,有许多术语:AArch64、x86_64、amd64、arm 等等。了解它们是什么以及它们之间的区别。 当你查看数据表或软件下载页面时是否被 ARM、AArch64、x86_64、i386 等术语混淆?…...

【SpringBoot】 jasypt配置文件密码加解密
目前我们对yml配置文件中的密码都是明文显示,显然这不安全,有的程序员离职了以后可能会做一些非法骚操作,所以我们最好要做一个加密,只能让领导架构师或者技术经理知道这个密码。所以这节课就需要来实现一下。 我们可以使用jasypt…...

复杂网络的任意子节点的网络最短距离
复杂网络的任意子节点的网络最短距离 题目要求介绍 本文算法测试用的数据集为空手道俱乐部,其中空手道俱乐部的数据集可通过这个链接进行下载•http://vlado.fmf.uni-lj.si/pub/networks/data/Ucinet/UciData.htm#zachary 摘要 本文旨在解决复杂网络中任意子节点…...

(Qt) 文件读写基础
文章目录 🗂️前言📄ref📄访问标记🗃️enum 标记 🗂️Code📄demo📄分点讲解🗃️继承体系🗃️打开/关闭🗃️写🗃️读 🗂️END…...

全产业布局对穿戴甲品牌连锁店的意义
对于美甲行业来说,穿戴甲虽然不是什么新生事物,但也就是近两年才流行开来。面对井喷的市场需求,相应的从业者,不管是品牌连锁店,还是做批发、外贸,美甲周边、亦或是OEM的,大家都忙得不亦乐乎&am…...

git的一些使用技巧(git fetch 和 git pull的区别,git merge 和 git rebase的区别)
最近闲来无聊,虽然会使用git操作,但是 git fetch 和 git pull 的区别,git merge 和 git rebase的区别只是一知半解,稍微研究一下; git fetch 和 git pull 的区别 git fetch git fetch 是将远程仓库中的改动拉到本地…...

展厅中控系统有哪些优势呢
格芬科技的展厅中控系统具有多方面的优势,主要体现在以下几个方面: 一、高度集成与灵活控制 全终端网络可编程:格芬科技的展厅中控系统采用全终端网络可编程技术,能够实现对展厅内各种设备的集中控制和管理,包括电脑…...

FPGA开发在verilog中关于阻塞和非阻塞赋值的区别
一、概念 阻塞赋值:阻塞赋值的赋值号用“”表示,对应的是串行执行。 对应的电路结构往往与触发沿没有关系,只与输入电平的变化有关系。阻塞赋值的操作可以认为是只有一个步骤的操作,即计算赋值号右边的语句并更新赋值号左边的语句…...