pytorch练习
使用torch.Tensor定义数据 , tensor的意思是张量,是数字各种形式的总称,可以定义数、向量、二维数组和张量。
import torch # 可以是一个数 x = torch.tensor(666) print(x) # 可以是一维数组(向量) x = torch.tensor([1,2,3,4,5,6]) print(x) # 可以是二维数组(矩阵) x = torch.ones(2,3) print(x) # 可以是任意维度的数组(张量) x = torch.ones(2,3,4) print(x)
可通过多种方法创建tensor
# 创建一个空张量 x = torch.empty(5,3) print(x) # 创建一个随机初始化的张量 x = torch.rand(5,3) print(x) # 创建一个全0的张量,里面的数据类型为 long x = torch.zeros(5,3,dtype=torch.long) print(x) # 基于现有的tensor,创建一个新tensor, # 从而可以利用原有的tensor的dtype,device,size之类的属性信息 y = x.new_ones(5,3) #tensor new_* 方法,利用原来tensor的dtype,device print(y) z = torch.randn_like(x, dtype=torch.float) # 利用原来的tensor的大小,但是重新定义了dtype print(z)
可使用tensor进行的运算
基本运算,加减乘除,求幂求余
布尔运算,大于小于,最大最小
线性运算,矩阵乘法,求模,求行列式
# 返回 m 中元素的数量 print(m.numel()) # 返回 第0行,第2列的数 print(m[0][2]) # 返回 第1列的全部元素 print(m[:, 1]) # 返回 第0行的全部元素 print(m[0, :]) # Create tensor of numbers from 1 to 5 # 注意这里结果是1到4,没有5 v = torch.arange(1, 5) print(v) # Scalar product m @ v # Calculated by 1*2 + 2*5 + 3*3 + 4*7 m[[0], :] @ v # Add a random tensor of size 2x4 to m m + torch.rand(2, 4) # 转置,由 2x4 变为 4x2 print(m.t()) # 使用 transpose 也可以达到相同的效果,具体使用方法可以百度 print(m.transpose(0, 1)) # returns a 1D tensor of steps equally spaced points between start=3, end=8 and steps=20 torch.linspace(3, 8, 20) #输出为tensor([3.0000, 3.2632, 3.5263, 3.7895, 4.0526, 4.3158, 4.5789, 4.8421, 5.1053,5.3684, 5.6316, 5.8947, 6.1579, 6.4211, 6.6842, 6.9474, 7.2105, 7.4737,7.7368, 8.0000]) from matplotlib import pyplot as plt # matlabplotlib 只能显示numpy类型的数据,下面展示了转换数据类型,然后显示 # 注意 randn 是生成均值为 0, 方差为 1 的随机数 # 下面是生成 1000 个随机数,并按照 100 个 bin 统计直方图 plt.hist(torch.randn(1000).numpy(), 100); #注意上面转换为numpy的方法 # 当数据非常非常多的时候,正态分布会体现的非常明显 plt.hist(torch.randn(10**6).numpy(), 100); # 创建两个 1x4 的tensor a = torch.Tensor([[1, 2, 3, 4]]) b = torch.Tensor([[5, 6, 7, 8]]) # 在 0 方向拼接 (即在 Y 方各上拼接), 会得到 2x4 的矩阵 print( torch.cat((a,b), 0)) # 在 1 方向拼接 (即在 X 方各上拼接), 会得到 1x8 的矩阵 print( torch.cat((a,b), 1))
螺旋数据分类
!wget https://raw.githubusercontent.com/Atcold/pytorch-Deep-Learning/master/res/plot_lib.py
下载plot_lib绘图库到本地,引入基本库,初始化参数。
import random import torch from torch import nn, optim import math from IPython import display from plot_lib import plot_data, plot_model, set_default # 因为colab是支持GPU的,torch 将在 GPU 上运行 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print('device: ', device) # 初始化随机数种子。神经网络的参数都是随机初始化的, # 不同的初始化参数往往会导致不同的结果,当得到比较好的结果时我们通常希望这个结果是可以复现的, # 因此,在pytorch中,通过设置随机数种子也可以达到这个目的 seed = 12345 random.seed(seed) torch.manual_seed(seed) N = 1000 # 每类样本的数量 D = 2 # 每个样本的特征维度 C = 3 # 样本的类别 H = 100 # 神经网络里隐层单元的数量
X = torch.zeros(N * C, D).to(device) Y = torch.zeros(N * C, dtype=torch.long).to(device) for c in range(C): index = 0 t = torch.linspace(0, 1, N) # 在[0,1]间均匀的取10000个数,赋给t # 下面的代码不用理解太多,总之是根据公式计算出三类样本(可以构成螺旋形) # torch.randn(N) 是得到 N 个均值为0,方差为 1 的一组随机数,注意要和 rand 区分开 inner_var = torch.linspace( (2*math.pi/C)*c, (2*math.pi/C)*(2+c), N) + torch.randn(N) * 0.2 # 每个样本的(x,y)坐标都保存在 X 里 # Y 里存储的是样本的类别,分别为 [0, 1, 2] for ix in range(N * c, N * (c + 1)): X[ix] = t[index] * torch.FloatTensor((math.sin(inner_var[index]), math.cos(inner_var[index]))) Y[ix] = c index += 1 print("Shapes:") print("X:", X.size()) print("Y:", Y.size())
使用plot_lib的plot_data函数显示图象。
构建线性模型
learning_rate = 1e-3 lambda_l2 = 1e-5 # nn 包用来创建线性模型 # 每一个线性模型都包含 weight 和 bias model = nn.Sequential( nn.Linear(D, H), nn.Linear(H, C) ) model.to(device) # 把模型放到GPU上 # nn 包含多种不同的损失函数,这里使用的是交叉熵(cross entropy loss)损失函数 criterion = torch.nn.CrossEntropyLoss() # 这里使用 optim 包进行随机梯度下降(stochastic gradient descent)优化 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # 开始训练 for t in range(1000): # 把数据输入模型,得到预测结果 y_pred = model(X) # 计算损失和准确率 loss = criterion(y_pred, Y) score, predicted = torch.max(y_pred, 1) acc = (Y == predicted).sum().float() / len(Y) print('[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f' % (t, loss.item(), acc)) display.clear_output(wait=True) # 反向传播前把梯度置 0 optimizer.zero_grad() # 反向传播优化 loss.backward() # 更新全部参数 optimizer.step() print(y_pred.shape) print(y_pred[10, :]) print(score[10]) print(predicted[10])
使用 print(model) 把模型输出,可以看到有两层:
- 第一层输入为 2(因为特征维度为主2),输出为 100;
- 第二层输入为 100 (上一层的输出),输出为 3(类别数)
从上面图示可以看出,线性模型的准确率最高只能达到 50% 左右,对于这样复杂的一个数据分布,线性模型难以实现准确分类。
构建双层神经网络模型
learning_rate = 1e-3 lambda_l2 = 1e-5 # 这里可以看到,和上面模型不同的是,在两层之间加入了一个 ReLU 激活函数 model = nn.Sequential( nn.Linear(D, H), nn.ReLU(), #与1代码块的唯一区别,加入了激活函数 nn.Linear(H, C) ) model.to(device) # 下面的代码和之前是完全一样的,这里不过多叙述 criterion = torch.nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # built-in L2 # 训练模型,和之前的代码是完全一样的 for t in range(1000): y_pred = model(X) loss = criterion(y_pred, Y) score, predicted = torch.max(y_pred, 1) acc = ((Y == predicted).sum().float() / len(Y)) print("[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f" % (t, loss.item(), acc)) display.clear_output(wait=True) # zero the gradients before running the backward pass. optimizer.zero_grad() # Backward pass to compute the gradient loss.backward() # Update params optimizer.step()
发现分类效果较好,关键在于其加入了ReLU激活函数。ReLU函数速度快,精度高,逐渐取代了Sigmoid函数。