[六點]莫煩Pytorch代碼筆記

莫煩Pytorch代碼筆記

pytorch已經(jīng)是非常流行的深度學習框架了荆忍,它的動態(tài)計算圖特性在NLP領(lǐng)域是非常有用的厨埋,如果不會tensorflow或缺乏Deep Learning相關(guān)基礎(chǔ)知識,直接看莫煩視頻和代碼是有一些困難劫扒,所以對代碼做了部分解釋和理解檬洞,希望能幫助到你。
莫煩Github代碼
網(wǎng)上流傳的pytorch中文文檔和最近的英文文檔隔了一個大版本沟饥,新版本完全可以用Tensor代替Variable添怔,所以推薦閱讀官方文檔
Pytorch官方文檔

公眾號:六點一刻研習室
(興趣使然环戈,不定期寫些有用的東西,沒有質(zhì)量保證)

目錄

  • 201 torch和numpy
  • 202 Variable
  • 203 激活函數(shù)
  • 301 回歸
  • 302 分類
  • 303 快速搭建神經(jīng)網(wǎng)絡(luò)
  • 304 保存與重新載入
  • 305 批訓練(batch_train)
  • 306 優(yōu)化器
  • 401 CNN
  • 402 RNN分類器
  • 403 RNN回歸
  • 404 自動編碼器
  • 405 Deep Q-learning Network(DQN)
  • 406 GAN
  • 501 pytorch的動態(tài)計算圖
  • 502 GPU加速
  • 503 Dropout
  • 504 批標準化batch_normalization

201 torch和numpy

  1. numpy與torch兩種類型使用from_numpy和numpy兩個方法可以很方便的相互轉(zhuǎn)換澎灸。
  2. 當然也可以用列表初始化torch
  3. numpy具有abs院塞,mean,abs等對每個元素的操作性昭,torch都有相同名稱的函數(shù)方法拦止。
  4. torch有mm方法來實現(xiàn)二維張量的矩陣乘法,torch的dot方法不同于矩陣點乘糜颠,torch會先自動展成一維張量在進行向量點乘汹族,得到的結(jié)果等于張量所有元素的平方和。

代碼依次如下:

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基本一致顶瞒,只有部分隱變量有區(qū)別,所以直接將代碼的Variable替換為Tensor應該是可以正常運行的的元旬。

  1. 引入
  2. 初始化
  3. 按照計算圖生成結(jié)果變量
  4. 使用backward函數(shù)回傳誤差
  5. 查看梯度
  6. variable與numpy的轉(zhuǎn)換
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的傳遞規(guī)律榴徐,只要所依賴的張量中一個為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即可穆端,算是優(yōu)化

203 激活函數(shù)

常用的激活函數(shù)有sigmoid袱贮,類sigmoid的tanh(大多數(shù)情況下優(yōu)于sigmoid),分段函數(shù)ReLu(保證了神經(jīng)網(wǎng)絡(luò)比較深時發(fā)生的梯度消失和梯度彌散問題)体啰,softplus(是光滑版的ReLu)攒巍。

  • 導入庫
  • 生成線性數(shù)據(jù)
  • torch的函數(shù)方法
  • torch.nn.functional的函數(shù)方法
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 回歸

這一部分的代碼莫煩修改過,基本上就沒出現(xiàn)Variable了荒勇,因為Tensor類已經(jīng)有backward函數(shù)柒莉。

  • 導入庫
  • 初始化x、y數(shù)據(jù)
  • 構(gòu)建只有一個隱含層的神經(jīng)網(wǎng)絡(luò)類枕屉,需要繼承Net(torch.nn.Module)常柄,super父類時不用傳任何參數(shù)
    • 初始化時定義層與層間的連接關(guān)系鲤氢,代碼使用了兩個nn的線性全連接
    • 定義前向傳播的計算方法搀擂,此時可以選擇隱層的激活函數(shù)
  • 神經(jīng)網(wǎng)絡(luò)實例化
  • 選擇優(yōu)化方式和損失函數(shù)(backward負責計算梯度,根據(jù)梯度可以選擇SGD等不同的優(yōu)化方法)
  • 循環(huán)更新網(wǎng)絡(luò)參數(shù)
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兩類數(shù)據(jù)并進行拼接(torch的很多操作與numpy類似)
  • 構(gòu)建一個隱層的神經(jīng)網(wǎng)絡(luò)來進行分類哨颂,與回歸使用的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)完全相似
  • 初始化一個神經(jīng)網(wǎng)絡(luò),并選擇優(yōu)化方法和損失函數(shù)(分類問題用CrossEntropyLoss)
  • 循環(huán)訓練(與回歸代碼完全相同)
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 快速搭建神經(jīng)網(wǎng)絡(luò)

  • 方法一:定義類(層級在init定義相种,激活函數(shù)在forward定義)
    • 導入庫(torch,F)
    • 定義只有一層的神經(jīng)網(wǎng)絡(luò)類(結(jié)構(gòu)與上兩節(jié)完全相同)
    • 初始化隱層節(jié)點個數(shù)為10的神經(jīng)網(wǎng)絡(luò)
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函數(shù)快速搭建(層級和激活函數(shù)按順序以此排放)威恼,但不能像方法一那樣給層級人工命名
net2 = torch.nn.Sequential(
    torch.nn.Linear(1, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1)
)

304 保存與重新載入

  • 導入庫
  • 制造一些假數(shù)據(jù)(squeeze和unsqueeze分別為降維和擴容)
  • 定義神經(jīng)網(wǎng)絡(luò)、初始化并進行訓練
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()
  • 保存神經(jīng)網(wǎng)絡(luò)
    • 框架和參數(shù)一起保存
    • 只保存參數(shù)
torch.save(net1, 'net.pkl')  # save entire net

torch.save(net1.state_dict(), 'net_params.pkl')
  • 重新載入
    • 直接載入
    • 構(gòu)建結(jié)構(gòu)相同的神經(jīng)網(wǎng)絡(luò),導入?yún)?shù)
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)的種子箫措,保證可以復現(xiàn)(reproducible)
  • 設(shè)置批的大小
  • 制造fake data和批訓練的分發(fā)器
  • 雙重循環(huán)開始訓練(大循環(huán)是epoch腹备,循環(huán)是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 優(yōu)化器

  • 導入庫(torch,Data,F)
  • 設(shè)置學習率、批大小斤蔓、epoch次數(shù)
  • 構(gòu)建虛假數(shù)據(jù)集植酥,y引入正態(tài)噪聲
  • 構(gòu)造數(shù)據(jù)集和批訓練分發(fā)器
  • 構(gòu)造神經(jīng)網(wǎng)絡(luò)類
  • 選擇不同的優(yōu)化方式,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

訓練使用的數(shù)據(jù)集是MNIST識別手寫文字0-9,文字標簽的編碼方式為one-hot編碼弦牡。

  • 導入庫 (os,torch,nn,Data)
  • 設(shè)置epoch友驮、批大小、學習率等
  • 使用torchvision.datasets下載數(shù)據(jù)集并制作批訓練分發(fā)器,train_data有train_data和train_labels兩個子屬性驾锰,以前2000條數(shù)據(jù)作為測試集加速測試過程
  • 定義CNN類(兩層卷積層再全連接到10個節(jié)點表示數(shù)字卸留,每層卷積后用ReLU激活,使用kernel_size為2的池化操作椭豫。)
  • 初始化網(wǎng)絡(luò)耻瑟,定義優(yōu)化器和損失函數(shù)
  • 訓練
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分類器

仍對手寫字體數(shù)據(jù)進行分類,由于序列較長赏酥,使用LSTM匆赃。

  • 導入庫(torch,nn,torchvision
  • 設(shè)置超參數(shù)(每張圖片輸入n個step,n表示圖片高度今缚,每個step輸入一行像素信息)
  • 獲取數(shù)據(jù)集并制作訓練集分發(fā)器
  • 定義RNN類
  • 事例化RNN算柳,并選擇優(yōu)化方法和損失函數(shù)
  • 循環(huán)訓練
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可以較好地根據(jù)原有的信息進行預測,適合于周期性函數(shù)的擬合和預測姓言。

  • 導入庫(torch, nn, numpy)
  • 設(shè)置超參數(shù)(TIME_STEP, INPUT_SIZE)
  • 構(gòu)造正余弦波數(shù)據(jù)
  • 定義RNN類(使用普通RNN瞬项,隱層節(jié)點32,RNN輸出最終隱含層狀態(tài)和中間輸出序列)
  • 初始化RNN,定義優(yōu)化方法和損失函數(shù)何荚,指定初始狀態(tài)為None
  • 分段訓練(每次訓練1pi的長度囱淋,每次訓練得到forward結(jié)果序列和forward后隱含層的狀態(tài),計算損失函數(shù)并反向傳播進行優(yōu)化)
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

  • 導入模塊
  • 設(shè)置超參數(shù)
  • 下載數(shù)據(jù)集餐塘,并制作訓練集的批訓練分發(fā)器(自編碼器是一種廣義的無監(jiān)督學習妥衣,沒有標簽數(shù)據(jù),先通過encoder網(wǎng)絡(luò)壓縮成低維數(shù)據(jù)戒傻,再拓展成高維數(shù)據(jù)税手,目標是擴展后能與原始數(shù)據(jù)一致。這樣訓練得到的中間產(chǎn)物——低維數(shù)據(jù)需纳,可以認為提煉了原數(shù)據(jù)最重要的特征芦倒,可以輸入其他網(wǎng)絡(luò)執(zhí)行下游任務。由于原始數(shù)據(jù)同時承擔了x和y的作用不翩,沒有使用金標準的標簽數(shù)據(jù)兵扬,可以認為是一種無監(jiān)督學習麻裳。)
  • 定義自動編碼器的函數(shù)
  • 初始化Autoencoder并選擇優(yōu)化方式和損失函數(shù)。
  • 循環(huán)訓練
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使用神經(jīng)網(wǎng)絡(luò)解決Q-learning的兩個痛點:1、狀態(tài)過多傲霸,Q值存儲不合適国瓮,直接將狀態(tài)S和動作A輸入網(wǎng)絡(luò)得到Q值,簡潔方便狞谱;2乃摹、使用網(wǎng)絡(luò)輸出狀態(tài)S下所有動作A的Reward以此進行決策選擇陵像。

  • 導入模塊(torch,nn,F,np,gym)
  • 設(shè)置超參數(shù)(TARGET_REPLACE_ITER為target_net滯后更新的頻率莉御,MEMORY_CAPACITY為最大記憶容量墩新,滿載后則新記憶覆蓋最初的記憶弦撩,gym.make("CartPole-v0")為創(chuàng)建平衡小車實例)
  • 定義神經(jīng)網(wǎng)絡(luò)類(單個隱層佣耐,激活函數(shù)為relu辱揭,與輸出輸入層全連接)
  • 定義DQN類:初始化時創(chuàng)建eval_net和target_net兩個神經(jīng)網(wǎng)絡(luò)亡容,選擇優(yōu)化方法和損失函數(shù)躺屁。choose_action函數(shù)以超參數(shù)0.8的概率選擇在神經(jīng)網(wǎng)絡(luò)評估下回報最高的行動叭莫,以0.2的概率隨機決策蹈集。learn函數(shù)定義了如何更新eval_net和target_net的更新方法,每次從2000(MEMORY_CAPACITY)個記憶中選32(BATCH_SIZE)個記憶計算Q評估和Q真實,以此計算損失函數(shù)雇初,對eval_net進行反向傳遞進行學習拢肆,每100(TARGET_REPLACE_ITER)次。后用eval_net的參數(shù)更新target_net靖诗。
  • 實例化并進行訓練:進行400輪游戲郭怪,最初進行記憶過程,不學習刊橘,當記夠2000(MEMORY_CAPACITY)種情況后鄙才,開始學習。done為游戲是否結(jié)束促绵,r為游戲自帶的默認reward攒庵,后面莫煩老師使用了效果更好的reward來代替,s為游戲返回的狀態(tài)败晴,包括位置浓冒、速度、角度位衩、角速度等信息裆蒸。
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是計算機視覺中圖像生成領(lǐng)域制霸地位的框架GAN熔萧,對抗性的思想也是非常易懂的糖驴。本代碼例子中莫煩老師用藝術(shù)家與鑒賞家的例子僚祷,具體可以參考論文。

  • 導入模塊(torch,nn,np)
  • 設(shè)置超參數(shù)(ART_COMPONENTS為15贮缕,可以理解為輸出的長度,N_IDEAS=5可以理解為input的長度辙谜,可以像該代碼一樣自主隨機生成,也可以是降維提取的主要特征感昼,比如自主編碼器的中間產(chǎn)物装哆,這樣的GAN一般可以訓練具體的P圖任務,比如給人化妝定嗓,變老蜕琴,戴眼鏡等)
  • 定義一個標簽數(shù)據(jù)生成函數(shù),或者標注一組特定目的的高質(zhì)量數(shù)據(jù)集
  • 定義生成器G網(wǎng)絡(luò)與判別器D網(wǎng)絡(luò)宵溅,注意D網(wǎng)絡(luò)最后用一個sigmoid函數(shù)來生成判別概率
  • 訓練10000次凌简,每次訓練先讓G生成一張圖片,然后讓D比較這張圖片和藝術(shù)大師的圖片恃逻,并給出判斷概率雏搂,計算G和D的損失函數(shù),并進行反向傳播更新誤差
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的動態(tài)計算圖

pytorch之所以能在tensorflow大火的情況下殺出一片天地主要是其動態(tài)計算圖的便利性寇损,對于RNN來說凸郑,time_step不一定固定(尤其是nlp任務中序列長度不固定的語料數(shù)據(jù),雖然可以用padding和truncating的方法標準化矛市,但顯然會損失信息和增加噪音)芙沥,time_step的改變會改變計算圖的結(jié)構(gòu),tensorflower必須以一種不方便的方式改寫浊吏,而pytorch在計算圖變動情況下的做法則非常直觀方便憨愉。

  • 導入模塊(torch,nn,np)
  • 設(shè)置超參數(shù)
  • 定義RNN類(與之前定義完全一致)
  • 初始化并訓練,每次訓練時隨機步長卿捎,根據(jù)隨機的步長產(chǎn)生訓練數(shù)據(jù)
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數(shù)據(jù)時在后面加上.cuda()躺孝,作用是將該數(shù)據(jù)移至GPU,當GPU內(nèi)存比較緊張時底桂,可以在同時訓練多個網(wǎng)絡(luò)的模型中合理設(shè)置達到計算資源的合理利用植袍。

#當兩個gpu中的tensor經(jīng)過神經(jīng)網(wǎng)絡(luò)的訓練計算時得到的仍然是結(jié)果仍在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

對于參數(shù)足夠多的神經(jīng)網(wǎng)絡(luò)于个,理論上可以擬合任意函數(shù),但是訓練數(shù)據(jù)往往是存在噪音和局限性的暮顺,為了增強泛化性能厅篓,防止過擬合秀存,可以用Dropout方法減少參數(shù)的過度更新,通過隨機的方式使網(wǎng)絡(luò)更加注重趨勢的捕捉羽氮。在激活函數(shù)與連接層之間加上Dropout層或链,并設(shè)置dropout的百分比。注意訓練時對網(wǎng)絡(luò)使用train()的方法開啟dropout功能档押,在測試時使用eval()方法關(guān)閉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

由于激活函數(shù)變化率比較大的區(qū)間實際上是比較短的,如果不對數(shù)據(jù)進行歸一化處理令宿,經(jīng)過tanh等激活函數(shù)作用后很容易落在0叼耙,1處,當層級比較深時容易出現(xiàn)梯度爆炸和梯度消失的問題粒没,導致網(wǎng)絡(luò)無法捕捉長期信息旬蟋。所以在正常傳遞和反向傳遞時都對每層數(shù)據(jù)進行批標準。在訓練和測試時也要使用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()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倾贰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拦惋,更是在濱河造成了極大的恐慌匆浙,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厕妖,死亡現(xiàn)場離奇詭異首尼,居然都是意外死亡,警方通過查閱死者的電腦和手機言秸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門软能,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人举畸,你說我怎么就攤上這事查排。” “怎么了抄沮?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵跋核,是天一觀的道長。 經(jīng)常有香客問我叛买,道長砂代,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任率挣,我火速辦了婚禮刻伊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己捶箱,他們只是感情好智什,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讼呢,像睡著了一般撩鹿。 火紅的嫁衣襯著肌膚如雪谦炬。 梳的紋絲不亂的頭發(fā)上悦屏,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音键思,去河邊找鬼础爬。 笑死,一個胖子當著我的面吹牛吼鳞,可吹牛的內(nèi)容都是我干的看蚜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼赔桌,長吁一口氣:“原來是場噩夢啊……” “哼供炎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疾党,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤音诫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后雪位,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竭钝,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年雹洗,在試婚紗的時候發(fā)現(xiàn)自己被綠了香罐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡时肿,死狀恐怖庇茫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情螃成,我是刑警寧澤港令,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站锈颗,受9級特大地震影響顷霹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜击吱,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一淋淀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦朵纷、人聲如沸炭臭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鞋仍。三九已至,卻和暖如春搅吁,著一層夾襖步出監(jiān)牢的瞬間威创,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工谎懦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肚豺,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓界拦,卻偏偏與公主長得像吸申,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子享甸,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容