最近我老师帮我找了篇论文来看,我看了,又是一个新模型,大概就是图神经网络+信息论IB。所以我去github上找了个简单的神经网络的项目,我跑一跑,加深对神经网络的认识。
https://github.com/buptsdz/CIFAR10-nn
1
这个简单的神经网络是做判断任务的,CIFAR-10这个数据集有60000个图片,十个类,那么如果是随机判断的话,只有10%的概率判断对。
# 导入数据集
transform = transforms.Compose([
transforms.ToTensor(),#将图像转换为张量
transforms.Normalize((0.5, ), (0.5, )) #数据归一化
])
dataset = datasets.CIFAR10(root='./data/', train=True, transform=transform, download=True)
datasets.CIFAR10共有四个参数,root是数据集的路径,data_batch_1,data_batch_2,data_batch_3,data_batch_4,data_batch_5代表了训练集的五万张图片,test_batch代表了测试集的一万张图片;train为true代表加载的是训练集,false代表加载的是测试集;transform代表的是预处理操作,所谓的张量就是torch里面的多维数组,这个是基本操作,原来均值0.5是像素值减去0.5,标准差0.5是像素值除以0.5;download没啥好说的,就是如果root路径没有数据集的话就下载它。
2
# 导入库
from torch.utils.data import random_split
# 设置学生ID的最后一位数字
student_last_id = 5
split_ratio = 0.7 if student_last_id <= 4 else 0.8
# 根据ID拆分数据集,8:2
train_size=int(len(dataset)*split_ratio)
val_size=len(dataset)-train_size
train_dataset,val_dataset=random_split(dataset,[train_size,val_size])
起初我看到这段代码的时候很疑惑,不是有测试集了吗,但是这个划分的是训练集和验证集。
这个student_last_id名字取得不好,干脆就叫id,那么8成是训练集,2成是验证集,train_size就是40000,vla_size就是10000。random_split就是划分方法而已。
3
# 数据加载器
from torch.utils.data import DataLoader
batch_size=32+id
train_loader=DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
val_loader=DataLoader(val_dataset,batch_size=batch_size,shuffle=False)
print(f"training on {train_size} images, validation on {val_size} images")
这部分是一个数据加载器,数据加载器其实也是参数,只不过它是model的参数,表示把数据读到模型里。
这个dataloader函数参数很多啊。train_dataset就是训练集,batch_size就是说多少个样本同时进行训练,像此处就是37个样本为一批同时进行训练,shuffle=true就是打乱处理。我觉得加上drop_last=False这个参数比较好,把最后一批丢掉,毕竟4000除以37不能整除。
4
# 定义神经网络模型
model = torch.nn.Sequential(
torch.nn.Flatten(), # 输入层:将 32x32x3 的图像展平为 3072 维向量
torch.nn.Linear(32 * 32 * 3, 512), # 全连接层:输入 3072 维,输出 512 维
torch.nn.BatchNorm1d(512), # 批标准化:加快训练并提高模型的泛化能力
torch.nn.ReLU(), # 激活函数:ReLU 激活函数引入非线性
torch.nn.Linear(512, 256), # 增加隐藏层:输入 512 维,输出 256 维
torch.nn.BatchNorm1d(256), # 批标准化:再次增强模型的稳定性和收敛速度
torch.nn.ReLU(), # 激活函数:隐藏层的 ReLU 激活
torch.nn.Linear(256, 10), # 输出层:将隐藏层输出映射到 10 类
)
我看懂这个神经网络了,发明神经网络的人真是个天才。它是利用了数学的矩阵操作,一个图像就是一个32323的三维张量,把这个三维张量展成一维就是3072。那么在这一批37个样本中,就可以看成是一个37行,3072列的二维矩阵[37,3072][3072512]=[37,512],这个[3072,512]就是权重值,哪些元素比较重要,哪些元素不重要,还有一个512列的一维向量是偏置向量。
|
| /
| /
| /
| /
|____/__________
0
尽管我还不理解ReLU激活函数为什么要是这样的,但是把它理解为炒菜要加盐就好了
5
现在是22:17,我到现在才开始学习,我感觉有点不合适。我觉得我应该记录我每天的学习时间,这样我才能逐渐进步。我登陆了一个番茄计时器的网站,我每次学习前都要去打卡,这样我就可以知道我昨天学习了多少时间。
# 模型训练和评估,并跟踪损失和准确性
train_losses=[]
train_accuracies=[]
val_accuracies=[]
for epoch in range(epochs):
model.train()
running_loss=0.0
corrects=0
total=0
for inputs,labels in train_loader:
optimizer.zero_grad()
outputs=model(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
running_loss+=loss.item()
_,preds=torch.max(outputs,1)
total+=labels.size(0)
corrects+=(preds==labels).sum().item()
train_accuracy=100*corrects/total
print(f'epoch:{epoch+1}/{epochs},loss:{running_loss:.4f},accuracy:{train_accuracy:.2f}%')
# 评估模型
model.eval()
corrects=0
total=0
with torch.no_grad():
for inputs,labels in val_loader:
outputs=model(inputs)
_,preds=torch.max(outputs,1)
total+=labels.size(0)
corrects+=(preds==labels).sum().item()
val_accuracy=100*corrects/total
print(f'Validation Accuracy:{val_accuracy:.2f}%')
train_losses.append(running_loss)
train_accuracies.append(train_accuracy)
val_accuracies.append(val_accuracy)
python真是太强大了,把复杂的操作用一句代码就完成了。计算损失,然后反向传播,其实反向传播这个词很玄乎,也很复杂,比如说有两个参数吧,w1和w2,就是用求导的办法求损失对参数的导数,原来这个导数就是梯度,只不过是多元函数的导数。我理解了比如说我们要到半山腰,然后走过了到山顶了,那就是走的太快了嘛,那就减慢速度,这就是反向传播和优化器。