在4*4的圖片中,比較外圍黑色像素點和內圈黑色像素點個數的大小將圖片分類python
如上圖圖片外圍黑色像素點5個大於內圈黑色像素點1個分爲0類反之1類算法
import torch import torchvision import torchvision.transforms as transforms import numpy as np from PIL import Image
import csv import collections import os import shutil def buildDataset(root,dataType,dataSize): """構造數據集 構造的圖片存到root/{dataType}Data 圖片地址和標籤的csv文件存到 root/{dataType}DataInfo.csv Args: root:str 項目目錄 dataType:str 'train'或者‘test' dataNum:int 數據大小 Returns: """ dataInfo = [] dataPath = f'{root}/{dataType}Data' if not os.path.exists(dataPath): os.makedirs(dataPath) else: shutil.rmtree(dataPath) os.mkdir(dataPath) for i in range(dataSize): # 建立0,1 數組 imageArray=np.random.randint(0,2,(4,4)) # 計算0,1數量獲得標籤 allBlackNum = collections.Counter(imageArray.flatten())[0] innerBlackNum = collections.Counter(imageArray[1:3,1:3].flatten())[0] label = 0 if (allBlackNum-innerBlackNum)>innerBlackNum else 1 # 將圖片保存 path = f'{dataPath}/{i}.jpg' dataInfo.append([path,label]) im = Image.fromarray(np.uint8(imageArray*255)) im = im.convert('1') im.save(path) # 將圖片地址和標籤存入csv文件 filePath = f'{root}/{dataType}DataInfo.csv' with open(filePath, 'w') as f: writer = csv.writer(f) writer.writerows(dataInfo)
root=r'/Users/null/Documents/PythonProject/Classifier'
buildDataset(root,'train',20000)
buildDataset(root,'test',10000)
class MyDataset(torch.utils.data.Dataset): def __init__(self, root, datacsv, transform=None): super(MyDataset, self).__init__() with open(f'{root}/{datacsv}', 'r') as f: imgs = [] # 讀取csv信息到imgs列表 for path,label in map(lambda line:line.rstrip().split(','),f): imgs.append((path, int(label))) self.imgs = imgs self.transform = transform if transform is not None else lambda x:x def __getitem__(self, index): path, label = self.imgs[index] img = self.transform(Image.open(path).convert('1')) return img, label def __len__(self): return len(self.imgs)
trainData=MyDataset(root = root,datacsv='trainDataInfo.csv', transform=transforms.ToTensor()) testData=MyDataset(root = root,datacsv='testDataInfo.csv', transform=transforms.ToTensor())
import itertools def chooseData(dataset,scale): # 將類別爲1的排序到前面 dataset.imgs.sort(key=lambda x:x[1],reverse=True) # 獲取類別1的數目 ,取scale倍的數組,得數據不那麼偏斜 trueNum =collections.Counter(itertools.chain.from_iterable(dataset.imgs))[1] end = min(trueNum*scale,len(dataset)) dataset.imgs=dataset.imgs[:end]
scale = 4 chooseData(trainData,scale) chooseData(testData,scale) len(trainData),len(testData)
(2250, 1122)
import torch.utils.data as Data # 超參數 batchSize = 50 lr = 0.1 numEpochs = 20 trainIter = Data.DataLoader(dataset=trainData, batch_size=batchSize, shuffle=True) testIter = Data.DataLoader(dataset=testData, batch_size=batchSize)
from torch import nn from torch.autograd import Variable from torch.nn import Module,Linear,Sequential,Conv2d,ReLU,ConstantPad2d import torch.nn.functional as F
class Net(Module): def __init__(self): super(Net, self).__init__() self.cnnLayers = Sequential( # padding添加1層常數1,設定卷積核爲2*2 ConstantPad2d(1, 1), Conv2d(1, 1, kernel_size=2, stride=2,bias=True) ) self.linearLayers = Sequential( Linear(9, 2) ) def forward(self, x): x = self.cnnLayers(x) x = x.view(x.shape[0], -1) x = self.linearLayers(x) return x
class Net2(Module): def __init__(self): super(Net2, self).__init__() self.cnnLayers = Sequential( Conv2d(1, 1, kernel_size=1, stride=1,bias=True) ) self.linearLayers = Sequential( ReLU(), Linear(16, 2) ) def forward(self, x): x = self.cnnLayers(x) x = x.view(x.shape[0], -1) x = self.linearLayers(x) return x
# 交叉熵損失函數 loss = nn.CrossEntropyLoss()
loss2 = nn.CrossEntropyLoss()
net = Net() optimizer = torch.optim.SGD(net.parameters(),lr = lr)
net2 = Net2() optimizer2 = torch.optim.SGD(net2.parameters(),lr = lr)
# 計算準確率 def evaluateAccuracy(dataIter, net): accSum, n = 0.0, 0 with torch.no_grad(): for X, y in dataIter: accSum += (net(X).argmax(dim=1) == y).float().sum().item() n += y.shape[0] return accSum / n
def train(net, trainIter, testIter, loss, numEpochs, batchSize, optimizer): for epoch in range(numEpochs): trainLossSum, trainAccSum, n = 0.0, 0.0, 0 for X,y in trainIter: yHat = net(X) l = loss(yHat,y).sum() optimizer.zero_grad() l.backward() optimizer.step() # 計算訓練準確度和loss trainLossSum += l.item() trainAccSum += (yHat.argmax(dim=1) == y).sum().item() n += y.shape[0] # 評估測試準確度 testAcc = evaluateAccuracy(testIter, net) print('epoch {:d}, loss {:.4f}, train acc {:.3f}, test acc {:.3f}'.format(epoch + 1, trainLossSum / n, trainAccSum / n, testAcc))
train(net, trainIter, testIter, loss, numEpochs, batchSize,optimizer)
epoch 1, loss 0.0128, train acc 0.667, test acc 0.667 epoch 2, loss 0.0118, train acc 0.683, test acc 0.760 epoch 3, loss 0.0104, train acc 0.742, test acc 0.807 epoch 4, loss 0.0093, train acc 0.769, test acc 0.772 epoch 5, loss 0.0085, train acc 0.797, test acc 0.745 epoch 6, loss 0.0084, train acc 0.798, test acc 0.807 epoch 7, loss 0.0082, train acc 0.804, test acc 0.816 epoch 8, loss 0.0078, train acc 0.816, test acc 0.812 epoch 9, loss 0.0077, train acc 0.818, test acc 0.817 epoch 10, loss 0.0074, train acc 0.824, test acc 0.826 epoch 11, loss 0.0072, train acc 0.836, test acc 0.819 epoch 12, loss 0.0075, train acc 0.823, test acc 0.829 epoch 13, loss 0.0071, train acc 0.839, test acc 0.797 epoch 14, loss 0.0067, train acc 0.849, test acc 0.824 epoch 15, loss 0.0069, train acc 0.848, test acc 0.843 epoch 16, loss 0.0064, train acc 0.864, test acc 0.851 epoch 17, loss 0.0062, train acc 0.867, test acc 0.780 epoch 18, loss 0.0060, train acc 0.871, test acc 0.864 epoch 19, loss 0.0057, train acc 0.881, test acc 0.890 epoch 20, loss 0.0055, train acc 0.885, test acc 0.897
# batchSize = 50 # lr = 0.1 # numEpochs = 15 下得出的結果 train(net2, trainIter, testIter, loss2, numEpochs, batchSize,optimizer2)
epoch 1, loss 0.0119, train acc 0.638, test acc 0.676 epoch 2, loss 0.0079, train acc 0.823, test acc 0.986 epoch 3, loss 0.0046, train acc 0.987, test acc 0.977 epoch 4, loss 0.0030, train acc 0.983, test acc 0.973 epoch 5, loss 0.0023, train acc 0.981, test acc 0.976 epoch 6, loss 0.0019, train acc 0.980, test acc 0.988 epoch 7, loss 0.0016, train acc 0.984, test acc 0.984 epoch 8, loss 0.0014, train acc 0.985, test acc 0.986 epoch 9, loss 0.0013, train acc 0.987, test acc 0.992 epoch 10, loss 0.0011, train acc 0.989, test acc 0.993 epoch 11, loss 0.0010, train acc 0.989, test acc 0.996 epoch 12, loss 0.0010, train acc 0.992, test acc 0.994 epoch 13, loss 0.0009, train acc 0.993, test acc 0.994 epoch 14, loss 0.0008, train acc 0.995, test acc 0.996 epoch 15, loss 0.0008, train acc 0.994, test acc 0.998
test = torch.Tensor([[[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]]], [[[1,1,1,1],[1,0,0,1],[1,0,0,1],[1,1,1,1]]], [[[0,1,0,1],[1,0,0,1],[1,0,0,1],[0,0,0,1]]], [[[0,1,1,1],[1,0,0,1],[1,0,0,1],[0,0,0,1]]], [[[0,0,1,1],[1,0,0,1],[1,0,0,1],[1,0,1,0]]], [[[0,0,1,0],[0,1,0,1],[0,0,1,1],[1,0,1,0]]], [[[1,1,1,0],[1,0,0,1],[1,0,1,1],[1,0,1,1]]] ]) target=torch.Tensor([0,1,0,1,1,0,1])
test
tensor([[[[0., 0., 0., 0.], [0., 1., 1., 0.], [0., 1., 1., 0.], [0., 0., 0., 0.]]],
[[[1., 1., 1., 1.], [1., 0., 0., 1.], [1., 0., 0., 1.], [1., 1., 1., 1.]]],
[[[0., 1., 0., 1.], [1., 0., 0., 1.], [1., 0., 0., 1.], [0., 0., 0., 1.]]],
[[[0., 1., 1., 1.], [1., 0., 0., 1.], [1., 0., 0., 1.], [0., 0., 0., 1.]]],
[[[0., 0., 1., 1.], [1., 0., 0., 1.], [1., 0., 0., 1.], [1., 0., 1., 0.]]],
[[[0., 0., 1., 0.], [0., 1., 0., 1.], [0., 0., 1., 1.], [1., 0., 1., 0.]]],
[[[1., 1., 1., 0.], [1., 0., 0., 1.], [1., 0., 1., 1.], [1., 0., 1., 1.]]]])
with torch.no_grad(): output = net(test) output2 = net2(test) predictions =output.argmax(dim=1) predictions2 =output2.argmax(dim=1)
# 比較結果 print(f'Net測試結果{predictions.eq(target)}') print(f'Net2測試結果{predictions2.eq(target)}')
Net測試結果tensor([ True, True, False, True, True, True, True]) Net2測試結果tensor([False, True, False, True, True, False, True])