精华内容
下载资源
问答
  • 2021-10-20 14:54:47

    基于pytorch的图像分类网络搭建思路
    本文的基本内容为:
    实现了一个基于pytorch框架,Resnet18网络结构的图像分类网络。经训练后可以良好的实现宝可梦(皮卡丘,小火龙,妙蛙种子,杰尼龟,超梦)图片的分类.
    key words:pytorch,Resnet18,迁移学习(transfer learning),图像分类(image classification)
    本文基于龙良曲的pytorch深度学习代码进行总结
    Tips:
    1.代码参考龙良曲老师的github 63节迁移学习
    https://github.com/dragen1860/Deep-Learning-with-PyTorch-Tutorials
    有改动,其中检测部分是自己写的
    2.本文中引入visdom进行实时训练情况监测,所以在运行前请在终端启动visdom

    python -m visdom.server
    

    1.数据集部分

    import torch
    import os, glob
    import random, csv
    
    from torch.utils.data import Dataset, DataLoader
    from torchvision import transforms
    from PIL import Image
    
    
    class Pokemon(Dataset):     # 定义Pokemon数据集,继承torch的Dataset类
    
        def __init__(self, root, resize, mode):
            super(Pokemon, self).__init__()
    
            self.root = root
            self.resize = resize
    
            self.name2label = {}
    
            for name in sorted(os.listdir(os.path.join(root))):   #  通过目录的安排规律获取预测值位置与Pokemon名字的对应关系字典
                if not os.path.isdir(os.path.join(root, name)):
                    continue
    
                self.name2label[name] = len(self.name2label.keys())
    
            # print(self.name2label)
            # print(self.name2label.keys())
    
            self.images, self.labels = self.load_csv('images.csv')   # 读取csv文件,获取images路径和对应的label
    
            if mode == 'train':       # 训练 验证 测试集划分 6:2:2
                self.images = self.images[:int(0.6*len(self.images))]
                self.labels = self.labels[:int(0.6*len(self.labels))]
            elif mode == 'val':
                self.images = self.images[int(0.6*len(self.images)):int(0.8*len(self.images))]
                self.labels = self.labels[int(0.6*len(self.labels)):int(0.8*len(self.labels))]
            else:
                self.images = self.images[int(0.8*len(self.images)):]
                self.labels = self.labels[int(0.8*len(self.labels)):]
    
    
    
        def load_csv(self, filename):  # 函数输入:需要读取的csv文件名字  函数输出:images,label的列表
    
            if not os.path.exists(os.path.join(self.root,filename)):  # 如果不存在csv文件,那么创建它
    
                images = []
                for name in self.name2label.keys():  # 用glob.glob()获取root目录下三种格式的图片
                    images += glob.glob(os.path.join(self.root, name, '*.png'))
                    images += glob.glob(os.path.join(self.root, name, '*.jpg'))
                    images += glob.glob(os.path.join(self.root, name, '*.jpeg'))
    
                random.shuffle(images)  # 打散图片顺序,不再根据名字排列
                with open(os.path.join(self.root,filename),mode='w',newline='') as f:
                    writer = csv.writer(f)
                    for img in images:
                        name = img.split(os.sep)[-2]
                        label = self.name2label[name]
    
                        writer.writerow([img,label])
                    print('written into csv file',filename)   # 写入csv文件,其中利用路径中的名字和name2label字典获取索引
    
            images, labels = [],[]      # 如果存在csv文件,那么读取它,此处先将images和labels清零防止受到前面写入csv时的影响
            with open(os.path.join(self.root,filename)) as f:
                reader = csv.reader(f)
                for row in reader:
                    img, label = row
                    label = int(label)
    
                    images.append(img)
                    labels.append(label)
    
            assert len(images) == len(labels)
    
            return images , labels    # 按行读取images和labels,值返回
    
        def __len__(self):
            return len(self.images)
    
    
        def denormalize(self,x_hat):
    
            mean = [0.485, 0.456, 0.406]
            std = [0.229, 0.224, 0.225]
    
            # x_hat = (x-mean)/std
            # x= x_hat*std+mean
            mean = torch.tensor(mean).unsqueeze(1).unsqueeze(1)
            std = torch.tensor(std).unsqueeze(1).unsqueeze(1)
    
            x = x_hat * std + mean
    
            return x
    
    
    
        def __getitem__(self, idx):
            # idx~[0~len(images)]
            # self.images, self.labels
            # img: 'pokemon\\bulbasaur\\00000000.png'
            # label: 0
            img, label = self.images[idx], self.labels[idx]
    
            tf = transforms.Compose([
                lambda x:Image.open(x).convert('RGB'), # string path= > image data
                transforms.Resize((int(self.resize*1.25), int(self.resize*1.25))),
                transforms.RandomRotation(15),
                transforms.CenterCrop(self.resize),
                transforms.ToTensor(),
                transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                     std=[0.229, 0.224, 0.225])
            ])
    
            img = tf(img)
            label = torch.tensor(label)
    
    
            return img, label
    
    def main():
        import visdom
        import time
    
        viz = visdom.Visdom()
        db = Pokemon('pokemon', 64, 'train')
        x,y = next(iter(db))
        print('sample:',x.shape,y.shape,y)
    
        viz.image(db.denormalize(x),win='sample_x',opts=dict(title='sample_x'))
    
        loader = DataLoader(db,batch_size=32,shuffle=True,num_workers=4)
    
        for x,y in loader:
            viz.images(db.denormalize(x),nrow=8,win='batch',opts=dict(title='batch'))
            viz.text(str(y.numpy()),win='label',opts=dict(title='batch-y'))
            time.sleep(10)
    
    
    
    if __name__ == '__main__':
        main()
    

    2.网络训练

    import  torch
    from    torch import optim, nn
    import  visdom
    import  torchvision
    from    torch.utils.data import DataLoader
    
    from    pokemon import Pokemon
    # from    resnet import ResNet18
    from    torchvision.models import resnet18
    
    from    utils import Flatten
    
    batchsz = 32
    lr = 5e-4
    epochs = 20
    
    device = torch.device('cuda')
    torch.manual_seed(1234)
    
    
    train_db = Pokemon('pokemon', 224, mode='train')
    val_db = Pokemon('pokemon', 224, mode='val')
    test_db = Pokemon('pokemon', 224, mode='test')
    train_loader = DataLoader(train_db, batch_size=batchsz, shuffle=True,
                              num_workers=4)
    val_loader = DataLoader(val_db, batch_size=batchsz, num_workers=2)
    test_loader = DataLoader(test_db, batch_size=batchsz, num_workers=2)
    
    
    viz = visdom.Visdom()
    
    def evalute(model, loader):
        model.eval()
        
        correct = 0
        total = len(loader.dataset)
    
        for x,y in loader:
            x,y = x.to(device), y.to(device)
            with torch.no_grad():
                logits = model(x)
                pred = logits.argmax(dim=1)
            correct += torch.eq(pred, y).sum().float().item()
    
        return correct / total
    
    def main():
    
        # model = ResNet18(5).to(device)
        trained_model = resnet18(pretrained=True)
        model = nn.Sequential(*list(trained_model.children())[:-1], #[b, 512, 1, 1]
                              Flatten(), # [b, 512, 1, 1] => [b, 512]
                              nn.Linear(512, 5)
                              ).to(device)
        # x = torch.randn(2, 3, 224, 224)
        # print(model(x).shape)
    
        optimizer = optim.Adam(model.parameters(), lr=lr)
        criteon = nn.CrossEntropyLoss()
    
    
        best_acc, best_epoch = 0, 0
        global_step = 0
        viz.line([0], [-1], win='loss', opts=dict(title='loss'))
        viz.line([0], [-1], win='val_acc', opts=dict(title='val_acc'))
        for epoch in range(epochs):
    
            for step, (x,y) in enumerate(train_loader):
    
                # x: [b, 3, 224, 224], y: [b]
                x, y = x.to(device), y.to(device)
    
                model.train()
                print(x.size())
                logits = model(x)
                loss = criteon(logits, y)
    
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
    
                viz.line([loss.item()], [global_step], win='loss', update='append')
                global_step += 1
    
            if epoch % 1 == 0:
    
                val_acc = evalute(model, val_loader)
                if val_acc> best_acc:
                    best_epoch = epoch
                    best_acc = val_acc
    
                    torch.save(model.state_dict(), 'best.mdl')
    
                    viz.line([val_acc], [global_step], win='val_acc', update='append')
    
    
        print('best acc:', best_acc, 'best epoch:', best_epoch)
    
        model.load_state_dict(torch.load('best.mdl'))
        print('loaded from ckpt!')
    
        test_acc = evalute(model, test_loader)
        print('test acc:', test_acc)
    
    
    
    
    
    if __name__ == '__main__':
        main()
    

    3.验证代码

    import torch
    from torch import optim, nn
    from PIL import Image, ImageDraw, ImageFont
    from torchvision import transforms
    from torchvision.models import resnet18
    import os
    
    resize = 224  # 设置resize参数,保持与事先设置的网络入口图片大小参数一致。Resnet18的图片大小参数为3*224*224
    device = torch.device('cuda')  # 设置device,试运行的电脑没有安装cuda,为cpu运行
    weights = 'F:/Deep-Learning-with-PyTorch-Tutorials-master/lesson63-transfer learning/best.mdl'  # 输入权重的路径,此处权重为前面的迁移学习获得
    path = 'images'  # 需要检测的文件夹名字
    
    
    # imgsz=224
    
    def label2name(root, label):  # 函数输入:数据集路径,网络预测类别数字  函数输出:网络预测类别名字
        namedic = {}
        for name in sorted(os.listdir(os.path.join(root))):   # 通过对pokemon文件夹的摆放获取预测数字值和pokemon名字的字典
            if not os.path.isdir(os.path.join(root, name)):
                continue
            namedic[len(namedic.keys())] = name
        # namedic = {0: 'bulbasaur', 1: 'charmander', 2: 'mewtwo', 3: 'pikachu', 4: 'squirtle'}
        # 也可以通过这行代码直接输入数字与pokemon名字的字典,此时不需要root参数
        # print(namedic)
        pokemon_name = namedic[label]
        return pokemon_name
    
    
    def creatmodel():   # 函数输出:返回网络结构模型
        trained_model = resnet18(pretrained=True) # 利用torch预训练的resnet18模型
        model = nn.Sequential(*list(trained_model.children())[:-1],  # [b, 512, 1, 1]  利用.children方法,将模型的前17层设置与resnet18一致
                              nn.Flatten(),  # [b, 512, 1, 1] => [b, 512]
                              nn.Linear(512, 5)  # 全连接层,输出为最后5种不同的pokemon类型
                              ).to(device)
        return model
    
    
    def getimagelist(source):   # 函数输入:检测文件夹路径  函数输出:所有检测文件的路径列表
        rlist = []
        for dir, folder, file in os.walk(source):
            for i in file:
                t = "%s\%s" % (dir, i)
                rlist.append(t)
        # print(rlist)
        return rlist
    
    
    def drawimagetext(image, context):   # 函数输入:需要写入内容的图片,需要写入的内容  函数输出:写入内容后的图片
        # get an image
        # make a blank image for the text, initialized to transparent text color
        img = Image.open(image)
        # get a font
        fnt = ImageFont.truetype("arial.ttf", 40)
        # get a drawing context
        d = ImageDraw.Draw(img)
        context = str(context)
        d.text((10, 10), context, font=fnt, fill=(0, 0, 0))
    
        return img
    
    
    def main():
        model = creatmodel() # 创建模型
        model.load_state_dict(torch.load('best.mdl'))  # load the parameters
        data_transform = transforms.Compose([  # 检测数据预处理步骤
            lambda x: Image.open(x).convert('RGB'),  # string path= > image data
            transforms.Resize((resize, resize)),   # Resize 到网络输入大小
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])     # 由于网络训练时进行了Normalize,检测时也应当进行Normalize再送入网络
        ])
    
        for image in getimagelist(path):  # 进行图片预测的for循环
            img = data_transform(image)   # 取出图片+预处理
            img = torch.unsqueeze(img, dim=0)  # 扩张batch维度,与网络入口对齐
            img = img.to(device)           # 转移到GPU上
            # print(img.size())
            model.eval()                    # 进入验证模式
            with torch.no_grad():
                logits = model(img)  # 送入模型的img为一个tensor,得到模型输出的五种神奇宝贝的分别的概率
                pred = logits.argmax(dim=1)   # 预测值为概率最大值所处的位置
                # print(int(pred[0]))
                image_afterdraw = drawimagetext(image, label2name('pokemon', int(pred[0])))  # 画图,将信息写入
            image_afterdraw.show()  # 展示图片
        # 图片保存模块
        #     image_afterdraw.save('./imagesave/{}.png'.format(i))
        #     i +=1
    
    if __name__ == '__main__':
        main()
    
    
    更多相关内容
  • 岩石声学特性可以对岩石内部结构及力学特性进行描述与分类。通过对岩石声学特性的研究可以得到岩石爆破破碎所需的诸多信息。通过试验分析可知,声波速度与岩石爆破破碎效果密切相关,且岩石波形与岩石声波速度密切相关...
  • 主要为大家详细介绍了基于循环神经网络(RNN)实现影评情感分类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • softmax的前世今生系列是作者在学习NLP神经网络时,以softmax为何能对文本进行分类、预测等问题为入手点,顺藤摸瓜进行的一系列研究学习。其中包含: 1.softmax函数的正推原理,softmax的代数和几何意义,softmax...

    导读:

    softmax的前世今生系列是作者在学习NLP神经网络时,以softmax层为何能对文本进行分类、预测等问题为入手点,顺藤摸瓜进行的一系列研究学习。其中包含:

    1.softmax函数的正推原理,softmax的代数和几何意义,softmax为什么能用作分类预测,softmax链式求导的过程。

    2.从数学的角度上研究了神经网络为什么能通过反向传播来训练网络的原理。

    3.结合信息熵理论,对二元交叉熵为何适合作为损失函数进行了探讨。

    通过对本系列的学习,你可以全面的了解softmax的来龙去脉。如果你尚不了解神经网络,通过本系列的学习,你也可以学到神经网络反向传播的基本原理。学完本系列,基本神经网络原理就算式入门了,毕竟神经网络基本的网络类型就那几种,很多变种,有一通百通的特点。

    网上对softmax或是神经网络反向传播知识的整理,基本都通过一个长篇大论堆积出来,一套下来面面俱到但又都不精细。本文将每个环节拆开,分别进行详细介绍,即清晰易懂,又减轻了阅读负担,增加可读性。本文也借鉴了其他作者的内容,并列举引用,希望大家在学习过程中能有所收获

    本章内容提要:

    从前两篇文章中,我们了解了softmax函数的基本原理,知道了他为什么叫做softmaxsoftmax函数有什么特性,以及softmax函数的推导过程。

    本文基于前两篇文章的基础上,讲一下为什么我们在做分类预测的时候,经常会选择在神经网络的最后一层的输出结果上,加一个softmax层,来对输出结果进行分类。

    一、softmax层和神经网络的关系

    先看一下神经网络的结构:

                                                                 

    红色是网络的开端,是输入层。蓝色的部分是网络的隐含层,用于计算。绿色是输出层,输出计算结果 。想了解更多网络内部原理可以参考之前的文章。

    那么加上softmax层后的网络形状如下:

                                             

    在output layer后多出来的一个黑色的layer,就是用于分类的softmax层。最后紫色的new output层就是经过softmax层后,转换成概率的新输出层。

    从这个图上可以看出来,softmax层只是对神经网络的输出结果进行了一次换算,将输出结果用概率的形式表现出来。

    二、神经网络各层的内部定义

    为了方便后续学习,我们对神经网络中每层节点的概念、及节点之间的计算关系介绍一下。因为输入层只做输入数据用,没有计算,图就去掉了。L1层对应隐含层,L2层对应输出层,L2层后链接的就是softmax层,最后输出的S就是经过softmax层转换后的概率输出。

                                                 

    (1)

    在隐含层L1中,x是L1上一层的输出结果,也是L1层的输入值,有j个神经元节点,记为:

                                                                                                     x_{j}

    (2)

    L1层和L2之间的W是权重矩阵,它连接L1层与L2层之间的神经元节点,每两个神经元节点之间由一条权重边链接。其中,L1层的第j个神经元节点x,指向L2层的第i个神经元节点z的权重边w,记为:

                                                                                                    w_{ij}

    (3)

    在输出层L2中,z是L1层的输入值x,与两层之间的权重矩阵W,计算后的结果,记为:

                                                                                                     z_{i}

    (4)

    z,x,w之间的关系为:

                                                                          z_{1} = x_{1} * w_{11} + x_{2} * w_{12} +x_{3} * w_{13}

    即如下,(其中b为独立的偏置项,为方便描述,暂不讨论):

                                                                          z_{i} = \sum x_{j}*w_{ij} + b

    (5)

    softmax层对L2层传来的数值进行一个换算,换算公式如下:

                                                                           softmax = \frac{e^{\eta _{i}}}{\sum_{j=1}^{k}e^{\eta _{j}}}

    公式的概念及推导过程请看之前的文章:softmax函数的正推原理——softmax前世今生系列(1)

    (6) 

    s指L2层中,神经元节点z的值,经过softmax层计算后,转换成的概率值,s与z的关系为:

                                                                           z_{i}\rightarrow softmax(z_{i}) \rightarrow s_{i}

    三、softmax表达式和概率的关系

    根据常识我们知道:表述一件事情发生的概率时,一般用百分数来表示。一定发生的事情的概率是100%,不会发生的事情概率是0%.不存在大于100%或者小于0%的概率。一件事情的所有可能性的概率之和等于1.

    再来观察一下,输出值经过softmax层计算后的结果表达式:

                                                            s_{i} = \frac{e^{z_{i}}}{e^{z_{1}}+e^{z_{2}} +...+e^{z_{i}}+...+e^{z_{k}}}

    显然有:

                                                                              s_{i}\in [0\%,100\%]

    对所有神经元s求和,可以得到一个结果:

                                                          \sum_{i=1}^{k}s_{i} = \frac{e^{z_{1}}+e^{z_{2}} +...+e^{z_{i}}+...+e^{z_{k}}}{e^{z_{1}}+e^{z_{2}} +...+e^{z_{i}}+...+e^{z_{k}}}

    即:

                                                                                      \sum_{i=1}^{k}s_{i} = 1

    由此可知,输出层的数据,经过softmax函数转换后的结果,即可满足概率表达式的特性。

    因此,输出层的数据转化成概率表达式后的输出值,就有了新的意义。对分类问题来说,不同大小的概率值表示,这个结果属于不同类别的可能性大小。

     

    四、示例

    引用一张网上的原理图,该图描述了softmax对输出结果的计算过程:

                                                 

    神经网络的输出向量为:

                                                                                   output=\begin{bmatrix} 3\\ 1\\ -3 \end{bmatrix}

    带入softmax计算公式:

                                                    softmax(3) = \tfrac{e^{3}}{e^{3}+e^{1}+e^{-3}} \approx \frac{20}{20+2.7+0.05} \approx0.88

                                                    softmax(1) = \tfrac{e^{1}}{e^{3}+e^{1}+e^{-3}} \approx \frac{2.7}{20+2.7+0.05} \approx0.12

                                                    softmax(-3) = \tfrac{e^{-3}}{e^{3}+e^{1}+e^{-3}} \approx \frac{0.05}{20+2.7+0.05} \approx 0

    通过softmax转换:

                                                                            newoutput = \begin{bmatrix} 0.88\\ 0.12\\ 0 \end{bmatrix}

    通过softmax转换后,结果表达的意思是:这个T向量属于“第一类”的概率是88%,属于“第二类”的概率是12%,属于“第三类”的概率是0%.这就是softmax层在神经网络中,解决分类问题的基本原理。通过softmax函数,将神经网络的输出结果转化成概率表达式。找到最大概率项,为其分类。

    五、总结

    通过本文学习,我们知道了softmax在神经网络中分类的原理。softmax适用于解决多分类问题,当分类情况只有两种的时候,softmax就转换成了回归问题,也就是二分类问题/逻辑回归/logistic回归。

    干脆我们顺手推导一番,当分类结果只有x1和x2两种情况时:

                                                   softmax(x) = \tfrac{e^{x_{1}}}{e^{x_{1}}+e^{x_{2}}} = \tfrac{e^{x_{1} }\div e^{x_{1} }}{e^{x_{1}} \div e^{x_{1} }+e^{x_{2}}\div e^{x_{1} }} = \tfrac{1}{1+e^{x_{2}-x_{1}}}

    我们来对比一下logistic回归的函数表达式:

                                                     logistic(x) = \frac{1}{1+e^{-x}} 

    咦?突然发现不知不觉中我们竟然把逻辑回归的知识也给学了。不仅如此,其实你马上就要在不知不觉中学会神经网络了。呵呵呵,让我们继续走下去。

    通过三篇文章的学习,此时对于softmax函数的概念和基本原理,我们已经基本理清楚了。但实践出真知,softmax函数到底应该怎么用呢?在BP神经网络中,它扮演着什么样的角色?当我们预测的概率结果和正确结果对比有差异时,我们要如何取修正这个神经网络,使得预测的概率更加准确?

    当你在思考这些问题时,你已经一只脚踏进了BP神经网络的大门。下一篇文章我们会学习一个叫做交叉熵的东西,我们会明白交叉熵如何帮助我们判断预测结果是否准确,以及如何根据预测结果来修正神经网络参数。

    此处是一个小阶段的完结,但也是一个新的开始。有什么问题可以留言问我,如有错误欢迎指正。

    相关链接:

    softmax函数的正推原理——softmax前世今生系列(1)

    softmax函数名字的由来(代数&几何原理)——softmax前世今生系列(2)

    六、附学习笔记如下:

     

    展开全文
  • 分类问题可能是应用最广泛的机器学习问题。在这个例子中,你将学习根据电影评论的 文字内容将其划分为正面或负面。本节使用IMDB 数据集,它包含来自互联网电影数据库(IMDB)的50 000 条严重两极分 化的评论。数据...

    写在前面

    二分类问题可能是应用最广泛的机器学习问题。在这个例子中,你将学习根据电影评论的 文字内容将其划分为正面或负面。本节使用IMDB 数据集,它包含来自互联网电影数据库(IMDB)的50 000 条严重两极分 化的评论。数据集被分为用于训练的 25 000 条评论与用于测试的 25 000 条评论,训练集和测试 集都包含 50% 的正面评论和 50% 的负面评论。再此之前,先说说相关的流程定义。相关代码基于TensorFlow实现,你也可以只用Keras实现,整个项目就是围绕Keras进行开发的。

    不同的张量格式与不同的数据处理类型需要用到不同的层。例如,简单的向量数据保存在 形状为 (samples, features) 的 2D 张量中,通常用密集连接层[densely connected layer,也叫全连接层(fully connected layer)或密集层(dense layer),对应于Keras 的 Dense 类]来处 理。序列数据保存在形状为 (samples, timesteps, features) 的 3D 张量中,通常用循环层(recurrent layer,比如Keras 的 LSTM 层)来处理。图像数据保存在4D 张量中,通常用二维卷积层(Keras 的 Conv2D)来处理。

    你可以将层看作深度学习的乐高积木,Keras 等框架则将这种比喻具体化。在 Keras 中,构 建深度学习模型就是将相互兼容的多个层拼接在一起,以建立有用的数据变换流程。这里层兼 容性(layer compatibility)具体指的是每一层只接受特定形状的输入张量,并返回特定形状的输 出张量。看看下面这个例子。

    from tensorflow.keras import layers
    layer = layers.Dense(32, input_shape(784,))
    

    我们创建了一个层,只接受第一个维度大小为784 的 2D 张量(第0 轴是批量维度,其大 小没有指定,因此可以任意取值)作为输入。这个层将返回一个张量,第一个维度的大小变成 了 32。

    模型

    深度学习模型是层构成的有向无环图。最常见的例子就是层的线性堆叠,将单一输入映射 为单一输出。 但随着深入学习,你会接触到更多类型的网络拓扑结构。一些常见的网络拓扑结构如下。

    • 双分支(two-branch)网络 +
    • 多头(multihead)网络
    • Inception 模块

    损失函数与优化器

    一旦确定了网络架构,你还需要选择以下两个参数。

    • 损失函数(目标函数)——在训练过程中需要将其最小化。它能够衡量当前任务是否已 成功完成。
    • 优化器——决定如何基于损失函数对网络进行更新。它执行的是随机梯度下降(SGD) 的某个变体。

    具有多个输出的神经网络可能具有多个损失函数(每个输出对应一个损失函数)。但是,梯 度下降过程必须基于单个标量损失值。因此,对于具有多个损失函数的网络,需要将所有损失函数取平均,变为一个标量值。

    对于分类、回归、序列预测等常见问题,你可以遵循一些简单的指导原则来选 择正确的损失函数。例如,对于二分类问题,你可以使用二元交叉熵(binary crossentropy)损失函数;对于多分类问题,可以用分类交叉熵(categorical crossentropy)损失函数;对于回归问题,可以用均方误差(mean-squared error)损失函数;对于序列学习问题,可以用联结主义 时序分类(CTC,connectionist temporal classification)损失函数,等等。

    二分类问题

    IMDB 数据集

    本节使用IMDB 数据集,它包含来自互联网电影数据库(IMDB)的50 000 条严重两极分 化的评论。数据集被分为用于训练的 25 000 条评论与用于测试的 25 000 条评论,训练集和测试 集都包含 50% 的正面评论和 50% 的负面评论。

    为什么要将训练集和测试集分开?因为你不应该将训练机器学习模型的同一批数据再用于 测试模型!模型在训练数据上的表现很好,并不意味着它在前所未见的数据上也会表现得很好, 而且你真正关心的是模型在新数据上的性能(因为你已经知道了训练数据对应的标签,显然不 再需要模型来进行预测)。例如,你的模型最终可能只是记住了训练样本和目标值之间的映射关系,但这对在前所未见的数据上进行预测毫无用处。下一章将会更详细地讨论这一点。 与 MNIST 数据集一样,IMDB 数据集也内置于 Keras 库。它已经过预处理:评论(单词序列) 已经被转换为整数序列,其中每个整数代表字典中的某个单词。 下列代码将会加载 IMDB 数据集(第一次运行时会下载大约 80MB 的数据)。

    from tensorflow.keras.datasets import imdb
    
    (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
    
    

    参数 num_words=10000 的意思是仅保留训练数据中前10 000 个最常出现的单词。低频单词将被舍弃。这样得到的向量数据不会太大,便于处理。 train_data 和 test_data 这两个变量都是评论组成的列表,每条评论又是单词索引组成 的列表(表示一系列单词)。train_labels 和 test_labels 都是0 和 1 组成的列表,其中0 代表负面(negative), 1 代表正面(positive)。

    print( train_data[0])
    # [1, 14, 22, 16, ... 178, 32] 
     
    print(train_labels[0])
    # 1
    
    # 由于限定为前 10 000 个最常见的单词,单词索引都不会超过 10 000。
    print(max([max(sequence) for sequence in train_data]))
    # 9999
    

    我们可以将某条评论迅速解码为英文单词。

    word_index = imdb.get_word_index()
    reverse_word_index = dict(
        [(value, key) for (key, value) in word_index.items()])
    decoded_review = ' '.join(
        [reverse_word_index.get(i - 3, '?') for i in train_data[0]])
    
    print(decoded_review)
    

    准备数据

    你不能将整数序列直接输入神经网络。你需要将列表转换为张量。转换方法有以下两种。

    • 填充列表,使其具有相同的长度,再将列表转换成形状为 (samples, word_indices) 的整数张量,然后网络第一层使用能处理这种整数张量的层(即 Embedding 层)。
    • 对列表进行 one-hot 编码,将其转换为 0 和 1 组成的向量。举个例子,序列 [3, 5] 将会被转换为10 000 维向量,只有索引为3 和 5 的元素是1,其余元素都是0。然后网络第一层可以用 Dense 层,它能够处理浮点数向量数据。 下面我们采用后一种方法将数据向量化。为了加深理解,你可以手动实现这一方法,如下所示。
    def vectorize_sequences(sequences, dimension=10000):
        results = np.zeros((len(sequences), dimension))
        for i, sequence in enumerate(sequences):
            results[i, sequence] = 1.
        return results
    
    x_train = vectorize_sequences(train_data)
    x_test = vectorize_sequences(test_data)
    
    y_train = np.asarray(train_labels).astype('float32')
    y_test = np.asarray(test_labels).astype('float32')
    

    构建网络

    输入数据是向量,而标签是标量(1 和 0),这是你会遇到的最简单的情况。有一类网络在这种问题上表现很好,就是带有relu 激活的全连接层(Dense)的简单堆叠,比如 Dense(16, activation='relu')。 传入 Dense 层的参数(16)是该层隐藏单元的个数。一个隐藏单元(hidden unit)是该层 表示空间的一个维度。每个带有 relu 激活的 Dense 层都实现了下列张量 运算:

    output = relu(dot(W, input) + b) 
    

    16 个隐藏单元对应的权重矩阵 W 的形状为 (input_dimension, 16),与 W 做点积相当于 将输入数据投影到16 维表示空间中(然后再加上偏置向量 b 并应用 relu 运算)。你可以将表 示空间的维度直观地理解为“网络学习内部表示时所拥有的自由度”。隐藏单元越多(即更高维 的表示空间),网络越能够学到更加复杂的表示,但网络的计算代价也变得更大,而且可能会导 致学到不好的模式(这种模式会提高训练数据上的性能,但不会提高测试数据上的性能)。

    对于这种 Dense 层的堆叠,你需要确定以下两个关键架构:

    • 网络有多少层;
    • 每层有多少个隐藏单元。

    而现在这个例子中,我们选择的下列架构:

    • 两个中间层,每层都有 16 个隐藏单元;
    • 第三层输出一个标量,预测当前评论的情感。

    中间层使用 relu 作为激活函数,最后一层使用 sigmoid 激活以输出一个 0~1 范围内的概率 值(表示样本的目标值等于1 的可能性,即评论为正面的可能性)。relu(rectified linear unit, 整流线性单元)函数将所有负值归零,而 sigmoid 函数则将任意值“压缩”到 [0, 1] 区间内,其输出值可以看作概率值。

    在这里插入图片描述

    model = models.Sequential()
    model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
    model.add(layers.Dense(16, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    

    什么是激活函数?为什么要使用激活函数?如果没有 relu 等激活函数(也叫非线性), Dense 层将只包含两个线性运算——点积 和加法:output = dot(W, input) + b。这样 Dense 层就只能学习输入数据的线性变换(仿射变换):该层的假设空间是从输 入数据到16 位空间所有可能的线性变换集合。这种假设空间非常有限,无法利用多个表示 层的优势,因为多个线性层堆叠实现的仍是线性运算,添加层数并不会扩展假设空间。 为了得到更丰富的假设空间,从而充分利用多层表示的优势,你需要添加非线性或激 活函数。relu 是深度学习中最常用的激活函数,但还有许多其他函数可选,它们都有类似 的奇怪名称,比如 prelu、elu 等。

    最后,你需要选择损失函数和优化器。由于你面对的是一个二分类问题,网络输出是一 个概率值(网络最后一层使用sigmoid 激活函数,仅包含一个单元),那么最好使用 binary_ crossentropy(二元交叉熵)损失。这并不是唯一可行的选择,比如你还可以使用mean_ squared_error(均方误差)。但对于输出概率值的模型,交叉熵(crossentropy)往往是最好 的选择。交叉熵是来自于信息论领域的概念,用于衡量概率分布之间的距离,在这个例子中就 是真实分布与预测值之间的距离。 下面的步骤是用 rmsprop 优化器和 binary_crossentropy 损失函数来配置模型。注意, 我们还在训练过程中监控精度。

    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    

    上述代码将优化器、损失函数和指标作为字符串传入,这是因为rmsprop、binary_ crossentropy 和 accuracy 都是Keras 内置的一部分。有时你可能希望配置自定义优化器的 参数,或者传入自定义的损失函数或指标函数。前者可通过向 optimizer 参数传入一个优化器 类实例来实现。后者可通过向 loss 和 metrics 参数传入函数对象来实现。

    from tensorflow.keras import optimizers 
    model.compile(optimizer=optimizers.RMSprop(lr=0.001),              
    				loss='binary_crossentropy',               
    				metrics=['accuracy'])
    
    
    from keras import losses 
    from keras import metrics 
     
    model.compile(optimizer=optimizers.RMSprop(lr=0.001),               
    			loss=losses.binary_crossentropy,               
    			metrics=[metrics.binary_accuracy])
    
    

    验证你的方法

    为了在训练过程中监控模型在前所未见的数据上的精度,你需要将原始训练数据留出 10 000 个样本作为验证集。

    x_val = x_train[:10000]
    partial_x_train = x_train[10000:]
    
    y_val = y_train[:10000]
    partial_y_train = y_train[10000:]
    

    现在使用512 个样本组成的小批量,将模型训练20 个轮次(即对 x_train 和 y_train 两 个张量中的所有样本进行20 次迭代)。与此同时,你还要监控在留出的 10 000 个样本上的损失 和精度。你可以通过将验证数据传入 validation_data 参数来完成。

    history = model.fit(partial_x_train, partial_y_train,
                        epochs=20,
                        batch_size=512,
                        validation_data=(x_val, y_val))
    

    在 CPU 上运行,每轮的时间不到2 秒,训练过程将在20 秒内结束。每轮结束时会有短暂 的停顿,因为模型要计算在验证集的 10 000 个样本上的损失和精度。 注意,调用 model.fit() 返回了一个 History 对象。这个对象有一个成员 history,它 是一个字典,包含训练过程中的所有数据。我们来看一下。

    history_dict = history.history
    print(history_dict.keys())
    

    字典中包含4 个条目,对应训练过程和验证过程中监控的指标。在下面两个代码清单中, 我们将使用Matplotlib 在同一张图上绘制训练损失和验证损失,以及训练精度和验证精度。请注意,由于网络的随机初始化不同,你得到的结果可能会略有不同。

    import matplotlib.pyplot as plt 
     
    history_dict = history.history 
    loss_values = history_dict['loss'] 
    val_loss_values = history_dict['val_loss'] 
     
    epochs = range(1, len(loss_values) + 1) 
     
    plt.plot(epochs, loss_values, 'bo', label='Training loss')   
    plt.plot(epochs, val_loss_values, 'b', label='Validation loss')   
    plt.title('Training and validation loss') 
    plt.xlabel('Epochs') 
    plt.ylabel('Loss') 
    plt.legend() 
     
    plt.show()
    

    在这里插入图片描述

    plt.clf()    
    acc = history_dict['acc']  
    val_acc = history_dict['val_acc'] 
     
    plt.plot(epochs, acc, 'bo', label='Training acc') 
    plt.plot(epochs, val_acc, 'b', label='Validation acc') 
    plt.title('Training and validation accuracy') 
    plt.xlabel('Epochs') 
    plt.ylabel('Accuracy') 
    plt.legend() 
     
    plt.show()
    
    

    在这里插入图片描述

    如你所见,训练损失每轮都在降低,训练精度每轮都在提升。这就是梯度下降优化的预期 结果——你想要最小化的量随着每次迭代越来越小。但验证损失和验证精度并非如此:它们似 乎在第四轮达到最佳值。这就是我们之前警告过的一种情况:模型在训练数据上的表现越来越好, 但在前所未见的数据上不一定表现得越来越好。准确地说,你看到的是过拟合(overfit):在第二轮之后,你对训练数据过度优化,最终学到的表示仅针对于训练数据,无法泛化到训练集之 外的数据。

    在这种情况下,为了防止过拟合,你可以在3 轮之后停止训练。通常来说,你可以使用许多方法来降低过拟合。 我们从头开始训练一个新的网络,训练 4 轮,然后在测试数据上评估模型。

    使用训练好的网络在新数据上生成预测结果

    训练好网络之后,你希望将其用于实践。你可以用 predict 方法来得到评论为正面的可能性大小。

    model.predict(x_test) 
    #array([[ 0.98006207]
    #        [ 0.99758697]
    #        [ 0.99975556]        
    #        ...,        
    #        [ 0.82167041]        
    #        [ 0.02885115]        
    #        [ 0.65371346]], dtype=float32)
    

    如你所见,网络对某些样本的结果非常确信(大于等于 0.99,或小于等于 0.01),但对其他 结果却不那么确信(0.6 或 0.4)。

    完整代码

    from tensorflow.keras.datasets import imdb
    from tensorflow.keras import layers
    from tensorflow.keras import models
    import matplotlib.pyplot as plt
    import numpy as np
    
    (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
    
    print(max([max(sequence) for sequence in train_data]))
    
    
    def vectorize_sequences(sequences, dimension=10000):
        results = np.zeros((len(sequences), dimension))
        for i, sequence in enumerate(sequences):
            results[i, sequence] = 1.
        return results
    
    x_train = vectorize_sequences(train_data)
    x_test = vectorize_sequences(test_data)
    
    y_train = np.asarray(train_labels).astype('float32')
    y_test = np.asarray(test_labels).astype('float32')
    
    model = models.Sequential()
    model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
    model.add(layers.Dense(16, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    x_val = x_train[:10000]
    partial_x_train = x_train[10000:]
    
    y_val = y_train[:10000]
    partial_y_train = y_train[10000:]
    
    history = model.fit(partial_x_train, partial_y_train,
                        epochs=20,
                        batch_size=512,
                        validation_data=(x_val, y_val))
    
    history_dict = history.history
    loss_values = history_dict['loss']
    val_loss_value = history_dict['val_loss']
    
    epochs = range(1, len(loss_values) + 1)
    
    plt.plot(epochs, loss_values, 'bo', label='训练损失')
    plt.plot(epochs, val_loss_value, 'b', label='验证损失')
    plt.title('训练和验证损失')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend
    
    plt.show()
    
    展开全文
  • 至于为什么会这样涉及,我的理解是分层的思想就是为了让每各司其职,自己负责自己的事情,否则会把某一弄得很臃肿失去了分层的意义,我们在涉及功能的时候也应该具有这种思想。 需要注意的是,这

    大家好,我是小杰。
    点赞+关注 是我最大的动力!

    老规矩,先上镇宝图——TCP/IP模型

    在这里插入图片描述

    本文并没有涉及IP地址分类和子网掩码内容。

    IP协议格式

    IP是TCP/IP协议中的核心协议。它包含两大特性:不可靠、无连接

    1. 不可靠指的是它本身不会保证数据一定完整送达,需要依靠上层协议解决。
    2. 无连接指的是每个IP数据报之间没有关系,相互独立。

    至于为什么会这样涉及,我的理解是分层的思想就是为了让每层各司其职,自己负责自己的事情,否则会把某一层弄得很臃肿失去了分层的意义,我们在涉及功能的时候也应该具有这种思想。

    IP数据报格式

    需要注意的是,这种传输次序被称为大端存储,又叫网络字节序,因此我们在代码中的数据必须转换成网络字节序。

    接下来简述一些各个字段的含义:

    1. 4位版本号,用来表示如0100(IPv4),0110(I

    展开全文
  • 全连接 1)可不用此—在卷积神经网络中起“分类器”的作用; 2)卷积层、池化和激活函数等操作是将原始数据映射到隐特征空间的话------全连接则起到将学到的“分布式特征表示”映射到样本标记空间的...
  • 作为一个合格的运维人员,一定要熟悉掌握OSI七网络和TCP/IP五网络结构知识。 废话不多说!下面就逐一展开对这两个网络架构知识的说明:一、OSI七网络协议 OSI是Open System Interconnect的缩写,意为开放式...
  • CNN卷积层、池化、全连接

    万次阅读 多人点赞 2019-03-02 14:25:00
    卷积神经网络是通过神经网络反向传播自动学习的手段,来得到各种有用的卷积核的过程。 卷积神经网络通过卷积和池化操作,自动学习图像在各个层次上...典型的卷积神经网络通常由以下三种结构共同组成:卷积层(Conv...
  • 接入交换机接入的主要目的是允许终端用户连接到网络,因此接入交换机往往具有低成本和高端口密度特性,通常建议使用性价比高的设备。管理型交换机和非管理型交换机都可以用...我们常用的交换机的实际带宽是...
  • 分类和多标签分类的区别 多分类: 一个样本属于且只属于多个分类中的...我们假设,一个神经网络模型最后的输出是一个向量logits = 【1,2,3,4】,这个就是神经网络全连接的输出。我们假设一共有4个类别。 softma
  • 信息组织 | 信息组织分类

    千次阅读 2020-05-02 09:51:22
    、招生等 类目设置概括、实用 科研项目分类 科研项目 用科研的管理、申报、 统计等 不稳定、时期阶段性 3 网络信息分类法   分类导航、分类目录 网络信息分类法与文献分类法、学科分类法的差异 类目体系比其他...
  • 前言:听说很多小伙伴们对计算机网络入门的模型总是云里雾里,感觉学了又往,其实还是没有真正理解,并有简短的记忆方式而导致的哦,因此本人就来帮帮小伙伴们来一理吧~ 一.基本认知 其实官方的计算机网络模型...
  • 深入理解CNN卷积层、池化、全连接

    万次阅读 多人点赞 2019-01-08 00:53:10
    文章目录深入理解CNN卷积层、池化、全连接卷积层(Convolution)池化(Pooling)全连接(Fully connected)全连接到底什么用?首先三点:接下来再主要谈谈全连接的意义 东拼西凑看到的各种观点,在此记录...
  • 分类(Two-Class Classification) 二分类问题,是最简单的分类问题,比如一个任务中只有猫和狗,每个样本中也只有其中的一类。 单标签多分类(Multi-Class Classification) 单标签多分类问题,指一个样本(一个...
  • [计算机网络]第四章——网络

    千次阅读 2022-04-13 20:39:39
    [计算机网络]第四章——网络
  • 第 28 卷 第 1 期 2006 年 1 月 武 汉 工 大 学 学 报 JOURNAL OF WUHAN UNIVERSITY OF TECHNOLOGY Vol. 28 No. 1 Jan. 2006 彩色遥感图像分类算法及 Matlab 实现 郭志强,蔡 嵩 (武汉理工大学信息工程学院 ,武汉...
  • 互金发展到现在,资产端从最初发展的房贷、车贷、信贷发展到目前的消费贷、供应链金融,商业保就属于供应链金融中的一种产品形式。资金端是资产端的相对一端,指资金出借的那一方,也就是我们通常所说的投资人与...
  • 分类边界布有形式的速度分如下中假设。下列指标中,微型指标的有属于速度。则(,计算机系邻时个相期的若两环比发展皆为速度。虑E开始2周应考生后,总线为典型喷射性呕吐。 每于喂水吐应考虑或喂奶后即呕,传输开始...
  • 作为一个合格的运维人员,一定要熟悉掌握OSI七网络和TCP/IP五网络结构知识。 废话不多说!下面就逐一展开对这两个网络架构知识的说明:一、OSI七网络协议OSI是Open System Interconnect的缩写,意为开放式...
  • 循环神经网络(RNN,recurrent neural network):它处理序列的方式是,遍历所有序列元素,并保存一个状态(state)... 将这个模型应用于 IMDB 电影评论分类问题,首先进行预处理。 from keras.datasets import imdb from ...
  • 机器视觉及图像分类

    千次阅读 2021-02-11 12:39:33
    机器视觉及图像分类 撰写本科毕业论文前期文献准备 扩大课题在知乎上查相关的文献并且下载,之后导入Endnote里面,如果下的是CAJ文件的话,需要再下载一个CAJViewer阅读器。 因为是第一次看论文。但每篇都做了相关的...
  • 浅谈化生实验室设计方案

    千次阅读 2020-07-18 10:51:32
    化生实验仪器室主要放置化生实验仪器,分类管理。化生实验准备室设有实验台,台上有电源、水源、气源,并设有操作台, 配有各种工具和原材料。化生分组实验室主要设有教师、学生实验桌,并有电源、水源和...
  • 针对大 规 模 文 本 的 自 动 次 分 类 问 题 , K 近 邻 ( KNN) 算 法 分 类 效 率 较 高 , 但 是 对 于 处 于 类 别 边 界 的 样 本 分 类 准 确 度 不是 很 高 。 而 支 持 向 量 机 ( SVM) 分 类...
  • 第六章、应用 本章的重要概念 应用协议是为了解决某一类应用问题,而问题的解决又是通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。应用规定了应用进程在通信时所遵循的协议。应用的许多...
  • 主要分类网络性能和参数比较

    千次阅读 2020-10-05 09:29:36
    主要分类网络性能和参数比较 文章目录主要分类网络性能和参数比较前言一、resnet二、使用步骤1.引入库2.读入数据总结 前言 本文主要比较一些图像分类网络的性能和参数 一、resnet 二、使用步骤 1.引入库 代码...
  • 大三课设-分类聚类预测系统

    千次阅读 2021-11-15 18:30:17
    大三机器学习课设 经过一学期在涛子的历练下,还是学到了在课堂上不动如钟! 下面介绍一下我们的课设系统 ...3.自行选择学习任务,按照机器学习流程,分别设计分类、预测、聚类系统,每个系统务必选择不同
  • 贝叶斯分类器算法及案例详解

    万次阅读 多人点赞 2019-01-01 19:40:38
    本文是对贝叶斯分类器(包括朴素贝叶斯分类器,半朴素贝叶斯分类器及贝叶斯网络)算法的演算及案例的详细分析。建议先阅读“理解贝叶斯分类器原理及关系”后再阅读本文,会对上述几种贝叶斯分类器有更深入的理解。...
  • 此时,为提高分类准确率,不得不加深模型的网络数,这是因为各结点状态更新时一般只聚合一跳邻居信息,那么网络数即反映结点的向量表示融合了几跳内的邻居信息,当标签很少时,结点在浅层聚合过程中可能无法获取...
  • 目录一、GRU介绍二、分类问题介绍三、PyTorch实现1、模型理解2、代码 一、GRU介绍 GRU(Gate Recurrent Unit)是循环神经网络(Recurrent Neural Network, RNN)的一种,和LSTM(Long-Short Term Memory)一样,也是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,179
精华内容 6,471
关键字:

层理的分类