Pytorch深度學(xué)習(xí)-用卷積做圖像分類

上一篇文章用的全連接來(lái)對(duì)MNIST數(shù)據(jù)集做多分類的訓(xùn)練

全連接的缺點(diǎn)有:

  1. 全連接參數(shù)過(guò)多冰蘑,會(huì)導(dǎo)致訓(xùn)練量過(guò)大

  2. 全連接把圖像展開(kāi)成一個(gè)向量,丟失了圖像原本的位置信息

  3. 全連接限制圖像的尺寸,而卷積則不關(guān)心圖像尺寸大小,只需要接受輸入的通道數(shù)揭北,輸出的通道數(shù)和卷積核大小即可確定圖像尺寸的變換過(guò)程,即

H_{out} = {H_{in}+2*padding-kernalsize\over stride}+1.
W_{out} = {W_{in}+2*padding-kernalsize\over stride}+1.
padding:對(duì)輸入圖片進(jìn)行填充胰蝠,一般用0填充违霞,padding=1,代表填充一圈弹谁,保證卷積前后的圖像尺寸大小一致乾巧,padding計(jì)算公式如下:
padding = {kernalsize-1\over 2}.

stride步長(zhǎng):指的是卷積核每次滑動(dòng)的距離大小

本文采用2d卷積來(lái)構(gòu)建深度網(wǎng)絡(luò)模型

1. 數(shù)據(jù)集構(gòu)建

每個(gè)像素點(diǎn)即每條數(shù)據(jù)中的值范圍為0-255句喜,有的數(shù)字過(guò)大不利于訓(xùn)練且難以收斂,故將其歸一化到(0-1)之間

# 數(shù)據(jù)集處理

# transforms.ToTensor()---shape從(H,W,C)->(C,H,W), 每個(gè)像素點(diǎn)從(0-255)映射到(0-1):直接除以255
# transforms.Normalize()---先將輸入歸一化到(0,1),像素點(diǎn)通過(guò)"(x-mean)/std",將每個(gè)元素分布到(-1,1)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(std=(0.1307,), mean=(0.3081,))
])
# 1.準(zhǔn)備數(shù)據(jù)集

train_dataset = datasets.MNIST(root="../DataSet/mnist",
                               train=True,
                               transform=transform,
                               download=True)
test_dataset = datasets.MNIST(root="../DataSet/mnist",
                              train=False,
                              transform=transform,
                              download=True)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

2. 用Pytorch提供的DataLoader來(lái)加載數(shù)據(jù)集

# dataset:數(shù)據(jù)集 batch_size:mini-batch的大小 shuffle:是否打亂數(shù)據(jù)集順序
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

3.采用全連接的神經(jīng)網(wǎng)絡(luò)來(lái)構(gòu)建模型沟于,最后接Softmax來(lái)處理output

# 構(gòu)建網(wǎng)絡(luò)模型
class Module(torch.nn.Module):
    def __init__(self):
        super(Module, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5, bias=False)
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5, bias=False)
        self.maxPooling = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(320, 10)

    def forward(self, x):
        # print(x.size()) == torch.Size([64, 1, 28, 28])
        # 卷積---池化---激活函數(shù)
        size = x.size(0)
        x = F.relu(self.maxPooling(self.conv1(x)))
        # print(x.size()) == torch.Size([64, 10, 12, 12])
        x = F.relu(self.maxPooling(self.conv2(x)))
        # print(x.size()) == torch.Size([64, 20, 4, 4])
        # 數(shù)據(jù)扁平化處理,為接下來(lái)的全連接測(cè)做準(zhǔn)備
        # Flatten data from (64, 20, 4, 4) to (64,320)
        x = x.view(size, -1)
        x = self.fc(x)
        # 全連接層之后不需要跟激活函數(shù),因?yàn)榧せ詈瘮?shù) softmax 的作用包含在 CrossEntropyLoss 中
        # softmax 函數(shù)的作用包含在 CrossEntropyLoss 中
        return x

4. 構(gòu)建損失函數(shù)和優(yōu)化器

損失函數(shù)采用CrossEntropyLoss
優(yōu)化器采用 SGD 隨機(jī)梯度優(yōu)化算法

# 3.構(gòu)造損失器和優(yōu)化器
criterion = torch.nn.CrossEntropyLoss()  # softmax 函數(shù)的作用包含在 CrossEntropyLoss 中,交叉熵算法
opt = optim.SGD(params=model.parameters(), lr=0.01, momentum=0.5)
# 動(dòng)態(tài)更新學(xué)習(xí)率------每隔step_size : lr = lr * gamma
schedule = optim.lr_scheduler.StepLR(opt, step_size=10, gamma=0.5, last_epoch=-1)

5.完整代碼

# -*- codeing = utf-8 -*-
# @Software : PyCharm

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

# Maxpooling: 最大池化,尋找每個(gè)空間的最大值然后組成一個(gè)新的圖像
# device = torch.device("cuda:0" if torch.cuda.is_available() else "CPU")
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

batch_size = 64

# transforms.ToTensor()---shape從(H,W,C)->(C,H,W), 每個(gè)像素點(diǎn)從(0-255)映射到(0-1):直接除以255
# transforms.Normalize()---先將輸入歸一化到(0,1),像素點(diǎn)通過(guò)"(x-mean)/std",將每個(gè)元素分布到(-1,1)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(std=(0.1307,), mean=(0.3081,))
])
# 1.準(zhǔn)備數(shù)據(jù)集
train_dataset = datasets.MNIST(root="../DataSet/mnist",
                               train=True,
                               transform=transform,
                               download=True)
test_dataset = datasets.MNIST(root="../DataSet/mnist",
                              train=False,
                              transform=transform,
                              download=True)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)


# 2.構(gòu)建網(wǎng)絡(luò)模型---模型是針對(duì)批次樣本的處理情況
class Module(torch.nn.Module):
    def __init__(self):
        super(Module, self).__init__()
        # MNIST 數(shù)據(jù)集是灰度圖-單通道咳胃,所以輸入通道為 1
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5, bias=False)
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5, bias=False)
        self.maxPooling = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(320, 10)

    def forward(self, x):
        # print(x.size()) == torch.Size([64, 1, 28, 28])
        # 卷積---池化---激活函數(shù)
        size = x.size(0)
        x = F.relu(self.maxPooling(self.conv1(x)))
        # print(x.size()) == torch.Size([64, 10, 12, 12])
        x = F.relu(self.maxPooling(self.conv2(x)))
        # print(x.size()) == torch.Size([64, 20, 4, 4])
        # 數(shù)據(jù)扁平化處理,為接下來(lái)的全連接測(cè)做準(zhǔn)備
        # Flatten data from (64, 20, 4, 4) to (64,320)
        x = x.view(size, -1)
        x = self.fc(x)
        # 全連接層之后不需要跟激活函數(shù),因?yàn)榧せ詈瘮?shù) softmax 的作用包含在 CrossEntropyLoss 中
        # softmax 函數(shù)的作用包含在 CrossEntropyLoss 中
        return x


model = Module()
model.to(device)
# 3.構(gòu)造損失器和優(yōu)化器
criterion = torch.nn.CrossEntropyLoss()  # softmax 函數(shù)的作用包含在 CrossEntropyLoss 中,交叉熵算法
opt = optim.SGD(params=model.parameters(), lr=0.01, momentum=0.5)
# 動(dòng)態(tài)更新學(xué)習(xí)率------每隔step_size : lr = lr * gamma
schedule = optim.lr_scheduler.StepLR(opt, step_size=10, gamma=0.5, last_epoch=-1)


# 4.訓(xùn)練數(shù)據(jù)集
def train(epoch):
    runing_loss = 0
    for batch_idx, (inputs, target) in enumerate(train_loader, 0):
        inputs, target = inputs.to(device), target.to(device)
        opt.zero_grad()
        y_pred_data = model(inputs)
        loss = criterion(y_pred_data, target)
        loss.backward()
        opt.step()

        runing_loss += loss.item()
        if batch_idx % 300 == 299:
            print("[%5d, %5d] loss: %f" % (epoch + 1, batch_idx + 1, runing_loss / 300))
            runing_loss == 0.0


# 5.測(cè)試數(shù)據(jù)集
def verify():
    correct = 0
    total = 0
    with torch.no_grad():  # 該語(yǔ)句下的所有tensor在進(jìn)行反向傳播時(shí),不會(huì)被計(jì)算梯度
        for (images, labels) in test_loader:
            images, labels = images.to(device), labels.to(device)
            # 數(shù)據(jù)進(jìn)入模型進(jìn)行計(jì)算
            outputs = model(images)
            # 沿著維度為1的方向(行方向) 尋找每行最大元素的值與其下標(biāo)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    print("Accuracy on test set: %d%%" % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(15):
        train(epoch)
        verify()
        # AlexNet: 卷積---池化---激活函數(shù)---全連接
        # 使用 卷積 + 全連接 的神經(jīng)網(wǎng)絡(luò)的準(zhǔn)確率在 98% 左右



6.結(jié)果展示

result.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市旷太,隨后出現(xiàn)的幾起案子展懈,更是在濱河造成了極大的恐慌,老刑警劉巖供璧,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件存崖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡睡毒,警方通過(guò)查閱死者的電腦和手機(jī)来惧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)演顾,“玉大人违寞,你說(shuō)我怎么就攤上這事∨挤浚” “怎么了趁曼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棕洋。 經(jīng)常有香客問(wèn)我挡闰,道長(zhǎng),這世上最難降的妖魔是什么掰盘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任摄悯,我火速辦了婚禮,結(jié)果婚禮上愧捕,老公的妹妹穿的比我還像新娘奢驯。我一直安慰自己,他們只是感情好次绘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布瘪阁。 她就那樣靜靜地躺著,像睡著了一般邮偎。 火紅的嫁衣襯著肌膚如雪管跺。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天禾进,我揣著相機(jī)與錄音豁跑,去河邊找鬼。 笑死泻云,一個(gè)胖子當(dāng)著我的面吹牛艇拍,可吹牛的內(nèi)容都是我干的狐蜕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼卸夕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼层释!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起娇哆,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤湃累,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后碍讨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體治力,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年勃黍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宵统。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡覆获,死狀恐怖马澈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弄息,我是刑警寧澤痊班,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站摹量,受9級(jí)特大地震影響涤伐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缨称,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一凝果、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧睦尽,春花似錦器净、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宁玫,卻和暖如春粗恢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欧瘪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匙赞,地道東北人佛掖。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓妖碉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親芥被。 傳聞我的和親對(duì)象是個(gè)殘疾皇子欧宜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容