{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":70203,"databundleVersionId":8068726,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import librosa\nfrom scipy.signal import butter, filtfilt\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport time\nimport os\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Input, Conv1D, MaxPooling1D, Flatten, Dense, Dropout\nfrom tqdm import tqdm\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\n","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:06:26.694956Z","iopub.execute_input":"2024-05-25T02:06:26.695342Z","iopub.status.idle":"2024-05-25T02:06:41.957531Z","shell.execute_reply.started":"2024-05-25T02:06:26.69531Z","shell.execute_reply":"2024-05-25T02:06:41.95636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#指定したファイルパスにあるoggファイルを5秒毎に分割した、numpyデータを吐き出してくれる君\ndef split_and_pad_ogg(file_path, segment_duration=5, sr=32000):\n    \"\"\"\n    OGGファイルを5秒ごとに分割し、各セグメントをnumpy配列に変換する。\n    5秒に満たないセグメントはゼロでパディングされる。\n\n    Args:\n    file_path (str): OGGファイルのパス。\n    segment_duration (int): セグメントの持続時間（秒）。\n    sr (int): サンプリングレート。\n\n    Returns:\n    List[np.ndarray]: 分割され、パディングされた音声データのリスト。\n    \"\"\"\n    # 音声ファイルを読み込む\n    audio, _ = librosa.load(file_path, sr=sr)\n\n    # セグメントのサンプル数を計算\n    samples_per_segment = segment_duration * sr\n\n    # 音声データをセグメントに分割\n    num_segments = int(np.ceil(len(audio) / samples_per_segment))\n    segments = []\n\n    for i in range(num_segments):\n        start_sample = i * samples_per_segment\n        end_sample = start_sample + samples_per_segment\n        segment = audio[start_sample:end_sample]\n        \n        # セグメントが5秒未満の場合、ゼロでパディング\n        if len(segment) < samples_per_segment:\n            segment = np.pad(segment, (0, samples_per_segment - len(segment)), 'constant')\n        \n        segments.append(segment)\n\n    return segments\n\ndef apply_bandpass_filter(signal, center_freq, freq_width, sr=32000):\n    low = (center_freq - freq_width / 2) / (sr / 2)\n    high = (center_freq + freq_width / 2) / (sr / 2)\n    b, a = butter(N=4, Wn=[low, high], btype='band')\n    filtered_signal = filtfilt(b, a, signal)\n    return filtered_signal\n\ndef multi_bandpass_filter(signal, sr=32000):\n    center_freqs = [1500, 2000, 7000]\n    freq_width = 1000\n    filtered_signals = [apply_bandpass_filter(signal, cf, freq_width) for cf in center_freqs]\n    return np.stack(filtered_signals, axis=1)\n\n#tf.data.datasetに正解ラベルを渡すための関数\ndef get_label_by_filename(filepath, df):\n    \"\"\"\n    ファイルパスに基づいて正解ラベルを返す関数。\n\n    Args:\n    filepath (str): ファイルの完全なパス。\n    df (pd.DataFrame): ファイル名と正解ラベルが格納されたDataFrame。\n\n    Returns:\n    int: 対応する正解ラベル。ファイルが見つからない場合はNone。\n    \"\"\"\n    # ファイル名を抽出\n    filename = filepath.split('/')[-1]\n    \n    # DataFrameからファイル名に対応するラベルを検索\n    label_row = df[df['filename'] == filename]\n    \n    # 対応するラベルがあれば返す\n    if not label_row.empty:\n        return label_row['target'].iloc[0]\n    else:\n        return None\n\n#オンデマンド読み込みを実現するための関数\n#すでに分割されたsignalをラベルと一緒に渡してdataset1.concatenate(dataset2)でどんどん結合していく形にしよう。\n\ndef build_dataset(filtered_signal, label):\n    # filtered_signal をテンソルに変換\n    filtered_signal = tf.convert_to_tensor([filtered_signal], dtype=tf.float32)\n    #print(filtered_signal)\n    filtered_signal_ds = tf.data.Dataset.from_tensor_slices(filtered_signal)\n    \n    label = tf.convert_to_tensor([label], dtype=tf.int32)\n    #print(label)\n    label_ds = tf.data.Dataset.from_tensor_slices(label)\n    \n    return tf.data.Dataset.zip((filtered_signal_ds, label_ds))\n\ndef process_file(file_path, df):\n    segments = split_and_pad_ogg(file_path, segment_duration=5, sr=32000)\n    datasets = None\n    for segment in segments:\n        filtered_signal = multi_bandpass_filter(segment, sr=32000)\n        label = get_label_by_filename(file_path, df)\n        dataset = build_dataset(filtered_signal, [label])\n        if datasets is None:\n            datasets = dataset\n        else:\n            datasets = datasets.concatenate(dataset)\n    return datasets\n\ndef process_valid_file(file_path, df):\n    segments = split_and_pad_ogg(file_path, segment_duration=5, sr=32000)\n    datasets = None\n    for segment in segments:\n        filtered_signal = multi_bandpass_filter(segment, sr=32000)\n        label = get_label_by_filename(file_path, df)\n        dataset = build_dataset(filtered_signal, [label])\n        if datasets is None:\n            datasets = dataset\n        else:\n            datasets = datasets.concatenate(dataset)\n    return datasets\n\n#１次元CNNの構築\ndef build_model(input_shape, num_classes):\n    model = Sequential([\n        Input(shape=input_shape),  \n        Conv1D(filters=64, kernel_size=10, activation='relu'),\n        MaxPooling1D(pool_size=2),\n        Conv1D(filters=128, kernel_size=10, activation='relu'),\n        MaxPooling1D(pool_size=2),\n        Flatten(),\n        Dense(128, activation='relu'),\n        Dropout(0.5),\n        Dense(num_classes, activation='softmax')\n    ])\n    return model\n\n# データセットの保存関数\ndef serialize_example(feature, label):\n    feature_np = feature.numpy()  # TensorFlowのテンソルをNumpy配列に変換\n    label_np = label.numpy()  # TensorFlowのテンソルをNumpy配列に変換\n    \n    feature_dict = {\n        'feature': tf.train.Feature(float_list=tf.train.FloatList(value=feature_np.flatten())),\n        'label': tf.train.Feature(int64_list=tf.train.Int64List(value=label_np.flatten()))\n    }\n    example_proto = tf.train.Example(features=tf.train.Features(feature=feature_dict))\n    return example_proto.SerializeToString()\n\ndef save_dataset(dataset, file_path_prefix, batch_size=32):\n    file_index = 0\n    for batch in dataset.batch(batch_size):\n        file_path = f\"{file_path_prefix}_{file_index}.tfrecord\"\n        with tf.io.TFRecordWriter(file_path) as writer:\n            for features, labels in batch:\n                for feature, label in zip(features, labels):\n                    serialized_example = serialize_example(feature, label)\n                    writer.write(serialized_example)\n        file_index += 1\n        \ndef parse_example(serialized_example, feature_shape, label_shape):\n    feature_description = {\n        'feature': tf.io.FixedLenFeature(feature_shape, tf.float32),\n        'label': tf.io.FixedLenFeature(label_shape, tf.int64)\n    }\n    example = tf.io.parse_single_example(serialized_example, feature_description)\n    feature = tf.reshape(example['feature'], feature_shape)\n    label = tf.reshape(example['label'], label_shape)\n    return feature, label\n\ndef load_dataset(file_path_pattern, feature_shape, label_shape, batch_size=32):\n    files = tf.data.Dataset.list_files(file_path_pattern)\n    raw_dataset = files.interleave(\n        tf.data.TFRecordDataset, \n        cycle_length=tf.data.AUTOTUNE, \n        num_parallel_calls=tf.data.AUTOTUNE\n    )\n    parsed_dataset = raw_dataset.map(lambda x: parse_example(x, feature_shape, label_shape))\n    parsed_dataset = parsed_dataset.shuffle(buffer_size=1000)\n    parsed_dataset = parsed_dataset.batch(batch_size)\n    parsed_dataset = parsed_dataset.prefetch(tf.data.AUTOTUNE)\n    return parsed_dataset\n","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:07:22.957824Z","iopub.execute_input":"2024-05-25T02:07:22.958497Z","iopub.status.idle":"2024-05-25T02:07:22.985302Z","shell.execute_reply.started":"2024-05-25T02:07:22.95846Z","shell.execute_reply":"2024-05-25T02:07:22.984273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_PATH = '/kaggle/input/birdclef-2024'\nclass_names = sorted(os.listdir('/kaggle/input/birdclef-2024/train_audio/'))\nnum_classes = len(class_names)\nclass_labels = list(range(num_classes))\nlabel2name = dict(zip(class_labels, class_names))\nname2label = {v:k for k,v in label2name.items()}\n\ndf = pd.read_csv(f'{BASE_PATH}/train_metadata.csv')\ndf['filepath'] = BASE_PATH + '/train_audio/' + df.filename\ndf['target'] = df.primary_label.map(name2label)\ndf['filename'] = df.filepath.map(lambda x: x.split('/')[-1])\ndf['xc_id'] = df.filepath.map(lambda x: x.split('/')[-1].split('.')[0])\n\n# Display rwos\ndisplay(df.head(1))\nprint(df[\"filepath\"][1])\n\n# get_label_by_filenameの使用例\n#filepath = \"/kaggle/input/birdclef-2024/train_audio/asbfly/XC134896.ogg\"\nfilepath = df[\"filepath\"][1000]\nlabel = get_label_by_filename(filepath, df)\nprint(f'Label for {filepath}: {label}')","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:07:29.163961Z","iopub.execute_input":"2024-05-25T02:07:29.164387Z","iopub.status.idle":"2024-05-25T02:07:29.461236Z","shell.execute_reply.started":"2024-05-25T02:07:29.164345Z","shell.execute_reply":"2024-05-25T02:07:29.459881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 使用するoggファイルのパスを指定\nfile_path = '/kaggle/input/birdclef-2024/train_audio/asbfly/XC134896.ogg'\n\nsr=32000\n\n# フィルタの中心周波数と周波数幅を設定\ncenter_freq_1 = 1500\nfreq_width_1 = 1000\n\ncenter_freq_2 = 2000\nfreq_width_2 = 1000\n\ncenter_freq_3 = 7000\nfreq_width_3 = 1000\n\n# 使用例\nsegments = split_and_pad_ogg(file_path)\nprint(\"number of waveforms:\",len(segments))\ni = 1 # index of the waveform in segments\n\n# 処理を開始する前の時間を記録\nstart_time = time.time()\n\n# フィルタ処理された信号を取得\n#filtered_signal_1, sr_1 = bandpass_filter_from_ogg(file_path, center_freq_1, freq_width_1)\n#filtered_signal_2, sr_2 = bandpass_filter_from_ogg(file_path, center_freq_2, freq_width_2)\n#filtered_signal_3, sr_3 = bandpass_filter_from_ogg(file_path, center_freq_3, freq_width_3)\n\n# フィルタ処理された信号を取得\n#filtered_signal_1, sr_1 = apply_bandpass_filter(segments[i], center_freq_1, freq_width_1)\n#filtered_signal_2, sr_2 = apply_bandpass_filter(segments[i], center_freq_2, freq_width_2)\n#filtered_signal_3, sr_3 = apply_bandpass_filter(segments[i], center_freq_3, freq_width_3)\n\nfiltered_signals = multi_bandpass_filter(segments[i])\n\n# 処理を終了する前の時間を記録\nend_time = time.time()\n# 計測した処理時間を表示\nelapsed_time = end_time - start_time\nprint(f\"処理時間:{elapsed_time}秒\")\n\n# 結果のプロット\n#print(\"Number of samples:\",filtered_signal_1.shape,filtered_signal_2.shape,filtered_signal_3.shape)\n#print(\"Sampling Hz:\",sr_1,sr_2,sr_3)\nprint(\"number of samples:\",filtered_signals.shape)\nplt.figure(figsize=(10, 4))\n#plt.plot(np.arange(len(filtered_signal_1)) / sr, filtered_signal_1)\n#plt.plot(np.arange(len(filtered_signal_2)) / sr, filtered_signal_2)\n#plt.plot(np.arange(len(filtered_signal_3)) / sr, filtered_signal_3)\nplt.plot(np.arange(len(filtered_signals)) / sr, filtered_signals)\n\nplt.title('Filtered Signals')\nplt.xlabel('Time')\nplt.ylabel('Amplitude')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-22T11:42:25.455094Z","iopub.execute_input":"2024-05-22T11:42:25.455741Z","iopub.status.idle":"2024-05-22T11:42:25.917963Z","shell.execute_reply.started":"2024-05-22T11:42:25.45571Z","shell.execute_reply":"2024-05-22T11:42:25.91665Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df, valid_df = train_test_split(df, test_size=0.2)\nprint(f\"Num Train: {len(train_df)} | Num Valid: {len(valid_df)}\")\n\n# Train\ntrain_paths = train_df.filepath.values\nprint(train_paths[0:5])\ntrain_labels = train_df.target.values\nprint(train_labels[0:5])\ntrain_unique_elements = len(np.unique(train_labels))\nprint(train_unique_elements) \n\n# Valid\nvalid_paths = valid_df.filepath.values\nprint(valid_paths[0:5])\nvalid_labels = valid_df.target.values\nprint(valid_labels[0:5])\nvalid_unique_elements = len(np.unique(valid_labels))\nprint(valid_unique_elements) ","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:07:32.683905Z","iopub.execute_input":"2024-05-25T02:07:32.684297Z","iopub.status.idle":"2024-05-25T02:07:32.71472Z","shell.execute_reply.started":"2024-05-25T02:07:32.684257Z","shell.execute_reply":"2024-05-25T02:07:32.713238Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデルの作成\ninput_shape = (160000, 3)\nnum_classes = 182\nmodel = build_model(input_shape, num_classes)\n\n# モデルのコンパイル\nmodel.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n\n# モデルのサマリーを表示\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:07:36.766703Z","iopub.execute_input":"2024-05-25T02:07:36.767155Z","iopub.status.idle":"2024-05-25T02:07:42.509793Z","shell.execute_reply.started":"2024-05-25T02:07:36.767123Z","shell.execute_reply":"2024-05-25T02:07:42.508608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datasets = None\nwith ThreadPoolExecutor(max_workers=64) as executor:\n    futures = [executor.submit(process_file, file_path, df) for file_path in train_paths[0:1000]]\n    for future in tqdm(as_completed(futures), total=len(futures)):\n        result = future.result()\n        if datasets is None:\n            datasets = result\n        else:\n            datasets = datasets.concatenate(result)\n\ndatasets = datasets.shuffle(buffer_size=1000)\ndatasets = datasets.batch(32)\ndatasets = datasets.prefetch(tf.data.AUTOTUNE)\n\nprint(\"Train Feature shape:\", datasets.element_spec[0].shape)\nprint(\"Train Label shape:\", datasets.element_spec[1].shape)\nsave_dataset(datasets, 'train_dataset', batch_size=8)","metadata":{"execution":{"iopub.status.busy":"2024-05-25T02:07:45.632725Z","iopub.execute_input":"2024-05-25T02:07:45.633094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_datasets = None\nwith ThreadPoolExecutor(max_workers=64) as executor:\n    futures = [executor.submit(process_valid_file, file_path, df) for file_path in valid_paths[0:500]]\n    for future in tqdm(as_completed(futures), total=len(futures)):\n        result = future.result()\n        if valid_datasets is None:\n            valid_datasets = result\n        else:\n            valid_datasets = valid_datasets.concatenate(result)\n\nvalid_datasets = valid_datasets.shuffle(buffer_size=1000)\nvalid_datasets = valid_datasets.batch(32)\nvalid_datasets = valid_datasets.prefetch(tf.data.AUTOTUNE)\n\nprint(\"Validation Feature shape:\", valid_datasets.element_spec[0].shape)\nprint(\"Validation Label shape:\", valid_datasets.element_spec[1].shape)\nsave_dataset(valid_datasets, 'valid_dataset', batch_size=8)","metadata":{"execution":{"iopub.status.busy":"2024-05-22T01:54:30.806937Z","iopub.execute_input":"2024-05-22T01:54:30.808103Z","iopub.status.idle":"2024-05-22T01:54:57.974147Z","shell.execute_reply.started":"2024-05-22T01:54:30.808063Z","shell.execute_reply":"2024-05-22T01:54:57.973219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"feature_shape = [160000, 3]  # 適切な形状に置き換えてください\nlabel_shape = [1]  # 適切な形状に置き換えてください\nbatch_size = 16\n\ntrain_dataset = load_dataset('train_dataset_*.tfrecord', feature_shape, label_shape, batch_size)\nvalid_dataset = load_dataset('valid_dataset_*.tfrecord', feature_shape, label_shape, batch_size)\n\n# モデルの訓練\nmodel.fit(\n    train_dataset,\n    validation_data=valid_dataset,\n    epochs=10  # 適切なエポック数を指定してください\n\n# モデルの訓練後に重みを保存\nmodel.save('my_model.h5')","metadata":{"execution":{"iopub.status.busy":"2024-05-22T01:55:25.477279Z","iopub.execute_input":"2024-05-22T01:55:25.477764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 保存したモデルを読み込む\nfrom tensorflow.keras.models import load_model\nloaded_model = load_model('my_model.h5')\n\n# モデルの評価\nloss, accuracy = model.evaluate(valid_datasets)\nprint(f\"Loss: {loss}, Accuracy: {accuracy}\")","metadata":{"execution":{"iopub.status.busy":"2024-05-22T02:28:54.127995Z","iopub.execute_input":"2024-05-22T02:28:54.128694Z","iopub.status.idle":"2024-05-22T02:29:53.323671Z","shell.execute_reply.started":"2024-05-22T02:28:54.128653Z","shell.execute_reply":"2024-05-22T02:29:53.322387Z"},"trusted":true},"execution_count":null,"outputs":[]}]}