自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(175)
  • 收藏
  • 关注

原创 机器学习编译(三):张量程序案例 TensorIR

当我们读取内存中的一个元素时,它会尝试将附近的元素(更正式的名称为“缓存行”)获取到缓存中。除了 TensorIR,TVM 中还可以用张量表示(Tensor Expression, TE)来做张量的抽象,这里略过,在介绍 TVM 的文章中再详细介绍。前面我们说了 TensorIR 是 TVM 里最接近硬件的 IR,而 IRModule 是 TVM 中可以编译的最小单位。是 TensorIR 中的基本计算单位。使用张量程序抽象,我们可以在较高层的抽象制定一些与特定硬件无关的较通用的 IR 优化(计算优化)。

2023-08-13 12:23:55 196

原创 深度学习框架 —— 分布式训练

分布式训练的动机很简答:单节点算力和内存不足,因此不得不做分布式训练。训练机器学习模型需要大量内存。假设一个大型神经网络模型具有 1000 亿的参数(LLM 时代有不少比这个参数量更大的模型),每个参数都由一个 32 位浮点数(4 个字节)表达,存储模型参数就需要 400GB 的内存。在实际中,我们需要更多内存来存储激活值和梯度。假设激活值和梯度也用 32 位浮点数表达,那么其各自至少需要 400GB 内存,总的内存需求就会超过 1200GB(即 1.2TB)。

2023-08-07 14:15:29 988

原创 深度学习编译器后端和运行时

编译器前端将用户代码解析得到计算图 IR,并且做了一些和计算设备无关的通用优化。编译器后端做的优化就和具体的设备有关了(不同设备有不同的 allocator,不同的编程模型,比如英伟达的 CUDA),后端优化更加贴合硬件,会针对硬件特点为 IR 中的计算节点选择在硬件上的算子,然后为每个算子的输入输出分配硬件内存,最终生成一个可以在硬件上执行的任务序列。如上图所示,编译器后端位于前端和硬件驱动层之间,主要做:计算图优化、算子选择、内存分配等工作。

2023-08-06 19:03:09 202

原创 深度学习编译器前端技术概述

AI 编译器在前端经常会做一些静态分析,方便在前端做一些优化:自动微分等。

2023-08-06 13:45:06 149

原创 计算图概念

机器学习程序从前端到后端需要编译成不同的 IR 来获得更好的优化性能,在 mlsys 中这个 IR 就是计算图。对机器学习程序描述的调度执行、自动更新模型所需的梯度都需要依赖计算图。一个计算图的逻辑结构大概是下图右边的前向部分:也就是由神经网络中的算子、各算子的输入、以及算子之间的计算顺序组成。有了计算图就可以从逻辑上表达一个神经网络前向的计算过程并由此得到在各个硬件平台的 IR 从而进行更多的优化。

2023-08-05 23:19:17 53

原创 机器学习工作流

因此,优化器定义API允许用户定义自己的损失函数,并且根据损失来引入(Import)和定义各种优化算法(Optimisation algorithms)来计算梯度(Gradient),完成对模型参数的更新;: 训练模型的过程中模型的参数会通过反向传播得到更新(一般初始时参数值是随机的),得到更新之后的模型参数我们可以用来部署或者继续训练(微调),有时候我们需要把模型参数保存下来,之后再训练可以在此基础上继续进行。反向就不用写了,现在框架基本都支持自动微分,梯度更新的时候框架会根据前向结构计算梯度;

2023-08-05 23:16:14 36

原创 机器学习框架的基本组成

参考。

2023-08-05 23:13:56 120

原创 机器学习框架的目标

训练神经网络的过程本质上是模型参数的迭代,这些参数需要持续计算梯度(Gradients)迭代改经。梯度的计算往往需要结合训练数据、数据标注和损失函数(Loss Function)。手工计算梯度很麻烦,机器学习框架需要根据用户给的框架全自动计算梯度。神经网络训练、测试、验证都需要数据,机器学习框架应该支持数据的读取、存储、和预处理(比如数据增强和数据清洗)。随着模型规模的增大,单机器训练神经网络效率太低,机器学习框架应该支持分布式训练。神经网络需要一个共同的系统进行开发、训练和部署。

2023-08-04 13:45:13 37

原创 升级 python 导致的坑

设置默认 python 软链接到 python3.8 之后,可能会导致之前一些 python3.6 的 pip install 的包找不到,我是在编译 MegBrain 的 cmake 的时候遇到的,然后 pip install 一些包可能会乱,感觉 python 这一点很蛋疼。解决办法:需要 pip install cpython,然后遇到下面这个错误。

2023-07-26 14:07:35 234

原创 C++ 类的非静态数据成员默认初始化

同时构造函数少了很多冗余代码,每个构造函数只需要专注于特殊成员的初始化(而不是写出全部数据成员的初始化),对于没写出来的数据成员,默认使用声明时初始化的值。因为有时候要给不同的成员变量进行初始化,所以要写好几个不同版本的构造函数,并且可以发现构造函数里有很多冗余代码。有个问题是,如果类的数据成员比较多,我们又需要定制一些数据成员的初始化操作的时候,需要写很多的构造函数。这种方式在数据成员变多的时候,需要频繁地更改和增加构造函数,维护起来非常的麻烦。列表初始化)和构造函数的列表初始化同时使用了。

2022-09-11 22:19:17 745 1

原创 C++ 类型别名和别名模板

在实例化的时候,只需要传需要的一个模板参数(这里是。起类型别名有点像赋值,除此以外似乎和。)替换原始模板中的对应类型,所以这里。是一个类型的别名,并且用到了模板。别名模板的本质也是一个模板。是我们为它起的别名。只是在实例化的过程中。

2022-09-09 23:00:28 633

原创 C++ 静态断言 static_assert

注意:**断言不能代替程序中的错误检查,它只应该出现在需要断言表达式为 true 的位置,通常用于检查参数或表达式的合法性。A:运行时断言在运行到断言位置时才触发断言,对于断言表达式是常量表达式的情况,如果可以在编译期就进行检查,能帮助我们提早发现错误,这(在编译阶段断言)正是静态断言所做的。因此,当断言表达式是常量表达式时,我们应该优先使用静态断言。注意,这里需要是常量表达式,也就是不涉及计算,只需要逻辑运算就可以知道结果的表达式。在静态断言出现前,运行时断言已经存在很久了,我们可以使用。

2022-09-08 00:32:02 780

原创 C++ decltype 类型推导

C++11 引入了 decltype 说明符,decltype 可以获取一个对象或者表达式的类型。除了可以推导表达式的类型,还可以用来推导类中的非静态成员变量的类型((在泛型编程的情况下只能表现引用语义的表达能力是不够的),就可以使用。如果不存在这样的类型(比如表达式里的变量不在当前作用域内)或者。要求是编译期确定返回类型),则无法进行推导。这就是上面的那个例子返回的是一个引用的原因。,返回一个引用,所以我们的断言可以通过。推断出的类型是其返回值的类型。是类的成员变量时,要同步。加上括号,推导的类型没有。

2022-09-07 23:26:12 275

原创 C++ auto 关键字

关键字推导复杂类型要比显示地写出来方便的多,而且很多时候我们没法准确写出来变量的类型(一些复杂类型在不同编译器下可能会生成不同的类型),这种情况下就可以用。关键字自动推导函数的返回值类型,只要确保即使在有多重返回值时函数的返回值类型依旧是确定的即可(也就是不存在可能返回类型。C++11 允许使用 auto 关键字对变量类型进行自动推导,通常用在变量类型较长或者很难写出变量类型的场景。的引用,众所周知引用和原变量指向的是相同的内存地址。的类型是有要求的,用错类型会导致编译错误。再提一嘴,上面的例子可以将。

2022-09-07 00:02:49 176

原创 C++ 内联和嵌套命名空间

类似于C++17的定义嵌套命名空间的简洁用法,C++20}}}}}}}inline可以出现在除第一个namespace(也就是最外层的namespace)之外的任意namespace之前。

2022-09-05 23:47:57 326

原创 C++11~C++20 新基础类型

char16_t 和 char32_t 的引入就是为了解决这个问题,它们明确规定了所占内存空间的大小:char16_t 占 2 字节,char32_t 占 4 字节。C++11 增加了两种字符类型 char16_t 和 char32_t,分别对应 Unicode 字符集的 UTF-16 和 UTF-32 编码方法。于是,C++20 引入了 char8_t 字符类型,它代替了 char 作为 UTF-8 的字符类型。C++98 的宽字符类型 wchar_t 在不同的平台长度不同,因此也就会导致不同的行为。

2022-09-05 22:39:02 371

原创 记水题两道

1输入一个十进制整数,输出对应的七进制结果.例如:Input1:20Output1:26Input2:-100Output2:-202题解:根据辗转相除法,输入 num,每次将 num 对 7 取余,再将 num 除 7,直到 num 为 0 为止,得到的余数加入到一个字符串中,对这个字符串翻转之后就是 num 对应的 7 进制数.特别注意一下对正负号的处理.C++ code:#include <bits/stdc++.h>using namespa

2022-04-24 00:08:54 1159

原创 洛谷B2001 入门测试题目

#include <iostream>#include <vector>#include <string>#include <algorithm>std::string add (const std::vector<int>& a, const std::vector<int>& b) { std::string ans = ""; int carry = 0; int i = 0;

2022-04-19 22:44:22 391

原创 《Effective C++》 rule 03: Use const whenever possible

const 可以修饰哪些东西?const 可以修饰全局 (global) 或命名空间 (namespace) 或类外部的常量.const 也可以修饰文件、函数或作用域中(block scope)被声明为 static 的对象.const 还可以修饰类内部的静态 (static) 和非静态 (non-static) 成员变量.const 与指针结合时,const 既可以修饰指针本身,也可以修饰指针所指对象.当 const 在 * 左边时,表示指针指向的对象是常量.当 const

2022-04-19 00:53:45 1980

原创 《Effective C++》rule 02: Prefer consts, enums, and inlines to #defines

宏定义的问题C++ 会在预处理阶段对宏定义进行字符串替换.因此,如果在一个头文件进行了类似如 #define ASPECT_RATIO 1.653 的宏定义,那么此常量相关的编译错误信息显示的会是 1.653, 而这个宏定义如果不在你写的程序内 (而是它包含的一个头文件内),那么定位问题就会很麻烦.原因很简单: 宏定义在预处理阶段就被处理,因此使用的名称并没有进入符号表 (symbol table) 中.如何解决对于常量,可以使用 const 来代替 #define:const double A

2022-04-14 02:57:12 132

原创 《Effective C++》rule 01: View C++ as a federation of languages

最开始,C++ 是 C + OO (Object Oriented),所以把 C++ 称为 C with Classes.而之后 C++ 多了很多新的特性:exceptions (异常)templates (模板)STL (Standard Template Library, 标准模板库)如今的 C++ 是个多范式编程语言,支持:面向过程 (procedural)面向对象 (object-oriented)函数式编程 (functional programming)泛型编程 (gen

2022-04-14 02:11:42 300

原创 LeetCode第243场周赛

第一题 1880. 检查某单词是否等于两单词之和题目链接:1880. 检查某单词是否等于两单词之和逐位计算单词之和即可class Solution {public: int count(string s) { int ans = 0; for(const auto& c: s) { ans = ans * 10 + c - 'a'; } return ans; } b

2021-05-31 11:47:53 78

原创 LeetCode第52场双周赛

第一题 1859. 将句子排序题目链接:1859. 将句子排序将单词切成只含英文字符的单词和数字的一对pair<string, int>然后根据第二关键字对pair排序排序后,把单词加到答案字符串ans里就行了class Solution {private: using PSI = pair<string, int>; vector<PSI> words; string ans; int n; public:

2021-05-20 14:22:49 73

原创 LeetCode第241场周赛

第一题 5759. 找出所有子集的异或总和再求和题目链接:5759. 找出所有子集的异或总和再求和直接爆搜,计算所有可能的子集的异或和curSum,加入到答案ans里class Solution {private: int ans; int n; public: void dfs(vector<int>& nums, int u, int curSum) { if(u == n) { retu

2021-05-16 20:44:43 89

原创 LeetCode第216场周赛

第一题 5605. 检查两个字符串数组是否相等对于每个数组,都连接这个数组的所有单词为一个单词,然后直接判断这两个单词是否相等即可。class Solution {public: bool arrayStringsAreEqual(vector<string>& word1, vector<string>& word2) { string w1, w2; for(auto &word : word1) {

2020-11-22 18:23:36 96

原创 LeetCode第215场周赛

第一题 1656. 设计有序流可以开一个字符串数组存放字符串,用一个额外的变量ptr存放ptr的位置,插入新的字符串的时候,检查从ptr开始是否有连续的按照id递增的序列即可。代码如下:class OrderedStream {public: int n; int ptr; vector<string> stream; OrderedStream(int _n) { n = _n; ptr = 1;

2020-11-16 21:23:32 185

原创 LeetCode530. 二叉搜索树的最小绝对差

因为是二叉搜索树,所以中序遍历可以得到一个升序序列。因此可以中序遍历这个二叉搜索树,把结果存在一个数组中,然后遍历这个数组,计算相邻值的最小值,这个最小值就是答案。/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), .

2020-11-14 13:06:47 70

原创 LeetCode529. 扫雷游戏

直接按照题意进行深度优先搜索,只要当前位置不是地雷,且周围还存在方块可以揭露(搜索)时,就继续搜索,否则停止搜索,返回面板(board)。(1)如果搜到当前位置是地雷,那就修改为’X’。(2)用一个int变量cnt记录周围8个位置的地雷数量。(i)如果cnt不为0,说明周围有地雷,用对应的数字字符更新这个位置。(ii)如果cnt为0,说明当前位置是一个空白方块,则从这个空白方块周围八个位置继续往下揭露(搜索)。当莫得方块可以继续揭露时,返回面板。代码如下:class Solution ...

2020-11-14 13:00:11 131

原创 LeetCode528. 按权重随机选择

要按照概率随机选择一个数,可以将数组的值看作一个区间上的长度,比如题目给的例子,当w = [1, 3]时,我们可以假设有一个一维的区间,区间前1/4是第0个数,区间的后3/4是第1个数。区间总长度4也就是w数组所有数的和。我们可以在总长度范围(0~4)内随机选择一个数,假设这个数是0~1,那么就返回0,如果这个数是1~4,那么就返回1。这样就解决了按照概率随机返回的问题。但是怎么判断我们随机选择的数该返回什么值呢?这里需要用到前缀和,比如上面的例子w = [1, 3],我们可以得到前缀和pre..

2020-11-14 12:46:24 102

原创 LeetCode526. 优美的排列

题目说了N不会超过15,这就是在暗示我们用DFS。直接DFS出1~N的排列,然后判断一下是否满足条件。不过这里要剪枝一下,不需要枚举出所有的排列之后逐个判断,对于某个排列的某一位u,如果已经不满足条件了,即不满足u % i == 0 或者 i % u == 0,那么就无需枚举剩下的位。这题不加这个剪枝貌似会超时。代码如下:class Solution {public: int res = 0; int n; vector<bool> visited; .

2020-11-14 12:29:56 69

原创 LeetCode525. 连续数组

题目说数组长度最长可能到50000,所以如果暴力枚举子数组的起点、终点,再计算数组和,复杂度就是o(n^3),肯定超时。可以预处理出前缀和,这样只需要枚举起点和终点即可,但时间复杂度依然是O(n^2), 也不行。这里需要一点奇技淫巧,因为数组只包含有0和1,如果一段子数组含有相同数量的0和1,则这个子数组中一半是0,一半是1,那么子数组的和就是这个子数组的长度的一半。更进一步,如果我们把数组中所有的0都当作-1处理,那么,当一个子数组中含有相同的0和1(也就是含有相同数量的-1和1)时,我们计算出来.

2020-11-14 12:14:56 107

原创 LeetCode524. 通过删除字母匹配到字典里最长单词

这题和LeetCode522. 最长特殊序列 II类似,都是在一个字符串数组中找出最长的一个“特殊序列”。思路也和522题类似,都是对字符串数组按照长度从大到小排序,枚举的时候也是按照字符串长度从大到小枚举,只不过这题里我们要找到最长的,属于字符串s子序列的字符串。判断某个字符串是否是另一个字符串的子序列的方法和522题完全相同。代码如下:class Solution {public: bool checkSubSeq(string a, string b) { .

2020-11-14 11:58:47 68

原创 LeetCode523. 连续的子数组和

因为子数组是连续的,所以判断连续的子数组的和时,我们往往开一个前缀和数组预处理出所有数的前缀和,这样能够降低求子数组的和的时间复杂度。这题需要单独处理k为0的情况,由于数组所有元素都是非负数,所以当k为0时,如果存在两个相邻的数的值都为0,则返回true,否则返回false。使用前缀和判断是否存在满足条件的子数组时,只需从小到大枚举子数组的长度,然后再在内层循环内枚举子数组的长度,然后使用前缀和计算区间和的公式计算是否存在子数组的和满足条件即可。有点类似区间dp,hh。代码如下:class Sol.

2020-11-14 11:38:58 153

原创 LeetCode522. 最长特殊序列 II

可以将字符串数组按照长度从大到小进行排序,然后从前往后遍历,找到第一个特殊序列,这个特殊序列的长度就是答案,如果遍历完数组,都没有找到特殊序列,这返回-1。特殊序列的判断方法如下:(1)如果这个字符串存在和它相同的字符串(排序后这两个字符串是相邻的),则这个字符串不是特殊序列。(2)从最开始(长度最长的)字符串枚举到这个字符串之前的字符串(也就是枚举所有长度比当前字符串大的字符串),判断当前这个字符串是不是其他字符串的子序列,如果是,则它不是特殊序列;如果不是,则当前这个字符串的长度就是最长特殊序列.

2020-11-14 11:26:16 84

原创 LeetCode521. 最长特殊序列 Ⅰ

根据题意,最长特殊序列就是一个字符串独有的最长子序列,也就是说找到不是另一个字符串子序列的最长子序列。题目给了两个字符串,如果两个字符串长度不一致,那么长的那个字符串肯定不是短的字符串的子序列,直接返回长的字符串的长度即可。如果两个字符串长度一致,只有当两个字符串相等时,才不存在最长特殊序列,否则,最长特殊序列的长度就是这两个字符串的长度。class Solution {public: int findLUSlength(string a, string b) { if(a.

2020-11-14 11:04:32 74

原创 LeetCode520. 检测大写字母

题目给出了正确的大写用法的三种情况,直接根据情况判断即可。首先要判断第一个字母是否是大写字母,如果第一个字母不是大写字母,那么单词后面如果出现小写字母,这个单词就不是正确的大写用法。如果第一个字母是大写字母,就判断从第二个字母开始到单词结尾的所有字母是否都是小写字母或者都是大写字母,如果都是小写字母或者都是大写字母,则是正确用法,否则不是正确用法。代码如下:class Solution {public: bool detectCapitalUse(string word) { .

2020-11-14 10:57:56 92

原创 LeetCode519. 随机翻转矩阵

因为n_rows和n_cols最大能到104,所以不能开二维数组,因为那样空间复杂度回到108。题目说了调用flip和reset的次数加起来不会超过1000次,所以矩阵是比较稀疏的,我们只需要记录所有1的位置即可。我们可以用一个哈希表记录所有1的位置。为了方便,我们把二维的位置映射到一个int变量,哈希表中只记录这个int变量,比如,如果位置是第r行第c列,那么我们得到:pos = r * cols + c,其中cols是二维矩阵的列数(即n_cols), pos是将{r, c}映射到一维空间的下标.

2020-11-12 10:24:07 159 5

原创 LeetCode518. 零钱兑换 II

用dp[i]表示当面值为i的时候,不同的方案个数。目标是求出凑出amount的方案个数,也就是dp[amount]。对于每个coins[i],可以得到当金额j为coins[i] ~ amount的方案数dp[j] += d[j - coins[i],也就是金额j可以由金额j - coins[i]加一枚coins[i]硬币得到,所以凑出j的所有方案里一定包含有凑出j - coins[i]的方案,在这个方案的基础上加上一枚coins[i]就得到金额j了。因此我们只需要枚举所有的coins,对于每个coi.

2020-11-12 10:08:25 54

原创 LeetCode517. 超级洗衣机

首先,我们可以把所有洗衣机内的衣服数量累加求和,得到总的衣物的数量sum,假设洗衣机的数量为n,如果sum % n不为0,则无解,因为无法让所有洗衣机的数量相同。如果sum % n为0,我们求出sum / n的结果avg,也就是最终当所有洗衣机衣服数量相同时每台洗衣机的衣服数量。题目要我们求让所有洗衣机的衣服数量相等的最小操作步数。由于多台洗衣机可以并行地同时进行运送,所以必存在一台洗衣机,这台洗衣机运送的衣服数量就是答案(最小操作步数)。也就是说,这台洗衣机运送的衣服数量最多,因为是并行的,所以它.

2020-11-12 09:52:41 93

原创 LeetCode516. 最长回文子序列

经典动态规划问题。用dp[i][j]表示字符串s的以i开头,以j结尾的子串的最大回文子序列的长度。我们要求的s的最长回文子序列的长度就是dp[0][n - 1]。考虑一下数组的初始化,对于所有的i(0 <= i < n),都有dp[i][i] = 1,表示单个字母可以组成一个长度为1的回文子序列。然后要进行递推和状态转移,我们枚举子串的长度len从2到n,子串的起点i从0到n - len + 1。n - len + 1是为了让当前子串的结尾不超过s的长度。这样我们得到当前子串的起点i,和.

2020-11-12 09:27:43 130

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除