{"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":"### Config","metadata":{}},{"cell_type":"code","source":"class Config:\n    seed=2024\n    image_transform=transforms.Resize((512,512))\n    batch_size=64\n    num_epochs=10#由于是预训练模型,训练10个epoch足够了\n    num_folds=5#5折交叉验证.","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\")\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":"### Loss function :Kullback Leibler Divergence","metadata":{}},{"cell_type":"code","source":"def 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":"device ='cuda' if  torch.cuda.is_available() else 'cpu'\nprint(f\"device:{device}\")\n\n\ntotal_idx=np.arange(len(train_feats))\nnp.random.shuffle(total_idx)\n\nfor fold in range(Config.num_folds):\n\n    test_idx=total_idx[fold*len(total_idx)//Config.num_folds:(fold+1)*len(total_idx)//Config.num_folds]\n    train_idx=np.array([idx for idx in total_idx if idx not in test_idx])\n\n    #下载模型resnet34d,并且将训练好的参数加载进来.每折初始化一个模型.\n    model = timm.create_model('resnet34d',pretrained=True, num_classes=6, in_chans=1)\n    \n    #优化器\n    optimizer=optim.AdamW(model.parameters(),lr=0.001,betas=(0.5,0.999),weight_decay=0.01)\n\n    best_test_loss=1.0#目前损失最好的成绩,每一折都要重新初始化\n    train_losses=[]\n    test_losses=[]\n\n    print(f\"start\")\n\n    for epoch in range(Config.num_epochs):\n        print(f\"epoch {epoch}:\")\n        model.to(device)#保存模型的时候可能会转成CPU,故设置这个来保证模型会在GPU上训练.\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)).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            print(f\"idx:{idx},loss:{loss}\")\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)).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        if test_loss<best_test_loss:#如果这折的这个模型的这次训练比上次好,保存起来\n            best_test_loss=test_loss\n            torch.save(model.to('cpu'),f\"HMS_resnet_fold{fold}.pth\")\n            \n        train_losses.append(train_loss)\n        test_losses.append(test_loss)\n        print(\"-\"*50)\n    print(f\"best_test_loss:{best_test_loss}\") \n    plt.title(\"train_losses VS test_losses\")\n    epochs=[i for i in range(len(train_losses))]\n    plt.plot(epochs,train_losses,marker=\"o\",markersize=1,label=\"train_losses\")\n    plt.plot(epochs,test_losses,marker=\"x\",markersize=1,label=\"test_losses\")\n    plt.legend()\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}