本系列文章为李沐老师《动手学深度学习》Pytorch版实践学习笔记,相关课程教学、书籍、代码均为开源,可通过以下链接参考学习:
跟李沐学AI的个人空间-跟李沐学AI个人主页-哔哩哔哩视频 (bilibili.com)
前言 — 动手学深度学习 2.0.0 documentation (d2l.ai)
安装 — 动手学深度学习 2.0.0 documentation (d2l.ai)
一、数据操作
- N维数组:N维数组是机器学习和神经网络的主要数据结构。其中0维为标量,例如一个类别;1维为向量,例如一个特征向量;2维为矩阵,例如一个样本的特征矩阵;3维例如一张RGB图片(宽×长×RGB通道);4维例如一个RGB图片批量(批量大小patch×宽×长×RGB通道);5维例如一个视频批量(批量大小×宽×高×通道)
- 创建数组需要:①形状;②每个元素的数据类型;③每个元素的值
- 深度学习框架比Numpy的ndarray多一些重要功能:首先,GPU很好地支持加速计算,而NumPy仅支持CPU计算;其次,张量类支持自动微分。 这些功能使得张量类更适合深度学习。
数据操作实现
-  导入torch: import torch
-  张量tensor表示一个数值组成的数组,这个数组可能有多个维度。可以通过张量的 shape属性【注意是属性,不是调用函数】来访问张量的形状。调用numel()函数(number of elements)可以查看张量中元素的总数,永远是标量。 
-  若要改变张量的形状,可以调用 reshape()函数,注意该函数生成的是一个新的张量: 我们不需要通过手动指定每个维度来改变形状。 也就是说,如果我们的目标形状是(高度,宽度), 那么在知道宽度后,高度会被自动计算得出,不必我们自己做除法。 我们也可以通过 -1来调用此自动计算出维度的功能。 即我们可以用x.reshape(-1,4)或x.reshape(3,-1)来取代x.reshape(3,4)。b = a.reshape()是对a的引用,操作b会改变a。
-  可以调用zeors()和ones()函数等生成具有指定元素值的张量:   在 PyTorch 中, torch.zeros(2,3,4)和torch.zeros((2,3,4))实际上是等价的,它们没有区别。两者都是用来创建一个形状为(2, 3, 4)的全零张量(Tensor),即该张量共有 2 层,每层有 3 行,每行有 4 列,总共包含 2 * 3 * 4 个元素,并且所有元素初始值都为零。
-  通过提供包含数值的Python列表或嵌套列表可以为张量中的每个元素赋值,使用 tensor()函数构造向量: 
-  常见的标准运算符(+、-、*、/、**)都可以被升级为按元素运算。 
-  可以使用 cat()函数将多个向量连结在一起,其中dim表示在第几维度进行合并,0为行,1为列,即第几层中括号: 
-  可以通过逻辑运算符构建二元张量,按元素进行比较:  
-  sum()函数对张量中所有元素进行求和,会产生一个只有一个元素的张量:  - 若要按照某一维度进行求和,使用X.sum(axis=…)。如果要保持最终结果的维度数不变,在sum()函数中使用参数keepdims=True,便于相同维度使用广播机制。
- X.cumsum(axis=…)函数为按维度进行累加求和,也就是维度数不变,将累加结果更新到当前计算到的位置: 
 
-  即使形状不同,也可以通过调用广播机制来执行按元素操作:  
-  和列表一样,可以通过指定索引读取或者修改元素。 
-  执行原地操作举例:  对元素进行操作时地址不变,或者使用命令 X += Y;使用X = X + Y地址会改变。X += Y: 这是一个就地操作(in-place operation),意味着它直接修改了张量X的内容而没有创建新的张量。由于张量数据是在同一块内存区域上进行更新,所以其内存地址不会改变。 X = X + Y: 在默认情况下,这个表达式会创建一个新的张量来存储X与Y相加的结果。这是因为Python中的赋值语句实际上是对引用的重新绑定,而不是原地修改对象内容。因此,在执行 X = X + Y时,首先计算X + Y得到一个新张量,然后将变量X指向这个新创建的张量,原来的X所指向的内存区域不再被X引用,从而导致X的内存地址发生了变化。在某些情况下,特别是在使用深度学习框架时,为了优化内存使用并减少数据复制,用户可能会选择使用就地操作以提高性能。不过,需要注意的是,频繁使用就地操作可能会影响梯度计算,因为它们破坏了原始数据,无法回溯到之前的计算状态。因此,在实际应用中,需要根据具体需求权衡是否采用就地操作。 
二、数据预处理
为了能用深度学习来解决现实世界的问题,我们经常从预处理原始数据开始, 而不是从那些准备好的张量格式数据开始。在Python中常用的数据分析工具中,我们通常使用pandas软件包,pandas可以与张量兼容。
(1)读入数据
-  人工创建一个数据集: import osos.makedirs(os.path.join('..', 'data'), exist_ok=True) # 如果在当前文件夹下,只指明data参数即可 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') 
-  使用pandas库的 read_csv()函数读取数据,data数据为DataFrame类型: 
(2)处理缺失值
为了处理缺失的数据,典型的方法包括插值法和删除法,]其中插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。
-  通过位置索引iloc(index location)将data分为inputs和outputs两部分,前两列为输入,最后一列为输出。对于inputs中缺失的数值,使用同一列的平均值代替。  
-  对于inputs中缺失的类别值或者离散值,将”NAN”视为一个类别。由于“巷子类型”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”, pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。 巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。 缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。在 pandas 库中, pd.get_dummies()函数用于将分类变量(通常是字符串类型)转换为虚拟/指示/独热编码形式的数值列。通过这种方式,非数值型类别特征可以被转化为机器学习模型可直接处理的形式。参数 dummy_na=True意味着包括一个额外的列来表示原始数据集中是否存在缺失值(NaN)。如果某个类别的值是 NaN,则会在生成的 dummy 变量中对应的位置上设置为 1,表示该观测值在这个类别上有缺失。 
-  若要删除具有最多缺失值的列,则需要先统计每列缺失值的个数,找出缺失最多的列,并使用 drop()函数删除:missing_counts = data.isnull().sum() # 统计每列缺失值的数量 # missing_counts = data.isnull().sum(axis=1) 对行统计 print(missing_counts) # Series,索引表示列名 most_missing_column = missing_counts.idxmax() # 返回最多的列,.idxmax() 方法用于返回具有最大值(在这个场景下是最大缺失值数量)的索引 print(most_missing_column) data = data.drop(most_missing_column, axis = 1) print(data) 
(3)转换为张量格式
由于inputs和outputs为DataFrame形式,要获取数值内容,需要先转换为numpy数组。

Python默认使用64位浮点数,但是对于深度学习而言比较慢,之后需要转换为32位浮点数。