Don't call me turkry!をcnnでとく。
ネットサーフィン中に面白そうなものを見つけたので、後出しになるが解いてみる。🦃 https://www.kaggle.com/c/dont-call-me-turkey/
学習データ
学習データは1データごとに下のような構造
- 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=2lAe1cqCOXo
の2lAe1cqCOXo
の値のよう。試しにis_turkey=1
の動画を見ると、七面鳥の鳴き声を確認できる。
モデル設計
- データ前処理 10秒に満たないデータがあるため、0で埋める。
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)でない。
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
- 学習部分
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の様子を見てるとまだまだ上がいるので、改良の余地がありそう。
出典・参考:
Don't call me turkey! kaggle https://www.kaggle.com/c/dont-call-me-turkey/
(PyTorch) Temporal Convolutional Networks https://www.kaggle.com/ceshine/pytorch-temporal-convolutional-networks
VGGish https://github.com/tensorflow/models/tree/master/research/audioset/vggish