1.使用pytorch写神经网络的第一步就是先构建一个数据集。
numpy的广播机制
我们使用一个简单的模型y=wx+b来进行理解。我们可以注意到在我们实际的应用当中xy将分别存在很多组,也就是说上面式子当中的y和x是一个向量,但是b实际上应该是一个数字b其实在实际操作中b会被numpy广播成为一个[b,b,b,b,b,…,b]所需维度的列向量。这样就可以顺利加和了。其实是自动扩充成前面矩阵相同大小的矩阵。大约可以参考下面的示意图:
所有的数据集都是一个矩阵的问题
另外我们在使用线性模型的过程当中,我们不是将这个yx想象成一个向量,我们必须将其当成一个矩阵,其是一个3*1的矩阵,如下所示:
这样的认识又有什么不同呢?这就意味着我们在定义数据集的时候需要将其定义为一个矩阵而不是一个向量,具体如下图所示:
2.接下来就是设定一个模型
线性模型
接下来一个问题就是线性模型的问题,我们这里先用最简单的模型来实验一下。
我们分析这个线性模型需要知道什么?其实只要知道这个变换矩阵的行数和列数就行,也就是只要知道输入和输出的维数就行了。
损失函数必须是一个标量,如果是一个向量那么就没法算梯度了。
模型一般是构造成一个类,并且这个类一定是要继承自nn.Module。因为其中很多方法是我们未来需要使用到的。
w转置的来源
我们在使用模型的过程当中,我们一般是认为每一行是一个数据的几个维度的输入让后有多少行就是数据的个数,但是在实际计算的过程中,是要对数据矩阵进行转置的,也就是每一列是数据的维度,然后列是数据的个数。
这样子对于我们正常理解的行是数据输入的维度,列是数据的个数的情况。w其实是后乘,如果变成我们习惯的前乘,那么实际上是一个转置的w。这就是很多书上中写的是w转置的原因。
但是不管是使用哪一个,其实目的是一样的。
下面展示模型定义的代码片
class LinearModule (torch.nn.Module):
def __init__(self):
super(LinearModule,self).__init__()#第一个是类的名称,第二个参数是self这是固定的调用父类的初始函数
self.linear = torch.nn.Linear(1,1)#这里其实就实现了一个权重。这里实际上w和b都一下子实现了
#参数是输入样本的维度、输出样本的维度:这是用来产生一个参数矩阵。第三个是一个bool量,默认是true是是否使用偏置量的问题、
'''
这里的其实是重写了一个函数,将1原来的函数覆盖了
self.linear也就是一个来自于Linear的实例是一个可以调用的实例。
Module当中的可调用韩式是要调用这个forward的,所以我们一定要定义这个
'''
def forward(self,x):
y_pred = self.linear(x)
return(y_pred)
'''
这里我们注意一个点Module是不需要自行定义一个反向传播函数的。
只要你是使用本身就有的库在进行模型实现的话。
Functions也是pytorch当中的一个类,一个特殊的地方就是,你是否需要自行构造一个反向传播的函数
如果你需要自行定义一个反向传播的函数,1.pytorch不会算的2.pytorch自动生成的效率低的。
才需要使用到Function
'''
module= LinearModule();
3.构造损失函数和优化器,主要体现使用应用接口来实现
criterion = torch.nn.MSELoss(size_average=False)
#这里其实是实例化一个损失函数,这个MSELoss其实也是继承自nn.Module
#这里面一共两个参数第一个是是否计算平均值,计算平均值一般用在各组数据量不同的时候
#第二个参数是是否转化为标量,两个参数都是默认TRUE的但是一般用不到求平均,设置为false还能节省一次计算。
#这个损失的实例也是一个可调用的实例,到时候只要把y_hat和y传进去就可以了。
optimizer =torch.optim.SGD(module.parameters(),lr=0.01)
#这里是将moudle中的全部参数全部都放入其中了,是应用于多层嵌套了。
#lr是优化率,就是每次优化多少的问题。
4.写一个训练的周期:前馈、反馈、更新就是一个周期了。
for epoch in range(1000):
y_pred=module(x_data)
loss=criterion(y_pred,y_data)#这里我们注意其实这里的loss是一个对象
print(epoch,loss)#但是在打印的时候会自动调用__str__()
criterion.zero_grad()#这里是进行手动的梯度归零。
loss.backward()#用loss这个对象来反向传播
optimizer.step()#优化器进行一次优化
print("w=",module.linear.weight.item())
print("b=",module.linear.bias.item())
#z这里说明白就是打印w和b取出来的时候我们需要weight和bias,
#但是注意他们是矩阵,所以我们需要使用item()来让其成为一个数字。
x_test=torch.Tensor([4.0])
y_test=module(x_test)
print("y_test=",y_test)