forked from YinHan-Zhang/TYUT-TreamLearning
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
49 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,49 @@ | ||
# Related Knowledge | ||
# Related Knowledge以及代码逐行解析 | ||
[Toc] | ||
# 如何查看nii文件 | ||
可以下载[ITK-SNAP 4.0](http://www.itksnap.org/pmwiki/pmwiki.php?n=Downloads.SNAP4) | ||
## 如何可视化查看nii文件 | ||
可以下载[ITK-SNAP 4.0](http://www.itksnap.org/pmwiki/pmwiki.php?n=Downloads.SNAP4) | ||
|
||
体素是**体积元素**(Volume Pixel)的简称,是数字数据于**三维空间**分割上的最小单位,类似于二维空间的像素。体素用于三维成像、科学数据与医学影像等领域。体素可以通过立体渲染或者提取给定阈值轮廓的多边形等值面表现出来。 | ||
|
||
nii的三维数组是一个包含了图像体素值的数据结构,它的每个元素代表了一个体素的灰度值或者信号强度。nii的三维数组的形状是(z,y,x),其中z是沿着图像的垂直方向,y是沿着图像的前后方向,x是沿着图像的左右方向。 | ||
|
||
每个体素的值代表了该体素在物理空间中的像素值,也就是该体素的灰度或颜色。(128, 128, 47, 1)表示图像数据的维度,也就是图像有多少个体素。第一个数字128表示图像在x轴方向上有128个体素,第二个数字128表示图像在y轴方向上有128个体素,第三个数字47表示图像在z轴方向上有47个体素,第四个数字1表示每个体素只有一个值,也就是单通道。如果第四个数字是3,就表示每个体素有三个值,也就是RGB三通道。 | ||
|
||
头文件信息是nii文件中用于描述图像属性的部分,它包括了以下一些参数: | ||
|
||
- **维度**:图像的维数和每个维度的大小,比如(256,256,256)表示一个三维图像,每个维度有256个体素。 | ||
- **方向**:图像的空间方向,比如左右、前后、上下等,用于确定图像的坐标系。 | ||
- **分辨率**:图像每个体素的物理尺寸,比如(1mm,1mm,1mm)表示每个体素占据一个立方毫米的空间。 | ||
- **仿射变换**:图像的空间变换矩阵,用于将体素索引(i,j,k)转换为空间位置(x,y,z)。 | ||
- **数据类型**:图像每个体素的数据类型,比如uint8、float32等,用于确定图像的灰度范围和精度。 | ||
- **其他信息**:图像的描述、单位、时间轴、意向代码等,用于提供更多的图像元数据。 | ||
|
||
头文件信息中有很多参数,介绍一些常见的: | ||
|
||
- sizeof_hdr: 头文件的大小,一般是348字节 | ||
- dim: 数据的维度,一般有7个维度,分别是空间维度x,y,z,时间维度t,和其他可供用户使用的维度 | ||
- datatype: 数据的类型,例如float32表示浮点数,bitpix表示每个数据占用的位数 | ||
- pixdim: 每个维度的物理尺寸,例如x,y,z方向上每个体素的长度 | ||
- vox_offset: 数据开始的偏移量,一般是0或者352 | ||
- qform_code和sform_code: 表示空间坐标系的类型,例如scanner表示扫描仪坐标系 | ||
- affine: 一个4x4的矩阵,表示空间坐标系和体素索引之间的变换关系 | ||
|
||
|
||
nii文件的仿射矩阵是一个4x4的矩阵,它的作用是将图像的**体素坐标**(即矩阵中的行、列、层)转换为**物理坐标**(即实际空间中的x、y、z)。这样可以方便地对不同的图像进行对齐、配准、变换等操作。仿射矩阵的形式如下: | ||
|
||
|
||
$$\begin{bmatrix}x \\y \\z \\1\end{bmatrix}=\begin{bmatrix}a_{11} & a_{12} & a_{13} & a_{14} \\a_{21} & a_{22} & a_{23} & a_{24} \\a_{31} & a_{32} & a_{33} & a_{34} \\0 & 0 & 0 & 1\end{bmatrix}\begin{bmatrix}i \\j \\k \\1\end{bmatrix}$$ | ||
|
||
其中,$x,y,z$是物理坐标,$i,j,k$是体素坐标,$a_{ij}$是仿射矩阵的元素。 | ||
|
||
最后一行是为了保证变换前后都是齐次坐标。 | ||
|
||
![Alt text](.\images\image-1.png) | ||
|
||
|
||
# ResNet50结果 | ||
![](.\images\2023-08-19-11-55-01.png) | ||
# Resnet-34结果 | ||
![Alt text](.\images\image-10.png) | ||
# ResNet-101结果 | ||
![Alt text](.\images\image-8.png) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"cells":[{"cell_type":"code","execution_count":25,"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2023-08-19T02:16:34.072862Z","iopub.status.busy":"2023-08-19T02:16:34.072469Z","iopub.status.idle":"2023-08-19T02:16:34.083940Z","shell.execute_reply":"2023-08-19T02:16:34.082753Z","shell.execute_reply.started":"2023-08-19T02:16:34.072827Z"},"trusted":true},"outputs":[],"source":["import os, sys, glob, argparse\n","import pandas as pd\n","import numpy as np\n","from tqdm import tqdm\n","import cv2\n","from PIL import Image\n","from sklearn.model_selection import train_test_split, StratifiedKFold, KFold\n","import torch\n","\n","# torch.manual_seed(seed)是用来为CPU设置生成随机数的种子,方便下次复现实验结果\n","torch.manual_seed(0)\n","# torch.backends.cudnn.deterministic和torch.backends.cudnn.benchmark是用来控制PyTorch在使用cuDNN时的行为。cuDNN是一个用于深度神经网络的加速库,它可以提高PyTorch在GPU上的运行速度。\n","# torch.backends.cudnn.deterministic如果设置为True,那么每次运行时都会选择一个确定的算法,保证结果的可复现性。torch.backends.cudnn.benchmark如果设置为True,那么会在开始时花费一些时间来寻找最适合当前配置的高效算法,以提高运行效率。\n","torch.backends.cudnn.deterministic = False\n","torch.backends.cudnn.benchmark = True\n","\n","# torchvision是一个用于计算机视觉的库,提供常用的模型、数据集和图像处理方法。\n","# torchvision.models是一个包含了预训练模型的模块,可以直接使用它们或者进行微调。\n","import torchvision.models as models\n","# torchvision.transforms包含了图像变换方法的模块,可以用它们来对图像进行裁剪、旋转、缩放等操作。\n","import torchvision.transforms as transforms\n","# torchvision.datasets包含了常见数据集的模块,可以用它们来加载和处理数据。\n","import torchvision.datasets as datasets\n","# torch.nn包含了神经网络相关类和函数的模块,可以用它们来构建和训练神经网络。\n","# torch.nn.functional包含了一些激活函数、损失函数和其他函数的子模块,例如ReLU、交叉熵、卷积等。\n","import torch.nn as nn\n","import torch.nn.functional as F\n","# torch.optim是一个包含了优化器相关类和函数的模块,可以用它们来更新神经网络的参数\n","import torch.optim as optim\n","# torch.autograd是一个包含了自动求导相关类和函数的模块,可以用它们来计算神经网络中参数的梯度\n","from torch.autograd import Variable\n","# torch.utils.data.dataset包含了数据集相关类和函数的子模块,可以用它们来自定义和管理数据集。\n","from torch.utils.data.dataset import Dataset\n","# nibabel是一个用于处理医学图像格式的库,例如NIfTI、DICOM等。可以用它们来读取、保存和显示医学图像。\n","# nibabel.viewers.OrthoSlicer3D()类来显示其三维切片视图\n","import nibabel as nib\n","from nibabel.viewers import OrthoSlicer3D\n"]},{"cell_type":"code","execution_count":68,"metadata":{"execution":{"iopub.execute_input":"2023-08-18T02:44:33.087924Z","iopub.status.busy":"2023-08-18T02:44:33.087521Z","iopub.status.idle":"2023-08-18T02:44:33.109221Z","shell.execute_reply":"2023-08-18T02:44:33.107919Z","shell.execute_reply.started":"2023-08-18T02:44:33.087890Z"},"trusted":true},"outputs":[],"source":["train_path = glob.glob('/kaggle/input/pet-data/��PETͼ������ͼ���Ԥ����ս����������/Train/*/*')\n","test_path = glob.glob('/kaggle/input/pet-data/��PETͼ������ͼ���Ԥ����ս����������/Test/*')\n","\n","np.random.shuffle(train_path)\n","np.random.shuffle(test_path)\n","# 数据缓存\n","DATA_CACHE = {}\n","\n","class XunFeiDataset(Dataset):\n"," def __init__(self, img_path, transform=None):\n"," # 定义数据集路径\n"," self.img_path = img_path\n"," if transform is not None:\n"," # 传入变换\n"," self.transform = transform\n"," else:\n"," # 未传入变换\n"," self.transform = None\n"," \n"," def __getitem__(self, index):\n"," # 如果数据在缓存中,直接从缓存中读取\n"," if self.img_path[index] in DATA_CACHE:\n"," img = DATA_CACHE[self.img_path[index]]\n"," else:\n"," # 否则重新加载\n"," img = nib.load(self.img_path[index]) \n"," # 取前三个维度\n"," img = img.dataobj[:,:,:, 0]\n"," # 存入缓存\n"," DATA_CACHE[self.img_path[index]] = img\n"," \n"," # 在通道中随机选择50个索引 \n"," idx = np.random.choice(range(img.shape[-1]), 50)\n"," # 在一张图片中选择这些索引作为使用的通道\n"," img = img[:, :, idx]\n"," # 转化为浮点型\n"," img = img.astype(np.float32)\n"," # 对图片进行变换\n"," if self.transform is not None:\n"," img = self.transform(image = img)['image']\n"," # img的维度从(高度, 宽度, 通道)变为(通道, 高度, 宽度),因为OpenCV和Pytorch对图像的维度顺序有不同的要求\n"," img = img.transpose([2,0,1])\n"," return img,torch.from_numpy(np.array(int('NC' in self.img_path[index])))\n"," \n"," def __len__(self):\n"," # 图片的张数\n"," return len(self.img_path)\n"," \n","import albumentations as A\n","train_loader = torch.utils.data.DataLoader(\n"," # 第一个位置是图片路径,第二个位置是变换\n"," XunFeiDataset(train_path[:-10],\n"," A.Compose([\n"," A.RandomRotate90(),\n"," A.RandomCrop(120, 120),\n"," A.HorizontalFlip(p=0.6),\n"," A.RandomContrast(p=0.6),\n"," A.RandomBrightnessContrast(p=0.5),\n"," ])\n"," ), \n"," # 些参数的意思是:\n"," # 每个批次加载2个样本\n"," # 每个epoch开始时,打乱数据集的顺序\n"," # 使用1个工作进程来加载数据\n"," # 不将数据存储在锁页内存中\n"," batch_size=2, shuffle=True, num_workers=1, pin_memory=False\n",")\n","\n","# 验证集取数据集的后十个\n","val_loader = torch.utils.data.DataLoader(\n"," XunFeiDataset(train_path[-10:],\n"," A.Compose([\n"," A.RandomCrop(120, 120),\n"," ])\n"," ), batch_size=2, shuffle=False, num_workers=1, pin_memory=False\n",")\n","\n","# 测试集\n","test_loader = torch.utils.data.DataLoader(\n"," XunFeiDataset(test_path,\n"," A.Compose([\n"," A.RandomCrop(128, 128),\n"," A.HorizontalFlip(p=0.5),\n"," A.RandomContrast(p=0.5),\n"," ])\n"," ), batch_size=2, shuffle=False, num_workers=1, pin_memory=False\n",")\n"]},{"cell_type":"code","execution_count":null,"metadata":{"execution":{"iopub.execute_input":"2023-08-19T03:40:59.836743Z","iopub.status.busy":"2023-08-19T03:40:59.836371Z","iopub.status.idle":"2023-08-19T03:41:00.798452Z","shell.execute_reply":"2023-08-19T03:41:00.797352Z","shell.execute_reply.started":"2023-08-19T03:40:59.836713Z"},"trusted":true},"outputs":[],"source":["class XunFeiNet(nn.Module):\n"," def __init__(self):\n"," super(XunFeiNet, self).__init__()\n"," model = models.resnet18(True)\n"," # `in_channels`:输入通道数,这里是50。\n"," # `out_channels`:输出通道数,这里是64。\n"," # `kernel_size`:卷积核大小,这里是(7, 7)。\n"," # `stride`:步长,这里是(2, 2)。\n"," # `padding`:填充大小,这里是(3, 3)。\n"," # `bias`:是否使用偏置项,这里是False。\n"," model.conv1 = torch.nn.Conv2d(50, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n"," model.avgpool = nn.AdaptiveAvgPool2d(1)\n"," model.fc = nn.Linear(512, 2)\n"," self.resnet = model\n"," # 前向函数\n"," def forward(self, img): \n"," out = self.resnet(img)\n"," return out\n","\n","# 实例化\n","model = XunFeiNet()\n","# 将模型移动到cuda设备上,在GPU上进行计算。如果你的电脑有多个GPU,可以使用model.to(torch.device('cuda:0'))这样的语法来指定使用哪个GPU。如果你想在CPU上计算,你可以使用model.to('cpu')来将模型移回CPU。\n","model = model.to('cuda')\n","# 创建一个交叉熵损失函数,用于计算模型输出的概率分布和真实标签之间的差异。并将其移动到cuda设备上,以便在GPU上进行计算。\n","criterion = nn.CrossEntropyLoss().cuda()\n","# optimizer = torch.optim.AdamW(model.parameters(), 0.001):创建一个AdamW优化器,用于更新模型的参数。0.001是学习率,表示每次更新参数时的步长。model.parameters()表示要优化的模型参数。\n","optimizer = torch.optim.AdamW(model.parameters(), 0.001)"]},{"cell_type":"code","execution_count":null,"metadata":{"execution":{"iopub.execute_input":"2023-08-19T03:41:05.373014Z","iopub.status.busy":"2023-08-19T03:41:05.372250Z","iopub.status.idle":"2023-08-19T03:41:16.242509Z","shell.execute_reply":"2023-08-19T03:41:16.241314Z","shell.execute_reply.started":"2023-08-19T03:41:05.372976Z"},"trusted":true},"outputs":[],"source":["# 传入训练加载器,模型,损失函数,优化器\n","def train(train_loader, model, criterion, optimizer):\n"," # 训练\n"," model.train()\n"," # 训练损失\n"," train_loss = 0.0\n"," for i, (input, target) in enumerate(train_loader):\n"," # input = input.cuda(non_blocking=True):将输入移动到cuda设备上,使用非阻塞模式,提高效率\n"," input = input.cuda(non_blocking=True)\n"," # target = target.cuda(non_blocking=True):将目标移动到cuda设备上,使用非阻塞模式,提高效率\n"," target = target.cuda(non_blocking=True)\n"," # 用模型对输入预测得到输出\n"," output = model(input)\n"," loss = criterion(output, target)\n"," # 所得结果与目标的差异\n"," optimizer.zero_grad()\n"," # 反向传播\n"," loss.backward()\n"," # 优化器更新参数\n"," optimizer.step()\n"," # 如果为20的倍数,\n"," if i % 20 == 0:\n"," print(\"loss\",loss.item())\n"," # 累加到训练误差上\n"," train_loss += loss.item()\n"," # 返回训练误差/训练集\n"," return train_loss/len(train_loader)\n"," \n","def validate(val_loader, model, criterion):\n"," # 评估模式\n"," model.eval()\n"," # 验证集准确率\n"," val_acc = 0.0\n"," \n"," with torch.no_grad():\n"," for i, (input, target) in enumerate(val_loader):\n"," input = input.cuda()\n"," target = target.cuda()\n"," # compute output\n"," output = model(input)\n"," loss = criterion(output, target)\n"," \n"," val_acc += (output.argmax(1) == target).sum().item()\n"," \n"," return val_acc / len(val_loader.dataset)\n"," \n","for i in range(3):\n"," print(f\"第{i}次\")\n"," train_loss = train(train_loader, model, criterion, optimizer)\n"," val_acc = validate(val_loader, model, criterion)\n"," train_acc = validate(train_loader, model, criterion)\n"," print(\"train_loss\",train_loss)\n"," print(\"tran_acc\",train_acc)\n"," print(\"val_acc\", val_acc)\n"," "]},{"cell_type":"code","execution_count":70,"metadata":{"execution":{"iopub.execute_input":"2023-08-19T03:41:22.732021Z","iopub.status.busy":"2023-08-19T03:41:22.731597Z","iopub.status.idle":"2023-08-19T03:41:49.064994Z","shell.execute_reply":"2023-08-19T03:41:49.063521Z","shell.execute_reply.started":"2023-08-19T03:41:22.731986Z"},"trusted":true},"outputs":[],"source":["def predict(test_loader, model, criterion):\n"," # 模型评估,这行代码的意思是将模型设置为评估模式,也就是关闭一些在训练时和评估时表现不同的层或部分,例如Dropout层和BatchNorm层。在进行推理或预测时,必须调用model.eval(),否则会导致不一致的结果。\n"," model.eval()\n"," # 验证准确率\n"," val_acc = 0.0\n"," # 预测值\n"," test_pred = []\n"," with torch.no_grad():\n"," for i, (input, target) in enumerate(test_loader):\n"," input = input.cuda()\n"," target = target.cuda()\n"," # 用模型对输入进行预测,得到输出\n"," output = model(input)\n"," # 将输出从cuda设备上移回cpu,并转换为numpy数组,然后追加到test_pred列表中,用于保存测试结果\n"," test_pred.append(output.data.cpu().numpy())\n"," # 将test_pred列表中的数组按照垂直方向(行顺序)堆叠起来,形成一个新的数组\n"," return np.vstack(test_pred)\n"," \n","pred = None\n","for _ in range(10):\n"," if pred is None:\n"," pred = predict(test_loader, model, criterion)\n"," else:\n"," pred += predict(test_loader, model, criterion)\n","submit = pd.DataFrame(\n"," {\n"," 'uuid': [int(x.split('/')[-1][:-4]) for x in test_path],\n"," 'label': pred.argmax(1)\n","})\n","# 将submit[‘label’]列中的值替换为另一组值,根据一个字典的映射关系。字典的键是原来的值,字典的值是替换后的值。例如,这里将1替换为’NC’,将0替换为’MCI’。\n","submit['label'] = submit['label'].map({1:'NC', 0: 'MCI'})\n","# 按照\"uuid\"排序\n","submit = submit.sort_values(by='uuid')\n","# 转化为csv文件\n","submit.to_csv('submit101.csv', index=None)\n"]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"}},"nbformat":4,"nbformat_minor":4} |
File renamed without changes.