神经网络-分类(复习)

神经网络-分类(复习篇)

最近觉得基础不扎实,回头复习,查缺补漏,增加对神经网络训练等方面的理解[加油!今天搞懂分类和基础算法为止!]

torchvision.transforms

  • torchvision.transforms.Compose(list:[transforms])
    • 把一些变换实例以"list"形式组合在一起。
  • torchvision.transforms.ToTensor()
    • 把具有(L,LA,P,I,F,RGB,YCbCr,RGBA,CMYK,1)其中一种模式的"PIL Image"或值在[0,255]之间类型为np.uint8、大小为(HXWXC)的"numpy.ndarray"转成值在[0.0,1.0]之间类型为torch.FloatTensor、大小为(CXHXW)的"Tensor",如果为其他类型的输入,返回的Tensor将不会缩放为[0.0,1.0]。
  • torchvision.transforms.Normalize(mean, std, inplace=False)
    • 用均值、标准差对图像归一化,它不支持PIL图像类型。n个通道对应mean:(mean[1],…mean[n])和std:(std[1],…std[n]),此变换归一化输入"Tensor"的每一个通道。例如:output[channel] = (input[channel]-mean[channel]) / std[channel]。
  • torchvision.transforms.Grayscale(num_output_channels=1)
    • 把图像转化成灰度图,输入图像可以是PIL Image或Tensor类型,若输入图像是torch Tensor类型,大小应为[…,3,H,W],"…"代表任意数字。num_output_channels == 1,返回一通道图像;num_output_channels == 3,返回三通道图像且r == g == b。
  • torchvision.transforms.RandomGrayscale(p=1)
    • 基本用法同上,p指图像被转为灰度图的概率,1-p的概率不会转换。
为什么torch.nn.Module类里的forward函数被直接调用?

1). 根据一些资料理解,类对象里面若实现一个特殊方法"__ call __",则此类实例化后变成为可调用对象。而 “__call __” 函数里面调用了方法"forward",因此,nn.Module类实例可以直接调用"forward"函数。示例如下,example1(“a secret”)语句其实相当于example1. __ call __(“a secret”)。

class example:
    def __init__(self, name):
        self.name = name
    def __call__(self, gender):
        print('My name is %s' % self.name)
        print('My gender is %s' % gender)
        
if __name__ == '__main__':
    example1 = example("kitty")
    example1("a secret")
    
输出为:
My name is kitty
My gender is a secret
" __ repr __ " 方法作用是什么?

2). 一般可以用来描述当前类、函数或者变量等。看下面两个例子~

class example:
    def __init__(self, name):
        self.name = name
    def __call__(self, gender):
        print('My name is %s' % self.name)
        
if __name__ == '__main__':
    example1 = example("kitty")
    print(example1)
    
输出为:<__main__.example object at 0x7fc6ee2a6ac8>
class example:
    def __init__(self, name):
        self.name = name
    def __call__(self, gender):
        print('My name is %s' % self.name)
    def __repr__(self):
        return 'example(%s)'%self.name

if __name__ == '__main__':
    example1 = example("kitty")
    print(example1)

输出为:example(kitty)
" __ item __ " 方法很重要,比如经常在torch.utils.data.Dataset中用来重写,如何理解它?

3). for循环为了兼容有两种机制,若对象有 __ iter __ 和 __ next __ 则会使用迭代器,若没有 __ iter __ 但实现了 __ getitem __ 则会改用下标迭代方式,默认从0开始依次读取相应下标。如下示例:

class NotIterable(object):
    def __init__(self, baselist):
        self.baselist = baselist
    def __getitem__(self, item):
        return self.baselist[item]

if __name__ == '__main__':
    example = NotIterable([1,2,3])
    for i in example:
        print(i)

输出:
1
2
3

实现了__ iter __ 或 __ getitem __的对象都是可迭代对象,但只有同时实现 __ iter __和 __ next __的对象才是迭代器,可以按如下方式判断是否是可迭代对象和迭代器。(迭代器和生成器也是Dataloader里面用到的重要python语法,真正实战再来补充!)

class NotIterable(object):
    def __init__(self, end):
        self.start = 0
        self.end = end

    def __iter__(self):
        return self

if __name__ == '__main__':
    from collections.abc import *
    a = NotIterable(5)
    print(isinstance(a,Iterable))
    print(isinstance(a,Iterator))

输出为:
True
False

了解了上述基础内容,就可以更好的明白为什么pytracking一气呵成这么大的工程了,里面用到的继承、其中的类以及对PyTorch中的类重写(子类对父类方法作一定修改)诸如一些__ call __、 __ getitem __等方法[重载(一个类里面方法名字相同,参数不同)],从而使得较多实例对象简洁串联处理数据,形成一条内部处理数据流。

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

class classifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784,256)
        self.fc2 = nn.Linear(256,128)
        self.fc3 = nn.Linear(128,64)
        self.fc4 = nn.Linear(64,10)
        self.dropout = nn.Dropout(p=0.2)
    def forward(self, x):
        x = x.view(x.shape[0], -1)
        x = self.dropout(F.relu(self.fc1(x)))
        x = self.dropout(F.relu(self.fc2(x)))
        x = self.dropout(F.relu(self.fc3(x)))
        x = F.log_softmax(self.fc4(x), dim=1)
        return x

#数据预处理,标准化图像数据,使得灰度数据在-1-+1之间
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,),(0.5,))])
#下载训练数据集数据,构建训练数据集载入器trainloader,每次从训练集载入64张图片,每次载入打乱顺序
trainset_root = os.path.join(os.path.dirname(__file__),'dataset')
if not os.path.exists(trainset_root):
    os.makedirs(trainset_root)
trainset = datasets.FashionMNIST(trainset_root, download=True, train=True, transform=transform)
trainloader = DataLoader(trainset,batch_size=64, shuffle=True)
#下载测试数据集数据,构建测试数据集载入器testloader,每次从训练集载入64张图片,每次载入打乱顺序
testset_root = os.path.join(os.path.dirname(__file__),'dataset')
testset = datasets.FashionMNIST(testset_root, download=True, train=False, transform=transform)
testloader = DataLoader(testset,batch_size=64, shuffle=True)

model = classifier().cuda()
criterion = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.003)
epochs = 20
train_losses = []
test_losses = []
print('Start training!')
for e in range(epochs):
    running_loss = 0
    #训练一遍数据集
    for images, labels in trainloader:
        #将优化器的每次求导结果设为0,否则每次反向传播之后叠加之前的
        optimizer.zero_grad()
        log_ps = model(images.cuda())
        loss = criterion(log_ps, labels.cuda())
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    #每次训练一遍数据集,都进行一次测试
    test_loss = 0
    accuracy = 0
    #测试时不需要开自动求导和反向传播
    with torch.no_grad():
        model.eval()
        for images, labels in testloader:
            log_ps = model(images.cuda())
            test_loss += criterion(log_ps, labels.cuda()).item()
            ps = torch.exp(log_ps)
            top_p, top_class = ps.topk(1, dim=1)
            equals = top_class == labels.cuda().view(*top_class.shape)
            accuracy += torch.mean(equals.type(torch.FloatTensor))
    model.train()
    train_losses.append(running_loss/len(trainloader))
    test_losses.append(test_loss/len(testloader))
    print("epoch: {}/{}.".format(e+1, epochs),
          "train loss: {:.3f}.".format(running_loss/len(trainloader)),
          "test loss: {:.3f}.".format(test_loss/len(testloader)),
          "accuracy: {:.3f}".format(accuracy/len(testloader)))

简单的分类网络,功能没那么全面,但基本训练模型的思想步骤有了,搭配简单网络和复杂的pytracking总结复习了一下,有时间还是要多理解多写代码,为了梦想继续加油!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值