トラッキングデータを扱う最適なニューラルネットワークを実験的に探索するwith pytorch

With Pytorch!

Pytorch.com上にRNNを用いた名前の出身国を識別するチュートリアルがある.

このチュートリアルでは単語(名前)を一文字ずつ読み込み、各タイムステップで隠れ状態を出力して、次のステップにその隠れ状態と次の文字を入力として読み込むRNNを作成する.

チュートリアルで作成するRNN

RNN Model

import torch.nn as nn

class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(RNN, self).__init__()

        self.hidden_size = hidden_size

        self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
        self.i2o = nn.Linear(input_size + hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden):
        combined = torch.cat((input, hidden), 1)
        hidden = self.i2h(combined)
        output = self.i2o(combined)
        output = self.softmax(output)
        return output, hidden

    def initHidden(self):
        return torch.zeros(1, self.hidden_size)

n_hidden = 128
rnn = RNN(n_letters, n_hidden, n_categories)

上記のようにチュートリアルのRNNモジュールは非常に簡単なものになっていて,線形レイヤーの組み合わせを使用している.

チュートリアルの中にLSTMやGRUといったアーキテクチャーはなく,演習として残されていた.自分が書いたコードは以下の通りである.

LSTM Model

import torch.nn as nn

class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, memory_size, output_size):
        super(LSTM, self).__init__()

        self.hidden_size = hidden_size
        self.memory_size = memory_size
        
        self.Wf = nn.Linear(input_size, hidden_size)
        self.Wi = nn.Linear(input_size, hidden_size)
        self.Wo = nn.Linear(input_size, hidden_size)
        self.Wc = nn.Linear(input_size, hidden_size)
        
        self.Uf = nn.Linear(hidden_size, hidden_size)
        self.Ui = nn.Linear(hidden_size, hidden_size)
        self.Uo = nn.Linear(hidden_size, hidden_size)
        self.Uc = nn.Linear(hidden_size, hidden_size)
        
        self.output = nn.Linear(hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden, memory):
        a1 = nn.Sigmoid()
        a2 = nn.Tanh()
        
        forget_gate = a1(self.Wf(input)+self.Uf(hidden))
        input_gate = a1(self.Wi(input)+self.Ui(hidden))
        output_gate = a1(self.Wo(input)+self.Uo(hidden))
        
        cell_gate = torch.mul(forget_gate, memory) + torch.mul(input_gate, a2(self.Wc(input)+self.Uc(hidden)))
        memory = cell_gate
        hidden = torch.mul(a2(memory), output_gate)
        
        output = self.output(hidden)
        output = self.softmax(output)
        return output, hidden, memory
      
    def initHidden(self):
        return torch.zeros(1, self.hidden_size)

    def initMemory(self):
        return torch.zeros(1, self.memory_size)
      
n_hidden = 128
n_memory = n_hidden
lstm = LSTM(n_letters, n_hidden, n_memory, n_categories)
{\displaystyle {\begin{aligned}f_{t}&=\sigma _{g}(W_{f}x_{t}+U_{f}h_{t-1}+b_{f})\\i_{t}&=\sigma _{g}(W_{i}x_{t}+U_{i}h_{t-1}+b_{i})\\o_{t}&=\sigma _{g}(W_{o}x_{t}+U_{o}h_{t-1}+b_{o})\\c_{t}&=f_{t}\circ c_{t-1}+i_{t}\circ \sigma _{c}(W_{c}x_{t}+U_{c}h_{t-1}+b_{c})\\h_{t}&=o_{t}\circ \sigma _{h}(c_{t})\end{aligned}}}

GRU Model

import torch.nn as nn

class GRU(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(GRU, self).__init__()

        self.hidden_size = hidden_size
        
        self.Wz = nn.Linear(input_size, hidden_size)
        self.Wr = nn.Linear(input_size, hidden_size)
        self.Wh = nn.Linear(input_size, hidden_size)
        
        self.Uz = nn.Linear(hidden_size, hidden_size)
        self.Ur = nn.Linear(hidden_size, hidden_size)
        self.Uh = nn.Linear(hidden_size, hidden_size)
        
        self.output = nn.Linear(hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden):
        a1 = nn.Sigmoid()
        a2 = nn.Tanh()
        ones = torch.ones(1, self.hidden_size)
        
        z = a1(self.Wz(input)+self.Uz(hidden))
        r = a1(self.Wr(input)+self.Ur(hidden))
        
        h = torch.mul(z, hidden) + torch.mul((ones-z), a2(self.Wh(input)+self.Uh(torch.mul(r,hidden))))
        hidden = h
        
        output = self.output(hidden)
        output = self.softmax(output)
        return output, hidden
      
    def initHidden(self):
        return torch.zeros(1, self.hidden_size)   
n_hidden = 128
gru = GRU(n_letters, n_hidden, n_categories)
{\displaystyle {\begin{aligned}z_{t}&=\sigma _{g}(W_{z}x_{t}+U_{z}h_{t-1}+b_{z})\\r_{t}&=\sigma _{g}(W_{r}x_{t}+U_{r}h_{t-1}+b_{r})\\h_{t}&=z_{t}\circ h_{t-1}+(1-z_{t})\circ \sigma _{h}(W_{h}x_{t}+U_{h}(r_{t}\circ h_{t-1})+b_{h})\end{aligned}}}

サッカーにどれが最適かを検証

トラッキングデータから選手のポジションを予測する(GK/DF/MF/FW)

という予測問題を考える.

RNN系もそうだが,トラッキングデータを一度図にしたものやクリエイティブにデータやアーキテクチャを加工し,どの組み合わせで損失が最も低いのかを検証してみることにする.

使用するアーキテクチャーは以下である:

  • 全結合NN
  • 畳み込みNN (VGG16\ResNet50)
  • RNN
  • LSTM/ Peep hole LSTM/ Peep hole Convolutional LSTM
  • GRU

使用するデータは以下である:

  • gps測定機器を用いて計測したサッカー選手のトラッキングデータ
  • ビデオに画像処理を行って取得したトラッキングデータ
  • トラッキングデータを可視化した画像データ

次回のアップデートは近日中に行います.楽しみにしててください!