ネットサーフィン中に面白そうなものを見つけたので、後出しになるが解いてみる。🦃
https://www.kaggle.com/c/dont-call-me-turkey/

学習データ

学習データは1データごとに下のような構造

1
2
3
4
5
6
7
8
9
10
- audio_embedding
- 0



- 9
- is_turkey
- vid_id
- end_time_seconds_youtube_clip
- start_time_seconds_youtube_clip

audio_embeddingとは、VGGishによって、YouTubeの動画データをを1秒ごとに128次元に圧縮したものらしい。これが最大10秒分ある。

vidはYouTubeで動画を開いたときにurlの末尾につく、youtube.com/watch?v=2lAe1cqCOXo2lAe1cqCOXoの値のよう。試しにis_turkey=1の動画を見ると、七面鳥の鳴き声を確認できる。

モデル設計

  • データ前処理
    10秒に満たないデータがあるため、0で埋める。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    train = pd.read_json('train.json')
    test = pd.read_json('test.json')
    #train data
    train_x_raw=np.array(train.audio_embedding)# [1195,10,128]たまに足りなくておかしい
    train_x =np.zeros((1195,10,128))
    ##整形
    for i in range(len(train_x_raw)):
    if(np.array(train_x_raw[i]).shape[0] is not 10):#足りない場合埋める
    lack=10 - np.array(train_x_raw[i]).shape[0]
    train_x[i]=np.append(train_x_raw[i],np.zeros((lack,128) ),axis=0)
    else:#足りてたらnumpyに変換
    train_x[i]=np.array(train_x_raw[i])
    train_y=train.is_turkey

    #test data
    test_x_raw=test.audio_embedding#[1196,10,128]
    test_x =np.zeros((1196,10,128))
    for i in range(len(test_x_raw)):
    if(np.array(test_x_raw[i]).shape[0] is not 10):#足りない場合埋める
    lack=10 - np.array(test_x_raw[i]).shape[0]
    test_x[i]=np.append(test_x_raw[i],np.zeros((lack,128)),ax is=0)
    else:#足りてたらnumpyに変換
    test_x[i]=np.array(test_x_raw[i])
  • モデル定義
    10x128を1枚の画像のようにcnnの入力とする。損失関数nn.BCEWithLogitsLoss()はsigmoidを含むため、モデルの出力は(0~1)でない。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ML(nn.Module):
def __init__(self, device='cuda'):
super().__init__()
self.device = device
self.pad = nn.ZeroPad2d(1)
self.conv1 = nn.Conv2d(1, 64,(2,12))
self.pool1 = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(64, 64, (2,2))
self.pool2 = nn.MaxPool2d(2)
self.dropout = nn.Dropout(p=0.3)
self.f1=nn.ReLU()
self.f2=nn.ReLU()
self.l = nn.Linear(5760,1)
def forward(self,x):
h=self.conv1(h)
h=self.f1(h)
h=self.dropout(h)
h=self.pool1(h)
h=self.conv2(h)
h=self.f2(h)
h=self.dropout(h)
h=self.pool2(h)

h=h.reshape(5760)
h=self.l(h)#出力形式に線形変換
h=self.dropout(h)
return h
  • 学習部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    device = torch.device('cuda')
    model = cnn(device=device).to(device)


    criterion = nn.BCEWithLogitsLoss()
    optimizer = optimizers.Adam(model.parameters())
    def train_step(x,t):
    model.train()
    y=model(x)
    loss = criterion(y,t)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    return loss

    #パラメータ更新開始
    epochs =100
    lists=np.array(range(len(train_x)))
    histories=np.array([])
    for epoch in tqdm(range(epochs)):
    train_loss = 0.
    np.random.shuffle(lists)
    for i in lists:
    x_tmp = np.array(train_x[i]).reshape(1,1,10,128)
    x = torch.from_numpy(x_tmp).type('torch.FloatTensor').to('cuda')#入力形式に変換(入力)
    t = torch.from_numpy(np.array([train_y[i]])).type('torch.Floa tTensor').to('cuda')#入力形式に変換(出力)
    loss = train_step(x,t)#順伝播,逆伝播,更新
    train_loss += loss.item()
    train_loss /= len(train_x)
    histories=np.append(histories,train_loss)
    print('Epoch: {}, Cost: {:.3f}'.format(epoch+1,train_loss))
  • 損失関数の推移

  • 結果
    実際のcompetitionの様子を見てるとまだまだ上がいるので、改良の余地がありそう。

出典・参考: