(提前声明:这边的操作系统为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的基本属性查看,我们经常用到的几个函数为
#访问形状(这个函数可以让你了解到这个tensor是啥形状的)
print(x.shape)
#tensor‘s size (the num of elements)
print(x.numel())
一个检查形状(维度和每一个维度的大小),一个可以检查元素数目,当然其他的api还有很多很多,按照自己的需求获取就可以了
然后是对与tensor的运算,其实对与普通的运算符:+-×/% ** == >........等等等,tensor奉行的原则是按照每一个元素对应进行计算。
如果两个tensor的shape和size不一致,底层会使用boardcast方案,将两个tensor通过复制某些维度上的数据,实现计算。
但是对于一些特别的要求,我们要使用函数进行计算
比如最常见的,tensor点乘就是我们在线性代数中常用的一种方式
#点乘
torch.dot(x, y)
#矩阵的乘法
torch.mm(x, y)
(这个好像同样存在广播机制,但是最好不要这样干。。。。你都用上向量了)
在比如对与某个tensor,我们可能刚开始创建的时候忘记shape了,我们就可以重新用reshap函数重新设置一遍形状
#amend the tensor (to more or less deminsions)
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的数量。比如这里我们举例一个降低维度的案例:
x = torch.arange(4, dtype=torch.float32)
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的底层运算中,施行的机制是先计算,然后再指向,这样就造成了一个很严重的影响
x=。。。。
y=。。。。。
y=x+y
在这个阶段中y的指向地址会发生变化,而不是在y的原本地址上修改
解决方案有两种:
第一种是是用切片语法进行赋值
Z = np.zeros_like(Y)
Z[:] = X + Y
这样子,Z的地址是不会发生改变的,但是终究还是有点麻烦
Y+=X
这种简单粗暴的做法反而更加有效果好吧
2.关于数据处理
数据在进行一些操作的时候,最要做的是就是一一个规定的形式进行我们需要的操作,但是我们采集到的原始数据集合并不是我们的函数能使用的东西,所以我们就要从csv等等来源中获取数据,然后使用
(1)从csv中获取数据
这里创建了一个csv文件,并且手动添加一些数据(NA代表这里没有数据的意思)
#创建一个数据集合文件
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
(2)我们通过函数接受文件
#获取到数据集合文件
data = pd.read_csv(data_file)
(3)数据填充
#为NA填充该列的平均值(如果不是数字就两说)
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean()) #填充数值
#将数值为有限离散数值的列拆分开
inputs = pd.get_dummies(inputs, dummy_na=True) #对与discrete来说,使用类似热编码的技术来进行处理
print(inputs)
(4)最后转化为tensor的形式
#转化为张量的形式
x = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
#其实这样的数据就可以拿去训练了(不过你连模型都没有)
3.一些可能会用得到的数学知识
因为毕竟我这三门课当是考得还是挺好的,但是忘了很多,这里只补充一些可能不是很接触到的情况
(1)微积分部分
微积分部分需要补充的概念其实就是梯度,这个东西我们在学习函数开始,我们就知道这个东西了,没错,二维函数图像中的倾率就是一种梯度的运算结果。
梯度本身是一个向量,代表着图像可视化以后,图像某一点上起伏的数值
梯度可以理解为函数的斜率或者在三维图上表示的下降或升高方向。
在数学中,梯度表示函数在某一点上的变化率或斜率。对于多元函数,梯度是一个向量,其中每个分量表示函数在相应变量方向上的偏导数。梯度的方向指示了函数在给定点上最陡峭的下降或升高方向。
在机器学习和优化算法中,梯度在训练模型和调整参数时起着重要的作用。通过计算损失函数对模型参数的梯度,可以确定参数的更新方向,使得损失函数最小化或最大化。
在三维图像中,可以将梯度看作是函数曲面上某一点处的切平面的法向量。梯度的方向指示了在该点上曲面上升最快或下降最快的方向。
(2)线性代数部分:
在线性代数的部分,只要补充一个范数的概念,不同的范数有不同的计算方式
这里举出一个例子,一个向量的二范数,其实就是模的长度
(3)概率论部分:
等待补充,我感觉这部分就是代码需要看看文档