- 博客(53)
- 收藏
- 关注
原创 cs336系列(1)
第一步先克隆到本地如果你的环境中没有下载uv,先安装一下然后激活下载需要的库和包,如果下载速度慢可以设置镜像源uv run。
2025-08-23 12:39:00
985
原创 dl学习笔记(13):从强化学习到PPO
一、我们为什么要有强化学习一、我们为什么要有强化学习为了更好的有一个宏观感受,下图是DeepMind在2024发表的文章中对AI做出了不同层次的定义可以看到左边分为了5个不同层次的AI,中间是对于细分的下游任务AI的能力展现,右边则是通用任务的AGI实现。我们可以看到中间的细分任务每个阶段都有AI能完成了,甚至最下面的超过人类的也已经有好几个实现了,而右边的通用还停留在第三个阶段。所以现在的主流任务是在右边往AGI的更深入的发展,而发展AGI具体需要哪些能力呢?
2025-04-26 20:20:56
921
原创 dl学习笔记(12):一文带你彻底搞懂ResNet
通过观察架构图我们会发现,所有的out都等于middle的4倍,而in除了conv1和conv2之间的连接这一种情况下是两倍,其他所有的情况in都是middle的4倍,所以这里进行单独的判断,其他的内容都和前面的一样。左边是传统的卷积层,右边是残差块的设计,虽然看起来没什么不同,只是加了右边一条通道直接原封不动加到f(x)上,但就是这个加法让网络能够做到至少不比原来差,因为我大不了中间的卷积层权重全都设置成0,那么最后的输出还是x没有变化。因为更深的网络有更强的特征表示能力,可以学习到更复杂的函数。
2025-02-16 18:26:38
984
原创 dl学习笔记(11):VGG,NIN,GooleNet经典架构pytorch实现
我们还是拿VGG鞭尸举例子,最让人老生常谈的就是VGG的参数量太多,已经到达一亿多的级别,各层之间的连接过于稠密,计算量太大很容易过拟合。其他部分没什么太大区别,按照架构图上的参数填就可以了。从参数量可以看出NIN并不算一个性能很优秀的架构,但是NIN最大的优点就是让人们看到了1*1卷积核和用卷积层去代替线性层的可能性,为后面的GoogleNet提供了灵感来源。所以为了解决稀疏性与稠密的矛盾,谷歌给出的思路就是既要又要,顾名思义就是既要结构稀疏,又要计算稠密:用普通卷积层,池化层这些稠密元素组成。
2025-02-15 15:14:48
1193
原创 dl学习笔记(10):LeNet5和AlexNet的pytorch简单实现
LeNet起源于上世纪九十年代,由Yann LeCun等人发表在论文《Gradient-Based Learning Applied to Document Recognition》上,后面的AlexNet、ResNet等都是在其基础上发展而来的,也正是LeNet5定下了再卷积池化的重复后最后全连接层的基调。下面是一个模型流程示意图:由于这个架构还比较简单所以没有多少需要具体讲解的地方,唯一需要注意的是在全连接层前面,需要进行矩阵乘法,所以要对结果进行维度上的调整也就用到了view方法。
2025-02-13 19:06:24
1070
原创 dl学习笔记(9):pytorch数据处理的完整流程
当我们查看LBC_train会发现它只有dataset和indices两个属性,同样的,是一个映射式的对象,其中dataset属性用于查看原数据集对象,indices属性用于查看切分后数据集的每一条数据的index。当我们可以自定义数据生成的规律,我们将数据喂给模型就可以判断模型是否掌握了我们定义的规律,从而判断模型的性能,这也是从炼丹师进步到化学家的必经之路。我们会发现一个有意思的地方,这里的dataset属性返回的其实是LBC_train,也就是说这里的dataset属性存在一种类似于回溯的还原机制。
2025-02-07 18:05:26
513
原创 dl学习笔记(8):fashion-mnist
图片有点长,如果我们仔细看的话,前面全是图片像素点的张量,最后有一个不起眼的9就是这张图片的标签,所以我们可以通过[0][0]来索引张量,下面我们来展示出来这张图片。由于前面已经看过标签和样本已经打包在一起了,所以这里我们不需要使用之前学的dataset的打包功能了,只需要dataloader的分批次。这里的size含义就是有六万张图片,每张都是28*28的像素,需要注意的是这里省略了颜色通道,由于该数据集是灰度图片所以这里默认是1。1)root指定数据集存储的本地路径,如果路径不存在,且。
2025-02-05 15:54:50
822
原创 dl学习笔记:(7)完整神经网络流程
在我们的前面的代码中,都是将所有的特征矩阵x传入,但是在实际的深度学习工作中,我们所面临的数据量都是大量的高维数据,如果每次进行梯度下降都要对所有的矩阵进行求导,那么将会非常耗费计算资源。极端情况下,当我们每次随机选取的批量中只有一个样本时,梯度下降的迭代轨迹就会变得异常不稳定。我们现在就可以看到当函数进行层层嵌套之后,式子就会变得非常复杂,是很不利于我们进行求导的操作的,并且这还只是一个双层的简单神经网络,可以想象当我们后面遇到更加复杂的网络结构的时候,式子就会变得超出能理解和求导的范围了。
2025-01-21 21:23:21
1026
1
原创 dl 学习笔记:(6)二分类交叉熵
在我们弄好正向传播之后,我们需要一个函数来衡量结果的好坏程度,一般的思路是用准确率来作为结果的衡量,但是由于这不是一个可导的函数,并且只关注于结果并不关注对结果的信心程度。所以这里我们在二分类的时候,使用的损失函数是大名鼎鼎的交叉熵损失函数。想要完整地推导出来交叉熵的函数需要从极大似然估计开始,如果没有学过概率论这方面的可以补一下。激活的模型输出(即模型的输出已经是概率值,范围在 [0, 1] 之间)。,我们希望选择一个模型参数 w,使得在此模型下观测到的标签。计算,因此在使用时,模型的输出不需要经过。
2025-01-19 19:28:06
412
原创 dl学习笔记:(5)深度神经网络的正向传播
我们会发现,这里面的每一层权重的形状都是下一层的神经元个数和上一层神经元个数,是反过来的。例如这里的第一层,输入是20个特征第一层有13个神经元,这里却是(13,20)。当你看到方法定义时,明确知道。首先定义__init__,由于开始的传入和最后的输出和模型没什么关系,取决于你的数据和任务,所以这里作为参数传入in_features和out_features。由于是3分类任务,所以这里的y取到的是0,1,2,这里的函数是左闭右开,所以参数是0和3。4.输出层:(3,8)*(8,500) = (3,500)
2025-01-19 15:03:00
810
原创 dl学习笔记:(4)简单神经网络
这里我们需要定义成浮点数的原因,是因为torch中有很多函数不接受两个类型不同的参数传入,例如这里的mv函数,如果我们省略浮点的定义,就会出现报错如下:这种静态的编程可以说既是pytorch的优点也是缺点,优点在于如果省略了对传入参数的检查处理,就会在运行速度上快很多,尤其是传入数据量大的时候,对每一个数据进行检查是一个很慢的过程。
2025-01-18 16:40:04
1190
原创 从零深度学习:(3)梯度下降
还是拿上节的例子:当我们这时想要知道x的梯度是多少时,我们是无法得知的,此时输出为空。这是因为我们得需要进行一次反向传播,我们需要知道每个变量之间的函数关系式等信息,进而得到叶节点的导数值。当我从最后的z节点进行反向传播之后,得到xyz三个变量之间的关系之后,就可以输出x的梯度值,这里也可以从高数的求导法则来检验一下:,求导得到8x,x=1带入得到8。
2025-01-17 16:27:25
1178
原创 从零深度学习:(2)最小二乘法
今天我们从比较简单的线性回归开始讲起,还是一样我们先导入包我们利用刚刚导入的画图的包将这两个点画出来,将1和3先索引出来作为横坐标,2和4作为纵坐标传入给plot,'o'表示画的是点而不是线现在我们希望找到一条直线去穿过拟合这两个点,也就是所谓的线性回归,不妨设方程如下:我们在初中就学过两个点能够带入两个方程进行求解,将a和b通过解方程的形式求解出来。除了这种矩阵求解以外,我们还可以转化为一个优化问题来进行求解。其中优化问题最关键的两个就是优化指标和优化目标函数。
2025-01-16 20:14:05
1043
原创 从零开始深度学习:(1)张量的常用操作
孩子们,懒大王回来了!正如标题所说,今天我们继续开始新的篇章,我们要开始高强度学习深度学习的相关内容,这个专栏内容较多、全是干货,我们还会在合适的地方进行拓展一些额外的语法或者别的相关知识,并且保证会持续更新,大家坐稳了这就出发!由于不方便插入jupyter代码,所以可能会包含很多图片。首先,预先善其事必先利其器,所以我们第一章从张量开始讲起。
2025-01-15 17:24:00
1175
2
原创 力扣力扣力:860柠檬水找零
所以我们可以看到决定一个顾客是否能成功找零的关键原因就是我们是否有足够多的5块。所以如果我们遇到情况3也就是顾客给了20块的时候,我们应该优先考虑将10块钱先花出去,尽可能的保留多的5块,选择第一种方案。否则就可能遇到找不过来的情况,例如考虑以下两个顾客先后来买,第一个给了20,第二个给了10块。如果我们选择了给三张5块那么就无法找零第二个顾客了。这也是贪心策略在这里的体现,在我们完整的思考过后,其实一般贪心的代码都很好写。需要注意的是,我们一开始是没有任何钱的,也就是说我们需要拿着顾客的钱去找零。
2024-11-21 17:26:38
566
原创 算法导论第四章:分治策略(下)
说是代入法,实际上就是一个猜解加上数学归纳法的证明,所以过程分为两步:1.猜测解的形式2.2.用数学归纳法求出解中的常数,并证明解是正确的例如:首先我们进行数学归纳法中的假设:然后将假设带入原来的递归式中:最后检查是否满足猜测的解:为了让大家熟悉这个流程,这里我们再举一个类似的例子:步骤1:递归式和猜测解步骤2:数学归纳假设步骤3:将假设带入递归式步骤4:整理并验证猜测解然而猜测正确的解是需要经验和创造力的,所以当你见到一个和已知的很像的递归式时,你就可以大胆假设然后小心验证了。
2024-11-21 15:03:11
773
1
原创 力扣力扣力:53.最大子数组和
由于原来的dp[0]现在往后挪动一位之后变成了dp[1],所以根据上面的状态转移方程可以得到:dp[1]=max(dp[0]+nums[0],nums[0]),而dp[1]位置相当于只有一个元素,所以最大和自然就是num[0],所以这里为了保证dp[1]等于num[0],这里dp[0]填上0就可以了。这里需要注意的是返回的不一定是dp表最后一个元素,因为最大字数组和不一定出现在最后,就像题目给出的例子一样,是可能出现在中间的,所以返回的应该是dp表里面的最大值。的初始值是 0 或其他较小的值,那么在所有。
2024-11-14 11:22:07
403
原创 算法导论第三章:函数的增长
这一章没有什么新的算法知识,更多的是一些数学上的知识回顾,本章给出了几种标准方法来简化算法的渐进分析,定义了几种渐进记号,我们可以粗略的直观的如下面公式理解: (g(n)) = {f(n):存在正常量、和,使得对所有n,有g(n) f(n) g(n)}类似于高等数学在极限中的定义式,若存在正常量和,使得对于足够大的n,函数f(n)能“夹在”g(n)与g(n)之间,则f(n)属于集合 (g(n))。因为 (g(n))是一个集合,所以可以记“f(n)∈(g(n))”,以指出
2024-11-12 12:20:45
648
原创 算法导论第二章
从今天开始会陆续更新关于算法导论的啃书相关文章,先从前往后而且比较常用的章节开始讲起,所以可能会有部分不怎么用的着的章节会跳过。由于第一章没讲什么具体内容,所以选择跳过从第二章开始讲起。
2024-11-11 21:51:29
726
原创 力扣力扣力:动态规划入门(1)
相信大家在第一次学动态规划的时候都是一脸懵逼的,在看了很多题解之后,陷入到了空的“最优子结构”等的大词上,依旧看不懂动态规划到底在干什么。今天我们也是老样子再一次的从零开始学习与讲解,俺也是从零开始学动态规划,所以学多少写多少,和大家一起领悟动态规划最自然的想法。
2024-11-10 15:44:40
1246
原创 从零实现数据结构:二叉搜索树
二叉搜索树概念二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:1. 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值2. 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值3. 它的左右子树也分别为二叉搜索树。
2024-10-31 18:11:04
849
1
原创 从零实现数据结构:一文搞定所有排序!(下集)
在有了前面冒泡选择插入希尔排序之后,人们就在想能不能再快一点,我们知道排序算法说人话就是把大的往后放小的往前放,问题就在于如何更快的把大的挪到数组队尾小的挪到数组前面。这里我们先总结一下上集前面几种排序算法,冒泡排序一轮单趟排序相当于只完成了把一个最大的挪到后面;选择排序可以做到一轮单趟把一个最小的往前放一个最大的往后放;插入排序是从队头开始重新建立一个有序数组,一轮单趟完成了插入一个元素;
2024-10-27 17:18:08
979
1
原创 从零实现数据结构:一文搞懂所有排序算法!(上集)
这样我们就完成了希尔排序的初步框架的构想,接下来就是一些实现细节的问题。总结:由此我们可以看到向下调整的复杂度更小,我们究其本质去看,其实主要归功于如果是满二叉树的话,最后一层的结点就占据了整个二叉树的一半,所以向下和向上的区别就在这里体现了,如果是向下调整只需要挪动一层数据,而向上要一直挪动到第一层,差距就体现出来了。第一层控制了gap组,第二层控制每组的排序,里面的while控制每个元素的插入,至此预排序已经完成了,接下来我们想想如何优化一下代码逻辑,三层循环有点多了能不能两层完成,实际上是可以的。
2024-10-25 19:03:04
800
原创 力扣力扣力:一文搞定前序遍历的所有方法!
但是我们注意这里的判空和正常非递归的题目判空有本质的区别,这里的判空实际上也是控制递归深度的判断条件,只有在遍历到空结点后才会停止递归,这也和上面提到的深度优先的思想一致。下面我举一个具体的例子来说明递归的过程是如何进行的,实际上递归的实现方式本质上是使用了系统的调用栈来管理函数调用,因此前序遍历和 DFS 都会用到栈结构,懂了递归的方式也就懂了栈的非递归遍历,都是相通的。然后将左子节点压入栈。适合浅树:在处理深度较浅的二叉树时,递归方式性能较好,因为它不需要手动管理栈,系统栈管理的开销是最小的。
2024-10-18 18:10:02
1067
原创 力扣力扣力:206. 反转链表
需要注意的是,这里有个常见错误,下面我在写这道题的时候就已经犯了,不能在循环外先定义front,这是因为会存在一种情况只有一个结点,这时我这种写法就已经错了造成空指针问题了。把当前节点的子节点的子节点指向当前节点。给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?这里引用一篇题解的动图来说明递归的实现过程下面是原文链接。1)可以new一个链表来倒着存值。2)在原链表上进行操作。
2024-10-17 19:13:58
927
原创 从零实现数据结构:堆的实现和简单堆排序
同理这里向下调整也是一样,需要注意的是这里的写法,我们先是假设左边的结点是小的,然后再用判断。如果不这样做,则需要将父节点和两个子节点进行比较,这样会造成多余的比较次数。当我们交换完成之后,发现依然不满足小堆的定义,所以很自然的想法是继续与父节点交换,然后向上调整的雏形就已经被我们构想出来了。当我们插入一个新的0的时候,这个时候就已经不满足小堆的定义了,我们需要对堆进行调整。由于小堆要求父节点比所有的子节点都小,所以很自然的想法就是向上和父节点进行交换。事先说明,这里采用的都是小堆。
2024-10-11 19:58:45
278
原创 二叉树的经典性质的简单证明
如图最大结点个数为当二叉树是满二叉树的时候的结点个数,第一层有2^0个,第二层有2^1个,一次类推形成一个等比数列,于是我们借用等比数列求和公式就可得出(2^h)-1。度为1:有1个子结点,比如在某些非叶子结点中,它只连接了一个子结点,因此这个结点与它的子结点之间形成了一条边。度为2:有2个子结点,比如一个结点有左子结点和右子结点,那么它与它的两个子结点之间各有一条边,总共2条边。总的结点数 N=n0+n1+n2,即叶子结点数、度为1的结点数、度为2的结点数之和。度为0:没有子结点,也就是叶子结点。
2024-10-11 15:29:46
553
原创 从零实现数据结构:循环队列的实现
在实现之前我们先搞清楚为什么我们需要循环队列,这是因为如果是以数组的方式来实现队列的话,在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。循环队列的一个好处是我们可以利用这个队列之前用过的空间。下面是具体的一个例子:假设你有一个大小为 5 的队列,初始状态如下如果执行dequeue操作,A此时,虽然A所在的位置已经被清空,队列依然被认为是满的,因为rear在数组的末尾,无法再插入新的元素。
2024-10-10 18:40:18
886
原创 力扣力扣力:用队列实现栈
值得注意的是这里的pop函数的逻辑,如果想要完成删除操作,只需要再将先入队的、除了要删除的元素重新入队一遍,然后删除原队列中的所有元素即可完成。依旧还是拿倒水的例子来举例,这道题的意思是,如果你想抽走水杯中最上面那层水,但是由于队列的特性你不能从下往上抽水,因此你只能把这杯子的底打穿向下流进另一个杯子中,直到原来杯子中只剩下你想抽走的那层水。队列是先进先出的规则,如果这题和上一题用栈实现队列一样,把一个队列中的数据导入另一个队列中,数据的顺序其实并没有变,依旧还是先进先出的顺序。// 返回 False。
2024-10-10 16:21:16
772
原创 力扣力扣力:用栈实现队列
1.用队列实现栈请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):实现MyQueueint pop()int peek()truefalsesizeis empty100pushpoppeekemptypoppeek分析思路:由于这道题目只能从栈顶取得数据,想要用栈实现队列就需要两个栈来实现。因为单独一个栈是后进先出,想要实现先进先出就要将后进先出倒一下。
2024-10-10 15:33:55
1152
原创 力扣力扣力!707设计链表
/ 链表变为 1->2->3。// 现在,链表变为 1->3。这道题和之前已经实现过的链表没有区别所以就不在这里进行过多赘述,详情请看前几篇关于链表的具体实现。的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。以指示链表中的上一个节点。假设链表中的所有节点下标从。等于链表的长度,那么该节点会被追加到链表的末尾。的节点追加到链表中作为链表的最后一个元素。如果下标有效,则删除链表中下标为。是指向下一个节点的指针/引用。如果是双向链表,则还需要属性。的节点插入到链表中下标为。
2024-10-08 21:05:29
465
原创 力扣力扣力!移除链表元素
所以这里首先想到的就是自己定义一个哨兵位头节点,这样就不用陷入到讨论空各种情况,但是随之而来的是增加了空间复杂度。这里大致分为三步走,第一步定义一个dummynode,第二部进行循环判断是否元素相同,第三步删除返回。所以这里需要注意的是,一开始不能用if来判断条件,必须要用while,是为了应对。如果不用头节点的话,就应该讨论删除的是否是头节点的情况。遍历一遍列表,每找到值相等的时候删除节点,返回头节点。2.当本来不为空,但是全部删除完为空,也应该返回空。时,它会删除这个节点,然后把。如果用了if来判断,
2024-10-07 16:56:36
183
原创 从零实现数据结构第三集:带头双向循环链表实现
需要注意的是我们不能再结构体里面使用重命名node,只能使用全称,这是因为编译器在当前上下文中并不知道。是什么类型,重命名宏类似的也会在预编译阶段被替换成全称。今天的函数实现和昨天第二集很相似所以注释少了些许。
2024-10-05 20:07:14
271
原创 Linux下权限的理解
当我们新建一个文件夹时,基础权限码是0666,当我们创建一个目录文件时,基础权限码是0777(这里的0表示八进制)。可是当我们需要和别人共享一个目录下,完成一定的工作时,这个时候我们两个人都同时拥有可写权限,也就是说,我写的代码可以被别人删掉。同时也意味着,在目录下,删除文件不与文件的权限有关,只与该目录的权限有关。由于三个为一组,也就是说至少需要三位二进制来表示该组的权限,所以这里采用一位八进制来代表一组的权限。,则实际创建的出来的文件权限是:原来的初始权限 &(~umask)。
2023-09-06 14:57:37
96
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅