jupyter labのカーネルがクラッシュした(音声ファイル処理時)

# python備忘録(音声ファイル処理時のカーネルクラッシュ)

個人レベルの備忘録です。

## カーネルクラッシュ

### 経緯
[kaggleのコンペ](https://www.kaggle.com/competitions/birdclef-2025)に参加して音声ファイルのノイズ処理をやっていた
処理中にカーネルクラッシュが発生
.oggファイルに対してノイズ処理を行い、.oggファイルを出力するイメージ


### 環境
WSL上のコンテナを使っています。
```bash
root@eb843b40dc0e:~/work# python3 -V
Python 3.10.12
```
```bash
root@eb843b40dc0e:~/work# jupyter --version
Selected Jupyter core packages...
IPython          : 8.35.0
ipykernel        : 6.29.5
ipywidgets       : 8.1.6
jupyter_client   : 8.6.3
jupyter_core     : 5.7.2
jupyter_server   : 2.15.0
jupyterlab       : 4.4.0
nbclient         : 0.10.2
nbconvert        : 7.16.6
nbformat         : 5.10.4
notebook         : not installed
qtconsole        : not installed
traitlets        : 5.14.3
```

### 確認したこと
#### メモリ使用率の確認
処理中に使用率コマンドを見て確認したが顕著に値が増加したことはなかった
キャッシュが多少増えるくらい
```bash
watch -n 1 free -h
```
#### gc.collect()の追加
処理中にgc.collect()で明示的にメモリ解放を行ったが変わらず

#### コンテナの使用制限の確認
コンテナでなにかメモリ制限を設けていないか確認したが特に制限はなかった
```bash
root@eb843b40dc0e:~/work# cat /sys/fs/cgroup/memory/memory.stat | grep limit
hierarchical_memory_limit 9223372036854771712
hierarchical_memsw_limit 9223372036854771712
```

#### dmesgの確認
セグメンテーションフォールトが発生していることはわかる
libsndfileのライブラリで落ちてる??
```bash
root@eb843b40dc0e:~/work# dmesg | tail -30
# いくつか抜粋
[ 2024.713070] python3[28252]: segfault at 7ffe9cb897c0 ip 00007efe2f7d05ef sp 00007ffe9cb897c0 error 6 in libsndfile_x86_64.so[7efe2f6ed000+1f9000]
[ 2024.714388] Code: 29 ce 66 66 2e 0f 1f 84 00 00 00 00 00 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 0f 10 00 48 83 e8 10 48 83 c2 10 0f c6 c0 1b <0f> 29 42 f0 48 39 f0 75 e8 48 89 c8 48 83 e0 fc 40 f6 c7 03 74 51
[ 2024.715146] potentially unexpected fatal signal 11.
[ 2024.715358] CPU: 1 PID: 28252 Comm: python3 Not tainted 5.15.167.4-microsoft-standard-WSL2 #1
[ 2024.715671] RIP: 0033:0x7efe2f7d05ef
[ 2024.715803] Code: 29 ce 66 66 2e 0f 1f 84 00 00 00 00 00 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 0f 10 00 48 83 e8 10 48 83 c2 10 0f c6 c0 1b <0f> 29 42 f0 48 39 f0 75 e8 48 89 c8 48 83 e0 fc 40 f6 c7 03 74 51
[ 2024.716550] RSP: 002b:00007ffe9cb897c0 EFLAGS: 00010202
[ 2024.716720] RAX: 000055e67e275670 RBX: 00007ffe9d44cfd0 RCX: 0000000000230e00
[ 2024.716979] RDX: 00007ffe9cb897d0 RSI: 000055e67d9b1e80 RDI: 0000000000230e00
[ 2024.717239] RBP: 00007ffe9d44d040 R08: 000055e67d9b1e90 R09: 00000000008c3800
[ 2024.717498] R10: 0000000000000400 R11: 0000000000000206 R12: 00007ffe9cb897c0
[ 2024.717763] R13: 000055e67ac7a420 R14: 0000000000000000 R15: 000055e67b7d4f00
[ 2024.718020] FS:  00007efe83803000 GS:  0000000000000000
[ 2024.718775] WSL (29122 - CaptureCrash): Capturing crash for pid: 25326, executable: !usr!bin!python3.10, signal: 11, port: 50005
[ 2070.677480] mini_init (202): drop_caches: 1
```

#### ファイルが破損していないか確認
ファイルの読み込みで落ちているか見てみた
結果としては問題なかった。
ちゃんとlibrosaで読み取れた
```python
# librosaで読み込めないファイルがないか確認
def check_files_one_by_one(file_list):
    for path in file_list:
        #print(f"チェック中: {path}")
        try:
            y, sr = librosa.load(path, sr=32000)
            #print("OK！")
        except Exception as e:
            print(f"❌ 読み込みエラー: {e}")
            print(f"ファイルパス: {path}")
            print("このファイルが犯人かも")
            break
```

#### faulthandlerの有効化
faulthandler.enable()でスタックトレースを出力させてみた
```python
# main部分に下記を記載
import datetime
import faulthandler
import os
# クラッシュ対策でfaulthandler有効化
now = datetime.now()
date_str = now.strftime("%Y-%m-%d %H:%M:%S")
log_filename = f"error_{date_str}.log"
error_log = open(log_filename, 'w')
faulthandler.enable(file=error_log)

# 処理が正常に終わったらerror_logを削除
os.remove(error_log)
```
error.logの現在のスレッド
```
Current thread 0x00007f9b88a59000 (most recent call first):
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1403 in _cdata_io
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1394 in _array_io
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1068 in write
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 366 in write
  File "/root/work/birdclef-2025/src/noise_removal/adaptive_noise_remover.py", line 101 in process_file
  File "/tmp/ipykernel_80406/2283393843.py", line 37 in process_sample_files_super_safe
  File "/tmp/ipykernel_80406/2283393843.py", line 54 in <module>
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py", line 3579 in run_code
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py", line 3519 in run_ast_nodes
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py", line 3336 in run_cell_async
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/async_helpers.py", line 128 in _pseudo_sync_runner
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py", line 3132 in _run_cell
  File "/usr/local/lib/python3.10/dist-packages/IPython/core/interactiveshell.py", line 3077 in run_cell
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/zmqshell.py", line 549 in run_cell
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/ipkernel.py", line 449 in do_execute
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py", line 778 in execute_request
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/ipkernel.py", line 362 in execute_request
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py", line 437 in dispatch_shell
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py", line 534 in process_one
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py", line 545 in dispatch_queue
  File "/usr/lib/python3.10/asyncio/events.py", line 80 in _run
  File "/usr/lib/python3.10/asyncio/base_events.py", line 1909 in _run_once
  File "/usr/lib/python3.10/asyncio/base_events.py", line 603 in run_forever
  File "/usr/local/lib/python3.10/dist-packages/tornado/platform/asyncio.py", line 205 in start
  File "/usr/local/lib/python3.10/dist-packages/ipykernel/kernelapp.py", line 739 in start
  File "/usr/local/lib/python3.10/dist-packages/traitlets/config/application.py", line 1075 in launch_instance
  File "/usr/local/lib/python3.10/dist-packages/ipykernel_launcher.py", line 18 in <module>
  File "/usr/lib/python3.10/runpy.py", line 86 in _run_code
  File "/usr/lib/python3.10/runpy.py", line 196 in _run_module_as_main
```
重要そうなところを見てみると
```
Current thread 0x00007f9b88a59000 (most recent call first):
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1403 in _cdata_io
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1394 in _array_io
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 1068 in write
  File "/usr/local/lib/python3.10/dist-packages/soundfile.py", line 366 in write
  File "/root/work/birdclef-2025/src/noise_removal/adaptive_noise_remover.py", line 101 in process_file
```
writeの処理で落ちているみたい
[soudfile.py](https://github.com/bastibe/python-soundfile/blob/master/soundfile.py)
adaptive_noise_remover.pyは自前のpythonファイル
```python
# 処理抜粋
import soundfile as sf
        # 結果の保存
        if output_path is not None:
            # ディレクトリが存在しない場合は作成
            os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
            sf.write(output_path, y_processed, sr) #★ここ★
            self._log(f"処理結果を保存しました: {output_path}")
```
読み込み処理では落ちていないからファイル破損では引っかからなかったのかな

### その後
oggファイルじゃなくてwavファイルとして保存したらうまくいった
oggが圧縮ファイルってことに関係してるのかな

結局、評価データは.oggだから.wavから.oggに直さなきゃいけないけども