{"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\nfrom joblib import Parallel, delayed","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-22T18:48:41.962567Z","iopub.execute_input":"2025-03-22T18:48:41.962934Z","iopub.status.idle":"2025-03-22T18:48:48.249156Z","shell.execute_reply.started":"2025-03-22T18:48:41.962898Z","shell.execute_reply":"2025-03-22T18:48:48.248054Z"}},"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-22T18:48:48.250451Z","iopub.execute_input":"2025-03-22T18:48:48.251031Z","iopub.status.idle":"2025-03-22T18:48:48.478741Z","shell.execute_reply.started":"2025-03-22T18:48:48.250995Z","shell.execute_reply":"2025-03-22T18:48:48.477377Z"}},"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-22T18:48:48.479836Z","iopub.execute_input":"2025-03-22T18:48:48.480115Z","iopub.status.idle":"2025-03-22T18:48:49.354878Z","shell.execute_reply.started":"2025-03-22T18:48:48.480092Z","shell.execute_reply":"2025-03-22T18:48:49.353852Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Quantizer:\n    def __init__(self, num_bits):\n        self.range = 2**num_bits\n        self.max = 2**(num_bits - 1) - 1\n        self.min = -2**(num_bits - 1)\n        if num_bits <= 8:\n            self.dtype = torch.int8\n        elif num_bits <= 16:\n            self.dtype = torch.int16\n        elif num_bits <= 32:\n            self.dtype = torch.int32\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, 0, dtype=self.dtype), min_val, max_val\n        scale = self.range / (max_val - min_val)\n        quantized_tensor = torch.round((tensor - min_val) * scale + self.min).clamp(self.min, 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.range\n        return (quantized_tensor.to(torch.float32) - self.min) * scale + min_val","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T18:48:49.357128Z","iopub.execute_input":"2025-03-22T18:48:49.357511Z","iopub.status.idle":"2025-03-22T18:48:49.365617Z","shell.execute_reply.started":"2025-03-22T18:48:49.357475Z","shell.execute_reply":"2025-03-22T18:48:49.364466Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"q = Quantizer(num_bits=16)\n\ndef process(f):\n    output_path = output_dir + os.path.splitext(f)[0] + '.pt'\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    torch.save(spec, output_path)\n    return {'filename': f, 'min_value': min_val.item(), 'max_value': max_val.item()}\n\nquantize_params = Parallel(n_jobs=-1)(\n    delayed(process)(f)\n    for f in tqdm(filenames, desc=\"Getting specs & running inference\")\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-22T18:48:59.133892Z","iopub.execute_input":"2025-03-22T18:48:59.134216Z","iopub.status.idle":"2025-03-22T18:49:01.210714Z","shell.execute_reply.started":"2025-03-22T18:48:59.134194Z","shell.execute_reply":"2025-03-22T18:49:01.209309Z"}},"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] + '.pt'\n    spec = torch.load(output_path, weights_only=True)[:, :size[1]]\n    spec = q.dequantize(spec, min_value, max_value)\n    show_spec(spec)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-22T18:49:37.745230Z","iopub.execute_input":"2025-03-22T18:49:37.745636Z","iopub.status.idle":"2025-03-22T18:49:38.160686Z","shell.execute_reply.started":"2025-03-22T18:49:37.745605Z","shell.execute_reply":"2025-03-22T18:49:38.159791Z"}},"outputs":[],"execution_count":null}]}