精华内容
下载资源
问答
  • 动手学深度学习》是2019年国内最受欢迎的人工智能学习教材之一,伯禹教育携手上海交通大学团队,以此书的知识架构为基础,沿用了其中的原理讲解文档,并将代码框架由MXNET迁移至PyTorch,还对这些优质的实践代码...
  • 疫情期间,宅家无聊,参加了由和鲸社区、Datawhale、伯禹人工智能学院等单位联合发起的免费公益学习活动,主要利用pytorch进行深度学习,时间比较紧凑,没怎么懂,得多花一点时间,代码都是向大佬借鉴的,错误之处...
  • 这是学习深度学习很好的资料。目前市面上大部分都是TensorFlow的版本,但是Pytorch正在成为学术界的主流,对初学者有帮助
  • 过拟合、欠拟合及其解决方案 1.概念 无法得到较低的训练误差称作欠拟合 得到的误差极小即远小于训练集的误差称作过拟合 2.模型选择 验证数据集 从严格意义上讲,测试集只能在所有超参数和模型参数选定后使用一次。...
  • 机器翻译及相关技术 机器翻译和数据集 机器翻译(MT):将一段文本从一种语言自动翻译为另一种语言,用神经网络解决这个问题通常称为神经机器翻译(NMT)。 主要特征:输出是单词序列而不是单个单词。...
  • 卷积神经网络基础 二维卷积层 二维互相关运算 二维互相关(cross-correlation)运算的输入是一个二维输入数组和一个二维核(kernel)数组,输出也是一个二维数组,其中核数组通常称为卷积核或过滤器(filter)。...
  • 线性回归——动手学习深度学习pytorch版1. 线性回归——从零开始1.1 用随机数生成并保存数据1.2 创建训练数据集的迭代器1.3 构造最简单的线性层网络1.4 构造自己的损失函数1.5 开始训练啦!   本系列是基于亚马逊...


      本系列是基于亚马逊李沐老师的教材《动手学习深度学习》,以及李沐老师对应的视频教程内容展开。但是李沐老师课程中使用的深度学习框架是MXNet,其实选择什么框架并不是重点,重点应该是其中的内容。课程既然叫动手学习深度学习,那当然要动手操作。用MXNet重复一遍教材内容并没有很好的学习效果,另外,我本身还是更喜欢使用pytorch框架,因此,希望将该教材的内容用pytorch实现一遍,并学习相关的知识内容。希望能给其他喜欢pytorch的读者一些帮助。代码开源供学习使用,如引用请注明出处,谢谢。

    1. 线性回归——从零开始

      由于线性回归已经反复介绍了许多遍了,因此其理论在此不再赘述,主要还是借助这个最基础最简单的算法来学习一下pytorch框架本身的搭建,因为其实其他高深的东西的套路和这个最简单的套路是一样的。

    1.1 用随机数生成并保存数据

      首先,生成线性回归需要使用的训练集数据,并保存为h5py文件,这是一个常用于数据存储的文件,其对应使用的API库名称为"h5py"。生成数据代码如下:

    def generator_data(n,m):
        """
            生成数据,样本数为n,维度为m
        :param n: 样本个数
        :param m: 数据维度
        :return: data_X,训练集;data_Y,训练集标签;coi 理想的线性回归系数
        """
        data_X = torch.randn((n, m))  # torch.randn((n,m))是生成n行m列的服从随机正态分布的随机数
        coi = torch.rand((m, 1)) * 3  # torch.rand((m,1))*3 是生成m行1列的系数向量,系数的随机数范围是从(0,3),因为后面乘了一个3
        data_Y = torch.mm(data_X, coi)+3  # torch.mm 是pytorch中对tensor张量的叉乘
        return data_X, data_Y, coi
    
    def save_data(data_X, data_Y, coi):
        """
        保存数据为hdf5文件和csv文件
        :param data_X: 训练集
        :param data_Y: 标签
        :param coi: 数据对应的真实线性回归系数
        :return: NULL
        """
        # h5py文件储存数据的结构和python中的字典类型很像,具有一个键名,及键对应的数据
        h5file = h5py.File("data.h5", 'w')  # 新建一个data.h5的数据集文件,并置为写入状态;注意要import h5py
        h5file.create_dataset("X", data=data_X)  # 在h5py数据文件中创建一个子集,名称为"X",内含数据为data_X,以下同理
        h5file.create_dataset("Y", data=data_Y)
        h5file.create_dataset("coi", data=coi)
        h5file.close()  # 写入完毕后要关闭h5py文件,和普通的文件读写操作很类似
        # 用pandas再保存一遍数据,熟悉一下另一种常见的数据读取库,使用前注意要import pandas as pd
        csvfile = pd.DataFrame(data_X.numpy())  # h5py文件的查看需要特定的查看软件,因此再保存成一份.csv文件方便查看
        csvfile.to_csv("data_X.csv")  # 把数据保存为data_X.csv文件,以下同理
        csvfile = pd.DataFrame(data_Y.numpy())
        csvfile.to_csv("data_Y.csv")
        csvfile = pd.DataFrame(coi.numpy())
        csvfile.to_csv("coi.csv")
    

      其中,生成数据使用了pytorch自带的随机数函数。其对应说明在代码注释中都比较详细了。

    1.2 创建训练数据集的迭代器

      这一步本身和pytorch关系不大,只是要注意,如果要使用pytorch库进行深度学习,所有数据都最好转化为torch.tensor的数据类型,因为这是pytorch中最基本的数据类型。关于tensor类型,以下有几点常用的成员函数(注意,以下的tensor都需要具体的tensor变量名称替换):

    • tensor.size():返回当前张量的维数尺寸;
    • tensor.numpy():将tensor转换为numpy的ndarray类型;
    • tensor.reshape(self, shape):重新定义tensor的尺寸;
    • tensor.dype:查看当前tensor的数据类型;
    • tensor.zero_:将张量清零,这里主要是要介绍以下这个下划线。pytorch中的所有包含下划线_的成员函数,意思是会将原tensor内的数据进行覆盖。也就是执行完tensor.zero_后,原来的tensor内的数据就被全部清零了,而不是生成一个新的复制而原数据不改变。
    • tensor.cuda():将张量送入GPU中进行计算,注意,GPU中的变量和CPU中的变量是不能进行计算的。如果要将张量从GPU中取出,则对应要使用tensor.detach()函数。

      创建数据集的迭代器代码如下:

    def dataset(batchsize):
        h5file = h5py.File("data.h5",'r')  # 读取data.h5文件内的数据
        X = torch.tensor(h5file['X'])  # 将h5file文件数据中名为'X'的子集取出,以下同理
        Y = torch.tensor(h5file['Y'])
        coi = torch.tensor(h5file['coi'])
        print("real coi:",coi)
        m = Y.size()[0]  # 当前样本集的数量为m
        id = list(range(m))  # 构造一个[0,1,2,...,m-1]的列表,列表内的数值表示样本序号
        random.shuffle(id)  # 将上述构造的列表内元素打乱,也就相当于将数据集样本的顺序打乱
        for i in range(m//batchsize):  #
            l = i*batchsize  # 当前batchsize的样本集起始序号
            r = min((i+1)*batchsize,m)  # 当前batchsize的样本集终止序号,加min函数是避免最后一个batchsize数量不够而越界
            # yield返回当前batchsize的数据,下次再进入该函数的时候,从此处继续往下执行,也就进入了下一个循环
            yield X[id[l:r],:],Y[id[l:r]]  
    

    1.3 构造最简单的线性层网络

      最简单的深度学习网络其实就是只有输入层和输出层的线性层网络,网络的权值为ww,网络的输出为y=wx+by=wx+b。下面我们就定义一个属于我们自己的神经网络,代码如下:

    class net(object):
    	"""创建网络的类"""
        def __init__(self):
        	# 网络实例在初始化的时候,需要对网络的权值和偏置(bias)进行初始化,这里简单的将其初始化为(0,1)内的数值
        	# 另外,需要注意,神经网络的权值是不能全部初始化为0的,这样会导致训练无法顺利进行
        	# 新生成的tensor W和b,由于损失函数需要对W,b进行反向传播求导,所以需要将tensor的成员属性requires_grad定义为True
        	# 当然,默认是False。
        	# 注意,pytorch中,使用tensor.backward()函数可以对与该tensor相关的张量进行反向传播求导
        	# 但是能对某个张量求导的要求是,该张量的requires_grad=True, is_leaf=True,必须两个成员属性均满足条件才行
        	# is_leaf是说明该张量是计算图中的叶结点,为了节约内存,pytorch中非叶结点的梯度数值最终都会清零
            self.W = torch.rand((3,1),requires_grad=True)  
            self.b = torch.rand((1,1),requires_grad=True)
    
    	# 网络的前向传播,因为只有一层线性层,所以其实就是y=wx+b,注意wx之间是叉乘
        def forward(self,X):
            X = torch.mm(X,self.W)+self.b
            return X
    
    	# __call__函数可以使得net类本身变成一个可调用的函数,当在代码中调用net(X)时,其实就是调用了net类里的内置函数__call__
        def __call__(self,X):
            return self.forward(X)
    
    	# 在每次反向传播求出损失函数对网络参数的导数后,需要更新网络的参数。更新方法就使用梯度下降法SGD。
    	# 该函数可以写在net类内作为成员函数,也可以写在net类外
        def updata_W(self,lr):
            self.W.data = self.W.data - lr * self.W.grad
            self.b.data = self.b.data - lr * self.b.grad
    
    	# 在每次反向传播求导前,需要对网络内的参数的导数进行清零。
    	# 因为这里存的导数是上一次求导遗留的数值,与新一轮的求导无关,但是会影响新一轮求导的正确性。
    	# 注意,pytorch中每个tensor内都具有成员属性tensor.grad
    	# 里面存放着特定tensor(如Loss)进行反向传播后,特定tensor(如Loss)对该tensor求出的导数
    	# 该导数也是一个tensor,所以可以用.zero_()进行清零。
        def zero_grad(self):
            if self.W.grad is not None:
                self.W.grad.zero_()
    
            if self.b.grad is not None:
                self.b.grad.zero_()
    

    1.4 构造自己的损失函数

      网络得到输出后,要根据输出值和真实值之间的差异设计损失函数,使得网络知道其内部参数应当如何修改(梯度下降法)才能更好地缩小损失函数数值。所以需要一个自己的损失函数,代码如下:

    def MSEloss(preds,labels):
        return 0.5*torch.sum((preds-labels)**2)/labels.size()[0]
    

      这个损失函数其实就是最普通的均方差损失(MSE,Mean Square Error)
    MSE=i=1m(y^y)22mMSE=\frac{\sum_{i=1}^m(\hat y-y)^2}{2m}

      其中m是用于计算当前均方差损失的样本集数量,如果是一个batchsize,那就是batchsize的大小。

    1.5 开始训练啦!

      深度学习的训练通常需要设置epoch。把所有训练集内的样本训练完一轮,就算是一个epoch。另外,还需要设置一个batchsize。batchsize=n的含义就是,把n个样本打包成一批,送进网络中进行预测,然后计算这批样本集的损失,再使用对应的损失值进行网络参数的反向传播和更新。也就是说,一个batchsize对应更新一次网络参数。每次更新网络参数都称为一个step,所以step=mbatchsizestep=\frac{样本总数m }{ batchsize}
      类比一下,深度学习相当于你高中学习一门课程。老师为了让你学好该课程,给你准备了m道练习题(相当于样本数据集)。你打算每天做n道题目来提高自己(相当于一天就是一个step,batchsize=n)。但是你也知道,练习题只做1遍,考试不一定能考好,所以你打算把所有练习题都多刷几遍,每刷一轮练习题,就相当于一个epoch。

    if __name__ == '__main__':
        LR = net()
        epoch = 20
        batchsize = 1
        lr = 0.01
        it = 0
        for e in range(epoch):
            for x,y in dataset(batchsize):
                pred = LR(x)
                loss = MSEloss(pred,y)
                LR.zero_grad()  # 在计算新一轮的梯度前,一定要注意将上一轮求解的梯度数值清零,否则会影响梯度的正确求导
                loss.backward()
                LR.updata_W(lr)  # 更新梯度,此处用梯度下降法更新
                print(LR.b.grad)
                print("Epoce %d step %d, loss = %.2f"%(e,it%20,loss.item()))
                it += 1
                # input()
        print(LR.W,LR.b)
    

      代码运行的结果如下图:上面的图是我们生成数据时真实使用的权值系数(漏了偏置,真实的偏置是3)。下面的图是我们的网络预测出来的权值系数和偏置,可以看到,两者是一模一样的,因为这里使用的数据集很简单,数量也比较少,所以训练效果很完美。大家可以在生成数据的时候加一点随机噪声,把数据集变得不那么完美,就会看到学习出来的系数和真实值很接近,但是有所偏差。
    在这里插入图片描述
    在这里插入图片描述

    2. 线性回归——pytorch版

      生成数据还是和前文一样,就不重复了。

    2.1 创建pytorch的数据集迭代器

      要训练自己的数据,首先要使用pytorch定义一个属于自己的数据集的类,具体步骤如下:

    • 定义类(假设名称为Mydata),并继承torch.utils.data.Dataset类,不用继承Dataset类的初始化函数。
    • 编写Mydata类的初始化函数__init__(self, *arg),通常需要包含将数据导入并储存在类内成员变量中的功能。注意,在数据集很大时(比如一个样本就是一张5M的图片),可以将每张图片的储存路径保存在成员变量中,在需要调用时再读取数据,而不需要在初始化的时候就读入所有数据,这样即占内存效率又不高。
    • 编写Mydata类的__len__(self)函数,通常只需要返回数据集样本总数就可以了。
    • 编写Mydata类的__getitem__(self,item)函数,该函数的意义是,取出序号为item的样本数据,包括输入数据和标签数据。通常在该函数内会读取样本数据,并对数据进行适当的初始化或数据类型转换等操作。如上文所述,如果类初始化的时候储存的数据的路径而不是真实数据,那么就需要在该函数内使用成员变量读取真实数据。该函数返回的参数就是后续送入网络中训练的参数。
    • 根据需要定义一些其他辅助函数。

      介绍完步骤后,直接上代码:

    class Mydata(torch.utils.data.Dataset):
        """自己的数据集,需要继承自pytorch中的Dataset类"""
        def __init__(self,filename, train=True):
        	"""数据类初始化,这里额外定义了一个用于读取数据的函数"""
            self.X, self.Y, self.coi = self.load_data(filename)
            # self.X=np.insert(self.X, 0, values=np.ones((1,self.X.shape[0])), axis=1)  # 增加全1的列,对应偏移量
    
        def __len__(self):
        	"""返回样本数量"""
            return self.X.shape[0]
    
        def __getitem__(self, item):
        	"""由于数据简单,这里直接读取即可,但是要注意需要转换为torch.tensor的数据类型,才能用于后续训练"""
            return torch.tensor(self.X[item,:]), torch.tensor(self.Y[item])
    
        def load_data(filename):
            """
            读取hdf5数据
            :param filename: 文件名
            :return:
            """
            data = h5py.File("data.h5", 'r')
            data_X = np.array(data["X"])
            data_Y = np.array(data["Y"])
            coi = np.array(data["coi"])
            return data_X, data_Y, coi
    

    2.2 构造自己的线性网络

      使用pytorch构造自己的网络结构,需要以下几个步骤:

    • 定义网络类,继承自torch.nn.Module类,需要继承Module类的初始化函数。
    • 定义网络类的初始化函数__init__,其中需要继承Module类的初始化函数,另外,可以根据需要新建一些pytorch提供的网络层,方便后续使用。
    • 定义网络类的forward函数,forward函数是被网络类的__call__函数调用的,也就是使网络类可以转换为函数的方式被调用。一旦将网络类实例用函数的方式调用,其实就是调用forward函数。在该函数中,需要进行网络的前向传播,并返回网络最终的输出值。
    • 根据需要定义一些其他辅助函数。

      代码如下:

    # from torch import nn
    class LR(nn.Module):
        def __init__(self):
            super(LR, self).__init__()  # 继承父类的初始化函数
            self.LR_layer = nn.Linear(3, 1)  # 用官方的线性层模块,线性层的输入为3维,输出为1维
    
        def forward(self, x):
        	"""进行网络的前向传播,即将x输入线性层,然后输出结果"""
            output = self.LR_layer(x)
            return output
    

    2.3 选择所需的损失函数

      在torch.nn中提供了很多损失函数的模块可供选择,所以不需要自己编写损失函数,可以直接调用。
      但是如果你要自己设计一个自己的损失函数怎么办?没问题,也很简单,其实和上文中构造网络类几乎是一模一样的:

    • 定义损失函数类,继承自torch.nn.Module类,需要继承Module类的初始化函数。
    • 定义损失函数类的初始化函数__init__,其中需要继承Module类的初始化函数。
    • 定义损失函数类的forward(self,y,y_hat)函数。在该函数中,需要根据输入的y和y_hat计算损失值,具体如何计算就根据自己的设计形式而定,最后返回损失数值即可。

      代码如下:

    class MyLossFunction(nn.Module):
        """自定义的损失函数,注意必须继承于nn.Module,另外,以下两个函数必须重载"""
        def __init__(self):
            super(MyLossFunction,self).__init__()
    
        def forward(self,x,y):
            """损失值计算,以MSE损失为例"""
            return torch.sum((x-y)**2)/(2*x.size(0))
    

    2.4 开始训练啦

      上述过程中还少了一步,就是定义网络参数更新的方式,也就是选择优化器。在pytorch中,torch.optim中提供了很多常用的优化器,大家也可以根据情况自行选用,这里就先不一一介绍了。
      下面的代码中还包含了pytorch官方提供的visdom绘图部分,只做简单介绍,使用起来很方便也比较简单,有兴趣的读者可以自行学习一下。注意,如果需要使用visdom可视化的话,需要提前打开命令提示符窗口,输入“visdom"命令打开visdom客户端,然会出现如下图中的信息,将红框内的网址复制到浏览器中,就可以看到绘制的图像了。
    在这里插入图片描述

    if __name__ == '__main__':
        h5file = h5py.File("data.h5", 'r')
        data_X = np.array(h5file["X"])
        data_Y = np.array(h5file["Y"])
        coi = np.array(h5file["coi"])  # 读取理想系数
    
        training_data = Mydata("data.h5")  # 新建自己的数据类的实例
        # 官方提供的from torch.utils.data import DataLoader中的DataLoader类能很方便地将数据进行打乱和分批
        # 首先需要传入数据类实例training_data
        # 然后设置batch_size的大小
        # 最后数据是否需要打乱是可选的,通过shuffle参数实现
        training_dataloader = DataLoader(training_data,batch_size=10,shuffle=True)
    
        net = LR()  # 新建网络类的实例
        # 此处需注意,网络在训练前要将网络调整为训练模式,而在用训练好的网络进行inference时需要调整为评估模式
        # 两种模式中,有一些网络层的状态是不同的,比如BN层和dropout层,训练时的参数是可变的,评估时其参数应该是固定的
        net.train()  
    
        criterion = nn.MSELoss()  # 创建损失函数实例
        # 创建优化器,这里用随机梯度下降,学习率设置为0.01
        # 第一个参数net.parameters()是提取网络所有参数的成员函数,优化器需要传入网络的参数,才能对其进行优化
        optimizer = torch.optim.SGD(net.parameters(),lr=0.01)  
    
        # 训练数据可视化部分,不需要的时候可以设置为False
        is_vis = True
        if is_vis:
            vis = visdom.Visdom()  # 新建一个代表visdom服务器的类
            viswin1 = vis.line(np.array([0]), np.array([0]),opts=dict(title="Training Loss/epoch",xlabel="epoch",ylabel="Loss"))  # 创建一个窗口,记录每个epoch内部的平均损失
            viswin2 = vis.line(np.array([0]), np.array([0]),opts=dict(title="Training Loss/step",xlabel="step",ylabel="Loss"))  # 创建一个窗口,记录每个step的损失
        ############# 训练数据可视化部分 #################
    
        it = 0  # 用于计数step的次数
        for epoch in range(1,20):
            eloss = 0.  # 计算一个epoch的损失均值
            # enumerate(training_dataloader)就是每次从training_dataloader中(按打乱/未打乱的顺序)提取一个batch_size数量的样本
            # (x,y)这个元组就对应于Mydata类中__getitem__函数的两个返回值
            for i, (x,y) in enumerate(training_dataloader):
                it += 1
                pred_y = net(x)  # 将net类用函数的方式调用,返回forward成员函数的返回值
                loss = criterion(pred_y,y)  # 根据预测值pred_y和真实值y计算损失
                optimizer.zero_grad()  # 在计算新一轮的梯度前,一定要注意将上一轮求解的梯度数值清零,否则会影响梯度的正确求导 
                loss.backward()
                optimizer.step()  # .step()是优化器根据损失值对各参数的导数进行一次网络参数更新,更新方式根据优化器种类而定
                #print("loss=%.2f \n"%loss)
                eloss += loss.item()
                if is_vis:
                    vis.line(np.array([loss.item()]), np.array([it]), viswin2, update='append')
                    # time.sleep(0.1)  # 延时方便visdom动图可视化
            if is_vis:
                vis.line(np.array([eloss/100]), np.array([epoch]), viswin1, update='append')
    
        net.eval()  # 将网络转换为评估模式,此处网络比较简单,其实转不转换无所谓,但是还是要养成好习惯
        data_X = torch.tensor(data_X)
        pred_y = net(data_X).numpy()  # 用网络对训练集进行预测
        data_X = data_X.numpy()
    
        # 将数据进行可视化,样本特征为1维时可用
        # if is_vis:
        #     viswin3 = vis.line(data_Y, data_X, opts=dict(title="Data",xlabel="X",ylabel="Y/Pred_Y"))
        #     vis.line(pred_y, data_X)
        #     vis.line(pred_y,data_X)
    
    	# 网络参数和真实系数的对比
        print("predicted parameters: ",end='')
        for i in net.parameters():
            print(i)
            # print("%.3f "%i.detach().numpy()[0],end='')
        print("real parameters: ",end='')
        for i in coi:
            print("%.3f "%i,end='')
    

    3. 结果分析

    - 训练loss过程记录
    从零开始版 在这里插入图片描述
    pytorch版 在这里插入图片描述

      表格中可以看到,epoch的平均损失还是比较平缓地下降,而每个step之间的损失却跳动比较大,为什么?
      还是以上文中的考试为例。在你第一轮刷题的过程中,越后面的题你的正确率可能会越高,因为你已经有前面一些习题的经验了,但是如果遇到新的题型,那可能还是很头疼,因为之前没见过,所以有时候你的错误率会突然提高(相当于图中的波动)。当然,在你第二遍刷题的时候,正确率肯定是要比第一遍刷题好得多,因为第一遍你其实已经基本都见过所有题型了,第二遍只是温故而知新,所以整体来说loss是呈下降趋势的。
      另外,我们自己写的网络和pytorch版的loss值,它们的纵轴数量级有一点点不同,这个原因可能是pytorch版计算MSEloss的时候没有除以样本数量,其实在本例中这影响不大,只要趋势差不多就可以了。

      我们再修改一下各种超参数(epoch,batch_size,lr),看看会有什么效果。

    参数 结果
    epoch=20
    batchsize=20
    lr=0.01
    在这里插入图片描述
    epoch=3
    batchsize=1
    lr=0.01
    在这里插入图片描述
    epoch=2
    batchsize=10
    lr=0.5
    在这里插入图片描述
    epoch=2
    batchsize=10
    lr=5
    在这里插入图片描述

      总的来说,结论如下:

    • 提高batch_size值,训练速度会大大提高,可以粗略认为一个step其实就算一个单位训练时间,如果batch_size数值大了,step的数量就少,训练时间也相应减少。对比表中前两行的结果可知,训练速度提高的代价就是,精度变差了,第一行同样训练20个epoch,其最终的loss值明显要差于batch_size=10的情况。而第二行,batch_size=1,训练速度大大降低了,但是训练了3个epoch之后loss基本就为0了。(题外话,这个故事是不是告诉我们,如果你每天刷题量大,你就得多刷很多轮才行;如果你每天精刷题,题量小,一套练习题你可能只要刷两三遍就够了。虽然要达到相同的学习效果,可能两种方式消耗的时间都差不多,但是每个人自己的喜好习惯不同,比如我就喜欢精刷^ ^)
    • 从表中第三行可知,提高lr数值,可以大大加速网络的学习效果(提高lr相当于让刷题人变聪明,可惜现实中刷题人的lr是无法改变的orz)。同样的batchsize,只要差不多2个epoch就能得到很不错的loss值。但是看表中第4行,lr数值太高,是会炸的。(可能验证了天才都是疯子这句名言)不止没有更好的学习效果,甚至都不收敛了,具体原理其实SGD中阐述的很明确,这里不详述了。
    • 另外需要提一句,lr是个比较玄学的参数,尤其是在损失函数非凸的情况下,梯度下降法只能找到局部最优解而无法找到全局最优解,这时候lr的步长大一些可能会跳过一些局部最优解,可是谁知道下一个找到的局部最优解到底有没有比跳过的那个好呢?但是基本原则还是有的,首先尽量调小lr,先保证网络训练能够收敛,然后再考虑如何优化lr,提高训练效率和效果。
    展开全文
  • 动手学深度学习PyTorch版-第一次打卡 从零开始 零基础动手学习深度学习,参加Datawhale的公益AI学习课程,使用伯禹平台和和鲸,本次学习参考教材使用PyTorch ...

    动手学深度学习PyTorch版-第一次打卡

    从零开始

    零基础动手学习深度学习,参加Datawhale的公益AI学习课程,使用伯禹平台和鲸,本次学习参考教材使用PyTorch版的动手学深度学习

    线性回归

    线性回归的基本要素

    训练模型

    为了简单起见,这里我们假设价格只取决于房屋状况的两个因素,即面积(平方米)和房龄(年)。接下来我们希望探索价格与这两个因素的具体关系。线性回归假设输出与各个输入之间是线性关系:

    在这里插入图片描述

    训练数据集

    我们通常收集一系列的真实数据,例如多栋房屋的真实售出价格和它们对应的面积和房龄。我们希望在这个数据上面寻找模型参数来使模型的预测价格与真实价格的误差最小。在机器学习术语里,该数据集被称为训练数据集(training data set)或训练集(training set),一栋房屋被称为一个样本(sample),其真实售出价格叫作标签(label),用来预测标签的两个因素叫作特征(feature)。特征用来表征样本的特点。

    损失函数

    在模型训练中,我们需要衡量价格预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数。 它在评估索引为 ii 的样本误差的表达式为
    在这里插入图片描述

    Softmax与分类模型

    多层感知机

    展开全文
  • 动手学深度学习 pytorch版学习记录-------(1)pytorch基本操作Tensor创建操作索引功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建...


    该书已经开源,以下对学习过程做一个记录。环境为anaconda,jupyter notebook。

    pytorch基本操作

    先介绍Tensor的一些基本功能

    Tensor创建

    首先导入Pytorch:

    import torch
    x = torch.empty(5, 3)
    print(x)
    y = torch.rand(5, 3)
    print(y)
    

    输出

    tensor([[0., 0., 0.],
            [0., 0., 0.],
            [0., 0., 0.],
            [0., 0., 0.],
            [0., 0., 0.]])
    tensor([[0.4963, 0.7682, 0.0885],
            [0.1320, 0.3074, 0.6341],
            [0.4901, 0.8964, 0.4556],
            [0.6323, 0.3489, 0.4017],
            [0.0223, 0.1689, 0.2939]])
    

    还可以直接根据数据创建:

    x = torch.tensor([5.5, 3])
    print(x)
    

    输出

    tensor([5.5000, 3.0000])
    

    还可以通过现有的 Tensor 来创建,此方法会默认重用输入 Tensor 的⼀些属性,例如数据类型,除非自定义数据类型。

    x = x.new_ones(5, 3, dtype=torch.float64)      # 返回的tensor默认具有相同的torch.dtype和torch.device
    print(x)
    
    x = torch.randn_like(x, dtype=torch.float)    # 指定新的数据类型
    print(x)                                    
    

    输出:
    下面展示一些 内联代码片

    tensor([[1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.]], dtype=torch.float64)
    tensor([[ 0.6035,  0.8110, -0.0451],
            [ 0.8797,  1.0482, -0.0445],
            [-0.7229,  2.8663, -0.5655],
            [ 0.1604, -0.0254,  1.0739],
            [ 2.2628, -0.9175, -0.2251]])
    

    通过shape或者size()来获取Tensor的形状:

    print(x.size())
    print(x.shape)
    

    输出:

    torch.Size([5, 3])
    torch.Size([5, 3])
    

    常用的创建Tensor函数

    函数 功能
    Tensor(*sizes) 基础构造函数
    tensor(data) 类似np.array的构造函数
    ones(*sizes) 全1Tensor
    zeros(*sizes) 全0Tensor
    eye(*sizes) 对角线为1,其他为0
    arange(s,e,step) 从s到e,步长为step
    linspace(s,e,step) 从s到e,均匀切分成steps份
    rand/randn(*sizes) 均匀/标准分布
    normal(mean,std)/uniform(from,to) 正态分布/均匀分布
    randperm(m) 随机排列

    操作

    算数操作

    // 加法形式一
    y = torch.rand(5, 3)
    print(x + y)
    
    //加法形式二
    print(torch.add(x, y))
    
    //加法形式三、inplace
    y.add_(x)
    print(y)
    

    索引

    y = x[0, :]
    y += 1
    print(y)
    print(x[0, :]) # 源tensor也被改了
    

    输出:

    tensor([1.6035, 1.8110, 0.9549])
    tensor([1.6035, 1.8110, 0.9549])
    

    PyTorch还提供了一些高级的选择函数

    函数 功能
    index_select(input,dim,index) 在指定维度dim上选取,比如选取某些行、某些列
    masked_select(input,mask) 例子如上,a(a>0),使用ByteTensor进行选取
    non_zero(input) 非0元素的下标
    gather(input,dim,index) 根据index,在dim维度上选取数据,输出的size与index一样

    改变形状

    用view()来改变Tensor的形状:

    y = x.view(15)
    z = x.view(-1, 5)  # -1所指的维度可以根据其他维度的值推出来
    print(x.size(), y.size(), z.size())
    

    输出:

    torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5])
    

    view()返回的新tensor与源tensor共享内存,更改其中一个,另一个也会跟着改变。

    x += 1
    print(x)
    print(y) # 也加一
    
    tensor([[2.6035, 2.8110, 1.9549],
            [1.8797, 2.0482, 0.9555],
            [0.2771, 3.8663, 0.4345],
            [1.1604, 0.9746, 2.0739],
            [3.2628, 0.0825, 0.7749]])
    tensor([2.6035, 2.8110, 1.9549])
    

    为了返回一个真正的副本,推荐使用clone创作一个副本然后使用view。

    x_cp = x.clone().view(15)
    x -= 1
    print(x)
    print(x_cp)
    

    输出:

    tensor([[ 1.6035,  1.8110,  0.9549],
            [ 0.8797,  1.0482, -0.0445],
            [-0.7229,  2.8663, -0.5655],
            [ 0.1604, -0.0254,  1.0739],
            [ 2.2628, -0.9175, -0.2251]])
    tensor([2.6035, 2.8110, 1.9549, 1.8797, 2.0482, 0.9555, 0.2771, 3.8663, 0.4345,
            1.1604, 0.9746, 2.0739, 3.2628, 0.0825, 0.7749])
    

    常用的函数就是item(),它可以将一个标量Tensor转换成一个Python number:

    x = torch.randn(1)
    print(x)
    print(x.item())
    

    输出:

    tensor([2.3466])
    2.3466382026672363
    

    线性代数

    另外,PyTorch还支持线性函数:

    函数 功能
    trace 对角线元素之和(矩阵的迹)
    diag 对角线元素
    triu/tril 矩阵的上三角/下三角,可指定偏移量
    mm/bmm 矩阵乘法,batch的矩阵乘法
    addmm/addbmm/addmv/addr/badbmm… 矩阵运算
    t 转置
    dot/cross 内积/外积
    inverse 求逆矩阵
    svd 奇异值分解

    其他操作可以参考官方文档。

    广播机制

    当两个形状不同的Tensor按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个Tensor形状相同后再按元素运算。

    x = torch.arange(1, 3).view(1, 2)
    print(x)
    y = torch.arange(1, 4).view(3, 1)
    print(y)
    print(x + y)
    

    输出:

    tensor([[1, 2]])
    tensor([[1],
            [2],
            [3]])
    tensor([[2, 3],
            [3, 4],
            [4, 5]])
    

    Tensor和NumPy相互转换

    numpy()from_numpy()这两个函数产生的Tensor和NumPy array实际是使用的相同的内存,改变其中一个时另一个也会改变。
    tensor转numpy

    a = torch.ones(5)
    b = a.numpy()
    print(a, b)
    
    a += 1
    print(a, b)
    b += 1
    print(a, b)
    
    tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
    tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
    tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]
    

    numpy转tensor

    import numpy as np
    a = np.ones(5)
    b = torch.from_numpy(a)
    print(a, b)
    
    a += 1
    print(a, b)
    b += 1
    print(a, b)
    
    [1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
    [2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
    [3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
    

    直接用torch.tensor()将NumPy数组转换成Tensor,该方法总是会进行数据拷贝,返回的Tensor和原来的数据不再共享内存。

    # 用torch.tensor()转换时不会共享内存
    c = torch.tensor(a)
    a += 1
    print(a, c)
    
    [4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
    

    Tensor ON GPU

    # 以下代码只有在PyTorch GPU版本上才会执行
    if torch.cuda.is_available():
        device = torch.device("cuda")          # GPU
        y = torch.ones_like(x, device=device)  # 直接创建一个在GPU上的Tensor
        x = x.to(device)                       # 等价于 .to("cuda")
        z = x + y
        print(z)
        print(z.to("cpu", torch.double))       # to()还可以同时更改数据类型
    
    展开全文
  • 机器翻译及相关技术 1、机器翻译和数据集 机器翻译(MT):将一段文本从一种语言自动翻译为另一种语言,用神经网络解决这个问题通常称为神经机器翻译(NMT)。 主要特征:输出是单词序列而不是单个单词。...
  • 目录   Day02 1.过拟合,欠拟合及解决 训练误差 泛化误差 过拟合 过拟合解决方案 欠拟合 2.梯度消失,梯度爆炸 考虑环境因素 协变量偏移 标签偏移 概念偏移 3.卷积神经网络基础 ALexNet ...过拟合
  • 1.机器翻译及相关技术 机器翻译(MT):将一段文本从一种语言自动翻译为另一种语言,用神经网络解决这个问题通常称为神经机器翻译(NMT)。 主要特征:输出是单词序列而不是单个单词。 输出序列的长度可能与源序列的...
  • 动手学深度学习PyTorch版学习记录 公益课程链接:ElitesAI·动手学深度学习PyTorch版 第一次打卡 一些废话 之前就想把学习过程记录下来,借着打卡整理出来,留作纪念也未尝不可。同时也感谢开展本次公益课程的相关...

    动手学深度学习PyTorch版学习记录

    公益课程链接:ElitesAI·动手学深度学习PyTorch版

    每日不定时更新(开学了开学了开学了,下次一定下次一定下次一定)

    一些废话

    之前就想把学习过程记录下来,借着打卡整理出来,留作纪念也未尝不可。同时也感谢开展本次公益课程的相关机构,以及负责上课学长学姐和组织相关事宜的助教们等,当然还有我们HENSHEN小队的成员们。

    其实这也是我第一次正式接触编程,可以说真正的动手学深度学习(之前查阅过有关的博客,看过圣经,啃过西瓜书,但碍于各种原因,始终没能敲上代码)。

    机缘巧合,原定这个暑假前往帝国理工学习AI有关知识,结果新冠病毒爆发,也正好从朋友圈了解到了本次公益课程。难得静下心来好好学学深度学习,倒是不错。

    那废话不多说,接下来就分享一些从零开始动手学深度学习的经验教训吧。

    从零开始

    conda,装conda,装conda。重要的事情说三遍,在此也感谢在MICCAI认识的超阳学长提供的Anaconda安装包(提取码:5glf ),直接下载解压安装就可以了。

    接下来去Pytorch官网找到对应自己电脑配置的安装指令(举个例子)在这里插入图片描述
    然后打开你的Anaconda Prompt(如图),通过这篇博客加入清华源,最后替换上对应的安装指令即可。
    在这里插入图片描述然后就是安装需要的库,注意,由于种种原因,在安装某些库的时候,可能由于ssl模块缺少无法正常使用pip,按该博客安装ssl_match_hostname,问题解决

    展开全文
  • 1.卷积神经网络基础 卷积其实就是将许多部分的信息进行压缩,在过大维度矩阵的情况下,因为存在过多的信息 第一是为运算上带来了很多麻烦 第二是类似拿着显微镜看一幅画,难以捕捉其整体的信息。...
  • 1.过拟合、欠拟合及其解决方案 过拟合:模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting); 欠拟合:模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合(overfitting)。...
  • 1.机器翻译及相关技术 1.1数据预处理 读取数据,处理数据中的编码问题,并将无效的字符串删除 分词,分词的目的就是将字符串转换成单词组成的列表。目前有很多现成的分词工具可以直接使用,也可以直接按照空格进行...
  • 卷积神经网络基础 本节我们介绍卷积神经网络的基础概念,主要是卷积层和池化层,并解释填充、步幅、输入通道和输出通道的含义。 二维卷积层 本节介绍的是最常见的二维卷积层,常用于处理图像数据。...
  • 1.过拟合、欠拟合及其解决方案 1.1对于过拟合、欠拟合的理解 我们探究模型训练中经常出现的两类典型问题: 一类是模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting); 另一类是模型的训练误差...
  • ElitesAI·动手学深度学习PyTorch版 Task01 线性回归¶ 主要内容包括: 线性回归的基本要素 线性回归模型从零开始的实现 线性回归模型使用pytorch的简洁实现 线性回归假设输出与各个输入之间是线性关系: price=warea...
  • 动手学深度学习PyTorch版-第二次打卡 文章目录动手学深度学习PyTorch版-第二次打卡Task03 过拟合、欠拟合及其解决方案;梯度消失、梯度爆炸;循环神经网络进阶Task04 机器翻译及相关技术;注意力机制与Seq2seq模型;...
  • 动手学深度学习PyTorch版-第三次打卡 文章目录动手学深度学习PyTorch版-第三次打卡Task06 批量归一化和残差网络;凸优化;梯度下降批量归一化和残差网络凸优化梯度下降Task07 优化算法进阶Task08 文本分类;数据增强...
  • 动手学深度学习PyTorch版-task1

    千次阅读 2020-02-13 12:42:39
    本课程面向希望更多的...《动手学深度学习》是2019年国内最受欢迎的人工智能学习教材之一,伯禹教育携手上海交通大学团队,以此书的知识架构为基础,沿用了其中的原理讲解文档,并将代码框架由MXNET迁移至PyTorch...
  • 动手深度学习pytorch版

    2021-03-25 06:20:45
    这里写自定义目录标题新的改变功能快捷键合理的创建标题,有助于目录的...动手深度学习pytorch版之获取数据集出错解决办法 出错原因应该是没有权限访问,解决方法是将~改为个下载地址(如D:) 如图 ** ** 新的改变 我
  • 伯禹公益AI《动手学深度学习PyTorch版》Task 06 学习笔记 Task 06:批量归一化和残差网络;凸优化;梯度下降 微信昵称:WarmIce 批量归一化和残差网络 BN和ResNet都没什么特别好说的。 DenseNet久闻其名,但是一直...
  • 伯禹公益AI《动手学深度学习PyTorch版》Task 05 学习笔记 Task 05:卷积神经网络基础;LeNet;卷积神经网络进阶 微信昵称:WarmIce 昨天打了一天的《大革命》,真挺好玩的。不过讲道理,里面有的剧情有点为了“动作...
  • 伯禹公益AI《动手学深度学习PyTorch版》Task 08 学习笔记 Task 08:文本分类;数据增强;模型微调 微信昵称:WarmIce 文本分类 前面一堆数据处理和对双向循环神经网络的讲解可以忽略了,之前都讲过,咱也都详细聊过...
  • 伯禹公益AI《动手学深度学习PyTorch版》Task 07 学习笔记 Task 07:优化算法进阶;word2vec;词嵌入进阶 微信昵称:WarmIce 优化算法进阶 emmmm,讲实话,关于所谓的病态问题是什么,条件数在复杂优化目标函数下的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,019
精华内容 2,007
关键字:

动手学深度pytorch版