{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nimport torchaudio\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport os","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:38.263863Z","iopub.execute_input":"2025-03-22T06:06:38.264253Z","iopub.status.idle":"2025-03-22T06:06:38.270052Z","shell.execute_reply.started":"2025-03-22T06:06:38.264217Z","shell.execute_reply":"2025-03-22T06:06:38.268545Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/birdclef-2025/train.csv')\ninput_dir = '/kaggle/input/birdclef-2025/train_audio/'\noutput_dir = 'train_audio_specs/'\nfilenames = list(df.filename)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:38.271583Z","iopub.execute_input":"2025-03-22T06:06:38.272042Z","iopub.status.idle":"2025-03-22T06:06:38.422381Z","shell.execute_reply.started":"2025-03-22T06:06:38.271998Z","shell.execute_reply":"2025-03-22T06:06:38.421019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"to_spec = torch.nn.Sequential(\n    torchaudio.transforms.MelSpectrogram(\n        sample_rate=32000,\n        n_mels=128,\n        n_fft=1920,\n        hop_length=640,\n        center=False,\n        power=2,\n    ),\n    torchaudio.transforms.AmplitudeToDB(\n        stype=\"power\",\n        top_db=80.0,\n    )\n)\n\ndef show_spec(spec):\n    plt.imshow(spec)\n    plt.colorbar()\n    plt.show()\n\nsize = to_spec(torch.zeros(32000*5)).shape\n\nfor f in filenames[:1]:\n    f = input_dir + f\n    audio = torchaudio.load(f)[0][0]\n    spec = to_spec(audio)[:, :size[1]]\n    show_spec(spec)\n\nprint(size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:38.424859Z","iopub.execute_input":"2025-03-22T06:06:38.425255Z","iopub.status.idle":"2025-03-22T06:06:38.959043Z","shell.execute_reply.started":"2025-03-22T06:06:38.425221Z","shell.execute_reply":"2025-03-22T06:06:38.957783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Quantizer:\n    def __init__(self, num_bits):\n        self.max = 2**num_bits - 1\n        self.mid = 2**(num_bits-1)\n        if num_bits <= 8:\n            self.dtype = torch.uint8\n        elif num_bits <= 16:\n            self.dtype = torch.uint16\n        elif num_bits <= 32:\n            self.dtype = torch.uint32\n\n    def quantize(self, tensor):\n        min_val = tensor.min()\n        max_val = tensor.max()\n        if min_val == max_val:  # Edge case: all values are the same\n            return torch.full_like(tensor, self.mid, dtype=torch.uint16), min_val, max_val\n        scale = self.max / (max_val - min_val)\n        quantized_tensor = torch.round((tensor - min_val) * scale).clamp(0, self.max).to(self.dtype)\n        return quantized_tensor, min_val, max_val\n\n    def dequantize(self, quantized_tensor, min_val, max_val):\n        if min_val == max_val:\n            return torch.full_like(quantized_tensor, min_val, dtype=torch.float32)\n        scale = (max_val - min_val) / self.max\n        return quantized_tensor.to(torch.float32) * scale + min_val","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:38.960477Z","iopub.execute_input":"2025-03-22T06:06:38.960767Z","iopub.status.idle":"2025-03-22T06:06:38.968959Z","shell.execute_reply.started":"2025-03-22T06:06:38.960743Z","shell.execute_reply":"2025-03-22T06:06:38.967613Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"q = Quantizer(num_bits=16)\nquantize_params = []\n\nos.makedirs(output_dir, exist_ok=True)\nfor f in tqdm(filenames):\n    output_path = output_dir + os.path.splitext(f)[0]\n    os.makedirs(os.path.dirname(output_path), exist_ok=True)\n    audio = torchaudio.load(input_dir + f)[0][0]\n    spec, min_val, max_val = q.quantize(to_spec(audio))\n    quantize_params.append({'filename': f, 'min_value': min_val.item(), 'max_value': max_val.item()})\n    np.save(output_path, spec.cpu().numpy())\n\nquantize_df = pd.DataFrame(quantize_params)\nquantize_df.to_parquet('quantize_params.parquet')\nquantize_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:38.970299Z","iopub.execute_input":"2025-03-22T06:06:38.970726Z","iopub.status.idle":"2025-03-22T06:06:40.710749Z","shell.execute_reply.started":"2025-03-22T06:06:38.970682Z","shell.execute_reply":"2025-03-22T06:06:40.709584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for f, min_value, max_value in quantize_df[:1].iloc:\n    output_path = output_dir + os.path.splitext(f)[0] + '.npy'\n    spec = torch.tensor(np.load(output_path)[:, :size[1]])\n    spec = q.dequantize(spec, min_value, max_value)\n    show_spec(spec)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T06:06:40.712069Z","iopub.execute_input":"2025-03-22T06:06:40.712564Z","iopub.status.idle":"2025-03-22T06:06:41.013769Z","shell.execute_reply.started":"2025-03-22T06:06:40.712521Z","shell.execute_reply":"2025-03-22T06:06:41.012418Z"}},"outputs":[],"execution_count":null}]}