Ошибка атрибута: объект ‘tuple’ не имеет атрибута ‘size’

#python #deep-learning #pytorch #recurrent-neural-network #gated-recurrent-unit

#python #глубокое обучение #pytorch #рекуррентная нейронная сеть #gated-recurrent-unit

Вопрос:

ОБНОВЛЕНИЕ: оглядываясь назад на этот вопрос, большая часть кода оказалась ненужной. Таким образом, скрытый слой Pytorch RNN должен быть тензором torch. Когда я опубликовал вопрос, скрытый слой был кортежем.

Ниже приведен мой загрузчик данных.

 from torch.utils.data import TensorDataset, DataLoader

def batch_data(log_returns, sequence_length, batch_size):
    """
    Batch the neural network data using DataLoader
    :param log_returns: asset's daily log returns
    :param sequence_length: The sequence length of each batch
    :param batch_size: The size of each batch; the number of sequences in a batch
    :return: DataLoader with batched data
    """
    
    # total number of batches we can make
    n_batches = len(log_returns)//batch_size
    
    # Keep only enough characters to make full batches
    log_returns = log_returns[:n_batches * batch_size]
    
    y_len = len(log_returns) - sequence_length
    
    x, y = [], []
    for idx in range(0, y_len):
        idx_end = sequence_length   idx
        x_batch = log_returns[idx:idx_end]
        x.append(x_batch)
        # only making predictions after the last word in the batch
        batch_y = log_returns[idx_end]    
        y.append(batch_y)    
    
    # create tensor datasets
    x_tensor = torch.from_numpy(np.asarray(x))
    y_tensor = torch.from_numpy(np.asarray(y))
    
    # make x_tensor 3-d instead of 2-d
    x_tensor = x_tensor.unsqueeze(-1)
    
    data = TensorDataset(x_tensor, y_tensor)
    
    data_loader = DataLoader(data, shuffle=False, batch_size=batch_size)
    
    # return a dataloader
    return data_loader
 
     def init_hidden(self, batch_size):
        ''' Initializes hidden state '''
        # Create two new tensors with sizes n_layers x batch_size x n_hidden,
        # initialized to zero, for hidden state and cell state of LSTM
        weight = next(self.parameters()).data
        
        if (train_on_gpu):
            hidden = (weight.new(self.n_layers, batch_size, self.n_hidden).zero_().cuda(),
                      weight.new(self.n_layers, batch_size, self.n_hidden).zero_().cuda())
        else:
            hidden = (weight.new(self.n_layers, batch_size, self.n_hidden).zero_(),
                      weight.new(self.n_layers, batch_size, self.n_hidden).zero_())
        
        return hidden
 

Я не знаю, что не так. Когда я пытаюсь начать обучение модели, я получаю сообщение об ошибке:

 AttributeError: 'tuple' object has no attribute 'size'
 

Комментарии:

1. Можете ли вы также предоставить код, в котором вы вызываете свою модель?

2. добавлено в мой пост… дайте мне знать, если вы также хотели бы увидеть циклы обучения

3. какой тип nn_input type(nn_input)

4. @Mattpats, да, это тоже было бы интересно посмотреть. Точнее, какое значение передается как hidden ?

5. github.com/mattpats/GRU_time_series_regression

Ответ №1:

Проблема проистекает из того факта, что hidden forward определении) не является a Torch.Tensor . Поэтому r_output, hidden = self.gru(nn_input, hidden) возникает довольно запутанная ошибка без точного указания того, что не так в аргументах. Хотя вы можете видеть, что он вызван внутри nn.RNN функции с именем check_hidden_size()

Сначала я был в замешательстве, думая, что второй аргумент nn.RNN : h0 содержит кортеж (hidden_state, cell_state) . То же самое можно сказать и о втором элементе, возвращаемом этим вызовом: hn . Это не так h0 , и hn оба Torch.Tensor являются s. Интересно, что вы можете распаковывать сложенные тензоры:

 >>> z = torch.stack([torch.Tensor([1,2,3]), torch.Tensor([4,5,6])])
>>> a, b = z
>>> a, b
(tensor([1., 2., 3.]), tensor([4., 5., 6.]))
 

Предполагается , что вы должны предоставить тензор в качестве второго аргумента a nn.GRU __call__ .


Редактировать — После дальнейшей проверки вашего кода я обнаружил, что вы снова преобразуете hidden обратно в кортеж… В ячейке [14] у вас есть hidden = tuple([each.data for each in hidden]) . Который в основном перезаписывает модификацию, которую вы выполнили init_hidden torch.stack .

Сделайте шаг назад и посмотрите на исходный код для RNNBase базового класса для модулей RNN. Если скрытое состояние не задано для пересылки, по умолчанию оно будет равно:

 if hx is None:
    num_directions = 2 if self.bidirectional else 1
    hx = torch.zeros(self.num_layers * num_directions,
                     max_batch_size, self.hidden_size,
                     dtype=input.dtype, device=input.device)
 

По сути, это точная инициализация, аналогичная той, которую вы пытаетесь реализовать. Конечно, вы хотите только сбросить скрытые состояния в каждую эпоху (я не понимаю, почему …). В любом случае, основной альтернативой было бы установить hidden значение None в начале эпохи, передаваемое как есть self.forward_back_prop , затем to rnn , затем to self.rnn , который, в свою очередь, инициализирует его по умолчанию для вас. Затем перезаписать hidden скрытым состоянием, возвращенным этим прямым вызовом RNN.

Подводя итог, я сохранил только соответствующие части кода. Удалите init_hidden функцию из AssetGRU и внесите эти изменения:

 def forward_back_prop(rnn, optimizer, criterion, inp, target, hidden):
    ...
    if hidden is not None:
        hidden = hidden.detach()
    ...
    output, hidden = rnn(inp, hidden)  
    ...
    return loss.item(), hidden


def train_rnn(rnn, batch_size, optimizer, criterion, n_epochs, show_every_n_batches):
    ...
    for epoch_i in range(1, n_epochs   1):
        
        hidden = None
        
        for batch_i, (inputs, labels) in enumerate(train_loader, 1):
            loss, hidden = forward_back_prop(rnn, optimizer, criterion, 
                                             inputs, labels, hidden)
            ...

    ...
 

Комментарии:

1. Спасибо за ваш ответ. К сожалению, я все еще получаю одно и то же сообщение об ошибке. Не уверен, поможет это или нет, но изначально этот блокнот был генератором слов НЛП. Я пытаюсь преобразовать его в регрессионную модель, чтобы вместо предсказания следующего слова он предсказывал следующее число во временном ряду. Основное различие между двумя моделями заключается в отсутствии слоя встраивания в новой модели. Может ли отсутствие слоя встраивания объяснить сообщение об ошибке?

2. Я не думаю, что проблема заключается в слое встраивания. Не могли бы вы предоставить код для основного цикла обучения, в котором вызывается ваш класс GRU?

3. Я подумал, что было бы проще опубликовать всю записную книжку и набор данных на github. Если вы предпочитаете видеть это в stackoverflow, просто дайте мне знать. github.com/mattpats/GRU_time_series_regression

4. Я думаю, что сейчас он обучается должным образом. Большое вам спасибо за вашу помощь. Однако у меня возник быстрый вопрос. Установив hidden = None в начале каждой эпохи, скрытое состояние будет инициализироваться / сбрасываться в скрытое состояние по умолчанию, указанное в коде RNNBase, который вы описываете. Но когда вы говорите «Я не понимаю, почему», когда ссылаетесь на это, есть ли лучший метод, о котором вы думаете?

5. Мне просто любопытно, в чем причина сохранения скрытых состояний в памяти для всех точек данных в наборе данных. Это то, что вы где-то читали? Я сам не знаю ответа. Я бы не стал делать это так и вместо этого просто позволил ему сбрасывать состояния при каждом вызове.

Ответ №2:

Вокруг 0 должны быть скобки [] вместо ().

 def forward(self, nn_input, hidden):
    ''' Forward pass through the network. 
        These inputs are x, and the hidden/cell state `hidden`. '''
    
    # batch_size equals the input's first dimension
    batch_size = nn_input.size(0)
 

Комментарии:

1. Нет, .size это функция, и вызов torch.Tensor.size с целым числом вернет размер по этой оси.