在pytorch

时间:2017-07-10 19:24:25

标签: python machine-learning neural-network deep-learning pytorch

因此,我对PyTorch和神经网络一般都很陌生,而且我在创建一个按性别对名称进行分类的神经网络时遇到了一些问题。
我基于RNNs的PyTorch教程,根据国籍对名称进行分类,但我决定不采用经常性方法... 如果这是错误的想法,请立即停止我! 但是,每当我尝试通过网络运行输入时,它都会告诉我:

RuntimeError: matrices expected, got 3D, 2D tensors at /py/conda-bld/pytorch_1493681908901/work/torch/lib/TH/generic/THTensorMath.c:1232

我知道这与PyTorch总是希望批量大小有什么关系有关,而且我的张量设置就是这样,但是你可以告诉我这点我不知道我是什么&# 39;我在谈论。 这是我的代码:

from future import unicode_literals, print_function, division
from io import open
import glob
import unicodedata
import string
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
import random
from torch.autograd import Variable
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

"""------GLOBAL VARIABLES------"""

all_letters = string.ascii_letters + " .,;'"
num_letters = len(all_letters)
all_names = {}
genders = ["Female", "Male"]

"""-------DATA EXTRACTION------"""

def findFiles(path):
    return glob.glob(path)

def unicodeToAscii(s):
    return ''.join(
        c for c in unicodedata.normalize('NFD', s)
        if unicodedata.category(c) != 'Mn'
        and c in all_letters
    )

# Read a file and split into lines
def readLines(filename):
    lines = open(filename, encoding='utf-8').read().strip().split('\n')
    return [unicodeToAscii(line) for line in lines]

for file in findFiles("/home/andrew/PyCharm/PycharmProjects/CantStop/data/names/*.txt"):
    gender = file.split("/")[-1].split(".")[0]
    names = readLines(file)
    all_names[gender] = names

"""-----DATA INTERPRETATION-----"""

def nameToTensor(name):
    tensor = torch.zeros(len(name), 1, num_letters)
    for index, letter in enumerate(name):
        tensor[index][0][all_letters.find(letter)] = 1
    return tensor

def outputToGender(output):
    gender, gender_index = output.data.topk(1)
    if gender_index[0][0] == 0:
        return "Female"
    return "Male"

"""------NETWORK SETUP------"""

class Net(nn.Module):
    def __init__(self, input_size, output_size):
        super(Net, self).__init__()
        #Layer 1
        self.Lin1 = nn.Linear(input_size, int(input_size/2))
        self.ReLu1 = nn.ReLU()
        self.Batch1 = nn.BatchNorm1d(int(input_size/2))
        #Layer 2
        self.Lin2 = nn.Linear(int(input_size/2), output_size)
        self.ReLu2 = nn.ReLU()
        self.Batch2 = nn.BatchNorm1d(output_size)
        self.softMax = nn.LogSoftmax()

    def forward(self, input):
        output1 = self.Batch1(self.ReLu1(self.Lin1(input)))
        output2 = self.softMax(self.Batch2(self.ReLu2(self.Lin2(output1))))
        return output2

NN = Net(num_letters, 2)

"""------TRAINING------"""

def getRandomTrainingEx():
    gender = genders[random.randint(0, 1)]
    name = all_names[gender][random.randint(0, len(all_names[gender])-1)]
    gender_tensor = Variable(torch.LongTensor([genders.index(gender)]))
    name_tensor = Variable(nameToTensor(name))
    return gender_tensor, name_tensor, gender

def train(input, target):
    loss_func = nn.NLLLoss()

    optimizer = optim.SGD(NN.parameters(), lr=0.0001, momentum=0.9)

    optimizer.zero_grad()

    output = NN(input)

    loss = loss_func(output, target)
    loss.backward()
    optimizer.step()

    return output, loss

all_losses = []
current_loss = 0

for i in range(100000):
    gender_tensor, name_tensor, gender = getRandomTrainingEx()
    output, loss = train(name_tensor, gender_tensor)
    current_loss += loss

    if i%1000 == 0:
        print("Guess: %s, Correct: %s, Loss: %s" % (outputToGender(output), gender, loss.data[0]))

    if i%100 == 0:
        all_losses.append(current_loss/10)
        current_loss = 0

# plt.figure()
# plt.plot(all_losses)
# plt.show()

请帮助新手!

2 个答案:

答案 0 :(得分:2)

  1. 调试您的错误:
  2. Pycharm是一个有用的python调试器,可让您设置断点和查看张量的维度。
    为了便于调试,请不要像那样堆叠前进

    output1 = self.Batch1(self.ReLu1(self.Lin1(input)))
    

    相反,

    h1 = self.ReLu1(self.Lin1(input))
    h2 = self.Batch1(h1)
    

    对于堆栈跟踪,Pytorch还提供了Pythonic错误堆栈跟踪。我相信之前

    RuntimeError: matrices expected, got 3D, 2D tensors at /py/conda-bld/pytorch_1493681908901/work/torch/lib/TH/generic/THTensorMath.c:1232
    

    有一些python错误堆栈跟踪指向代码。为了便于调试,正如我所说,不要向前堆叠。

    使用Pycharm在崩溃点之前创建断点。在调试器观察器中然后使用Variable(torch.rand(dim1, dim2))测试前向传递输入,输出尺寸以及尺寸是否不正确。与输入维度比较。在调试器观察器中调用input.size()

    例如,self.ReLu1(self.Lin1(Variable(torch.rand(10, 20)))).size()。如果它显示读取文本(错误),则输入维度不正确。否则,它显示输出的大小。

    pycharm

    1. 阅读文档
    2. Pytorch Docs中,它指定输入/输出维度。它还有一个示例代码片段

      >>> rnn = nn.RNN(10, 20, 2)
      >>> input = Variable(torch.randn(5, 3, 10))
      >>> h0 = Variable(torch.randn(2, 3, 20))
      >>> output, hn = rnn(input, h0)
      

      您可以使用PyCharm Debugger中的代码片段来探索输入的维度,您感兴趣的特定层的输出(RNN,Linear,BatchNorm1d)。

答案 1 :(得分:0)

首先,关于您的错误,正如其他答案所说的那样以及您的异常,可能是因为您的输入参数形状不正确。您可以尝试调试以隔离出错的行,然后用它编辑您的问题,这样我们就可以确定导致问题的原因并纠正它(没有完整的堆栈跟踪,更难以知道问题是什么)。

现在,您正在尝试实施神经网络,按性别分类名称,如您所示。我们可以看到,此任务需要以某种方式输入名称(具有不同的大小)并输出性别(二进制变量:男性,女性)。然而,神经网络通常被构建和训练,以对固定大小的特征的输入(向量)进行分类,就像他们在pytorch docs中提到的那样:

  

参数:input_size - 输入x

预期功能的数量      

...

看看你提到的tutorial,他们确实考虑了这种情况,因为在他们的情况下,网络的输入是一个转换为“单热矢量”的单个字母,因为它们表明:

  

要运行此网络的一个步骤,我们需要传递一个输入(在我们的例子中,是当前字母的Tensor )和之前的隐藏状态(我们首先将其初始化为零)。我们将获得输出(每种语言的概率)和下一个隐藏状态(我们将在下一步中保留)。

甚至给出一个例子(记得在pytorch中张量为Variable):

input = Variable(letterToTensor('A'))
hidden = Variable(torch.zeros(1, n_hidden))
output, next_hidden = rnn(input, hidden)

注意:话虽如此,您还可以采取其他一些措施来使您的实施适应可变大小的输入。根据我的经验以及thisthis other个重要问题的补充,您可以:

  1. 预处理数据以提取新功能并将其转换为固定大小的输入。这通常是最常用的方法,但需要经验和耐心才能获得好的功能。使用的一些技术是PCA(主成分分析)和LDA(潜在Dirichlet分配)

    例如,您可以从数据中提取以下内容:名称的长度,名称中的字母 a 的数量(女性名称往往更多) a's),名称中的字母 e 的数量(相同但男性名字可能是?),以及其他...因此您可以生成[name_length, a_found, e_found, ...]等新功能。然后,您可以按照常规方法使用新的固定大小向量。请注意,这些功能必须有意义;这些是我刚才提出的(尽管它们可以起作用)。

  2. 将您的输入名称拆分为固定大小的子字符串(或使用滑动窗口进行迭代),然后您可以使用为该大小设计的网络对它们进行分类,并以整体方式组合输出以获得最终结果分类。