torch.nn搭建神经网络–回归问题
import torch
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
y = x.pow(2) + 0.2 * torch.rand(x.size())
# plt.scatter(x, y)
# plt.show()
class Net(nn.Module):
def __init__(self, n_feature, n_hidden, n_output):
super(Net, self).__init__()
self.hidden = nn.Linear(n_feature, n_hidden)
self.predict = nn.Linear(n_hidden, n_output)
def forward(self, x):
x = F.relu(self.hidden(x))
x = self.predict(x)
return x
net = Net(1, 10, 1)
print(net)
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
loss_func = nn.MSELoss()
plt.ion()
for t in range(100):
prediction = net(x)
loss = loss_func(prediction, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if t % 5 == 0:
plt.cla()
plt.scatter(x, y)
plt.plot(x.detach().numpy(), prediction.detach().numpy(), color='r')
plt.text(0.5, 0, 'Loss=%.4f' % loss, color='r')
plt.pause(0.1)
plt.ioff()
plt.show()
和利用Tensorflow构建神经网络的过程非常类似,主要包括以下几点相同和不同点:
相同点:
1.都是利用class结构定义一个框架,搭建层,规定optimizer和loss。
不同点:
1.在之前tensorflow中,需要定义weights,并且定义linear运算wx+b和activation运算activation function=;在torch中利用nn.Linear()就可以直接进行线性运算,而且在forward过程中,直接利用F.relu()激活。
2.直接的体验是Pytorch是一个动态结构,不需要像Tensorflow一样,需要先搭建一个静态框架,利用下面的结构作为一个窗口进入。
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
而在torch更强调的是梯度下降的过程,所以务必要加的语句是:
optimizer.zero_grad()
loss.backward()
optimizer.step()
3.loss函数的定义方式不同,Tensorflow中是tf.reduce_mean(),这里直接就是nn.MSEloss().
总体而言,torch的语句更加便捷,而且操作更加灵活。
需要注意的是,torch中主要就是用tensor运算,需要在tensor和numpy之间相互转换,尤其是利用plot画图时,只能对numpy进行操作,所以需要利用语句.detach().numpy()转换为数组形式。
torch.nn搭建神经网络–分类问题
import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
x0 = torch.normal(-2, 1, [1000, 2])
y0 = torch.zeros(1000)
x1 = torch.normal(2, 1, [1000, 2])
y1 = torch.ones(1000)
x = torch.cat((x0, x1), 0).type(torch.FloatTensor)
y = torch.cat((y0, y1), 0).type(torch.LongTensor)
print(y.shape)
plt.scatter(x.detach().numpy()[:, 0], x.detach().numpy()[:, 1])
plt.show()
class Net(nn.Module):
def __init__(self, n_input, n_hidden, n_output):
super(Net, self).__init__()
self.hidden = nn.Linear(n_input, n_hidden)
self.output = nn.Linear(n_hidden, n_output)
def forward(self, x):
x = F.relu(self.hidden(x))
x = F.softmax(self.output(x), dim=1)
return x
net = Net(2, 10, 2)
# print(net)
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
loss_fun = nn.CrossEntropyLoss()
plt.ion()
for i in range(50):
out = net(x)
loss = loss_fun(out, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if i % 2 == 0:
plt.cla()
prediction = torch.max(out, dim=1)[1]
pre_y = prediction.detach().numpy()
plt.scatter(x.detach().numpy()[:, 0], x.detach().numpy()[:, 1], c=pre_y, s=10)
accuracy = torch.sum(torch.eq(prediction, y)).item() / 2000
plt.text(1.5, -4, 'Accuracy=%.4f' % accuracy)
plt.pause(0.1)
plt.ioff()
plt.show()
输出结果为:
在这里需要注意的问题主要是plt当中数组、标量、张量之间的转换。
1.标签集y必须是LongTensor。
2.softmax函数版本更新,要明确dim。
3.在plt.scatter中画散点图必须是numpy格式,所以要用语句.detach().numpy()。
4.比较两个张量a,b中的元素是否相等,用语句torch.eq(a,b),比较结果为True或者False。比较时务必要注意两者的shape必须是相等的,否则就会出错。这里prediction和y的shape都是torch.Size([2000])。下面的错误代码就是一个教训。
5.当利用torch.sum将正确个数求出来之后。获得的值并不是一个标量,而是一个tensor。而计算精度时用到的除法运算是针对标量的。所以对于tensor a要用语句**a.item()**将其转换为标量。
错误代码
第一次编写时,定义
y0 = torch.zeros(1000, 1)
y1 = torch.ones(1000, 1)
y = torch.cat((y0, y1), 0).type(torch.LongTensor)
后面是:
for i in range(100):
out = net(x)
loss = loss_fun(out, y.squeeze()) #
optimizer.zero_grad()
loss.backward()
optimizer.step()
if i % 5 == 0:
plt.cla()
prediction = torch.max(out, dim=1)[1]
pre_y = prediction.detach().numpy()
plt.scatter(x.detach().numpy()[:, 0], x.detach().numpy()[:, 1], c=pre_y, s=10)
accuracy = (torch.sum(torch.eq(prediction, y)) / 2000).detach().numpy()
accuarcy = accuracy.item()
plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy)
plt.pause(0.1)
plt.ioff()
plt.show()
输出结果为:精度都上1000了(头发又掉了),显然是错的。
所以在使用torch.eq时务必要保证两个的shape是一样的。