gcan pytorch实现_[六点]莫烦Pytorch代码笔记

莫烦Pytorch代码笔记

pytorch已经是非常流行的深度学习框架了,它的动态计算图特性在NLP领域是非常有用的,如果不会tensorflow或缺乏Deep Learning相关基础知识,直接看莫烦视频和代码是有一些困难,所以对代码做了部分解释和理解,希望能帮助到你。

莫烦Github代码

网上流传的pytorch中文文档和最近的英文文档隔了一个大版本,新版本完全可以用Tensor代替Variable,所以推荐阅读官方文档

Pytorch官方文档

公众号:六点一刻研习室

(兴趣使然,不定期写些有用的东西,没有质量保证)

目录

201 torch和numpy

202 Variable

203 激活函数

301 回归

302 分类

303 快速搭建神经网络

304 保存与重新载入

305 批训练(batch_train)

306 优化器

401 CNN

402 RNN分类器

403 RNN回归

404 自动编码器

405 Deep Q-learning Network(DQN)

406 GAN

501 pytorch的动态计算图

502 GPU加速

503 Dropout

504 批标准化batch_normalization

201 torch和numpy

numpy与torch两种类型使用from_numpy和numpy两个方法可以很方便的相互转换。

当然也可以用列表初始化torch

numpy具有abs,mean,abs等对每个元素的操作,torch都有相同名称的函数方法。

torch有mm方法来实现二维张量的矩阵乘法,torch的dot方法不同于矩阵点乘,torch会先自动展成一维张量在进行向量点乘,得到的结果等于张量所有元素的平方和。

代码依次如下:

np_data = np.arange(6).reshape((2, 3))

torch_data = torch.from_numpy(np_data)

tensor2array = torch_data.numpy()

data = [[1,2], [3,4]]

tensor = torch.FloatTensor(data)

torch.abs(tensor)

torch.sin(tensor)

torch.mean(tensor)

torch.mm(tensor, tensor)

tensor.dot(tensor)

202 Variable

莫烦老师使用的torch版本为 0.1.11,当前版本Tersor和Variable的API基本一致,只有部分隐变量有区别,所以直接将代码的Variable替换为Tensor应该是可以正常运行的的。

引入

初始化

按照计算图生成结果变量

使用backward函数回传误差

查看梯度

variable与numpy的转换

from torch.autograd import Variable

#from torch import Tensor

tensor = torch.FloatTensor([[1,2],[3,4]]) # 通过Tensor来对Varible初始化

variable = Variable(tensor, requires_grad=True) #注意require_grad的传递规律,只要所依赖的张量中一个为True则所有的都为True

v_out = torch.mean(variable*variable) # x^2 = 7.5

v_out.backward() # backpropagation from v_out

print(variable.grad)

variable.data.numpy() # numpy format,与tensor不同,variable需要使用属性data,返回一个tensor类再numpify,而新版本使用使用tensor即可,算是优化

203 激活函数

常用的激活函数有sigmoid,类sigmoid的tanh(大多数情况下优于sigmoid),分段函数ReLu(保证了神经网络比较深时发生的梯度消失和梯度弥散问题),softplus(是光滑版的ReLu)。

导入库

生成线性数据

torch的函数方法

torch.nn.functional的函数方法

import torch

import torch.nn.functional as F

from torch.autograd import Variable

x = torch.linspace(-5, 5, 200) # x data (tensor), shape=(100, 1)

x = Variable(x)

y_relu = torch.relu(x).data.numpy()

y_sigmoid = torch.sigmoid(x).data.numpy()

y_tanh = torch.tanh(x).data.numpy()

y_softplus = F.softplus(x).data.numpy() # there's no softplus in torch

y_softmax = torch.softmax(x, dim=0).data.numpy() softmax is a special kind of activation function, it is about probability

301 回归

这一部分的代码莫烦修改过,基本上就没出现Variable了,因为Tensor类已经有backward函数。

导入库

初始化x、y数据

构建只有一个隐含层的神经网络类,需要继承Net(torch.nn.Module),super父类时不用传任何参数

初始化时定义层与层间的连接关系,代码使用了两个nn的线性全连接

定义前向传播的计算方法,此时可以选择隐层的激活函数

神经网络实例化

选择优化方式和损失函数(backward负责计算梯度,根据梯度可以选择SGD等不同的优化方法)

循环更新网络参数

import torch

import torch.nn.functional as F

import matplotlib.pyplot as plt

x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # x data (tensor), shape=(100, 1)

y = x.pow(2) + 0.2*torch.rand(x.size())

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) # hidden layer

self.predict = torch.nn.Linear(n_hidden, n_output) # output layer

def forward(self, x):

x = F.relu(self.hidden(x)) # activation function for hidden layer

x = self.predict(x) # linear output

return x

net = Net(n_feature=1, n_hidden=10, n_output=1) # define the network

optimizer = torch.optim.SGD(net.parameters(), lr=0.2)

loss_func = torch.nn.MSELoss() # this is for regression mean squared loss

for t in range(200):

prediction = net(x) # input x and predict based on x

loss = loss_func(prediction, y) # must be (1. nn output, 2. target)

optimizer.zero_grad() # clear gradients for next train

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

302 分类

导入库

初始化0、1两类数据并进行拼接(torch的很多操作与numpy类似)

构建一个隐层的神经网络来进行分类,与回归使用的神经网络结构完全相似

初始化一个神经网络,并选择优化方法和损失函数(分类问题用CrossEntropyLoss)

循环训练(与回归代码完全相同)

import torch

import torch.nn.functional as F

import matplotlib.pyplot as plt

n_data = torch.ones(100, 2)

x0 = torch.normal(2*n_data, 1) # class0 x data (tensor), shape=(100, 2)

y0 = torch.zeros(100) # class0 y data (tensor), shape=(100, 1)

x1 = torch.normal(-2*n_data, 1) # class1 x data (tensor), shape=(100, 2)

y1 = torch.ones(100) # class1 y data (tensor), shape=(100, 1)

x = torch.cat((x0, x1), 0).type(torch.FloatTensor) # shape (200, 2) FloatTensor = 32-bit floating

y = torch.cat((y0, y1), ).type(torch.LongTensor) # shape (200,) LongTensor = 64-bit integer

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) # hidden layer

self.out = torch.nn.Linear(n_hidden, n_output) # output layer

def forward(self, x):

x = F.relu(self.hidden(x)) # activation function for hidden layer

x = self.out(x)

return x

net = Net(n_feature=2, n_hidden=10, n_output=2) # define the network

optimizer = torch.optim.SGD(net.parameters(), lr=0.02)

loss_func = torch.nn.CrossEntropyLoss() # the target label is NOT an one-hotted

for t in range(100):

out = net(x) # input x and predict based on x

loss = loss_func(out, y) # must be (1. nn output, 2. target), the target label is NOT one-hotted

optimizer.zero_grad() # clear gradients for next train

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

303 快速搭建神经网络

方法一:定义类(层级在init定义,激活函数在forward定义)

导入库(torch,F)

定义只有一层的神经网络类(结构与上两节完全相同)

初始化隐层节点个数为10的神经网络

import torch

import torch.nn.functional as F

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) # hidden layer

self.predict = torch.nn.Linear(n_hidden, n_output) # output layer

def forward(self, x):

x = F.relu(self.hidden(x)) # activation function for hidden layer

x = self.predict(x) # linear output

return x

net1 = Net(1, 10, 1)

方法二:使用Sequential函数快速搭建(层级和激活函数按顺序以此排放),但不能像方法一那样给层级人工命名

net2 = torch.nn.Sequential(

torch.nn.Linear(1, 10),

torch.nn.ReLU(),

torch.nn.Linear(10, 1)

)

304 保存与重新载入

导入库

制造一些假数据(squeeze和unsqueeze分别为降维和扩容)

定义神经网络、初始化并进行训练

import torch

x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # x data (tensor), shape=(100, 1)

y = x.pow(2) + 0.2*torch.rand(x.size()) # noisy y data (tensor), shape=(100, 1)

net1 = torch.nn.Sequential(

torch.nn.Linear(1, 10),

torch.nn.ReLU(),

torch.nn.Linear(10, 1)

)

optimizer = torch.optim.SGD(net1.parameters(), lr=0.5)

loss_func = torch.nn.MSELoss()

for t in range(100):

prediction = net1(x)

loss = loss_func(prediction, y)

optimizer.zero_grad()

loss.backward()

optimizer.step()

保存神经网络

框架和参数一起保存

只保存参数

torch.save(net1, 'net.pkl') # save entire net

torch.save(net1.state_dict(), 'net_params.pkl')

重新载入

直接载入

构建结构相同的神经网络,导入参数

net2 = torch.load('net.pkl')

net3 = torch.nn.Sequential(

torch.nn.Linear(1, 10),

torch.nn.ReLU(),

torch.nn.Linear(10, 1)

)

# copy net1's parameters into net3

net3.load_state_dict(torch.load('net_params.pkl'))

305 批训练(batch_train)

导入库(torch和Data)

固定随机批训练(shuffle)的种子,保证可以复现(reproducible)

设置批的大小

制造fake data和批训练的分发器

双重循环开始训练(大循环是epoch,循环是batch)

import torch

import torch.utils.data as Data

torch.manual_seed(1) # reproducible

BATCH_SIZE = 5

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

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

torch_dataset = Data.TensorDataset(x, y)

loader = Data.DataLoader(

dataset=torch_dataset, # torch TensorDataset format

batch_size=BATCH_SIZE, # mini batch size

shuffle=True, # random shuffle for training

num_workers=2, # subprocesses for loading data

)

for epoch in range(3): # train entire dataset 3 times

for step, (batch_x, batch_y) in enumerate(loader): # for each training step

# train your data...

306 优化器

导入库(torch,Data,F)

设置学习率、批大小、epoch次数

构建虚假数据集,y引入正态噪声

构造数据集和批训练分发器

构造神经网络类

选择不同的优化方式,e.g. SGD,Momentum,RMSprop,Adam

import torch

import torch.utils.data as Data

import torch.nn.functional as F

LR = 0.01

BATCH_SIZE = 32

EPOCH = 12

# fake dataset

x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)

y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))

# put dateset into torch dataset

torch_dataset = Data.TensorDataset(x, y)

loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2,)

# default network

class Net(torch.nn.Module):

def __init__(self):

super(Net, self).__init__()

self.hidden = torch.nn.Linear(1, 20) # hidden layer

self.predict = torch.nn.Linear(20, 1) # output layer

def forward(self, x):

x = F.relu(self.hidden(x)) # activation function for hidden layer

x = self.predict(x) # linear output

return x

show_batch()

net_SGD = Net()

net_Momentum = Net()

net_RMSprop = Net()

net_Adam = Net()

nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]

# different optimizers

opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)

opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)

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]

loss_func = torch.nn.MSELoss()

losses_his = [[], [], [], []] # record loss

# training

for epoch in range(EPOCH):

print('Epoch: ', epoch)

for step, (b_x, b_y) in enumerate(loader): # for each training step

for net, opt, l_his in zip(nets, optimizers, losses_his):

output = net(b_x) # get output for every net

loss = loss_func(output, b_y) # compute loss for every net

opt.zero_grad() # clear gradients for next train

loss.backward() # backpropagation, compute gradients

opt.step() # apply gradients

401 CNN

训练使用的数据集是MNIST识别手写文字0-9,文字标签的编码方式为one-hot编码。

导入库 (os,torch,nn,Data)

设置epoch、批大小、学习率等

使用torchvision.datasets下载数据集并制作批训练分发器,train_data有train_data和train_labels两个子属性,以前2000条数据作为测试集加速测试过程

定义CNN类(两层卷积层再全连接到10个节点表示数字,每层卷积后用ReLU激活,使用kernel_size为2的池化操作。)

初始化网络,定义优化器和损失函数

训练

import torch

import torch.nn as nn

import torch.utils.data as Data

import torchvision

# Hyper Parameters

EPOCH = 1 # train the training data n times, to save time, we just train 1 epoch

BATCH_SIZE = 50

LR = 0.001 # learning rate

DOWNLOAD_MNIST = False

train_data = torchvision.datasets.MNIST(

root='./mnist/',

train=True, # this is training data

transform=torchvision.transforms.ToTensor(), # Converts a PIL.Image or numpy.ndarray to

# torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]

download=DOWNLOAD_MNIST,

)

# Data Loader for easy mini-batch return in training, the image batch shape will be (50, 1, 28, 28)

train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)

# pick 2000 samples to speed up testing

test_data = torchvision.datasets.MNIST(root='./mnist/', train=False)

test_x = torch.unsqueeze(test_data.test_data, dim=1).type(torch.FloatTensor)[:2000]/255. # shape from (2000, 28, 28) to (2000, 1, 28, 28), value in range(0,1)

test_y = test_data.test_labels[:2000]

class CNN(nn.Module):

def __init__(self):

super(CNN, self).__init__()

self.conv1 = nn.Sequential( # input shape (1, 28, 28)

nn.Conv2d(

in_channels=1, # input height

out_channels=16, # n_filters

kernel_size=5, # filter size

stride=1, # filter movement/step

padding=2, # if want same width and length of this image after Conv2d, padding=(kernel_size-1)/2 if stride=1

), # output shape (16, 28, 28)

nn.ReLU(), # activation

nn.MaxPool2d(kernel_size=2), # choose max value in 2x2 area, output shape (16, 14, 14)

)

self.conv2 = nn.Sequential( # input shape (16, 14, 14)

nn.Conv2d(16, 32, 5, 1, 2), # output shape (32, 14, 14)

nn.ReLU(), # activation

nn.MaxPool2d(2), # output shape (32, 7, 7)

)

self.out = nn.Linear(32 * 7 * 7, 10) # fully connected layer, output 10 classes

def forward(self, x):

x = self.conv1(x)

x = self.conv2(x)

x = x.view(x.size(0), -1) # flatten the output of conv2 to (batch_size, 32 * 7 * 7)

output = self.out(x)

return output, x # return x for visualization

cnn = CNN()

optimizer = torch.optim.Adam(cnn.parameters(), lr=LR) # optimize all cnn parameters

loss_func = nn.CrossEntropyLoss() # the target label is not one-hotted

for epoch in range(EPOCH):

for step, (b_x, b_y) in enumerate(train_loader): # gives batch data, normalize x when iterate train_loader

output = cnn(b_x)[0] # cnn output

loss = loss_func(output, b_y) # cross entropy loss

optimizer.zero_grad() # clear gradients for this training step

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

# print 10 predictions from test data

test_output, _ = cnn(test_x[:10])

pred_y = torch.max(test_output, 1)[1].data.numpy()

print(pred_y, 'prediction number')

print(test_y[:10].numpy(), 'real number')

402 RNN分类器

仍对手写字体数据进行分类,由于序列较长,使用LSTM。

导入库(torch,nn,torchvision

设置超参数(每张图片输入n个step,n表示图片高度,每个step输入一行像素信息)

获取数据集并制作训练集分发器

定义RNN类

事例化RNN,并选择优化方法和损失函数

循环训练

import torch

from torch import nn

import torchvision.datasets as dsets

import torchvision.transforms as transforms

# Hyper Parameters

EPOCH = 1 # train the training data n times, to save time, we just train 1 epoch

BATCH_SIZE = 64

TIME_STEP = 28 # rnn time step / image height

INPUT_SIZE = 28 # rnn input size / image width

LR = 0.01 # learning rate

DOWNLOAD_MNIST = True # set to True if haven't download the data

train_data = dsets.MNIST(

root='./mnist/',

train=True, # this is training data

transform=transforms.ToTensor(), # Converts a PIL.Image or numpy.ndarray to

# torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]

download=DOWNLOAD_MNIST, # download it if you don't have it

)

train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)

# convert test data into Variable, pick 2000 samples to speed up testing

test_data = dsets.MNIST(root='./mnist/', train=False, transform=transforms.ToTensor())

test_x = test_data.test_data.type(torch.FloatTensor)[:2000]/255. # shape (2000, 28, 28) value in range(0,1)

test_y = test_data.test_labels.numpy()[:2000] # covert to numpy array

class RNN(nn.Module):

def __init__(self):

super(RNN, self).__init__()

self.rnn = nn.LSTM( # if use nn.RNN(), it hardly learns

input_size=INPUT_SIZE,

hidden_size=64, # rnn hidden unit

num_layers=1, # number of rnn layer

batch_first=True, # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)

)

self.out = nn.Linear(64, 10)

def forward(self, x):

# x shape (batch, time_step, input_size)

# r_out shape (batch, time_step, output_size)

# h_n shape (n_layers, batch, hidden_size)

# h_c shape (n_layers, batch, hidden_size)

r_out, (h_n, h_c) = self.rnn(x, None) # None represents zero initial hidden state

# choose r_out at the last time step

out = self.out(r_out[:, -1, :])

return out

rnn = RNN()

optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) # optimize all cnn parameters

loss_func = nn.CrossEntropyLoss() # the target label is not one-hotted

# training and testing

for epoch in range(EPOCH):

for step, (b_x, b_y) in enumerate(train_loader): # gives batch data

b_x = b_x.view(-1, 28, 28) # reshape x to (batch, time_step, input_size)

output = rnn(b_x) # rnn output

loss = loss_func(output, b_y) # cross entropy loss

optimizer.zero_grad() # clear gradients for this training step

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

403 RNN回归

使用RNN可以较好地根据原有的信息进行预测,适合于周期性函数的拟合和预测。

导入库(torch, nn, numpy)

设置超参数(TIME_STEP, INPUT_SIZE)

构造正余弦波数据

定义RNN类(使用普通RNN,隐层节点32,RNN输出最终隐含层状态和中间输出序列)

初始化RNN,定义优化方法和损失函数,指定初始状态为None

分段训练(每次训练1pi的长度,每次训练得到forward结果序列和forward后隐含层的状态,计算损失函数并反向传播进行优化)

import numpy as np

import torch

from torch import nn

# Hyper Parameters

TIME_STEP = 10 # rnn time step

INPUT_SIZE = 1 # rnn input size

LR = 0.02 # learning rate

# show data

steps = np.linspace(0, np.pi*2, 100, dtype=np.float32) # float32 for converting torch FloatTensor

x_np = np.sin(steps)

y_np = np.cos(steps)

class RNN(nn.Module):

def __init__(self):

super(RNN, self).__init__()

self.rnn = nn.RNN(

input_size=INPUT_SIZE,

hidden_size=32, # rnn hidden unit

num_layers=1, # number of rnn layer

batch_first=True, # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)

)

self.out = nn.Linear(32, 1)

def forward(self, x, h_state):

# x (batch, time_step, input_size)

# h_state (n_layers, batch, hidden_size)

# r_out (batch, time_step, hidden_size)

r_out, h_state = self.rnn(x, h_state)

outs = [] # save all predictions

for time_step in range(r_out.size(1)): # calculate output for each time step

outs.append(self.out(r_out[:, time_step, :]))

return torch.stack(outs, dim=1), h_state

class RNN(nn.Module):

def __init__(self):

super(RNN, self).__init__()

self.rnn = nn.RNN(

input_size=INPUT_SIZE,

hidden_size=32, # rnn hidden unit

num_layers=1, # number of rnn layer

batch_first=True, # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)

)

self.out = nn.Linear(32, 1)

def forward(self, x, h_state):

# x (batch, time_step, input_size)

# h_state (n_layers, batch, hidden_size)

# r_out (batch, time_step, hidden_size)

r_out, h_state = self.rnn(x, h_state)

outs = [] # save all predictions

for time_step in range(r_out.size(1)): # calculate output for each time step

outs.append(self.out(r_out[:, time_step, :]))

return torch.stack(outs, dim=1), h_state

rnn = RNN()

optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) # optimize all cnn parameters

loss_func = nn.MSELoss()

h_state = None # for initial hidden state

for step in range(100):

start, end = step * np.pi, (step+1)*np.pi # time range

# use sin predicts cos

steps = np.linspace(start, end, TIME_STEP, dtype=np.float32, endpoint=False) # float32 for converting torch FloatTensor

x_np = np.sin(steps)

y_np = np.cos(steps)

x = torch.from_numpy(x_np[np.newaxis, :, np.newaxis]) # shape (batch, time_step, input_size)

y = torch.from_numpy(y_np[np.newaxis, :, np.newaxis])

prediction, h_state = rnn(x, h_state) # rnn output

# !! next step is important !!

h_state = h_state.data # repack the hidden state, break the connection from last iteration

loss = loss_func(prediction, y) # calculate loss

optimizer.zero_grad() # clear gradients for this training step

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

404 自动编码器autoencoder

导入模块

设置超参数

下载数据集,并制作训练集的批训练分发器(自编码器是一种广义的无监督学习,没有标签数据,先通过encoder网络压缩成低维数据,再拓展成高维数据,目标是扩展后能与原始数据一致。这样训练得到的中间产物——低维数据,可以认为提炼了原数据最重要的特征,可以输入其他网络执行下游任务。由于原始数据同时承担了x和y的作用,没有使用金标准的标签数据,可以认为是一种无监督学习。)

定义自动编码器的函数

初始化Autoencoder并选择优化方式和损失函数。

循环训练

import torch

import torch.nn as nn

import torch.utils.data as Data

import torchvision

import matplotlib.pyplot as plt

import numpy as np

EPOCH = 10

BATCH_SIZE = 64

LR = 0.005 # learning rate

DOWNLOAD_MNIST = False

N_TEST_IMG = 5

train_data = torchvision.datasets.MNIST(

root='./mnist/',

train=True, # this is training data

transform=torchvision.transforms.ToTensor(), # Converts a PIL.Image or numpy.ndarray to

# torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]

download=DOWNLOAD_MNIST, # download it if you don't have it

)

# Data Loader for easy mini-batch return in training, the image batch shape will be (50, 1, 28, 28)

train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)

class AutoEncoder(nn.Module):

def __init__(self):

super(AutoEncoder, self).__init__()

self.encoder = nn.Sequential(

nn.Linear(28*28, 128),

nn.Tanh(),

nn.Linear(128, 64),

nn.Tanh(),

nn.Linear(64, 12),

nn.Tanh(),

nn.Linear(12, 3), # compress to 3 features which can be visualized in plt

)

self.decoder = nn.Sequential(

nn.Linear(3, 12),

nn.Tanh(),

nn.Linear(12, 64),

nn.Tanh(),

nn.Linear(64, 128),

nn.Tanh(),

nn.Linear(128, 28*28),

nn.Sigmoid(), # compress to a range (0, 1)

)

def forward(self, x):

encoded = self.encoder(x)

decoded = self.decoder(encoded)

return encoded, decoded

autoencoder = AutoEncoder()

optimizer = torch.optim.Adam(autoencoder.parameters(), lr=LR)

loss_func = nn.MSELoss()

for epoch in range(EPOCH):

for step, (x, b_label) in enumerate(train_loader):

b_x = x.view(-1, 28*28) # batch x, shape (batch, 28*28)

b_y = x.view(-1, 28*28) # batch y, shape (batch, 28*28)

encoded, decoded = autoencoder(b_x)

loss = loss_func(decoded, b_y) # mean square error

optimizer.zero_grad() # clear gradients for this training step

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

405 Deep Q-learning Network(DQN)

这里莫烦用了强化学习非常入门的一个例子:平衡小车游戏,需要用到物理引擎库gym。DQN使用神经网络解决Q-learning的两个痛点:1、状态过多,Q值存储不合适,直接将状态S和动作A输入网络得到Q值,简洁方便;2、使用网络输出状态S下所有动作A的Reward以此进行决策选择。

导入模块(torch,nn,F,np,gym)

设置超参数(TARGET_REPLACE_ITER为target_net滞后更新的频率,MEMORY_CAPACITY为最大记忆容量,满载后则新记忆覆盖最初的记忆,gym.make("CartPole-v0")为创建平衡小车实例)

定义神经网络类(单个隐层,激活函数为relu,与输出输入层全连接)

定义DQN类:初始化时创建eval_net和target_net两个神经网络,选择优化方法和损失函数。choose_action函数以超参数0.8的概率选择在神经网络评估下回报最高的行动,以0.2的概率随机决策。learn函数定义了如何更新eval_net和target_net的更新方法,每次从2000(MEMORY_CAPACITY)个记忆中选32(BATCH_SIZE)个记忆计算Q评估和Q真实,以此计算损失函数,对eval_net进行反向传递进行学习,每100(TARGET_REPLACE_ITER)次。后用eval_net的参数更新target_net。

实例化并进行训练:进行400轮游戏,最初进行记忆过程,不学习,当记够2000(MEMORY_CAPACITY)种情况后,开始学习。done为游戏是否结束,r为游戏自带的默认reward,后面莫烦老师使用了效果更好的reward来代替,s为游戏返回的状态,包括位置、速度、角度、角速度等信息。

import torch

import torch.nn as nn

import torch.nn.functional as F

import numpy as np

import gym

# Hyper Parameters

BATCH_SIZE = 32

LR = 0.01 # learning rate

EPSILON = 0.9 # greedy policy

GAMMA = 0.9 # reward discount

TARGET_REPLACE_ITER = 100 # target update frequency

MEMORY_CAPACITY = 2000

env = gym.make('CartPole-v0')

env = env.unwrapped

N_ACTIONS = env.action_space.n

N_STATES = env.observation_space.shape[0]

ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape # to confirm the shape

class Net(nn.Module):

def __init__(self, ):

super(Net, self).__init__()

self.fc1 = nn.Linear(N_STATES, 50)

self.fc1.weight.data.normal_(0, 0.1) # initialization

self.out = nn.Linear(50, N_ACTIONS)

self.out.weight.data.normal_(0, 0.1) # initialization

def forward(self, x):

x = self.fc1(x)

x = F.relu(x)

actions_value = self.out(x)

return actions_value

class DQN(object):

def __init__(self):

self.eval_net, self.target_net = Net(), Net()

self.learn_step_counter = 0 # for target updating

self.memory_counter = 0 # for storing memory

self.memory = np.zeros((MEMORY_CAPACITY, N_STATES * 2 + 2)) # initialize memory

self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=LR)

self.loss_func = nn.MSELoss()

def choose_action(self, x):

x = torch.unsqueeze(torch.FloatTensor(x), 0)

# input only one sample

if np.random.uniform() < EPSILON: # greedy

actions_value = self.eval_net.forward(x)

action = torch.max(actions_value, 1)[1].data.numpy()

action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) # return the argmax index

else: # random

action = np.random.randint(0, N_ACTIONS)

action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)

return action

def store_transition(self, s, a, r, s_):

transition = np.hstack((s, [a, r], s_))

# replace the old memory with new memory

index = self.memory_counter % MEMORY_CAPACITY

self.memory[index, :] = transition

self.memory_counter += 1

def learn(self):

# target parameter update

if self.learn_step_counter % TARGET_REPLACE_ITER == 0:

self.target_net.load_state_dict(self.eval_net.state_dict())

self.learn_step_counter += 1

# sample batch transitions

sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE)

b_memory = self.memory[sample_index, :]

b_s = torch.FloatTensor(b_memory[:, :N_STATES])

b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int))

b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2])

b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:])

# q_eval w.r.t the action in experience

q_eval = self.eval_net(b_s).gather(1, b_a) # shape (batch, 1)

q_next = self.target_net(b_s_).detach() # detach from graph, don't backpropagate

q_target = b_r + GAMMA * q_next.max(1)[0].view(BATCH_SIZE, 1) # shape (batch, 1)

loss = self.loss_func(q_eval, q_target)

self.optimizer.zero_grad()

loss.backward()

self.optimizer.step()

dqn = DQN()

print('\nCollecting experience...')

for i_episode in range(400):

s = env.reset()

ep_r = 0

while True:

env.render()

a = dqn.choose_action(s)

# take action

s_, r, done, info = env.step(a)

# modify the reward

x, x_dot, theta, theta_dot = s_

r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8

r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5

r = r1 + r2

dqn.store_transition(s, a, r, s_)

ep_r += r

if dqn.memory_counter > MEMORY_CAPACITY:

dqn.learn()

if done:

print('Ep: ', i_episode,

'| Ep_r: ', round(ep_r, 2))

if done:

break

s = s_

406 GAN

GAN是计算机视觉中图像生成领域制霸地位的框架GAN,对抗性的思想也是非常易懂的。本代码例子中莫烦老师用艺术家与鉴赏家的例子,具体可以参考论文。

导入模块(torch,nn,np)

设置超参数(ART_COMPONENTS为15,可以理解为输出的长度,N_IDEAS=5可以理解为input的长度,可以像该代码一样自主随机生成,也可以是降维提取的主要特征,比如自主编码器的中间产物,这样的GAN一般可以训练具体的P图任务,比如给人化妆,变老,戴眼镜等)

定义一个标签数据生成函数,或者标注一组特定目的的高质量数据集

定义生成器G网络与判别器D网络,注意D网络最后用一个sigmoid函数来生成判别概率

训练10000次,每次训练先让G生成一张图片,然后让D比较这张图片和艺术大师的图片,并给出判断概率,计算G和D的损失函数,并进行反向传播更新误差

import torch

import torch.nn as nn

import numpy as np

# Hyper Parameters

BATCH_SIZE = 64

LR_G = 0.0001 # learning rate for generator

LR_D = 0.0001 # learning rate for discriminator

N_IDEAS = 5 # think of this as number of ideas for generating an art work (Generator)

ART_COMPONENTS = 15 # it could be total point G can draw in the canvas

PAINT_POINTS = np.vstack([np.linspace(-1, 1, ART_COMPONENTS) for _ in range(BATCH_SIZE)])

def artist_works(): # painting from the famous artist (real target)

a = np.random.uniform(1, 2, size=BATCH_SIZE)[:, np.newaxis]

paintings = a * np.power(PAINT_POINTS, 2) + (a-1)

paintings = torch.from_numpy(paintings).float()

return paintings

G = nn.Sequential( # Generator

nn.Linear(N_IDEAS, 128), # random ideas (could from normal distribution)

nn.ReLU(),

nn.Linear(128, ART_COMPONENTS), # making a painting from these random ideas

)

D = nn.Sequential( # Discriminator

nn.Linear(ART_COMPONENTS, 128), # receive art work either from the famous artist or a newbie like G

nn.ReLU(),

nn.Linear(128, 1),

nn.Sigmoid(), # tell the probability that the art work is made by artist

)

opt_D = torch.optim.Adam(D.parameters(), lr=LR_D)

opt_G = torch.optim.Adam(G.parameters(), lr=LR_G)

for step in range(10000):

artist_paintings = artist_works() # real painting from artist

G_ideas = torch.randn(BATCH_SIZE, N_IDEAS) # random ideas

G_paintings = G(G_ideas) # fake painting from G (random ideas)

prob_artist0 = D(artist_paintings) # D try to increase this prob

prob_artist1 = D(G_paintings) # D try to reduce this prob

D_loss = - torch.mean(torch.log(prob_artist0) + torch.log(1. - prob_artist1))

G_loss = torch.mean(torch.log(1. - prob_artist1))

opt_D.zero_grad()

D_loss.backward(retain_graph=True) # reusing computational graph

opt_D.step()

opt_G.zero_grad()

G_loss.backward()

opt_G.step()

501 pytorch的动态计算图

pytorch之所以能在tensorflow大火的情况下杀出一片天地主要是其动态计算图的便利性,对于RNN来说,time_step不一定固定(尤其是nlp任务中序列长度不固定的语料数据,虽然可以用padding和truncating的方法标准化,但显然会损失信息和增加噪音),time_step的改变会改变计算图的结构,tensorflower必须以一种不方便的方式改写,而pytorch在计算图变动情况下的做法则非常直观方便。

导入模块(torch,nn,np)

设置超参数

定义RNN类(与之前定义完全一致)

初始化并训练,每次训练时随机步长,根据随机的步长产生训练数据

import torch

from torch import nn

import numpy as np

# Hyper Parameters

INPUT_SIZE = 1 # rnn input size / image width

LR = 0.02 # learning rate

class RNN(nn.Module):

def __init__(self):

super(RNN, self).__init__()

self.rnn = nn.RNN(

input_size=1,

hidden_size=32, # rnn hidden unit

num_layers=1, # number of rnn layer

batch_first=True, # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)

)

self.out = nn.Linear(32, 1)

def forward(self, x, h_state):

# x (batch, time_step, input_size)

# h_state (n_layers, batch, hidden_size)

# r_out (batch, time_step, output_size)

r_out, h_state = self.rnn(x, h_state)

outs = [] # this is where you can find torch is dynamic

for time_step in range(r_out.size(1)): # calculate output for each time step

outs.append(self.out(r_out[:, time_step, :]))

return torch.stack(outs, dim=1), h_state

rnn = RNN()

optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) # optimize all cnn parameters

loss_func = nn.MSELoss() # the target label is not one-hotted

h_state = None

################ dynamic time steps #########

step = 0

for i in range(60):

dynamic_steps = np.random.randint(1, 4) # has random time steps

start, end = step * np.pi, (step + dynamic_steps) * np.pi # different time steps length

step += dynamic_steps

# use sin predicts cos

steps = np.linspace(start, end, 10 * dynamic_steps, dtype=np.float32)

####################### Above is different ###########################

print(len(steps)) # print how many time step feed to RNN

x_np = np.sin(steps) # float32 for converting torch FloatTensor

y_np = np.cos(steps)

x = torch.from_numpy(x_np[np.newaxis, :, np.newaxis]) # shape (batch, time_step, input_size)

y = torch.from_numpy(y_np[np.newaxis, :, np.newaxis])

prediction, h_state = rnn(x, h_state) # rnn output

# !! next step is important !!

h_state = h_state.data # repack the hidden state, break the connection from last iteration

loss = loss_func(prediction, y) # cross entropy loss

optimizer.zero_grad() # clear gradients for this training step

loss.backward() # backpropagation, compute gradients

optimizer.step() # apply gradients

502 GPU加速

与tensorflow的自动选择cpu和gpu的特性不同,pytorch需要自主决定使用GPU还是CPU。该部分不暂时全部代码,简言之在最初定义tensor数据时在后面加上.cuda(),作用是将该数据移至GPU,当GPU内存比较紧张时,可以在同时训练多个网络的模型中合理设置达到计算资源的合理利用。

#当两个gpu中的tensor经过神经网络的训练计算时得到的仍然是结果仍在gpu计算

b_x = x.cuda() # Tensor on GPU

b_y = y.cuda() # Tensor on GPU

output = cnn(b_x)

loss = loss_func(output, b_y)

optimizer.zero_grad()

loss.backward()

optimizer.step()

#对于部分torch移植的numpy操作,比如max,也可以丢到gpu中加速计算

pred_y = torch.max(test_output, 1)[1].cuda().data # move the computation in GPU

503 Dropout

对于参数足够多的神经网络,理论上可以拟合任意函数,但是训练数据往往是存在噪音和局限性的,为了增强泛化性能,防止过拟合,可以用Dropout方法减少参数的过度更新,通过随机的方式使网络更加注重趋势的捕捉。在激活函数与连接层之间加上Dropout层,并设置dropout的百分比。注意训练时对网络使用train()的方法开启dropout功能,在测试时使用eval()方法关闭dropout功能。

import torch

import matplotlib.pyplot as plt

# torch.manual_seed(1) # reproducible

N_SAMPLES = 20

N_HIDDEN = 300

# training data

x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)

y = x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))

# test data

test_x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)

test_y = test_x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))

# show data

plt.scatter(x.data.numpy(), y.data.numpy(), c='magenta', s=50, alpha=0.5, label='train')

plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='cyan', s=50, alpha=0.5, label='test')

plt.legend(loc='upper left')

plt.ylim((-2.5, 2.5))

plt.show()

net_overfitting = torch.nn.Sequential(

torch.nn.Linear(1, N_HIDDEN),

torch.nn.ReLU(),

torch.nn.Linear(N_HIDDEN, N_HIDDEN),

torch.nn.ReLU(),

torch.nn.Linear(N_HIDDEN, 1),

)

net_dropped = torch.nn.Sequential(

torch.nn.Linear(1, N_HIDDEN),

torch.nn.Dropout(0.5), # drop 50% of the neuron

torch.nn.ReLU(),

torch.nn.Linear(N_HIDDEN, N_HIDDEN),

torch.nn.Dropout(0.5), # drop 50% of the neuron

torch.nn.ReLU(),

torch.nn.Linear(N_HIDDEN, 1),

)

print(net_overfitting) # net architecture

print(net_dropped)

optimizer_ofit = torch.optim.Adam(net_overfitting.parameters(), lr=0.01)

optimizer_drop = torch.optim.Adam(net_dropped.parameters(), lr=0.01)

loss_func = torch.nn.MSELoss()

plt.ion() # something about plotting

for t in range(500):

pred_ofit = net_overfitting(x)

pred_drop = net_dropped(x)

loss_ofit = loss_func(pred_ofit, y)

loss_drop = loss_func(pred_drop, y)

optimizer_ofit.zero_grad()

optimizer_drop.zero_grad()

loss_ofit.backward()

loss_drop.backward()

optimizer_ofit.step()

optimizer_drop.step()

if t % 10 == 0:

# change to eval mode in order to fix drop out effect

net_overfitting.eval()

net_dropped.eval() # parameters for dropout differ from train mode

# plotting

plt.cla()

test_pred_ofit = net_overfitting(test_x)

test_pred_drop = net_dropped(test_x)

plt.scatter(x.data.numpy(), y.data.numpy(), c='magenta', s=50, alpha=0.3, label='train')

plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='cyan', s=50, alpha=0.3, label='test')

plt.plot(test_x.data.numpy(), test_pred_ofit.data.numpy(), 'r-', lw=3, label='overfitting')

plt.plot(test_x.data.numpy(), test_pred_drop.data.numpy(), 'b--', lw=3, label='dropout(50%)')

plt.text(0, -1.2, 'overfitting loss=%.4f' % loss_func(test_pred_ofit, test_y).data.numpy(), fontdict={'size': 20, 'color': 'red'})

plt.text(0, -1.5, 'dropout loss=%.4f' % loss_func(test_pred_drop, test_y).data.numpy(), fontdict={'size': 20, 'color': 'blue'})

plt.legend(loc='upper left'); plt.ylim((-2.5, 2.5));plt.pause(0.1)

# change back to train mode

net_overfitting.train()

net_dropped.train()

plt.ioff()

plt.show()

504 批标准化batch_normalization

由于激活函数变化率比较大的区间实际上是比较短的,如果不对数据进行归一化处理,经过tanh等激活函数作用后很容易落在0,1处,当层级比较深时容易出现梯度爆炸和梯度消失的问题,导致网络无法捕捉长期信息。所以在正常传递和反向传递时都对每层数据进行批标准。在训练和测试时也要使用train()和eval()方法。

import torch

from torch import nn

from torch.nn import init

import torch.utils.data as Data

import matplotlib.pyplot as plt

import numpy as np

# torch.manual_seed(1) # reproducible

# np.random.seed(1)

# Hyper parameters

N_SAMPLES = 2000

BATCH_SIZE = 64

EPOCH = 12

LR = 0.03

N_HIDDEN = 8

ACTIVATION = torch.tanh

B_INIT = -0.2 # use a bad bias constant initializer

# training data

x = np.linspace(-7, 10, N_SAMPLES)[:, np.newaxis]

noise = np.random.normal(0, 2, x.shape)

y = np.square(x) - 5 + noise

# test data

test_x = np.linspace(-7, 10, 200)[:, np.newaxis]

noise = np.random.normal(0, 2, test_x.shape)

test_y = np.square(test_x) - 5 + noise

train_x, train_y = torch.from_numpy(x).float(), torch.from_numpy(y).float()

test_x = torch.from_numpy(test_x).float()

test_y = torch.from_numpy(test_y).float()

train_dataset = Data.TensorDataset(train_x, train_y)

train_loader = Data.DataLoader(dataset=train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2,)

# show data

plt.scatter(train_x.numpy(), train_y.numpy(), c='#FF9359', s=50, alpha=0.2, label='train')

plt.legend(loc='upper left')

class Net(nn.Module):

def __init__(self, batch_normalization=False):

super(Net, self).__init__()

self.do_bn = batch_normalization

self.fcs = []

self.bns = []

self.bn_input = nn.BatchNorm1d(1, momentum=0.5) # for input data

for i in range(N_HIDDEN): # build hidden layers and BN layers

input_size = 1 if i == 0 else 10

fc = nn.Linear(input_size, 10)

setattr(self, 'fc%i' % i, fc) # IMPORTANT set layer to the Module

self._set_init(fc) # parameters initialization

self.fcs.append(fc)

if self.do_bn:

bn = nn.BatchNorm1d(10, momentum=0.5)

setattr(self, 'bn%i' % i, bn) # IMPORTANT set layer to the Module

self.bns.append(bn)

self.predict = nn.Linear(10, 1) # output layer

self._set_init(self.predict) # parameters initialization

def _set_init(self, layer):

init.normal_(layer.weight, mean=0., std=.1)

init.constant_(layer.bias, B_INIT)

def forward(self, x):

pre_activation = [x]

if self.do_bn: x = self.bn_input(x) # input batch normalization

layer_input = [x]

for i in range(N_HIDDEN):

x = self.fcs[i](x)

pre_activation.append(x)

if self.do_bn: x = self.bns[i](x) # batch normalization

x = ACTIVATION(x)

layer_input.append(x)

out = self.predict(x)

return out, layer_input, pre_activation

nets = [Net(batch_normalization=False), Net(batch_normalization=True)]

# print(*nets) # print net architecture

opts = [torch.optim.Adam(net.parameters(), lr=LR) for net in nets]

loss_func = torch.nn.MSELoss()

def plot_histogram(l_in, l_in_bn, pre_ac, pre_ac_bn):

for i, (ax_pa, ax_pa_bn, ax, ax_bn) in enumerate(zip(axs[0, :], axs[1, :], axs[2, :], axs[3, :])):

[a.clear() for a in [ax_pa, ax_pa_bn, ax, ax_bn]]

if i == 0:

p_range = (-7, 10);the_range = (-7, 10)

else:

p_range = (-4, 4);the_range = (-1, 1)

ax_pa.set_title('L' + str(i))

ax_pa.hist(pre_ac[i].data.numpy().ravel(), bins=10, range=p_range, color='#FF9359', alpha=0.5);ax_pa_bn.hist(pre_ac_bn[i].data.numpy().ravel(), bins=10, range=p_range, color='#74BCFF', alpha=0.5)

ax.hist(l_in[i].data.numpy().ravel(), bins=10, range=the_range, color='#FF9359');ax_bn.hist(l_in_bn[i].data.numpy().ravel(), bins=10, range=the_range, color='#74BCFF')

for a in [ax_pa, ax, ax_pa_bn, ax_bn]: a.set_yticks(());a.set_xticks(())

ax_pa_bn.set_xticks(p_range);ax_bn.set_xticks(the_range)

axs[0, 0].set_ylabel('PreAct');axs[1, 0].set_ylabel('BN PreAct');axs[2, 0].set_ylabel('Act');axs[3, 0].set_ylabel('BN Act')

plt.pause(0.01)

if __name__ == "__main__":

f, axs = plt.subplots(4, N_HIDDEN + 1, figsize=(10, 5))

plt.ion() # something about plotting

plt.show()

# training

losses = [[], []] # recode loss for two networks

for epoch in range(EPOCH):

print('Epoch: ', epoch)

layer_inputs, pre_acts = [], []

for net, l in zip(nets, losses):

net.eval() # set eval mode to fix moving_mean and moving_var

pred, layer_input, pre_act = net(test_x)

l.append(loss_func(pred, test_y).data.item())

layer_inputs.append(layer_input)

pre_acts.append(pre_act)

net.train() # free moving_mean and moving_var

plot_histogram(*layer_inputs, *pre_acts) # plot histogram

for step, (b_x, b_y) in enumerate(train_loader):

for net, opt in zip(nets, opts): # train for each network

pred, _, _ = net(b_x)

loss = loss_func(pred, b_y)

opt.zero_grad()

loss.backward()

opt.step() # it will also learns the parameters in Batch Normalization

plt.ioff()

# plot training loss

plt.figure(2)

plt.plot(losses[0], c='#FF9359', lw=3, label='Original')

plt.plot(losses[1], c='#74BCFF', lw=3, label='Batch Normalization')

plt.xlabel('step');plt.ylabel('test loss');plt.ylim((0, 2000));plt.legend(loc='best')

# evaluation

# set net to eval mode to freeze the parameters in batch normalization layers

[net.eval() for net in nets] # set eval mode to fix moving_mean and moving_var

preds = [net(test_x)[0] for net in nets]

plt.figure(3)

plt.plot(test_x.data.numpy(), preds[0].data.numpy(), c='#FF9359', lw=4, label='Original')

plt.plot(test_x.data.numpy(), preds[1].data.numpy(), c='#74BCFF', lw=4, label='Batch Normalization')

plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='r', s=50, alpha=0.2, label='train')

plt.legend(loc='best')

plt.show()

你可能感兴趣的:(gcan,pytorch实现)