• [deeplearning]深度学习框架torch的概念以及数学内容


    (提前声明:这边的操作系统为ubuntn22.04,至于window上如何进行安装和导入按这边不是很理解)

    (另外代码样例基本不使用notebook,paddle等等在线工具,而是使用本机安装好的python环境,和pytorch框架)

    pytorch的安装这里也不太多阐述了,其实就是一个函数库罢了,另外一些不同的数学库,自己按需寻找就好了捏。其实具体的使用后面会与很多,这里只简单介绍一些数学相关的知识捏

    1.关于代码部分

    其实关于代码,这里其实更多的讲一些关于张量tensor的操作

    当然在进行pytorch以及相关的操作之前,我们需要做的一件事情就是激活d2l环境

    (conda安装详见文章最开始的一个链接)

     conda activate d2l

    (1)tensor

    在pytorch和tf中,用来表示数据基本就是是用tensor这种东西,中文称之为“张量”。

    tensor很类似数组的封装对象,但是tensor本质上可以理解为一个多维度的数据存储容器

    其中,如果我们想要创建一个tensor,则大概是这样的

    x = torch.arange(12)

    这样会自动创建出一个一个维度的向量,尺寸为12的tensor,其中数据是从0开始,一直排列到11,如果你用打印输出的方式,你能见到这个东西

    (其实应该是底层修改了tostring之类的方法。。。。)

    当然除此之外,我们可以直接指定数据和形式

    torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
    

    这样最终的输出结果为

    这就是我们需要的格式了

    以及,如果我们想要创建更多维度的时候,仍然是可以是用这种方法

    x=torch.arange(3,3,3)

    这个最中的创造结果我就先不打出来了,反正就是一个多维度的情况,3,3,3的一个立方体

    总的来说tensor是这两种主流框架存储数据最基本的形式之一,获取数据要转化成这样子,训练的数据需要这个样子,就连最后的输出也是这个东西。。。

    (2)tensor的基本操作

    对与tensor的基本操作我想简单的分为两种,对与对与tensor本身的修改和查看,以及对与彼此之间的运算情况。

    首先是对与tensor的基本属性查看,我们经常用到的几个函数为

    1. #访问形状(这个函数可以让你了解到这个tensor是啥形状的)
    2. print(x.shape)
    3. #tensor‘s size (the num of elements)
    4. print(x.numel())

    一个检查形状(维度和每一个维度的大小),一个可以检查元素数目,当然其他的api还有很多很多,按照自己的需求获取就可以了

    然后是对与tensor的运算,其实对与普通的运算符:+-×/% ** == >........等等等,tensor奉行的原则是按照每一个元素对应进行计算。

    如果两个tensor的shape和size不一致,底层会使用boardcast方案,将两个tensor通过复制某些维度上的数据,实现计算。

    但是对于一些特别的要求,我们要使用函数进行计算

    比如最常见的,tensor点乘就是我们在线性代数中常用的一种方式

    1. #点乘
    2. torch.dot(x, y)
    3. #矩阵的乘法
    4. torch.mm(x, y)

    (这个好像同样存在广播机制,但是最好不要这样干。。。。你都用上向量了)

    在比如对与某个tensor,我们可能刚开始创建的时候忘记shape了,我们就可以重新用reshap函数重新设置一遍形状

    1. #amend the tensor (to more or less deminsions)
    2. X = x.reshape(3, 4)

    这样形状就会被我设置为一个三行四列的tensor了,数据会按照顺序重新进行排列。

    其实对与tensor来说能调用的函数和功能非常多,按照需求进行更改吧

    (3)维度,升维,降维,拼接

    首先我们必须要引入tensor dimension这个东西,一般来说,我们生活中的最高维度是三维,但是实际在数学计算的过程中,dim不一定局限于3。

    我们举个实际应用中的例子:在构建tensor的时候,比如我们也许会构建一个2,3,4的东西

    则第一个维度,编号为0(和数组一样的索引开始),尺寸为2

    第二个维度,编号为1,尺寸为3

    第三个维度,编号为2,尺寸为4

    在目前这个上下文语境中,我们可以人为0是行展开的方向,1是列展开的方向。。。。

    这就是维度的概念和现实情况的匹配

    至于升高和降低维度,其实就是在修改axis的数量。比如这里我们举例一个降低维度的案例:

    1. x = torch.arange(4, dtype=torch.float32)
    2. x, x.sum()

    整体求和,算是一种比较极端的降维方法之一,当然也可以沿着某个方向进行求和,降低维度

    A_sum_axis0 = A.sum(0)
    

    沿着0方向进行降低维度,在一般的矩阵中,这个代码实现的就是按照行展开的方向进行求和

    升高维度其实一般都是reshape。。。。毕竟没人喜欢闲着没事给自己填堵

    其实在这里我还想要介绍一个api,对与tensor进行某个方向的拼接

    tensor.cat(x,y,dim=0)

    这个是让两个矩阵or向量按照地一个维度的方向进行和并操作的方法

    其实这些函数在本质上都不难,其实重点就是关于dim/axis的理解问题

    (4)切片,索引

    对有数组来说,我们通过索引可以很轻松的访问某个元素,而对与tensor来说也是一样的,我们按照维度的顺序,确定某个数据的做表,我们可以修改这些数据

    加入我们现在存在这样的一个数据

    tensor([[2, 1, 4, 3],
            [1, 2, 3, 4],
            [4, 3, 2, 1]])

    很显然这个矩阵的形状应该是3,4 ,其中比如说我们想要读取第二行第二列的数据,则为

    print( x[1,1] ),输出结果为2

    其实这个和数组没有人和去别,那么我们为什么还要作出一个区分呢,因为切片

    切片这个东西在不同的语言里面都不一样,在go中就是数组的意思

    但在这里,切片是一种语法,用来在某个维度上划分范围

    语法为a:b,意思是在这个维度切割出a到b-1这段范围的内容,

    来吧,我们据个例子

    X=x[:,0:2,:]

    这个意思是,第一个维度保留,第二个维度保留0到1的位置,第三个维度全部保留

    (由于上面的东西不太一样,所以这里我们只看前面两个维度)

    所以结果就是

    tensor([[2, 1],
                 [1, 2],
                 [4, 3]])

     差不多这个样子,简单来说就是用来划分范围用来划分维度,这就是在pytorch中切片的用法

    (5)内存的重新分配问题

    其实在其他语言中,我们通过改变指向修改地址的方式很常见,因为毕竟存在指针这个东西,而且以地址作为根本机制存在

    但是在pytorch的底层运算中,施行的机制是先计算,然后再指向,这样就造成了一个很严重的影响

    1. x=。。。。
    2. y=。。。。。
    3. y=x+y

    在这个阶段中y的指向地址会发生变化,而不是在y的原本地址上修改

    解决方案有两种:

    第一种是是用切片语法进行赋值

    1. Z = np.zeros_like(Y)
    2. Z[:] = X + Y

    这样子,Z的地址是不会发生改变的,但是终究还是有点麻烦

    Y+=X

    这种简单粗暴的做法反而更加有效果好吧

    2.关于数据处理

    数据在进行一些操作的时候,最要做的是就是一一个规定的形式进行我们需要的操作,但是我们采集到的原始数据集合并不是我们的函数能使用的东西,所以我们就要从csv等等来源中获取数据,然后使用

    (1)从csv中获取数据

    这里创建了一个csv文件,并且手动添加一些数据(NA代表这里没有数据的意思)

    1. #创建一个数据集合文件
    2. os.makedirs(os.path.join('..', 'data'), exist_ok=True)
    3. data_file = os.path.join('..', 'data', 'house_tiny.csv')
    4. with open(data_file, 'w') as f:
    5. f.write('NumRooms,Alley,Price\n') # 列名
    6. f.write('NA,Pave,127500\n') # 每行表示一个数据样本
    7. f.write('2,NA,106000\n')
    8. f.write('4,NA,178100\n')
    9. f.write('NA,NA,140000\n')

    (2)我们通过函数接受文件

    1. #获取到数据集合文件
    2. data = pd.read_csv(data_file)

    (3)数据填充

    1. #为NA填充该列的平均值(如果不是数字就两说)
    2. inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
    3. inputs = inputs.fillna(inputs.mean()) #填充数值
    4. #将数值为有限离散数值的列拆分开
    5. inputs = pd.get_dummies(inputs, dummy_na=True) #对与discrete来说,使用类似热编码的技术来进行处理
    6. print(inputs)

    (4)最后转化为tensor的形式

    1. #转化为张量的形式
    2. x = torch.tensor(inputs.to_numpy(dtype=float))
    3. y = torch.tensor(outputs.to_numpy(dtype=float))
    4. #其实这样的数据就可以拿去训练了(不过你连模型都没有)

    3.一些可能会用得到的数学知识

    因为毕竟我这三门课当是考得还是挺好的,但是忘了很多,这里只补充一些可能不是很接触到的情况

    (1)微积分部分

    微积分部分需要补充的概念其实就是梯度,这个东西我们在学习函数开始,我们就知道这个东西了,没错,二维函数图像中的倾率就是一种梯度的运算结果。

    梯度本身是一个向量,代表着图像可视化以后,图像某一点上起伏的数值

    梯度可以理解为函数的斜率或者在三维图上表示的下降或升高方向。

    在数学中,梯度表示函数在某一点上的变化率或斜率。对于多元函数,梯度是一个向量,其中每个分量表示函数在相应变量方向上的偏导数。梯度的方向指示了函数在给定点上最陡峭的下降或升高方向。

    在机器学习和优化算法中,梯度在训练模型和调整参数时起着重要的作用。通过计算损失函数对模型参数的梯度,可以确定参数的更新方向,使得损失函数最小化或最大化。

    在三维图像中,可以将梯度看作是函数曲面上某一点处的切平面的法向量。梯度的方向指示了在该点上曲面上升最快或下降最快的方向。

    (2)线性代数部分:

    在线性代数的部分,只要补充一个范数的概念,不同的范数有不同的计算方式

    这里举出一个例子,一个向量的二范数,其实就是模的长度

    (3)概率论部分:

    等待补充,我感觉这部分就是代码需要看看文档

  • 相关阅读:
    c语言进阶篇:指针(五)
    yolov1模型
    Android进阶之路 - 盈利、亏损金额格式化
    内外通、效益增 | 数商云•瓴犀产品3.0开启全方位精准精细化协同模式
    C++设计模式
    MYSQL:B树和B+树存储索引比较
    python如何读写excel
    JavaScript函数进阶:函数的定义和调用
    这是啥SQL,室友看了人傻了
    软件安装教程1——Neo4j下载与安装
  • 原文地址:https://blog.csdn.net/weixin_62697030/article/details/132802996