{"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":"gpu","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"}],"dockerImageVersionId":30636,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### Created by yunsuxiaozi","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"markdown","source":"### Import necessary libraries","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/ttahara/hms-hbac-resnet34d-baseline-training\n#https://www.kaggle.com/code/ttahara/hms-hbac-resnet34d-baseline-inference\n#necessary\nimport pandas as pd#导入csv文件的库\nimport numpy as np#进行矩阵运算的库\nimport matplotlib.pyplot as plt#导入强大的绘图库\nimport torch #一个深度学习的库Pytorch\nimport timm#图像分类预训练模型库\nimport torch.nn as nn#neural network,神经网络\nimport torch.optim as optim#一个实现了各种优化算法的库\nimport torch.nn.functional as F#神经网络函数库\nimport torchvision.transforms as transforms#Pytorch下面的图像处理库,用于对图像进行数据增强\n#设置随机种子\nimport random\nimport warnings#避免一些可以忽略的报错\nwarnings.filterwarnings('ignore')#filterwarnings()方法是用于设置警告过滤器的方法，它可以控制警告信息的输出方式和级别。","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### pretrain_model","metadata":{}},{"cell_type":"code","source":"#下载模型resnet34d,并且将训练好的参数加载进来\nmodel = timm.create_model('resnet34d',pretrained=True, num_classes=6, in_chans=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Config","metadata":{}},{"cell_type":"code","source":"class Config:\n    seed=2024\n    image_transform=transforms.Resize((512,512))\n    batch_size=32\n    num_epochs=10#由于是预训练模型,训练10个epoch足够了","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Seed ","metadata":{}},{"cell_type":"code","source":"def seed_everything(seed):\n    torch.backends.cudnn.deterministic = True#将cuda加速的随机数生成器设为确定性模式\n    torch.backends.cudnn.benchmark = True#关闭CuDNN框架的自动寻找最优卷积算法的功能，以避免不同的算法对结果产生影响\n    torch.manual_seed(seed)#pytorch的随机种子\n    np.random.seed(seed)#numpy的随机种子\n    random.seed(seed)#python内置的随机种子\nseed_everything(Config.seed)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### labels","metadata":{}},{"cell_type":"code","source":"train_df=pd.read_csv(\"/kaggle/input/hms-harmful-brain-activity-classification/train.csv\")\ntrain_df=train_df[train_df['eeg_sub_id']==0]\n\nlabels=['seizure','lpd','gpd','lrda','grda','other']\nfor label in labels:\n    group=train_df[f'{label}_vote'].groupby(train_df['spectrogram_id']).sum()\n    label_vote_sum = pd.DataFrame({'spectrogram_id': group.index, f'{label}_vote_sum': group.values})\n    if label=='seizure':\n        train_feats=label_vote_sum\n    else:\n        train_feats=train_feats.merge(label_vote_sum,on='spectrogram_id',how='left')\ntrain_feats['total_vote']=0\nfor label in labels:\n      train_feats['total_vote']+=train_feats[f'{label}_vote_sum']\nfor label in labels:\n      train_feats[f'{label}_vote']=train_feats[f'{label}_vote_sum']/train_feats['total_vote']\nchoose_cols=['spectrogram_id']\nfor label in labels:\n    choose_cols+=[f'{label}_vote']\ntrain_feats=train_feats[choose_cols]\ntrain_feats['path']=train_feats['spectrogram_id'].apply(lambda x: \"/kaggle/input/hms-harmful-brain-activity-classification/train_spectrograms/\"+str(x)+\".parquet\" )\ntrain_feats.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train_Test_split","metadata":{}},{"cell_type":"code","source":"split=0.8\nrandom_num=np.arange(len(train_feats))\nnp.random.shuffle(random_num)\nsplit_num=int(len(train_feats)*split)\ntrain_idx=random_num[:split_num]\ntest_idx=random_num[split_num:]\nprint(f\"train_idx\")\nfor label in labels:\n    print(f\"{label}:{train_feats.iloc[train_idx][label+'_vote'].sum()}\")\nprint(f\"test_idx\")\nfor label in labels:\n    print(f\"{label}:{train_feats.iloc[test_idx][label+'_vote'].sum()}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Loss function :Kullback Leibler Divergence","metadata":{}},{"cell_type":"code","source":"#这个代码才是现在KL散度的写法.\ndef KL_loss(p,q):\n    epsilon=10**(-15)\n    p=torch.clip(p,epsilon,1-epsilon)\n    q = nn.functional.log_softmax(q,dim=1)\n    #对第一个维度,就是num_classes维度的损失求和,得到每个样本的损失,然后对第0维求平均,得到每个样本平均KL散度.\n    return torch.mean(torch.sum(p*(torch.log(p)-q),dim=1))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### get_batch_data","metadata":{}},{"cell_type":"code","source":"def get_batch(paths,batch_size=Config.batch_size):\n    eps=1e-6\n    batch_data=[]\n    for path in paths:\n        data=pd.read_parquet(path[0])\n        #这里最小值是0,故用-1填充.第一列是时间列,故去掉 ,行是不同列,列是时间\n        data = data.fillna(-1).values[:,1:].T\n        #选取一段时间的数据进行训练\n        data=data[:,0:300]#(400,300)\n        data=np.clip(data,np.exp(-6),np.exp(10))#最大值为89209464.0\n        data= np.log(data)#对数变换\n        #对数据进行归一化\n        data_mean=data.mean(axis=(0,1))\n        data_std=data.std(axis=(0,1))\n        data=(data-data_mean)/(data_std+eps)\n        data_tensor = torch.unsqueeze(torch.Tensor(data), dim=0)\n        data=Config.image_transform(data_tensor)\n        batch_data.append(data)\n    batch_data=torch.stack(batch_data)\n    return batch_data","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model_training","metadata":{}},{"cell_type":"code","source":"#优化器\noptimizer=optim.AdamW(model.parameters(),lr=0.001,betas=(0.5,0.999),weight_decay=0.01)\n\ndevice ='cuda' if  torch.cuda.is_available() else 'cpu'\nprint(f\"device:{device}\")\nmodel.to(device)\n\ntrain_losses=[]\ntest_losses=[]\n\nprint(f\"start\")\n\nfor epoch in range(Config.num_epochs):\n    print(f\"epoch {epoch}:\")\n    #训练\n    model.train()\n    train_loss=[]\n    random_num=np.arange(len(train_idx))\n    np.random.shuffle(random_num)\n    train_idx=train_idx[random_num]\n    \n    for idx in range(0,len(train_idx),Config.batch_size): \n        #将梯度清空\n        optimizer.zero_grad()\n        train_idx1=train_idx[idx:idx+Config.batch_size]\n        train_X1_path=train_feats[['path']].iloc[train_idx1].values\n        train_X1=get_batch(train_X1_path,batch_size=Config.batch_size)\n        train_y1=train_feats[['seizure_vote','lpd_vote','gpd_vote','lrda_vote','grda_vote','other_vote']].iloc[train_idx1].values\n        train_y1=torch.Tensor(train_y1)\n        #将数据放进去训练\n        train_pred=model(train_X1.to(device))\n        #计算每次的损失函数\n        loss=KL_loss(train_y1.to(device),train_pred.to(device)).to(device)\n        #反向传播\n        loss.backward()\n        #优化器进行优化(梯度下降,降低误差)\n        optimizer.step()\n        train_loss.append(loss.detach().cpu().numpy())\n    train_loss=np.mean(np.array(train_loss))\n    print(f\"train_loss:{train_loss}\")\n    test_loss=[]\n    model.eval()\n    with torch.no_grad():\n        for idx in range(0,len(test_idx),Config.batch_size): \n            test_idx1=test_idx[idx:idx+Config.batch_size]\n            test_X1_path=train_feats[['path']].iloc[test_idx1].values\n            test_X1=get_batch(test_X1_path,batch_size=Config.batch_size)\n\n            test_y1=train_feats[['seizure_vote','lpd_vote','gpd_vote','lrda_vote','grda_vote','other_vote']].iloc[test_idx1].values\n            test_y1=torch.Tensor(test_y1)\n            #将数据放进去训练\n            test_pred=model(test_X1.to(device))\n            #计算每次的损失函数\n            loss=KL_loss(test_y1.to(device),test_pred.to(device)).to(device)\n            test_loss.append(loss.detach().cpu().numpy())\n    test_loss=np.mean(np.array(test_loss))\n    print(f\"test_loss:{test_loss}\")\n    train_losses.append(train_loss)\n    test_losses.append(test_loss)\n    print(\"-\"*50)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Plot train_losses VS test_losses","metadata":{}},{"cell_type":"code","source":"plt.title(\"train_losses VS test_losses\")\nepochs=[i for i in range(len(train_losses))]\nplt.plot(epochs,train_losses,marker=\"o\",markersize=1,label=\"train_losses\")\nplt.plot(epochs,test_losses,marker=\"x\",markersize=1,label=\"test_losses\")\nplt.legend()\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save model","metadata":{}},{"cell_type":"code","source":"torch.save(model.to('cpu'),\"HMS_resnet.pth\")\n#model=torch.load(\"\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}