写于2021-12-31 23:04,2021年最后一篇博客了,也是2022年第一篇博客。
今年的格言:有一分热,发一分光,就令萤火一般,也可以在黑暗里发一点光,不必等候炬火,此后如竟没有炬火,我便是唯一的光。
前几天不是发了一个MNIST图像识别的文章吗,但那篇还是有一些东西没讲的很好。MNIST图像是灰度图像,很多小伙伴想看看RGB的写法。这次拿RGB图做一个细胞分类吧~
此篇博客是对上篇博客的修正、补充以及拓展。
请先参阅上期博客:【Pytorch】MNIST 图像分类代码 - 超详细解读_CSDN_千鱼干的博客
有地方看不懂没事,看完后看这篇的补充内容。
import torch
as nn
import Sequential
from matplotlib import pyplot as plt
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
ansforms as transforms
torch库就不解释了。
库是一个包含了神经网络的Modules和用来继承的包以及一些函数方法,比如nn.functional。因为我们之后定义网络时是从nn.Module继承的,还用了nn里面的卷积、激活函数等等,所以这个库必不可少。
Sequential(中文:序列)是里面“整合”层用的。就相当于饼干盒,把饼干“像序列一样”装进去。
matplotlib在这里是一个显示图像的库。我们引入了pyplot,用来显示图像。
torchvision包含一些数据集、模型、图像处理方法。这里用datasets来处理数据集(我们自己的图片)。
torch.utils.data里面的DataLoader是用来将数据集装载用的,以便训练。
ansforms在这里用于定义数据集处理形式。往下看就知道。
这里假设我们数据集的路径是当前你的python文件所在文件夹下data/CELLS/。这个文件夹下有两个子文件夹,一个叫“linba”,另一个叫“xianxingli”
插播一句,现在是2022-1-1 0:00,这篇博客写了一年(笑)
也就是说,我们的数据集分为淋巴细胞和线性粒细胞两种细胞的图片。
所以我们要设置两个类别:classes = [“linba”, “zhongxingli”]
我们这里设置一下批次大小位64,迭代250次,学习率0.001。
学习率选一个小小的数,这样有助于梯度下降。具体原因见上一篇博客。
这里还要写一个get_variable()函数以获取cuda加速后的自动求导结果。
这里 再次 详细解释一下epochs和batch_szie:
->batch_size表示每轮迭代训练时每次训练的数据量;
->epochs表示训练几轮。
每一次迭代(Iteration)都是一次权重更新,每一次权重更新需要batch_size个数据进行正向传递(Forward)运算得到损失函数,再通过反向传导(Backward)更新参数(注意,在这个过程中需要把梯度(Grad)设置为0,这个后面再讲)。1个迭代等于使用batch_size个样本训练一次。比如有256个样本数据,完整训练完这些样本数据需要:
->batch_size=64;
->迭代4次;
->epochs=1。
而通常会将epochs设为不仅1次,这就跟磨面一样,磨完一轮不够,磨多轮才能得到更加精细的面粉。
这时候因为我们处理的是图片,而我们处理的应该是张量(Pytorch处理的是张量,类似向量,矩阵)。我们怎么让数据集图片变成数据集矩阵呢?
这时就要设置transform(翻译:转换)了。
同时,我们的图片不能太大,否则会让训练很慢。
所以我们首先将图片转化为张量,然后将裁剪为 w ∗ h = 128 ∗ 128 w*h=128*128 w∗h=128∗128(w是width,宽;h是height,高;c是channel,通道,就是颜色通道,RGB是红绿蓝三通道)大小的张量。同时我们还要让每个像素数值服从标准为0.5的正态分布。
因为我们需要训练集和测试集两部分,所以将数据集分成两个处理内容,最后将训练集和测试集装载,数据集处理完毕。
最后,我们展示一下某张数据集图片转换为向量并处理之后的样子(可选)。
全部代码如下:
path = "./data/CELLS/"
classes = ["linba", "zhongxingli"]def get_variable(x):x = torch.autograd.Variable(x)return x.cuda() if torch.cuda.is_available() else xbatch_size = 64
epochs = 250
lr = 0.001test_path = "./data/CELLS/"transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((128, 128)),transforms.CenterCrop(128),transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])
])data_train = datasets.ImageFolder(root=path, transform=transform)
train_loader = DataLoader(data_train, batch_size=batch_size, shuffle=True)data_test = datasets.ImageFolder(root=test_path, transform=transform)
test_loader = DataLoader(data_test, batch_size=batch_size, shuffle=True)# -----------------------展示数据集---------------------------
images, labels = next(iter(train_loader))
img = images[0].numpy().transpose(1, 2, 0)
plt.imshow(img)
plt.title(labels[0])
plt.show()# -----------------------展示数据集---------------------------
网络结构如下图:
注意,输入出的“?x128x128x3”的意思是“?”张图片,“128x128x3”是 w ∗ h ∗ c = 128 ∗ 128 ∗ 3 w*h*c=128*128*3 w∗h∗c=128∗128∗3。
怎样定义网络呢?首先我们要从nn.Module继承,然后“装填”入我们的架构,最后在前向计算(forward)函数中进行前向计算。
这里注意一下:forward函数不需要显式调用,因为nn.Module类中有一个函数会自动调用forward。
上一篇博客没写明这里每层的参数是怎么计算的。这一部分相当重要,因为最后传入全连接层时必须要求输入和输出匹配,但这里我上篇没细讲。
这里贴出nn.Conv2d()在Pytorch官方文档里的图:
–>猛戳我 - 原文链接<–
注意这里的符号, H o u t H_{out} Hout是进行的向下取整。
定义类的方式和上一篇相似。
代码:
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()v1 = Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(2, 2))v2 = Sequential(nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(2, 2))v3 = Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.MaxPool2d(2, 2))v4 = Sequential(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.MaxPool2d(2, 2))self.dense = Sequential(nn.Linear(8 * 8 * 256, 256),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(256, 128),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(128, 2))def forward(self, x):x1 = v1(x)x2 = v2(x1)x3 = v3(x2)x4 = v4(x3)x5 = x4.view(-1, 8 * 8 * 256)out = self.dense(x5)return out
这一部分我上一篇讲的很详细了。我只贴出代码:
cnn = CNN()
if torch.cuda.is_available():cnn = cnn.cuda()lossF = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(cnn.parameters(), lr=ain()loss_pth = 999999999.99
i_pth = 0for epoch in range(epochs):running_loss = 0.0running_correct = 0.0print("Epochs [{}/{}]".format(epoch, epochs))for data in train_loader:X_train, y_train = dataX_train, y_train = get_variable(X_train), get_variable(y_train)outputs = cnn(X_train)_, predict = torch.max(outputs.data, 1)# ----------------------------------_grad()loss = lossF(outputs, y_train)loss.backward()optimizer.step()# ----------------------------------running_loss += loss.item()running_correct += torch.sum(predict == y_train.data)testing_correct = 0.0for data in test_loader:X_test, y_test = dataX_test, y_test = get_variable(X_test), get_variable(y_test)outputs = cnn(X_test)_, predict = torch.max(outputs.data, 1)testing_correct += torch.sum(predict == y_test.data)print("Loss: {} Training Accuracy: {}% Testing Accuracy:{}%".format(running_loss,100 * running_correct / len(data_train),100 * testing_correct / len(data_test)))if running_loss < loss_pth:loss_pth = running_losstorch.save(cnn, "./models/cell_classify_%d.pth" % i_pth)i_pth = i_pth + 1torch.save(cnn, "cell_classify.pth")
print("训练完成!最小损失为:%f" % loss_pth)
这一部分我在上一篇博客也是讲得比较详细。我只贴出代码。
这里设pics文件夹下还有一个文件夹,里面有待预测图片:
import torch
as nn
import Sequential
from matplotlib import pyplot as plt
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
ansforms as transformsmodel_path = "./models/cell_classify.pth"
test_path = "./pics/"classes = ["linbaxibao", "zhongxinglixibao"]transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((128, 128)),transforms.CenterCrop(128),transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])
])data_test = datasets.ImageFolder(root=test_path, transform=transform)
test_loader = DataLoader(data_test, batch_size=64, shuffle=True)class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()v1 = Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(2, 2))v2 = Sequential(nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(2, 2))v3 = Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.MaxPool2d(2, 2))v4 = Sequential(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.MaxPool2d(2, 2))self.dense = Sequential(nn.Linear(8 * 8 * 256, 256),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(256, 128),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(128, 2))def forward(self, x):x1 = v1(x)x2 = v2(x1)x3 = v3(x2)x4 = v4(x3)x5 = x4.view(-1, 8 * 8 * 256)out = self.dense(x5)return outnet = torch.load(model_path)
net.eval()def get_variable(x):x = torch.autograd.Variable(x)return x.cuda() if torch.cuda.is_available() else xdef inference_model(test_img):for data in test_loader:test, _ = dataimg, _ = datatest = get_variable(test)outputs = net(test)rate, predict = torch.max(outputs.data, 1)for i in range(len(data_test)):print("It may be %s." % classes[predict[i]])img0 = img[i]img0 = img0.numpy().transpose(1, 2, 0)plt.imshow(img0)plt.title("It may be %s." % classes[predict[i]])# plt.title("It may be %s, probability is %f." % (classes[predict[i]], rate[i]))plt.show()inference_model(test_path)
结果(预测结果在图片上方和console里):
可以看到预测还是蛮准的嘛~
现在已经是2022年1月1日1:24了。我又长大了一岁(唉,我又老了)
回首2021年。我2021年4月19日突发感想 脑瓜一热 记下了这么一句话:
可惜的是,这个愿望只实现了,但没完全实现(谁说人工智能就一定只是会聊天的机器人啊(~o ̄3 ̄)~),我的初衷是做一个和小爱同学一样的人工智能…
目前在做超分辨率重构。
2021年初,我报名了CSDN上的一个深度学习课,当时只是打算听着玩,谁知道听的感兴趣了,就自己自学。没人指导,走了不少弯路,但还是走下来了。
笔者小时候最讨厌电脑了(小学6年级之前)。可是六年级一次电脑课上我接触了画画,我就觉得很好玩,就去研究怎么下载这样的软件,结果接触了Photoshop。谁知道这东西收费,就自己去学怎么破解。初中一年级我想为什么我自己不能编一个这样的程序呢?我就这样接触了编程。(后来还因为进了某网站后台差点惹出事,幸亏自己悬崖勒马)。
笔者从前并不喜欢数学,从前数学一直是我最讨厌的科目之一,因为我觉得我学的数学知识没有什么用到的地方,很枯燥,不理解为什么有人那么喜欢数学(我从前单纯觉得这些人是骗人的)(尽管为了高考要自我欺骗我很爱数学)。大学在某普通本科读计算机科学与技术。大一学了半年ACM,但是并不能听懂(呜呜呜)。大一上学期的寒假接触的机器学习。有趣的是,从接触机器学习开始,我发现数学原来这么实用。和编程结合后,似乎孕育出了某种神奇的力量。
啊。已经1:47了啊。以后再聊吧,我睡了()。
最后祝大家:
贴一张喜欢的图(侵删):
本文发布于:2024-02-01 05:35:54,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170673695634272.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |