线性回归——动手学习深度学习pytorch版
本系列是基于亚马逊李沐老师的教材《动手学习深度学习》,以及 李沐老师对应的视频教程内容展开。但是李沐老师课程中使用的深度学习框架是MXNet,其实选择什么框架并不是重点,重点应该是其中的内容。课程既然叫动手学习深度学习,那当然要动手操作。用MXNet重复一遍教材内容并没有很好的学习效果,另外,我本身还是更喜欢使用pytorch框架,因此,希望将该教材的内容用pytorch实现一遍,并学习相关的知识内容。希望能给其他喜欢pytorch的读者一些帮助。 代码开源供学习使用,如引用请注明出处,谢谢。
1. 线性回归——从零开始
由于线性回归已经反复介绍了许多遍了,因此其理论在此不再赘述,主要还是借助这个最基础最简单的算法来学习一下pytorch框架本身的搭建,因为其实其他高深的东西的套路和这个最简单的套路是一样的。
1.1 用随机数生成并保存数据
首先,生成线性回归需要使用的训练集数据,并保存为h5py文件,这是一个常用于数据存储的文件,其对应使用的API库名称为"h5py"。生成数据代码如下:
def generator_data(n,m):
"""
生成数据,样本数为n,维度为m
:param n: 样本个数
:param m: 数据维度
:return: data_X,训练集;data_Y,训练集标签;coi 理想的线性回归系数
"""
data_X = torch.randn((n, m)) # torch.randn((n,m))是生成n行m列的服从随机正态分布的随机数
coi = torch.rand((m, 1)) * 3 # torch.rand((m,1))*3 是生成m行1列的系数向量,系数的随机数范围是从(0,3),因为后面乘了一个3
data_Y = torch.mm(data_X, coi)+3 # torch.mm 是pytorch中对tensor张量的叉乘
return data_X, data_Y, coi
def save_data(data_X, data_Y, coi):
"""
保存数据为hdf5文件和csv文件
:param data_X: 训练集
:param data_Y: 标签
:param coi: 数据对应的真实线性回归系数
:return: NULL
"""
# h5py文件储存数据的结构和python中的字典类型很像,具有一个键名,及键对应的数据
h5file = h5py.File("data.h5", 'w') # 新建一个data.h5的数据集文件,并置为写入状态;注意要import h5py
h5file.create_dataset("X", data=data_X) # 在h5py数据文件中创建一个子集,名称为"X",内含数据为data_X,以下同理
h5file.create_dataset("Y", data=data_Y)
h5file.create_dataset("coi", data=coi)
h5file.close() # 写入完毕后要关闭h5py文件,和普通的文件读写操作很类似
# 用pandas再保存一遍数据,熟悉一下另一种常见的数据读取库,使用前注意要import pandas as pd
csvfile = pd.DataFrame(data_X.numpy()) # h5py文件的查看需要特定的查看软件,因此再保存成一份.csv文件方便查看
csvfile.to_csv("data_X.csv") # 把数据保存为data_X.csv文件,以下同理
csvfile = pd.DataFrame(data_Y.numpy())
csvfile.to_csv("data_Y.csv")
csvfile = pd.DataFrame(coi.numpy())
csvfile.to_csv("coi.csv")
其中,生成数据使用了pytorch自带的随机数函数。其对应说明在代码注释中都比较详细了。
1.2 创建训练数据集的迭代器
这一步本身和pytorch关系不大,只是要注意,如果要使用pytorch库进行深度学习,所有数据都最好转化为torch.tensor的数据类型,因为这是pytorch中最基本的数据类型。关于tensor类型,以下有几点常用的成员函数(注意,以下的tensor都需要具体的tensor变量名称替换):
- tensor.size():返回当前张量的维数尺寸;
- tensor.numpy():将tensor转换为numpy的ndarray类型;
- tensor.reshape(self, shape):重新定义tensor的尺寸;
- tensor.dype:查看当前tensor的数据类型;
- tensor.zero_:将张量清零,这里主要是要介绍以下这个下划线。pytorch中的所有包含下划线_的成员函数,意思是会将原tensor内的数据进行覆盖。也就是执行完tensor.zero_后,原来的tensor内的数据就被全部清零了,而不是生成一个新的复制而原数据不改变。
- tensor.cuda():将张量送入GPU中进行计算,注意,GPU中的变量和CPU中的变量是不能进行计算的。如果要将张量从GPU中取出,则对应要使用tensor.detach()函数。
创建数据集的迭代器代码如下:
def dataset(batchsize):
h5file = h5py.File("data.h5",'r') # 读取data.h5文件内的数据
X = torch.tensor(h5file['X']) # 将h5file文件数据中名为'X'的子集取出,以下同理
Y = torch.tensor(h5file['Y'])
coi = torch.tensor(h5file['coi'])
print("real coi:",coi)
m = Y.size()[0] # 当前样本集的数量为m
id = list(range(m)) # 构造一个[0,1,2,...,m-1]的列表,列表内的数值表示样本序号
random.shuffle(id) # 将上述构造的列表内元素打乱,也就相当于将数据集样本的顺序打乱
for i in range(m//batchsize): #
l = i*batchsize # 当前batchsize的样本集起始序号
r = min((i+1)*batchsize,m) # 当前batchsize的样本集终止序号,加min函数是避免最后一个batchsize数量不够而越界
# yield返回当前batchsize的数据,下次再进入该函数的时候,从此处继续往下执行,也就进入了下一个循环
yield X[id[l:r],:],Y[id[l:r]]
1.3 构造最简单的线性层网络
最简单的深度学习网络其实就是只有输入层和输出层的线性层网络,网络的权值为 w w w,网络的输出为 y = w x +