简单神经网络
首先是包导入、数据生成:
这里做的是线性的拟合,所以准备了一些数据,并定义了一个线性函数。
# 导入文件
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# make data
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # 进行解压,
y = x.pow(2) + 0.2 * torch.rand(x.size()) # 添加噪声
print (x)
print (x.size())
print (y)
网络的定义:
这里是定义网络,只有一个隐藏层,和输出层,使用 relu 作为激活函数。在__init__中定义了网络的基本元素,在函数fowward中定义了前向计算过程,也就是网络的结构。
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):
hidden_x = self.hidden(x)
hidde_x_out = F.relu(hidden_x) # 使用relu 进行激活
out = self.predict(hidde_x_out)
return out
net = Net(n_feature=1, n_hidden=10, n_output=1) # 网络初始化
print (net)
定义优化器、损失函数并进行训练(拟合):
optim = torch.optim.SGD(net.parameters(), lr=0.1)
loss_func = torch.nn.MSELoss()
plt.ion()
for step in range(1000):
prediction = net(x)
loss = loss_func(prediction, y)
optim.zero_grad() # 清空梯度
loss.backward() # 计算梯度
optim.step() # 应用梯度,并更新参数
if step % 10 == 0:
plt.cla()
plt.scatter(x.data.numpy(), y.data.numpy())
plt.plot(x.data.numpy(), prediction.data.numpy(), "r-", lw=5)
plt.text(0.5, 0, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
plt.pause(0.1)
plt.ioff()
plt.show()
定义NN的简单方式
上面介绍了如何定义并使用简单的神经网络,这里给出另外一种更加简单的定义神经网络的方式。可以进行对比:
首先是自定义的神经网络:
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(1, 10, 1)
然后,重点是下面这种方式:使用提供的简单的方式进行定义
net2 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
两种网络的作用是相同的,只不过定义的方式不同,第二种更加简便些。一般考虑使用第二种的定义方式。
模型保存,重载
上面介绍了如何简单定义连续序列,并且给出了如何进行训练一个网络。当我们的模型训练完毕之后,如果需要后面进行使用,就涉及到报错和重载,这里进行简单介绍:
模型的保存主要使用了:torch.save() 函数
模型的载入主要使用了:torch.load() 函数
保存模型的时候可以保存整个模型(网络结构,和参数),同样也可只保存参数,这样就能见效模型体积。
只保存参数:torch.save(net1.state_dict(), "net1_params.pkl") # 主要保存的是状态字典
保存模型和参数: torch.save(net1, "net1.pkl") # 这样保存体积比较大
示例代码:(如果已经理解可直接跳过此部分代码看下一小节)
# save or reload model
import torch
import matplotlib.pyplot as plt
# fake data
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
y = x.pow(2) + 0.2 * torch.rand(x.size())
# save
def save():
net1 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
optim = torch.optim.SGD(net1.parameters(), lr=0.1)
loss_func = torch.nn.MSELoss()
for step in range(200):
predict = net1(x)
loss = loss_func(predict, y)
optim.zero_grad()
loss.backward()
optim.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(), predict.data.numpy(), c="red", lw=2)
# svae
torch.save(net1, "net.pkl")
torch.save(net1.state_dict(), "net_params.pkl")
# restore net
def restore_net():
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(), c="red", lw=2)
def restore_params():
net3 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
state_dict = torch.load("net_params.pkl")
print(state_dict)
net3.load_state_dict(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(), c= "red", lw=2)
save()
restore_net()
restore_params()
如何批量加载数据
如果批量加载数据可以使用torch提供的torch.utils.data 包。
具体的步骤:
- 先构造数据集对象,例如:使用 torch.utils.data.TensorDataset() 生成对象
- 使用数据加载器加载为可迭代的对象,也即初始化迭代器: torch.utils.data.DataLoader
- 迭代使用,每次迭代,会返回batch_size 大小的数据
例如:
加载数据:
BATCH_SIZE = 4
x = torch.linspace(1, 10, 10)
y = torch.linspace(10, 1, 10)
print(x, y)
torch_dataset = Data.TensorDataset(x, y)
print(torch_dataset)
loader = Data.DataLoader(
dataset=torch_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=2
)
使用数据:
print(len(loader))
def show_batch():
for epoch in range(3):
for step, (batch_x, batch_y) in enumerate(loader):
print(
'Epoch: ', epoch, '| Step: ', step, '| batch x: ',
batch_x.numpy(), '| batch y: ', batch_y.numpy()
)