欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch进行深度学习(二)

程序员文章站 2022-07-12 22:59:55
...

1、深度学习构建基块

深度学习包括以巧妙的方式将线性与非线性组成。非线性的引入允许强大的模型。在本节中,我们将使用这些核心组件,组成目标函数,并了解如何训练模型。深度学习构建基块:仿射图,非线性和目标

1.1、仿射线性函数

仿射图是深度学习的核心动力之一,仿射图是一种功能 f(x) :

pytorch进行深度学习(二)

对于矩阵 A和向量 x,b。这里要学习的参数是A和 b。经常,b被称为偏差项。

PyTorch和大多数其他深度学习框架的功能与传统线性代数略有不同。它映射输入的行而不是列。也就是,输出的第i行对应输入A的第行,加上偏差项,看下面的例子。

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

torch.manual_seed(1)

'''实例:声明一个20维到10维的映射函数'''
lin = nn.Linear(10, 2)  # 数学函数为:`y = xA^T + b`, parameters A, b;nn.Linear(in_features:int, out_features:int, bias:bool=True) -> None
input = torch.randn(20, 10)
output = lin(input)
print(output.size()) #A为10*2的映射矩阵;输出torch.Size([20, 2])
print(output)  

1.2、非线性函数

首先,请注意以下事实,这将解释为什么我们首先需要非线性。假设我们有两个仿射图 f(x)=Ax+b和 g(x)=Cx+d。什么是 f(g(x))

f(g(x))=A(Cx+d)+b=ACx+(Ad+b)

AC是一个矩阵, Ad+b是向量,因此我们看到组成仿射图会为您提供仿射图。

从中可以看出,如果您希望神经网络是仿射成分的长链,那么仅制作一个仿射图就不会为模型增加新的功能。

如果我们在仿射层之间引入非线性,则不再是这种情况,我们可以构建功能更强大的模型。

有一些核心非线性。 tanh(x),σ(x),ReLU(x)是最常见的。您可能想知道:“为什么要使用这些功能?我可以想到很多其他非线性因素。” 这是因为它们具有易于计算的梯度,并且计算梯度对于学习至关重要。例如

dσ/dx=σ(x)(1−σ(x))

快速说明:尽管您可能在AI入门课程中学习了一些神经网络,但其中 σ(x)是默认的非线性,通常人们在实践中会回避它。这是因为随着参数的绝对值增加,梯度很快消失。小梯度意味着很难学习。大多数人默认使用tanh或ReLU。

'''
在pytorch中大部分非线性函数在torch.nn.functional中,非线性函数没有映射参数;在训练过程中无需更新权重。
'''
data = torch.randn(2, 2)
print(data)     #输出tensor([[-0.4519, -0.1661],[-1.5228,  0.3817]])
print(F.relu(data))  #输出tensor([[0.0000, 0.0000],[0.0000, 0.3817]])

 

1.3、Softmax和概率

功能 Softmax(x)也是非线性的,但是它的特殊之处在于它通常是网络中的最后一个操作。这是因为它接受实数向量并返回概率分布。其定义如下。让 xx是实数的向量(正数,负数,等等,没有约束)。然后是 Softmax(x)Softmax(x) 是

exp(xi)/∑jexp(xj)

应该清楚的是,输出是概率分布:每个元素都是非负的,所有分量的总和为1。

您也可以将其视为仅对输入应用按元素取幂的运算符,以使所有内容均为非负值,然后除以归一化常数。

# Softmax也在函数torch.nn.functional
data = torch.randn(5)
print(data)
print(F.softmax(data, dim=0))
print(F.softmax(data, dim=0).sum())  # Sums to 1 because it is a distribution!
print(F.log_softmax(data, dim=0))  # theres also log_softmax

1.4、目标函数

目标函数是训练网络以使其最小化的函数(在这种情况下,通常称为损失函数 或成本函数)。首先,选择一个训练实例,通过您的神经网络运行它,然后计算输出损失。然后,通过采用损失函数的导数来更新模型的参数。凭直觉,如果您的模型对答案完全有信心,而答案是错误的,那么您的损失将会很高。如果它对答案非常有信心,并且答案正确,那么损失将很小。

最小化训练示例中的损失函数的想法是,您的网络有望很好地推广,并且在开发集,测试集或生产环境中的未见示例中损失很小。损失函数的一个示例是负对数似然损失,它是多类分类的一个非常常见的目标。对于有监督的多类分类,这意味着训练网络以最小化正确输出的负对数概率(或等效地,最大化正确输出的对数概率)。

2、优化与训练

那么我们可以为实例计算损失函数吗?我们该怎么办?我们之前已经看到过Tensors知道如何相对于用于计算梯度的事物来计算梯度。由于我们的损失是张量,因此我们可以针对用于计算它的所有参数计算梯度!然后,我们可以执行标准梯度更新。让θ 作为我们的参数, L(θ)损失函数,以及 η积极的学习率。然后:

         pytorch进行深度学习(二)

尝试进行更多的操作而不仅仅是这种原始梯度更新的方法,还有大量的算法和研究。许多人尝试根据训练时的变化来改变学习率。除非您真的很感兴趣,否则您不必担心这些算法在做什么。Torch在torch.optim包中提供了许多功能,并且它们都是完全透明的。使用最简单的梯度更新与更复杂的算法相同。尝试使用不同的更新算法和不同的更新算法参数(例如不同的初始学习率)对于优化网络性能非常重要。通常,仅用Adam或RMSProp之类的优化器替换SGD即可显着提高性能。

3、在PyTorch中创建网络组件

在继续关注NLP之前,让我们做一个带注释的示例,该示例仅使用仿射图和非线性关系在PyTorch中构建网络。我们还将看到如何使用PyTorch内置的负对数似然来计算损失函数,以及如何通过反向传播更新参数。

所有网络组件都应继承自nn.Module并重写forward()方法。从nn.Module继承为您的组件提供功能。例如,它可以跟踪可训练的参数,可以使用.to(device) 方法在CPU和GPU之间切换,其中设备可以是CPU设备torch.device("cpu")或CUDA设备torch.device("cuda:0")

3.1、逻辑回归词袋分类器

我们的模型将映射稀疏的BoW表示形式以记录标签上的概率。我们为词汇中的每个单词分配一个索引。例如,假设我们的整个词汇是两个单词“ hello”和“ world”,分别具有索引0和1。句子“ hello hello hello hello”的BoW向量是[4,0]对于“ hello world world hello”,它是[2,2]等,通常是

a)词向量表示

[Count(hello),Count(world)]将此BOW向量表示为 x

b) 逻辑回归表示

输出为:logSoftmax(Ax+b)

也就是说,我们通过仿射映射传递输入,然后记录softmax。

c)定义目标函数

传递实例以获取对数概率,计算损失函数,计算损失函数的梯度,然后使用梯度步长更新参数。损耗功能由nn包中的Torch提供。nn.NLLLoss()是我们想要的负对数似然损失。它还在torch.optim中定义了优化功能。在这里,我们将仅使用SGD。

请注意,NLLLoss的输入是对数概率的向量和目标标签。它不会为我们计算对数概率。这就是为什么我们网络的最后一层是log softmax。损失函数nn.CrossEntropyLoss()与NLLLoss()相同,不同之处在于它为您执行了log softmax。

'''
bow构建词向量;简单的逻辑分类
训练数据:4条训练数据,两个标签SPANISH,ENGLISH
测试数据:2条测试数据,两个标签
'''
data = [("me gusta comer en la cafeteria".split(), "SPANISH"),
        ("Give it to me".split(), "ENGLISH"),
        ("No creo que sea una buena idea".split(), "SPANISH"),
        ("No it is not a good idea to get lost at sea".split(), "ENGLISH")]

test_data = [("Yo creo que si".split(), "SPANISH"),
             ("it is lost on me".split(), "ENGLISH")]

'''
构建词和id的映射关系
'''
word_to_ix = {}
for sent, _ in data + test_data:
    for word in sent:
        if word not in word_to_ix:
            word_to_ix[word] = len(word_to_ix)
print("词典word_to_ix:",word_to_ix)

VOCAB_SIZE = len(word_to_ix)
NUM_LABELS = 2

'''
定义一个BowClassifier分类器nn.Module
'''
class BowClassifier(nn.Module):
    def __init__(self,num_labels,vocab_size):
        '''
           调用nn.Module的初始化函数
        '''
        super(BowClassifier,self).__init__()
        self.linear=nn.Linear(vocab_size,num_labels) #定义线性分类器
    
    def forward(self,bow_vec):
        '''
           重写前向传播函数
           bow_vec:词向量
        '''
        return F.softmax(self.linear(bow_vec),dim=1)
 
'''
构造bow词典
'''
def make_bow_vec(sen,word2id):
    vec=torch.zeros(len(word2id))
    for word in sen:
        vec[word2id[word]]+=1
    return vec.view(1,-1)


def make_target(label, label_to_ix):
    print(torch.LongTensor([label_to_ix[label]]))
    return torch.LongTensor([label_to_ix[label]])


model=BowClassifier(NUM_LABELS,VOCAB_SIZE)

'''
遍历参数
'''
def print_param_steps(model,step):
    for param in model.parameters():
        print("step:{},param:{} ".format(step,param))


'''
获取forward返回的结果softmax预测概率
'''
with torch.no_grad():
    sample=data[0] #msg,label
    vec=make_bow_vec(sample[0],word_to_ix)
    print("vec size:",vec.size())
    prob=model(vec)
    print("prob size:",prob)
    
label_to_ix = {"SPANISH": 0, "ENGLISH": 1}

#定义损失函数公式
loss_function=nn.NLLLoss()
opt=optim.SGD(model.parameters(),lr=0.1)

#训练
i=0
for epoch in range(5):
    for inst,label in data:
        #1、PyTorch累积梯度,初始时需将梯度清零
        print_param_steps(model,i) #每更新一个示例,参数更新一次
        model.zero_grad()
        #2、构建bow向量,获取标签数字
        vec=make_bow_vec(inst,word_to_ix)
        target=make_target(label,label_to_ix)
        #3、执行并前向传播
        probs=model(vec)
        #4、计算损失函数,梯度,调用optimizer.step()更新参数
        loss=loss_function(probs,target)
        loss.backward()
        opt.step()
        i+=1
        
#预测
with torch.no_grad():
    for inst,label in test_data:
        vec=make_bow_vec(inst,word_to_ix)
        probs=model(vec)
        print(probs,label)