Pytorch知识点学习

1 Numpy

本节要点:

  • ·如何生成Numpy数组。
  • 如何存取元素。
  • Numpy的算术运算。
  • 数组变形。
  • 批量处理。
  • Numpy的通用函数。
  • Numpy的广播机制。

1.1 生成Numpy数组

  1. 从已有数据中创建数组
import numpy as np
# np.+Tab键,查看可使用的函数
# np.abs? 可查看函数abs的详细帮助信息
# random创建,创建特定形状的多维数组

list1 = [1,2,3]
ls1 = np.array(list1)
ls1.dtype
ls1.ndim
type(ls1)

list2 = [[1,2,3],[4,5,6]]
ls2 = np.array(list2)
len(list2)
ls2.ndim
  1. 利用random模块生成数组
np.random.random(100).reshape(10,10).shape
np.random.uniform()
np.random.uniform(0,1,[2,3])
np.random.randn(10)
np.random.randint(0,255,dtype=np.uint8)
np.random.randint(0,255,[2,3],dtype=np.uint8)
np.random.normal(10,100,[2,3])

arr = np.arange(10).reshape(2,5)
np.random.shuffle(arr)
arr

np.random.sample(20)
  1. 创建特定形状的多维数组
a = np.zeros([3,3])
b = np.ones([3,3])
c = np.empty([2,3])
a0 = np.zeros_like(a)
b0 = np.ones_like(b)
c0 = np.empty_like(c)
np.eye(5)
np.full([2,3],10)

# 应用
img = np.random.randint(0,255,[5,5],dtype=np.uint8)
mask = np.zeros_like(img,dtype=np.bool)
mask[1:4,1:4] = 1
img0 = img[mask]

img = np.random.randint(0,255,[5,5],dtype=np.uint8)
mask = np.zeros_like(img)
mask[1:4,1:4] = 1
img1 = img*mask

np.savetxt(X=img0,fname = '/Users/ls/PycharmProjects/LS_Test/img0.txt')
t = np.loadtxt('/Users/ls/PycharmProjects/LS_Test/img0.txt')

  1. 利用arange、linspace函数生成数组
np.arange(1,10,2)
np.arange(2,10,2)
x = np.linspace(0, 1, 10)
y = np.sin(x)

1.2 获取元素

1.获取元素

n11 = np.random.randint(0,10,10)
n11[5]
n11[:3]
n11[4:8]
n11[2:9:2]
n11[::-1]
n11[::-3]
n11[::3]

n45 = np.random.randint(0,10,[4,5])
n45[1,3]
n45[[1,3],:]
n45[[1,3],2:4]
n45[[1,3],[1,3,5]]
n45[[1,3],:][:,[0,4]]
n45[(n45>3)&(n45<9)]
  1. random.choice函数从指定的样本中随机抽取数据。
a=np.arange(1,25,0.5,dtype=float)
s1 = np.random.choice(a,10)
s2 = np.random.choice(a,[3,4],replace=True)
s3 = np.random.choice(a,[3,4],p=a/sum(a))

1.3 Numpy的算术运算

Numpy的算术运算,一种是对应元素相乘,又称为逐元乘法(Element-Wise Product),运算符为 np.multiply(),或*。另一种是点积或内积元素,运算符为np.dot()。

  1. 对应元素相乘
np.random.randint(0,10,[2,3])
B = np.random.randint(3,12,[2,3])
A,B
A*B
np.multiply(A,B)
A*2   # 广播机制
A/2
A*np.full([2,3],2)

# [2,3]
# [1,1]
# [2,3]
#
# [2,4]--> [2,1,4]-->[2,3,4]
# [3,4]--> [1,3,4]-->[2,3,4]
A = np.random.randint(0,10,[2,4])
B = np.random.randint(0,10,[3,4])
np.expand_dims(A,1)+np.expand_dims(B,0)

  1. 点积运算
A = np.random.randn(3,5)
B = np.random.randn(5,3)
np.dot(A,B)
    a.dot(B)
    B.dot(A)

1.4 数组变形

  1. 更改数组的形状
np.reshape()       # 不修改arr本身
np.resize()        # 修改arr本身
arr.T              # 转置
arr.ravel()        # 不产生原数组的副本
arr.faltten()      # 返回原数组的副本
arr.squeeze()      # 降维
arr.transpose()    # 调整坐标轴位置
a = np.random.randint(0,10,[2,3])
a.reshape(3,2) # 不改变变量本身
a
a.resize([3,2])   # 改变变量本身
a
a.T
a.ravel() # 不改变变量本身
a.ravel('F')
a
a.flatten() # 不改变变量本身
a
a.squeeze()
a = np.random.randint(0,10,[1,2,3,4,1])
a.squeeze().shape
a.transpose()

  1. 合并数组
np.append()       # 占内存
np.concatenate()  # 没有内存问题
np.stack()        # 增加新的轴
np.hstack()       # 按照行堆砌
np.vstack()       # 按照列堆砌
np.dstack()       # 按照第d维堆砌
np.vsplit()       # 按照列分割
# append和concatenate,按照行(列)合并时,必须要求数组有相同的列(行),即其他坐标轴的数值相等。
# stack、hstack、dstack,要求待合并的数组必须具有相同的形状(shape)。
a0 = np.random.randint(0,10,[4,2,3,4])
a1 = np.random.randint(0,10,[3,2,3,4])
a01 = np.append((a0,a1),0)
a01 = np.append(a0,a1,0)
a01.shape

a01 = np.concatenate((a0,a1),0)
a01.shape


a0 = np.random.randint(0,10,[4,2,3,4])
a1 = np.random.randint(0,10,[4,2,3,4])
a = np.stack(a0,a1)
a = np.stack((a0,a1))
a.shape
np.hstack((a0,a1)).shape
np.vstack((a0,a1)).shape
np.dstack((a0,a1)).shape
np.stack((a0,a1),-1).shape
np.vsplit(a,0)
np.vsplit(a,2)[0].shape

1.5 批量处理

samples = np.random.randn(1000,3,2)
np.random.shuffle(samples)
bs = 100
for i in range(0,1000,bs):
    s_sum = np.sum(samples[i:i+bs])
    print(f'epoch:{i},sum of data:{s_sum}')

1.6 通用函数

s= np.random.randint(0,10,[3,4,5])
np.sqrt(s)
np.sin(s)
np.log10(s)
np.exp(s)
np.sum(s,0).shape
np.mean(s,2).shape
np.median(s)
np.median(s,0)
np.median(s,1)
np.median(s,2)
np.std(s)
np.std(s,0)
np.std(s,1)
np.std(s,2)
np.var(s)
np.var(s,0)
np.var(s,1)
np.var(s,2)
np.corrcoef(s[0])

1.7 广播机制

两个数组能否做数学运算,把数组的shape右对齐排列,如果对应位置上的数值为1、相同、不存在就可以运算,反之需要增加维度才可以运算。

[2,3]
[  3]
[2,3]

[3,1,5]
[1,4,5]
[3,4,5]

[2,3]
[2,3]
[2,3]

[2,3]-->[1,2,1,3]
[3,2]-->[3,1,2,1]
[3,2,2,3]

(np.random.randn(2,3)+np.random.randn(3)).shape

(np.random.randn(3,1,5)+np.random.randn(1,4,5)).shape

(np.random.randn(2,3)+np.random.randn(2,3)).shape

(np.expand_dims(np.random.randn(2,3),[0,2])+np.expand_dims(np.random.randn(3,2),[1,3])).shape

2 PyTorch

本章要点:

  • Numpy与Tensor。
  • Tensor与Autograd。
  • 使用Numpy实现机器学习。
  • 使用Tensor及Antograd实现机器学习。
  • 使用TensorFlow架构。

2.1 Numpy与Tensor

1 Tensor

import torch
import numpy as np

a = torch.tensor([1,2])
b = torch.tensor([1,2])*2
torch.add(a,b)

a.add_(b)   # 改变a的值,修改自身数据
a.add(b)    # 不改变a的值

2 创建Tensor

a = torch.tensor([[1,2]])
torch.eye(3)
torch.eye(3,4)
torch.linspace(0,100,10)
torch.logspace(1,3,10)
torch.rand(3,3)
torch.ones(3,4)
torch.zeros(5,6)
torch.ones_like(a)
torch.zeros_like(a)
torch.arange(0,10,0.9)
b=np.array([1,2,3])
torch.from_numpy(b)

t=torch.Tensor([[1,2,3],[4,5,6]])
t.size()
t.shape
torch.Tensor(t.size())


1)torch.Tensor是torch.empty和torch.tensor之间的一种混合,但是,当传入数据时,
torch.Tensor使用全局默认dtype(FloatTensor),而torch.tensor是从数据中推断数据类型。 

2)torch.tensor(1)返回一个固定值1,而torch.Tensor(1)返回一个大小为1的张量,它是
随机初始化的值。

torch.tensor(1)
torch.Tensor(1)
torch.tensor(1).type()
torch.Tensor(1).type()

3 修改Tensor形状

a = torch.randn(3,4)
a.size()
a.numel()
a.view(2,6)
a.reshape(2,6)
a.resize(2,6)
a.view(-1)
[i.item() for i in a.flatten()]
[i.item() for i in a.view(-1)]
a.unsqueeze([0,-1]).shape
a.squeeze().shape

4 索引操作

a = torch.randn(10,5,4)
torch.index_select(a,0,torch.tensor([0,2]))

b = torch.zeros(10)
b[5:]+=torch.rand(5)
b.nonzero()

mask = b>0.5
torch.masked_select(b,mask)
torch.gather(b,0,torch.tensor([2,3]))
torch.gather(b,0,torch.tensor([2,3,7,9]))
torch.scatter(b,0,torch.tensor([2,3,7,9]),100)

5 广播机制

a = torch.tensor([1,2,3])
a.expand(4,3)

6 逐元素操作


x1 = -torch.randint(0,10,[2,3])
x2 = torch.randint(0,10,[2,3])
torch.abs(x1)
torch.add(x1,x2)
x1.add_(x2)

t = torch.randn(1, 3)
t1 = torch.randn(3, 1)
t2 = torch.randn(1, 3)
torch.addcdiv(t, t1, t2, value=0.1)
torch.addcmul(t, t1, t2, value=0.1)

t.ceil()
t.floor()
t.clamp(-0.03,0.02)
t.exp()
t.log()
t.pow(2)
t.mul(3)
t.neg()
t.sigmoid()
t.tanh()
t.softmax(dim=0)

7 归并操作

a = torch.randint(0,10,[2,3])
b = torch.randint(0,10,[2,3])
a.cumprod(1)
a.cumsum(1)
torch.dist(a*1.,b*1.,p=2)
(a*1.).mean(0)
torch.norm(a*1.,p=2)
a.prod(1)

8 比较操作

a = torch.randn(4,5)
b = a*1.0
a.eq(b)
a.equal(b*2)
a.max(1)
a.min(0)
a.ge(b)
a.le(b*0.2)
a.gt(b*2)
a.lt(b*0.2)
torch.topk(a,1)

9 矩阵操作

1)Torch的dot与Numpy的dot有点不同,Torch中的dot是对两个为1D张量进行点积运 算,Numpy中的dot无此限制。

2)mm是对2D的矩阵进行点积,bmm对含batch的3D进行点积运算。

3)转置运算会导致存储空间不连续,需要调用contiguous方法转为连续。

a = torch.rand(3)
b = torch.rand(3)
torch.dot(a,b)

a = torch.rand(2,3)
b = torch.rand(2,3)
torch.mm(a,b.T)
b.t()
b.svd()

a = torch.rand(3)
b = torch.rand(2,3)
torch.mv(b,a)

a = torch.rand(2,3,4)
b = torch.rand(2,4,3)
torch.bmm(b,a)

2.2 Tensor与Autograd

1 自动求导要点

为实现对Tensor自动求导,需考虑如下事项:
1)创建叶子节点(Leaf Node)的Tensor,使用requires_grad参数指定是否记录对其 的操作,以便之后利用backward()方法进行梯度求解。requires_grad参数的缺省值为 False,如果要对其求导需设置为True,然后与之有依赖关系的节点会自动变为True。

2)可利用requires_grad_()方法修改Tensor的requires_grad属性。可以调用.detach()或 with torch.no_grad():,将不再计算张量的梯度,跟踪张量的历史记录。这点在评估模 型、测试模型阶段中常常用到。

3)通过运算创建的Tensor(即非叶子节点),会自动被赋予grad_fn属性。该属性表 示梯度函数。叶子节点的grad_fn为None。

4)最后得到的Tensor执行backward()函数,此时自动计算各变量的梯度,并将累加结 果保存到grad属性中。计算完成后,非叶子节点的梯度自动释放。

5)backward()函数接收参数,该参数应和调用backward()函数的Tensor的维度相同, 或者是可broadcast的维度。如果求导的Tensor为标量(即一个数字),则backward中的参 数可省略。

6)反向传播的中间缓存会被清空,如果需要进行多次反向传播,需要指定backward 中的参数retain_graph=True。多次反向传播时,梯度是累加的。

7)非叶子节点的梯度backward调用后即被清空。

8)可以通过用torch.no_grad()包裹代码块的形式来阻止autograd去跟踪那些标记
为.requesgrad=True的张量的历史记录。这步在测试阶段经常使用。

2.3使用Numpy实现参数更新

用Numpy求解梯度

y = w*x^2+b
1. 生成样本x,y.
2. 计算预测值、损失,参数梯度。
3. 初始化参数,迭代循环更新参数,直到循环结束或者参数收敛。
import torch
import numpy as np

# 1 数据集
N = 1000
w = 1.3
b = 1
lr = 1e-3
x = torch.linspace(-1,1,N) # [1000]
y = w*torch.pow(x,2)+b        # [1000]

epoch = 60
w = torch.rand(1)
b = torch.rand(1)
for i in range(epoch):
    y_ = w*torch.pow(x,2)+b
    loss = 1/2*torch.sum((y_-y)**2)
    w -= lr*torch.sum((y_-y)*torch.pow(x,2))
    b -= lr*torch.sum(y_-y)
    if i%10 == 0:
        print(f'i:{i},w:{w},b:{b}')

2.4使用Tensor及Antograd实现参数更新

N = 1000
w =1.3 #torch.tensor([[1.3]])
b = 1
lr = 1e-3
x = torch.linspace(-1,1,N) # [1000]
y = w*torch.pow(x,2)+b+torch.rand(1000)*0.01        # [1000]

epoch = 120
w = torch.randn(1,dtype=torch.float32,requires_grad=True)
b = torch.randn(1,dtype=torch.float32,requires_grad=True)
for i in range(epoch):
    y_ = w*torch.pow(x,2)+b
    loss = 1/2*torch.sum((y_-y)**2)
    loss.backward()
    with torch.no_grad():
        w -= lr*w.grad
        b -= lr*b.grad
        w.grad.zero_()
        b.grad.zero_()
    if i%10 == 0:
        print(f'i:{i},w:{w},b:{b}')

3 PyTorch神经网络工具箱

  • 介绍神经网络核心组件。
  • 如何构建一个神经网络。
  • 详细介绍如何构建一个神经网络。
  • 如何使用nn模块中Module及functional。
  • 如何选择优化器。
  • 动态修改学习率参数。

3.1 实现神经网络实例

  1. 主要步骤
1)数据集。 
2)利用torchvision对数据进行预处理,调用torch.utils建立一个数据迭代器。 
3)可视化源数据。
4)利用nn工具箱构建神经网络模型。 5)实例化模型,并定义损失函数及优化器。
6)训练模型。
7)可视化结果。
# 1.导人必要的模块
import torch
import numpy as np
from torchvision.datasets import mnist
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import torch.nn.functional as F
import torch.optim as optim
from torch import nn

# 2.定义一些超参数
train_batch_size = 8
test_batch_size = 8
learning_rate = 0.01
num_epoches = 20
lr = 0.01
momentum = 0.5

# 下载数据并对数据进行预处理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
train_dataset = mnist.MNIST('./data',train=True,transform=transform,download=True)
test_dataset = mnist.MNIST('./data',train=True,transform=transform)
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)

# 3可视化源数据
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
fig = plt.figure()
for i in range(6):
    plt.subplot(2,3,i+1)
    plt.tight_layout()
    plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
    plt.title("Ground Truth: {}".format(example_targets[i]))
    plt.xticks([])
    plt.yticks([])

# 4 构建模型
class Net(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Net, self).__init__()
        self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1),nn.BatchNorm1d(n_hidden_1))
        self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d (n_hidden_2))
        self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))
    def forward(self, x):
        x = F.relu(self.layer1(x))
        x = F.relu(self.layer2(x))
        x = self.layer3(x)
        return x
# 4.2 实例化网络。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") #实例化网络
model = Net(28 * 28, 300, 100, 10)
model.to(device)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)

# 5 训练模型
# 5.1 开始训练
losses = []
acces = []
eval_losses = []
eval_acces = []
for epoch in range(num_epoches):
    train_loss = 0
    train_acc = 0
    model.train() #动态修改参数学习率
    if epoch%5==0:
        optimizer.param_groups[0]['lr'] *= 0.1
    for img, label in train_loader:
        img = img.to(device)
        label = label.to(device)
        img = img.view(img.size(0), -1)
        # 前向传播
        out = model(img)
        loss = criterion(out, label)
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        # 记录误差
        train_loss += loss.item()
        # 计算分类的准确率
        _, pred = out.max(1)
        num_correct = (pred == label).sum().item()
        acc = num_correct / img.shape[0]
        train_acc += acc
    losses.append(train_loss / len(train_loader))
    acces.append(train_acc / len(train_loader))
    # 在测试集上检验效果
    eval_loss = 0
    eval_acc = 0 # 将模型改为预测模式
    model.eval()
    for img, label in test_loader:
        img = img.to(device)
        label = label.to(device)
        img = img.view(img.size(0), -1)
        out = model(img)
        loss = criterion(out, label)
        # 记录误差
        eval_loss += loss.item()
        # 记录准确率
        _, pred = out.max(1)
        num_correct = (pred == label).sum().item()
        acc = num_correct / img.shape[0]
        eval_acc += acc
    eval_losses.append(eval_loss / len(test_loader))
    eval_acces.append(eval_acc / len(test_loader))
    print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f},\
           Test Loss: {:.4f}, Test Acc: {:.4f}'
          .format(epoch, train_loss / len(train_loader), \
          train_acc / len(train_loader), eval_loss / len(test_loader),\
          eval_acc / len(test_loader)))
# 5.2 可视化训练及测试损失值
plt.title('trainloss')
plt.plot(np.arange(len(losses)), losses)
plt.legend(['Train Loss'], loc='upper right')

调用model.train()会把所有的module 设置为训练模式。如果是测试或验证阶段,需要使模型处于验证阶段,即调用 model.eval(),调用model.eval()会把所有的training属性设置为False。

1)nn.Xxx继承于nn.Module,nn.Xxx需要先实例化并传入参数,然后以函数调用的方 式调用实例化的对象并传入输入数据。它能够很好地与nn.Sequential结合使用,而 nn.functional.xxx无法与nn.Sequential结合使用。
2)nn.Xxx不需要自己定义和管理weight、bias参数;而nn.functional.xxx需要自己定义 weight、bias参数,每次调用的时候都需要手动传入weight、bias等参数,不利于代码复 用。
3)Dropout操作在训练和测试阶段是有区别的,使用nn.Xxx方式定义Dropout,在调 用model.eval()之后,自动实现状态的转换,而使用nn.functional.xxx却无此功能。
总的来说,两种功能都是相同的,但PyTorch官方推荐:具有学习参数的(例如, conv2d,linear,batch_norm)采用nn.Xxx方式。没有学习参数的(例如,maxpool、loss func、 activation func)等根据个人选择使用nn.functional.xxx或者nn.Xxx方式。3.2小节中使用激 活层,我们采用F.relu来实现,即nn.functional.xxx方式。

3.3 如何构建神经网络?

3.3.1 构建网络层

# 1)导入需要的模块

import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 超参数
LR = 0.01
BATCH_SIZE = 32
EPOCH = 12
# 2)生成数据。
# 生成训练数据
# torch.unsqueeze() 的作用是将一维变二维,torch只能处理二维的数据
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
# 0.1 * torch.normal(x.size())增加噪点
y = x.pow(2) + 0.1 * torch.normal(torch.zeros(*x.size()))
torch_dataset = Data.TensorDataset(x,y)
#得到一个代批量的生成器
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True)
# 3)构建神经网络。

class Net(torch.nn.Module): # 初始化
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(1, 20)
        self.predict = torch.nn.Linear(20, 1)
# 前向传递
def forward(self, x):
    x = F.relu(self.hidden(x))
    x = self.predict(x)
    return x
# 4)使用多种优化器。

net_SGD = Net()
net_Momentum = Net()
net_RMSProp = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSProp, net_Adam]
opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.9)
opt_RMSProp = torch.optim.RMSprop(net_RMSProp.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSProp, opt_Adam]
# 5)训练模型。

loss_func = torch.nn.MSELoss()
loss_his = [[], [], [], []] # 记录损失
for epoch in range(EPOCH):
    for step, (batch_x, batch_y) in enumerate(loader):
        for net, opt,l_his in zip(nets, optimizers, loss_his):
            output = net(batch_x) # get output for every net
            loss = loss_func(output, batch_y) # compute loss for every net
            opt.zero_grad() # clear gradients for next train
            loss.backward() # backpropagation, compute gradients
            opt.step() # apply gradients
            l_his.append(loss.data.numpy()) # loss recoder
labels = ['SGD', 'Momentum', 'RMSprop', 'Adam']
# 6)可视化结果。

for i, l_his in enumerate(loss_his):
    plt.plot(l_his, label=labels[i])
plt.legend(loc='best')
plt.xlabel('Steps')
plt.ylabel('Loss')
plt.ylim((0, 0.2))
plt.show()

4 PyTorch数据处理工具箱

  • 简单介绍PyTorch相关的数据处理工具箱。
  • utils.data简介。
  • torchvision简介。
  • tensorboardX简介及实例。

4.1 数据处理工具箱概述

  1. torch.utils.data工具包包括以下4个类。

1)Dataset:是一个抽象类,其他数据集需要继承这个类,并且覆写其中的两个方法
(getitem_、len)。

2)DataLoader:定义一个新的迭代器,实现批量(batch)读取,打乱数据
(shuffle)并提供并行加速等功能。

3)random_split:把数据集随机拆分为给定长度的非重叠的新数据集。

4)*sampler:多种采样函数。

  1. torchvision包括4个类,各类的主要功能如下。

1)datasets:提供常用的数据集加载,设计上都是继承自torch.utils.data.Dataset,主要
包括MMIST、CIFAR10/100、ImageNet和COCO等。

2)models:提供深度学习中各种经典的网络结构以及训练好的模型(如果选择
pretrained=True),包括AlexNet、VGG系列、ResNet系列、Inception系列等。

3)transforms:常用的数据预处理操作,主要包括对Tensor及PIL Image对象的操作。

4)utils:含两个函数,一个是make_grid,它能将多张图片拼接在一个网格中;另一 个是save_img,它能将Tensor保存成图片。

4.2 utils.data简介

utils.data包括Dataset和DataLoader。torch.utils.data.Dataset为抽象类。自定义数据集需 要继承这个类,并实现两个函数,一个是__len__,另一个是__getitem__,前者提供数据 的大小(size),后者通过给定索引获取数据和标签。__getitem__一次只能获取一个数 据,所以需要通过torch.utils.data.DataLoader来定义一个新的迭代器,实现batch读取。首 先我们来定义一个简单的数据集,然后通过具体使用Dataset及DataLoader,给读者一个直 观的认识。

import torch
from torch.utils import data 
import numpy as np

# 2)定义获取数据集的类
class TestDataset(data.Dataset):#继承Dataset 
    def __init__(self):
        self.Data=np.asarray([[1,2],[3,4],[2,1],[3,4],[4,5]])#一些由2维向量表示的数据集 self.Label=np.asarray([0,1,0,1,2])#这是数据集对应的标签
    def __getitem__(self, index): #把numpy转换为Tensor
        txt=torch.from_numpy(self.Data[index]) 
        label=torch.tensor(self.Label[index]) 
        return txt,label
    def __len__(self):
        return len(self.Data)
# 3)获取数据集中数据
Test=TestDataset()
print(Test[2]) #相当于调用__getitem__(2) print(Test.__len__())
#输出:
#(tensor([2, 1]), tensor(0)) #5

以上数据以tuple返回,每次只返回一个样本。实际上,Dateset只负责数据的抽取,调 用一次__getitem__只返回一个样本。如果希望批量处理(batch),还要同时进行shuffle和 并行加速等操作,可选择DataLoader。DataLoader的格式为:

data.DataLoader( dataset,
                batch_size=1,
                shuffle=False,
                sampler=None,
                batch_sampler=None,
                num_workers=0,
                collate_fn=<function default_collate at 0x7f108ee01620>,
                pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None,
                )
主要参数说明:
·dataset:加载的数据集。
·batch_size:批大小。
·shuffle:是否将数据打乱。
·sampler:样本抽样。
·num_workers:使用多进程加载的进程数,0代表不使用多进程。
·collate_fn:如何将多个样本数据拼接成一个batch,一般使用默认的拼接方式即可。
·pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快 一些。
·drop_last:dataset中的数据个数可能不是batch_size的整数倍,drop_last为True会将多 出来不足一个batch的数据丢弃。
test_loader = data.DataLoader(Test,batch_size=2,shuffle=False,num_workers=2) 
for i,traindata in enumerate(test_loader):
   print('i:',i)
   Data,Label=traindata
   print('data:',Data)
   print('Label:',Label)
dataiter=iter(test_loader)
imgs,labels=next(dataiter)

一般用data.Dataset处理同一个目录下的数据。如果数据在不同目录下,因为不同的目

录代表不同类别(这种情况比较普遍),使用data.Dataset来处理就很不方便。不过,使用 PyTorch另一种可视化数据处理工具(即torchvision)就非常方便,不但可以自动获取标 签,还提供很多数据预处理、数据增强等转换函数。

4.3 torchvision简介

1 transforms

transforms提供了对PIL Image对象和Tensor对象的常用操作。
1)对PIL Image的常见操作如下。
·Scale/Resize:调整尺寸,长宽比保持不变。
·CenterCrop、RandomCrop、RandomSizedCrop:裁剪图片,CenterCrop和 RandomCrop在crop时是固定size,RandomResizedCrop则是random size的crop。
·Pad:填充。 
·ToTensor:把一个取值范围是[0,255]的PIL.Image转换成Tensor。形状为(H,W,C)的
Numpy.ndarray转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloatTensor。 ·RandomHorizontalFlip:图像随机水平翻转,翻转概率为0.5。 
·RandomVerticalFlip:图像随机垂直翻转。 ·ColorJitter:修改亮度、对比度和饱和度。
2)对Tensor的常见操作如下。
·Normalize:标准化,即,减均值,除以标准差。
·ToPILImage:将Tensor转为PIL Image。

如果要对数据集进行多个操作,可通过Compose将这些操作像管道一样拼接起来,类 似于nn.Sequential。以下为示例代码:


transforms.Compose([
#将给定的 PIL.Image 进行中心切割,得到给定的 size,
#size 可以是 tuple,(target_height, target_width)。
#size 也可以是一个 Integer,在这种情况下,切出来的图片形状是正方形。 
transforms.CenterCrop(10),
#切割中心点的位置随机选取
transforms.RandomCrop(20, padding=0),
#把一个取值范围是 [0, 255] 的 PIL.Image 或者 shape 为 (H, W, C) 的 numpy.ndarray, #转换为形状为 (C, H, W),取值范围是 [0, 1] 的 torch.FloatTensor 
transforms.ToTensor(),
#规范化到[-1,1]
transforms.Normalize(mean = (0.5, 0.5, 0.5), std = (0.5, 0.5, 0.5))
])

还可以自己定义一个Python Lambda表达式,如将每个像素值加10,可表示为: transforms.Lambda(lambda x:x.add(10))。

官网:https://PyTorch.org/docs/stable/torchvision/transforms.html。
2 ImageFolder
当文件依据标签处于不同文件下时。可以利用torchvision.datasets.ImageFolder来直接构造出dataset,代码如下:

loader = datasets.ImageFolder(path)
loader = data.DataLoader(dataset)

ImageFolder会将目录中的文件夹名自动转化成序列,当DataLoader载入时,标签自动 就是整数序列了。
下面我们利用ImageFolder读取不同目录下的图片数据,然后使用transforms进行图像 预处理,预处理有多个,我们用compose把这些操作拼接在一起。然后使用DataLoader加 载。
对处理后的数据用torchvision.utils中的save_image保存为一个png格式文件,然后用 Image.open打开该png文件,详细代码如下:

import torch
from torchvision import transforms,utils,datasets
import matplotlib.pyplot as plt

my_trans = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor()
])
train_data = datasets.ImageFolder('./data/torchvision_data',transforms=my_trans)
train_loader = utils.data.DataLoader(train_data,batch_size = 8,shuffle=True)
for i_batch, img in enumerate(train_loader):
    if i_batch == 0:
        print(img[1])
        fig = plt.figure()
        grid = utils.make_grid(img[0])  # 将多张图片拼接在一个网格中
        plt.imshow(grid.numpy().transpose((1, 2, 0)))
        plt.show()
        utils.save_image(grid,'test01.png')
        break

from PIL import Image
Image.open('test01.png')

4.4 可视化工具

4.4.1 tensorboardX简介

from tensorboardX import SummaryWriter
from tensorboardx import SummaryWriter
writer = SummaryWriter(log_dir = 'logs') 
SummaryWriter(log_dir=None, comment='', **kwargs)
#其中comment在文件命名加上comment后缀
# 如果不写log_dir,系统将在当前目录创建一个runs的目录。
writer.add_xxX()  
2)调用相应的API接口,接口一般格式为:
# add_xxx(tag-name, object, iteration-number) #即add_xxx(标签,记录的对象,迭代次数)
writer.close()

## 3)启动tensorboard服务:cd到logs目录所在的同级目录,在命令行输入如下命令,
# logdir等式右边可以是相对路 径或绝对路径。

# tensorboard --logdir=logs --port 6006 #如果是Windows环境,要注意路径解析,如
#tensorboard --logdir=r'D:\myboard\test\logs' --port 6006

# 4)web展示。在浏览器输入: http://服务器IP或名称:6006 #如果是本机,服务器名称可以使用localhost
https://github.com/lanpa/tensorboardX。

2 用tensorboardX可视化神经网络

'''用tensorboardX可视化神经网络'''
# (1)导入需要的模块
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from tensboardX import SummaryWriter

# (2)构建神经网络
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)
        self.bn = nn.BatchNorm2d(20)
    def forward(self, x):
        x = F.max_pool2d(self.conv1(x), 2)
        x = F.relu(x) + F.relu(-x)
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = self.bn(x)
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        x = F.softmax(x, dim=1)
        return x

# (3)把模型保存为graph
#定义输入
input = torch.rand(32, 1, 28, 28)
#实例化神经网络
model = Net()
out = model(input)
print(out.shape)
#将model保存为graph
with SummaryWriter(log_dir='logs',comment='Net') as w:
     w.add_graph(model, (input, ))




3 用tensorboardX可视化损失值
可视化损失值,需要使用add_scalar函数,这里利用一层全连接神经网络,训练一元
二次函数的参数。

import torch
import numpy as np
import torch.nn as nn
from tensboardX import SummaryWriter

input_size=1
output_size=1
learning_rate = 0.0001
num_epoches = 1000
dtype = torch.FloatTensor
writer = SummaryWriter(log_dir='logs',comment='Linear')
np.random.seed(100)
x_train = np.linspace(-1, 1, 100).reshape(100,1)
y_train = 3*np.power(x_train, 2) +2+ 0.2*np.random.rand(x_train.size).reshape(100,1)
model = nn.Linear(input_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for epoch in range(num_epoches):
    inputs = torch.from_numpy(x_train).type(dtype)
    targets = torch.from_numpy(y_train).type(dtype)
    output = model(inputs)
    loss = criterion(output, targets)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    # 保存loss的数据与epoch数值 
    writer.add_scalar('训练损失值', loss, epoch)

4 用tensorboardX可视化特征图

import torchvision.utils as vutils
from tensboardX import SummaryWriter

writer = SummaryWriter(log_dir='logs',comment='feature map')
img_grid = vutils.make_grid(x, normalize=True, scale_each=True, nrow=2)
net.eval()
for name, layer in net._modules.items():
    # 为fc层预处理x
    x = x.view(x.size(0), -1) if "fc" in name else x
    print(x.size())
    x = layer(x)
    print(f'{name}')
# 查看卷积层的特征图
    if 'layer' in name or 'conv' in name:
        x1 = x.transpose(0, 1) # C,B, H, W ---> B,C, H, W
        img_grid = vutils.make_grid(x1, normalize=True, scale_each=True, nrow=4) # normalize进行归一化处理 
        writer.add_image(f'{name}_feature_maps', img_grid, global_step=0)

5 机器学习

  1. 选择模型及损失函数
二分类、单标签   有sigmoid  nn.BCELoss
二分类、单标签   无sigmoid  nn.BCEWithLogistsLoss

二分类、多标签   无激活函数  nn.SoftMarginLoss(target 1/-1)

多分类、单标签   无softmax  nn.CrossEntropyLoss(target 为one_hot)
多分类、单标签   有softmax  nn.NLLLoss

多分类、多标签   无激活函数  nn.MultiLabelSoftMarginLoss

  1. 评估及优化模型
·留出法(Holdout):留出法的步骤相对简单,直接将数据集划分为两个互斥的集 合,其中一个集合作为训练集,另一个作为测试集。在训练集上训练出模型后,用测试集 来评估测试误差,作为泛化误差的估计。使用留出法,还可以优化出一种更好的方法,就 是把数据分成3部分:训练数据集、验证数据集、测试数据集。训练数据集用来训练模 型,验证数据集用来调优超参数,测试集则用来测试模型的泛化能力。数据量较大时可采 用这种方法。

·K折交叉验证:不重复地随机将训练数据集划分为k个,其中k-1个用于模型训练,剩 余的一个用于测试。

·重复的K折交叉验证:当数据量比较小,数据分布不很均匀时可以采用这种方法。

6 视觉处理基础

  • ·卷积神经网络简介。
  • ·卷积定义。
  • ·卷积运算。
  • ·卷积层。
  • ·池化层。
  • ·现代经典网络架构。
  • ·实例:用TensorFlow实现一个卷积神经网络。
  1. LeNet-5模型

LeCun提出的LeNet,系统地提出了卷积层、池化层、全连 接层等概念.

LeNet-5模型结构为输入层-卷积层-池化层-卷积层-池化层-全连接层-全连接层-输出。

(2)模型特点 

·每个卷积层包含3个部分:卷积、池化和非线性激活函数。 

·使用卷积提取空间特征。 

·采用降采样(Subsample)的平均池化层(Average Pooling)。

·使用双曲正切(Tanh)的激活函数。 ·最后用MLP作为分类器。
  1. AlexNet模型

AlexNet,提出一些训练深度网络的重要方 法或技巧,如Dropout、ReLu、GPU、数据增强方法等

AlexNet为8层深度网络,其中5层卷积层和3层全连接层,不计LRN层和池化层。

·由5层卷积和3层全连接组成,输入图像为3通道224×224大小,网络规模远大于
LeNet。

·使用ReLU激活函数。

·使用Dropout,可以作为正则项防止过拟合,提升模型鲁棒性。 

·具备一些很好的训练技巧,包括数据增广、学习率策略、Weight Decay等。
  1. VGG模型
VGG可以看成是加深版本的AlexNet.都是 Conv Layer+FC layer,在当时看来这是一个非常深的网络了,层数高达1619层。
  1. GoogleNet模型
GG是增加网络的深度,但深度达到一个程度时,可能就成为瓶颈。GoogLeNet则从 另一个维度来增加网络能力,每单元有许多层并行计算,让网络更宽了。

模型特点
1)引入Inception结构,这是一种网中网(Network In Network)的结构。 通过网络的水平排布,可以用较浅的网络得到较好的模型能力,并进行多特征融合,
同时更容易训练。另外,为了减少计算量,使用了1×1卷积来先对特征通道进行降维。

2)采用全局平均池化层。
将后面的全连接层全部替换为简单的全局平均池化,在最后参数会变得更少。GoogleNet移除全连接层,但并不会影响到结果的精度,在ImageNet中实现93.3%的精 度,而且要比VGG还快。
  1. ResNet模型
模型特点:

·层数非常深,已经超过百层。
  
·引入残差单元来解决退化问题。
  1. 显示参数:

import collections
import torch
import torch.nn as nn
def paras_summary(input_size, model):
    def register_hook(module):
        def hook(module, input, output):
            class_name = str(module.__class__).split('.')[-1].split("'")[0]
            module_idx = len(summary)
            m_key = '%s-%i' % (class_name, module_idx+1)
            summary[m_key] = collections.OrderedDict()
            summary[m_key]['input_shape'] = list(input[0].size())
            summary[m_key]['input_shape'][0] = -1
            summary[m_key]['output_shape'] = list(output.size())
            summary[m_key]['output_shape'][0] = -1
            params = 0
            if hasattr(module, 'weight'):
                params += torch.prod(torch.LongTensor(list(module.weight.size())))
                if module.weight.requires_grad:
                    summary[m_key]['trainable'] = True
                else:
                    summary[m_key]['trainable'] = False
            if hasattr(module, 'bias'):
                params += torch.prod(torch.LongTensor(list(module.bias.size())))
            summary[m_key]['nb_params'] = params
        if not isinstance(module, nn.Sequential) and \
                not isinstance(module, nn.ModuleList) and \
                not (module == model):
            hooks.append(module.register_forward_hook(hook))
    # check if there are multiple inputs to the network
    if isinstance(input_size[0], (list, tuple)):
        x = [torch.rand(1,*in_size) for in_size in input_size]
    else:
        x = torch.rand(1,*input_size)
    # create properties
    summary = collections.OrderedDict()
    hooks = []
    # register hook
    model.apply(register_hook)
    # make a forward pass
    model(x)
    # remove these hooks
    for h in hooks:
        h.remove()
    return summary


import torch.nn as nn
import torch.nn.functional as F
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 5)
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(16, 36, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.pool2 = nn.MaxPool2d(2, 2) #使用全局平均池化层
        self.aap=nn.AdaptiveAvgPool2d(1)
        self.fc3 = nn.Linear(36, 10)
    def forward(self, x):
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))
        x = self.aap(x)
        x = x.view(x.shape[0], -1)
        x = self.fc3(x)
        return x
net = Net()
net=net.to(device)

if __name__=='__main__':
    net = Net() #输入格式为[c,h,w]即通道数,图像的高级宽度
    input_size=[3,32,32]
    pa = paras_summary(input_size,net)
    for i ,j in zip(pa.keys(),pa.values()):
        print(f'k: {i},v:{j}')
  1. 集成效果

mlps=[net1.to(device),net2.to(device),net3.to(device)] 
optimizer=torch.optim.Adam([{"params":mlp.parameters()} for mlp in mlps],lr=LR)
loss_function=nn.CrossEntropyLoss()

for ep in range(EPOCHES):
    for img,label in trainloader:
        img,label=img.to(device),label.to(device) optimizer.zero_grad()#10个网络清除梯度
        for mlp in mlps:
            mlp.train()
            out=mlp(img) loss=loss_function(out,label) loss.backward()#网络获得的梯度
        optimizer.step()
    pre=[]
    vote_correct=0
    mlps_correct=[0 for i in range(len(mlps))]
    for img,label in testloader:
        img,label=img.to(device),label.to(device) 
        for i, mlp in enumerate( mlps):
            mlp.eval() 
            out=mlp(img)
            _,prediction=torch.max(out,1) #按行取最大值 pre_num=prediction.cpu().numpy() mlps_correct[i]+=(pre_num==label.cpu().numpy()).sum()
            
            pre.append(pre_num)
        arr=np.array(pre)
        pre.clear()
        result=[Counter(arr[:,i]).most_common(1)[0][0] for i in range(BATCHSIZE)] 
        vote_correct+=(result == label.cpu().numpy()).sum()
    print("epoch:" + str(ep)+"集成模型的正确率"+str(vote_correct/len(testloader)))
    for idx, coreect in enumerate( mlps_correct): 
        print("模型"+str(idx)+"的正确率为:"+str(coreect/len(testloader)))

6 相关的数学知识

  1. 标量Scalar:单独的一个数,维数为0。
  2. 向量Vector:一列按顺序排列的元素,维数为1。
  3. 矩阵Matrix:二维数组结构,用大写字母来表示。
  4. 张量Tensor: 数组的维度超过了二维的高维数组。
import numpy as np
scalar = np.array(3)
vector = np.array([1,2,3])
matrix = np.arange(9).reshape(3,3)
tensor = np.arange(24).reshape(2,3,4)
print(' shape ',' ndim ')
print(scalar.shape,'       ',scalar.ndim)
print(vector.shape,'     ',vector.ndim)
print(matrix.shape,'   ',matrix.ndim)
print(tensor.shape,'',tensor.ndim)
'''
shape    ndim 
()         0
(3,)       1
(3, 3)     2
(2, 3, 4)  3
'''
  1. 矩阵的转置
a = np.random.randint(0,10,[3,4])
c = np.zeros_like(a.T)
print('a:\n',a)
print('c: \n',c)
for i in range(c.shape[0]):
    for j in range(c.shape[1]):
        c[i,j]= a[j,i]
print('a.T:  \n',c)
'''
a:
 [[4 1 0 5]
 [2 8 5 6]
 [9 9 6 5]]
c: 
 [[0 0 0]
 [0 0 0]
 [0 0 0]
 [0 0 0]]
a.T:  
 [[4 2 9]
 [1 8 9]
 [0 5 6]
 [5 6 5]]

'''
  1. 矩阵加减乘
import numpy as np
a = np.random.randint(0,10,[3,4])
b = np.random.randint(0,10,[5,3])
def add(a,b):
    assert a.shape==b.shape
    h,w = a.shape
    c = np.zeros([h,w])
    for i in range(h):
        for j in range(w):
            c[i,j] = a[i,j]+b[i,j]
    return c

def sub(a,b):
    assert a.shape==b.shape
    h,w = a.shape
    c = np.zeros([h,w])
    for i in range(h):
        for j in range(w):
            c[i,j] = a[i,j]-b[i,j]
    return c

def mal(a,b):
    assert a.shape==b.shape
    h,w = a.shape
    c = np.zeros([h,w])
    for i in range(h):
        for j in range(w):
            c[i,j] = a[i,j]*b[i,j]
    return c

def matrix(a,b):
    assert a.shape[1]==b.shape[0]
    h,w = a.shape[0],b.shape[1]
    c = np.zeros([h,w])
    for i in range(h):
        for j in range(w):
            for k in range(a.shape[1]):
                c[i,j] += a[i,k]*b[k,j]
    return c

if __name__ =='__main__':
    a = np.random.randint(0,10,[3,4])
    b = np.random.randint(0,10,a.shape)
    print('a:\n',a)
    print('b:\n',b)
    print('a+b:\n',add(a,b))
    print('a-b:\n',sub(a,b))
    print('a·b:\n',mal(a,b))
    print('a*b:\n',matrix(a,b.T))
'''
a:
 [[1 0 1 8]
 [3 6 1 8]
 [4 9 0 8]]
b:
 [[3 3 9 7]
 [5 1 6 6]
 [8 6 3 9]]
a+b:
 [[ 4.  3. 10. 15.]
 [ 8.  7.  7. 14.]
 [12. 15.  3. 17.]]
a-b:
 [[-2. -3. -8.  1.]
 [-2.  5. -5.  2.]
 [-4.  3. -3. -1.]]
a·b:
 [[ 3.  0.  9. 56.]
 [15.  6.  6. 48.]
 [32. 54.  0. 72.]]
a*b:
 [[ 68.  59.  83.]
 [ 92.  75. 135.]
 [ 95.  77. 158.]]
 
'''
  1. 激活函数
import numpy as np
def sigmoid(x):
    return 1./(1.+np.exp(-x))

def tanh(x):
    return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))

def ReLU(x):
    return np.maximum(0,x)

def LeakReLU(x,a):
    return np.where(x>=0,np.maximum(0,x),a*x)

if __name__ =='__main__':
    np.random.seed(1024)
    x = np.random.randn(6)
    print(sigmoid(x))
    print(tanh(x))
    print(ReLU(x))
    print(LeakReLU(x,a=0.1))
'''
[0.89325684 0.5628277  0.81064072 0.63858774 0.61259269 0.30803255]
[ 0.97184215  0.24740444  0.89651607  0.51480076  0.42863533 -0.66922239]
[2.12444863 0.25264613 1.45417876 0.56923979 0.45822365 0.        ]
[ 2.12444863  0.25264613  1.45417876  0.56923979  0.45822365 -0.08093334]
'''

(1) 自动求导

from torch import nn
import torch
import torch.nn.functional as F
from torch.autograd import Variable

if __name__=='__main__':
    batch_n = 100
    input_data = 1000
    hidden_layer = 100
    output_data = 10
    epoch_n = 10001
    learning_rate = 1e-6

    x = Variable(torch.randn(batch_n,input_data),requires_grad=False)
    y = Variable(torch.randn(hidden_layer,output_data),requires_grad=False)
    w1 = Variable(torch.randn(input_data,hidden_layer),requires_grad=True)
    w2 = Variable(torch.randn(hidden_layer,output_data),requires_grad=True)

    for epoch in range(epoch_n):
        y_pred = x.mm(w1).clamp(min=0).mm(w2)
        loss = (y_pred-y).pow(2).sum()
        if epoch%500==0:
            print('Epoch:{}, Loss:{:.4f}'.format(epoch,loss.data))

        loss.backward()
        w1.data -= learning_rate*w1.grad.data
        w2.data -= learning_rate*w2.grad.data

        w1.grad.data.zero_()
        w2.grad.data.zero_()
'''
Epoch:0, Loss:46297568.0000
Epoch:500, Loss:2064.5229
Epoch:1000, Loss:332.0856
Epoch:1500, Loss:92.1883
Epoch:2000, Loss:34.2231
Epoch:2500, Loss:15.4424
Epoch:3000, Loss:8.0198
Epoch:3500, Loss:4.5941
Epoch:4000, Loss:2.8243
Epoch:4500, Loss:1.8257
Epoch:5000, Loss:1.2236
Epoch:5500, Loss:0.8433
Epoch:6000, Loss:0.5939
Epoch:6500, Loss:0.4257
Epoch:7000, Loss:0.3103
Epoch:7500, Loss:0.2297
Epoch:8000, Loss:0.1725
Epoch:8500, Loss:0.1313
Epoch:9000, Loss:0.1013
Epoch:9500, Loss:0.0791
Epoch:10000, Loss:0.0625

Process finished with exit code 0

'''

(2) 自定义传播函数

from torch import nn
import torch
import torch.nn.functional as F
from torch.autograd import Variable

class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()

    def forward(self, input, w1, w2):
        x = torch.mm(input ,w1)
        x = torch.clamp(x,min=0)
        x = torch.mm(x,w2)
        return x


if __name__=='__main__':
    batch_n = 100
    input_data = 1000
    hidden_layer = 100
    output_data = 10
    epoch_n = 10001
    learning_rate = 1e-6

    x = Variable(torch.randn(batch_n,input_data),requires_grad=False)
    y = Variable(torch.randn(hidden_layer,output_data),requires_grad=False)
    w1 = Variable(torch.randn(input_data,hidden_layer),requires_grad=True)
    w2 = Variable(torch.randn(hidden_layer,output_data),requires_grad=True)

    for epoch in range(epoch_n):
        y_pred = Model()(x,w1,w2)
        loss = (y_pred-y).pow(2).sum()
        if epoch%500==0:
            print('Epoch:{}, Loss:{:.4f}'.format(epoch,loss.data))

        loss.backward()
        w1.data -= learning_rate*w1.grad.data
        w2.data -= learning_rate*w2.grad.data

        w1.grad.data.zero_()
        w2.grad.data.zero_()
'''
Epoch:0, Loss:45101876.0000
Epoch:500, Loss:2105.3201
Epoch:1000, Loss:351.6454
Epoch:1500, Loss:115.2642
Epoch:2000, Loss:53.0504
Epoch:2500, Loss:30.2131
Epoch:3000, Loss:19.8175
Epoch:3500, Loss:14.4892
Epoch:4000, Loss:11.3584
Epoch:4500, Loss:9.3450
Epoch:5000, Loss:7.9523
Epoch:5500, Loss:6.9340
Epoch:6000, Loss:6.1545
Epoch:6500, Loss:5.5373
Epoch:7000, Loss:5.0327
Epoch:7500, Loss:4.6104
Epoch:8000, Loss:4.2507
Epoch:8500, Loss:3.9397
Epoch:9000, Loss:3.6656
Epoch:9500, Loss:3.4207
Epoch:10000, Loss:3.1994

Process finished with exit code 0


'''

(3) optimizer

from torch import nn
import torch
import torch.nn.functional as F
from torch.autograd import Variable

class Model(torch.nn.Module):
    def __init__(self,input_data,hidden_layer,output_data):
        super(Model, self).__init__()
        self.model = torch.nn.Sequential(nn.Linear(input_data,hidden_layer),
                                      nn.ReLU(),
                                      nn.Linear(hidden_layer,output_data))
    def forward(self, x):
        x = self.model(x)
        return x

if __name__=='__main__':
    batch_n = 100
    input_data = 1000
    hidden_layer = 100
    output_data = 10
    epoch_n = 1001
    learning_rate = 1e-6

    x = Variable(torch.randn(batch_n,input_data),requires_grad=False)
    y = Variable(torch.randn(hidden_layer,output_data),requires_grad=False)
    model = Model(input_data,hidden_layer,output_data)
    loss_fn = torch.nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(),lr= learning_rate)


    for epoch in range(epoch_n):
        y_pred = model(x)
        loss = loss_fn (y_pred,y)
        if epoch%500==0:
            print('Epoch:{}, Loss:{:.4f}'.format(epoch,loss.data))

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()


'''
Epoch:0, Loss:1.1027
Epoch:500, Loss:0.9990
Epoch:1000, Loss:0.9066

Process finished with exit code 0
'''

(4) No optimizer

from torch import nn
import torch
import torch.nn.functional as F
from torch.autograd import Variable

class Model(torch.nn.Module):
    def __init__(self,input_data,hidden_layer,output_data):
        super(Model, self).__init__()
        self.model = torch.nn.Sequential(nn.Linear(input_data,hidden_layer),
                                      nn.ReLU(),
                                      nn.Linear(hidden_layer,output_data))
    def forward(self, x):
        x = self.model(x)
        return x

if __name__=='__main__':
    batch_n = 100
    input_data = 1000
    hidden_layer = 100
    output_data = 10
    epoch_n = 1001
    learning_rate = 1e-6

    x = Variable(torch.randn(batch_n,input_data),requires_grad=False)
    y = Variable(torch.randn(hidden_layer,output_data),requires_grad=False)
    model = Model(input_data,hidden_layer,output_data)
    loss_fn = torch.nn.MSELoss()

    for epoch in range(epoch_n):
        y_pred = model(x)
        loss = loss_fn (y_pred,y)
        if epoch%500==0:
            print('Epoch:{}, Loss:{:.4f}'.format(epoch,loss.data))

        model.zero_grad()
        loss.backward()
        for param in model.parameters():
            param.data -= learning_rate * param.grad.data
'''
Epoch:0, Loss:1.0688
Epoch:500, Loss:1.0684
Epoch:1000, Loss:1.0680

Process finished with exit code 0
'''

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值