内容原文:https://morvanzhou.github.io/tutorials/machine-learning/torch/ 接着之前的学习继续:

1、快速搭建神经网络

import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

n_data = torch.ones(100,2)
x0 = torch.normal (2*n_data,1)
y0 = torch.zeros(100)
x1 = torch.normal(-2*n_data,1)
y1 = torch.ones(100)
x = torch.cat((x0.x1),0).type(torch.FloatTensor)
y = torch.cat((y0,y1),).type(torch.LongTensor)

x,y = Variable(x), Variable(y)

# method 1
class Net(torch.nn.Module):
      def __init__(self,n_feature,n_hidden,n_output):
            super(Net,self).__init__()
            self.hidden = torch.nn.Linear(n_feature,n_hidden)
            self.predict = torch.nn.Linear(n_hidden,n_output)
      def forward(self,x):
            x = F.relu(self.hidden(x))
            x = self.predict(x)
            return x
 net1 = Net(2,10,2)
 print(net1)

# method 2
net2 = torch.nn.Sequential(
	torch.nn.Linear(2,10),
	torch.nn.ReLU(),
	torch.nn.Linear(10,2),
)
print (net2)

optimizer = torch.optim.SGD(net2.parameters(),lr=0.02)
loss_func = torch.nn.CrossEntropyLoss()

for t in range(100):
     prediction = net2(x)
     loss = loss_func(prediction,y)
     optimizer.zero_grad()
     loss.backward()
     optimizer.step()

虽然method 1于method 2效果相同,但是net1和net2的输出还是有点不一样的

动态图神经网络 动态图神经网络模型 python_神经网络

我们发现,net1 每一层都是有名字的,而且没有relu层,因为在net1中,给每一层命了名字,同时这里relu是小写的,所以其实relu就是一个函数,说白了就是一个功能,而net2中ReLU相当于一个类,ReLU()相当于调用了类的构造函数,所以一个层的类,这时就会存在这一层。.
总的来说其实效果和结果是一样的。
需要注意的是:快速搭建时使用大写的ReLU,因为此时相当于调用类的构造函数。

2、保存提取

搭建好神经网络并且已经训练好神经网络,需要将训练好的网络保存下来,这样下次就可以直接进行试验或者测试了

import torch
from torch.autograd import Variable 
import matplotlib.pyplot as plt

#torch.manual_seed(1)

x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y = x.pow(2) + 0.2*torch.rand(x.size())
x,y = Variable(x, requires_grad=False),Variable(y, requires_grad = False)
#保留也有两种,一种是保留整个网络图,另一个是只保留参数
def save():
	net1 = torch.nn.Sequential(
	torch.nn.Linear(1,10),
	torch.nn.ReLU(),
	torch.nn.Linear(10,1),
)
	print (net1)

	optimizer = torch.optim.SGD(net1.parameters(),lr=0.02)
	loss_func = torch.nn.CrossEntropyLoss()

	for t in range(100):
	     prediction = net1(x)
	     loss = loss_func(prediction,y)
	     optimizer.zero_grad()
	     loss.backward()
	     optimizer.step()
	plt.figure(1,figsize=(10,3))
	plt.subplot(131)
	plt.title('Net1')
	plt.scatter(x.data.numpy(),y.data.numpy())
	plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
	#直接save(net1)保留整个图
	torch.save(net1,'net.pkl')
	#只保留网络的参数
	torch.save(net1.state_dict(),'net_params.pkl')
	
#重新加载神经网络
def restore_net():
	#因为这个是之前保留了整个网络图,所以这里直接load就可以恢复整个神经网络了
	net2 = torch.load('net.pkl')
	prediction = net2(x)
	plt.subplot(132)
	plt.title('Net2')
	plt.scatter(x.data.numpy(),y.data.numpy())
	plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
	
def restore_params():
	#因为这里的话,上面只保留了参数并没有保留只能图,所以首先要搭建和net1一样的网络,然后再load那些参数复制到net3中就可以了
	net3 = torch.nn.Sequential(
	torch.nn.Linear(1,10),
	torch.nn.ReLU(),
	torch.nn.Linear(10,1),
)
	net3.load_state_dict()
	prediction = net3(x)
	plt.subplot(133)
	plt.title('Net3')
	plt.scatter(x.data.numpy(),y.data.numpy())
	plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
	
save()
restore_net()
restore_params()
	
#据说保留和恢复参数的方式要快一点,所以还是推荐这种方式

动态图神经网络 动态图神经网络模型 python_数据_02

3、批训练

因为torch.nn只支持小批量,不支持一次输入一个很大的样本,即一次必须是一个batch。Torch中提供了一种帮你整理你的数据结构的好东西,叫做DataLoader,我们可以用它来包装自己的数据,进行批训练。而且批训练可以有很多种途径
DataLoader是torch给你用来包装你的数据的工具,所以你要将自己的数据形式(numpy array 或者其他)装换成Tensor,然后再放在这个包装器中,使用DataLoader可以帮你有效地迭代数据。

import torch
import torch.utils.data as Data   #进行小批训练的模块

BATCH_SIZE = 5      #每个小批的数量

x = torch.linspace(1,10,10)   # this is x data
y = torch.linspace(10,1,10)   # this is y data

#定义一个torch的数据库,将数据放到数据库中
torch_dataset = Data.TensorDataset(data_tensor=x,target_tensor=y)
#loader将训练变成一小批一小批的
loader = Data.DataLoader(
	dataset = torch_dataset,
	batch_size = BATCH_SIZE,
	shuffle = True,     #定义是否在训练的时候要不要打乱顺序
	num_workers = 2,     #用两个线程或者进程来提取
)  
for epoch in range(3):       #epoch就是每个训练次,然后数据样本按照batch_size来进行拆分,每次训练的时候,可以设置loader是否将拆分的数据块打乱顺序。如果不打乱顺序的话那每个epoch的训练形式是一样的,如果打乱顺序的话,epoch的训练就是不同顺序的。
	for step, (batch_x,batch_y) in enumerate(loader):
		#training.....
		print('Epoch:', epoch, '|Step:',step,'|batch x:',
		       batch_x.numpy(),'| batch y: ',batch_y.numpy())

动态图神经网络 动态图神经网络模型 python_Data_03

我们发现对于每一个epoch,训练数据都是不同顺序的,这是因为loader中设置了随机打乱顺序:shuffle = True,让我们把shuffle设置成False再来看下结果:

动态图神经网络 动态图神经网络模型 python_Data_04

这时我们就会发现,此时的每个epoch训练数据就相同了。

我们将batch_size改成8呢,来看下结果,因为数据量一共10个,每个batch就是8,那就意味了分成了代码块数据量是不相同的,那这时又会怎么训练呢?
修改:

BATCH_SIZE = 8

再来看结果:

动态图神经网络 动态图神经网络模型 python_神经网络_05

可以看到每一个epoch都是将数据分成了8,2两个部分,也就是数据从头开始数,一个一个batch_size块的数据进行训练,最后一个数据块如果不够一个batch _size,epoch就只训练剩下的部分,这个也很容易理解。