Pytorch Day1

Day1

深度学习的核心是梯度

求解y的最小值

 

梯度:梯度的本意是一个向量(矢量),某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向梯度的方向变化最快变化率最大(为该梯度的模)

每一步迭代都是梯度下降

每一步:x的值=当前x的值-x在y函数的导数

求x*即loss函数最小值时x的

反复迭代

学习率(Learning rate):作为监督学习以及深度学习中重要的超参,其决定着目标函数能否收敛到局部最小值以及何时收敛到最小值。合适的学习率能够使目标函数在合适的时间内收敛到局部最小值。(具体随问题调整,一般0.001)

学习率设置的过小时,收敛过程将变得十分缓慢。而当学习率设置的过大时,梯度可能会在最小值附近来回震荡,甚至可能无法收敛

在第一个图可见x=5时,梯度较小

 

精确求解叫做Closed Form Solution(闭式解closed form solution)也叫解析解(analytical solution),就是一些严格的公式,给出任意的自变量就可以求出其因变量,也就是问题的解 )

但一般现实中,我们的数据都是有一定偏差的,对实际的问题不一定需要精确解Closed Form Solution,只要得到相似解并且在经验上证明可行即可(例如如图上半部分得到相似解即可)

在y=w*x+b + eps (添加高斯噪声,模拟现实中的数据)

求解在实际中具有较好的效果即可

 

 

x采样[0,15]

拿到100个有高斯噪声的采样点

假设函数符合线性分布

优化的目标即求loss=(WX+b+eps-y)²的极小值

我们把式子正式化一下,就是说对于这个方程,求解的参数是w和b

观测的样本是x和y,(Xi表示观测到第i个样本)

梯度下降能帮我们求最小值

 

而当loss=(y-(wx+b))取到最小值,此时的w和b也就是我们要求解的参数

 

(wx+b-y)²是非常好求解的,可视化求解过程

loss=∑(WXi+b-y)²,通过调整w和b的值,会取的不同的loss的值

i=1

我们希望求解loss最小值的点

现实中一般很难可视化,因为x的维度很高导致w的维度也很高

对w和b求导

比较直观的描述整个学习的过程,希望能看到直线能穿过整个数据集,使得整体误差较小

 

 

总体过程:WX+b = y

我们通过观察

WX1+b = y1

WX2+b = y2

...

等一系列样本来求w和b的值

最终目的给出任意Xn的值,能够很好的预测yn的值

linear regression:线性回归 (预测的值的取值范围是连续的,属于连续空间)

Logistic Regression:逻辑回归,在线性回归的基础上把X[负无穷,正无穷]数据压缩到[0,1]的范围,适合表达概率问题(例如二分类问题:抛硬币)

Classification:多分类问题(比如0-9手写数字,即每个点概率范围[0,1],10个点的概率加起来=1)

实战

points就是一系列x和y的组合

totaError/float(len(points))即loss=∑(i=1)(WXi+b-y)²

 计算梯度信息,取得每个点x和y的值

 

对w求导,把x,b,y看成常量

loss

=2(wx+b-y)x

再对w求导

=2(wx+b-y)*1

#learning_rate学习率设置的过小时,收敛过程将变得十分缓慢。而当学习率设置的过大时,梯度可能会在最小值附近来回震荡,甚至可能无法收敛。

循环迭代梯度信息

循环100次取得的w,b的值就是比较理想的结果

 

def run():
    points = np.genfromtxt("data.csv", delimiter=",")
    learning_rate = 0.0001
    initial_b = 0 # initial y-intercept guess
    initial_m = 0 # initial slope guess
    num_iterations = 1000
    print("Starting gradient descent at b = {0}, w = {1}, error = {2}"
          .format(initial_b, initial_m,
                  compute_error_for_line_given_points(initial_b, initial_m, points))
          )
    print("Running...")
    [b, m] = gradient_descent_runner(points, initial_b, initial_m, learning_rate, num_iterations)
    print("After {0} iterations b = {1}, w = {2}, error = {3}".
          format(num_iterations, b, m,
                 compute_error_for_line_given_points(b, m, points))
          )

if __name__ == '__main__':
    run()

结果:

Starting gradient descent at b = 0, w = 0, error = 5565.107834483211

Running...

After 1000 iterations b = 0.08893651993741346, w = 1.4777440851894448, error = 112.61481011613473

 

手写数字识别问题

训练集:测试集60K:10K

 

三层的神经网络

每张图片,长28宽28 用矩阵表示(0-1表示图像的灰度值)

[784] 变为[1,784]加一维

 

T表示矩阵转置

X=[v1,v2,...v784](X:[1,dx])作为第一个模型的输入

H1(=XW1+b1)的维度=[1,784][d1,784]T+[d1]=[1,d1]+[d1]-->[1,d1]([1,d1]即H1的维度)

H1作为第二个模型的输入:

H2(=H1W2+b2)的维度=[1,d1][d2,d1]T+[d2]=[1,d2]+[d2]-->[1,d2]([1,d2]即H2的维度)

H2作为第三个模型的输入:

H3(=H2W3+b3)的维度=[1,d2][d3,d2]T+[d3]=[1,d3]+[d3]-->[1,d3]([1,d3]即H3的维度)

H3作为最后的输出,如何表示信息呢?

1)0-9,H3:[1,1],第一个1表示照片数量,第二个1表示0-9中1这个数字

(如果按1,2,3编码,这种方式会产生编码1<2<3的问题)

2)one-hot编码方式(适合表示属于哪一类),此处采用one—hot

 

举例:(如图)H3的向量和真实的向量

loss如何计算:欧氏距离:(两个向量相减)²

pred(即predict预测值)不采用0-9表示,而是采用one-hot形式(一个10维(0-9总共10个数)向量)表示

然后通过欧氏距离法计算

对于线性模型是很难实现类似手写数字识别的现实问题的,因此引入一个新的非线性的部分(来自生物学神经元)

神经元有多个输入,输出不是输入的简单线性求和,有预值

比如:

当输入非常小的时候,输出就是0,0,0...

一定范围内的输入,则输出有一定的线性关系

当输入很大,输出也不会很大,会慢慢的饱和,即不完全满足线性关系(即sigmoid激活函数

 

此处我们使用更简单广泛的ReLU函数

输入的和大于0则输出和,输入的和小于0则忽略(非线性函数)

特性:梯度非常容易计算,一直是1或0,防止梯度离散

 

如何把Relu函数加进到线性模型呢

在线性函数H1=(XW1+b1)添加ReLU

新的H1=relu(XW1+b1)

新的H2=relu(XW2+b2)

新的H3=relu(XW3+b3)

 

pred中:在原来的嵌套上面分别添加三个激活函数,三个非线性的模型叠加在一起,表达能力和又加强了,而且还有非线性表达能力

希望pred的值越接近真是的ylabel(标签)的值越好

因此构造∑(pred-y)²越小越好

[w,b]x-->y

此处的w,b不是具体的,由三组参数构成[w1,w2,w3] [b1,b2,b3]

w1,b1来自第一个非线性模型   w2,b2来自第二个非线性模型

w3,b3来自第三个非线性模型

 

对于一个新的X(没有在traindata中出现)

代入运算得到pred,[1,10]

[0.1,0.8,0.01,0,0.02,...]

分别代表P(0/X)=0.1,P(1/X)=0.8...即给定X的label为1的概率是0.8

真实的’1’:[0,1,0,0,0..]

argmax(pred)即可得到真实的label

argmax得到的是0.8所在的索引号,即’1’

案例

 

神经网络的结构

左边是输入的图片(例如手写数字0,1,2的图片)

经过一层网络,再经过一层网络得到输出,输出和我们真实的label之间有误差,通过误差求梯度,再通过梯度去更新我们的W1,W2,W3这些权值,直到达到一个比较合适的网络的状态。

 

通过三层线性层的嵌套,并且在线性层的末尾添加非线性的函数

第一层接收的输入(X)是图片,经过W1和b1以后,再经过一个relu非线性激活函数,得到输出H1;H1送到第二层得到H2;H2送到第三层得到H3,H3就是我们网络的输出,第三层的激活函数一般不会是relu,会根据具体的任务来选择函数(比如sigmoid,softmax等)

此处我们第三层的输出就不加激活函数。

我们如何完成手写数字体识别的任务呢?

 

第一步:Load data 加载图片(手写数字图片大概7W张)

第二步:Build Model 新建一个三层的非线性的网层

第三步:Train训练

第四步:Test测试

对于pytorch的深度学习框架,在建立人工神经网络时整体的步骤主要有以下四步:

1、载入原始数据

2、构建具体神经网络

3、进行数据的训练

4、数据测试和验证

Pytorch已经提供了MNIST数据集,只要调用datasets.MNIST()下载即可

PyTorch中数据读取的一个重要接口是torch.utils.data.DataLoader,该接口定义在dataloader.py脚本中,只要是用PyTorch来训练模型基本都会用到该接口,该接口主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor,后续只需要再包装成Variable即可作为模型的输入,

torchvision 之 transforms 模块详解

torchvision 是独立于 PyTorch 的关于图像操作的一个工具库,目前包括六个模块:

   1)torchvision.datasets:几个常用视觉数据集,可以下载和加载,以及如何编写自己的 Dataset。

   2)torchvision.models:经典模型,例如 AlexNet、VGG、ResNet 等,以及训练好的参数。

   3)torchvision.transforms:常用的图像操作,例随机切割、旋转、数据类型转换、tensor 与 numpy 和 PIL Image 的互换等。

   4)torchvision.ops:提供 CV 中常用的一些操作,比如 NMS、ROI_Align、ROI_Pool 等。

   5)torchvision.io:提供输入输出的一些操作,目前针对的是视频的写入写出。

   6)torchvision.utils:其他工具,比如产生一个图像网格等。

#encoding=utf-8
import torch
from torch import nn  #完成神经网络的构建包
from torch.nn import functional as F  #包含常用函数包
from torch import optim   #优化工具包
import torchvision  #视觉工具包,构建计算机视觉模型
from matplotlib import pyplot as plt
#从utils导入loss下降曲线,图片识别结果,和onehot编码方式
from utils import plot_image,plot_curve,one_hot
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'

#GPU一次可以处理多张图片,通过并行处理多张图片,可以节省计算时间
#一次处理图片的数量,minsit图片28行*28列,图片较小,所以batch_size可以大一点
batch_size = 512

#step 1. load dataset 加载数据集
train_loader = torch.utils.data.DataLoader(
    #加载数据集(70K中60K做Training,10K做Test)
    #调用datasets.MNIST()下载数据
    #download=True即若没有minst_data,则自动去网上下载
    #transforms.Compose()类,作用串联多个图片变换的操作
    #ToTensor即把numpy格式转换为tensor(一种数据载体)
    #Normalize标准化,原本数据都在0-1,Normalize使得数据均匀分布在0附件
    # 均值是0.1307,标准差是0.3081利用这两个值将每个通道数据的分布转换为标准正态分布。
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    #一次加载多少张图片,shuffle=True即每次将图片随机打散
    batch_size=batch_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data/', train=False, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    #此处shuffle=False,数据不用打散
    batch_size=batch_size, shuffle=False)

#显示加载的图片
#迭代器不断使用next()函数来获取下⼀条数据。
x,y = next(iter(train_loader))
print(x.shape, y.shape)  #512张图片
print(x.min(),x.max())
#tensor(-0.4242) tensor(2.8215),位于0附近,如果不Normalize,则为0-1

#参数(数据,label标签,名字)
#plot_image(x,y,'image sample')

#2.新建一个三层的非线性的层,创建网络
class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        #wx+b
        #第一层(28*28是图片,256根据经验随机决定)
        self.fc1 = nn.Linear(28*28, 256)  #线性层
        #第二层(输入的256,是上一层的输出,64也是根据经验随机决定)
        self.fc2 = nn.Linear(256, 64)
        #第三层(因为十分类,所以最后一层输出一定是10)
        self.fc3 = nn.Linear(64,10)

    def forward(self,x):
        # (输入的图片:x)x.shape : [b, 1 ,28, 28]
        # h1 = relu(w1x+b1)
        x = F.relu(self.fc1(x))
        #x是第一层的输出
        #h2 = relu(h1w2 + b2)
        x = F.relu(self.fc2(x))
        #根据具体情况决定最后一层是否加激活函数
        #h3 = h2w3 + b3
        x = self.fc3(x)

        return x

#3.训练
net = Net()   #网络初始化
#优化器 优化参数[w1, b1, w2, b2, w3, b3],lr学习率
optimizer = optim.SGD(net.parameters(),lr=0.01,momentum=0.9)
train_loss = []
#迭代3次
for epoch in range(3):
    #enumerate()函数用于将一个可遍历的数据对象
    #(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
    for batch_idx, (x,y) in enumerate(train_loader):

        # x: torch.Size([512, 1, 28, 28])
        # x: [b, 1, 28, 28], y.shape [512]
        #print(x.shape,y.shape)
        #网络只能接收 [b, feature]的数据,但实际数据x是四维[b, 1, 28, 28]
        #[b, 1, 28, 28] -> [b,784]
        #把整个图片看成特征向量
        x = x.view(x.size(0), 28*28)
        #->out: [b,10]
        #得到网络的输出
        out = net(x)
        #希望out能接近y_onehot
        y_onehot = one_hot(y)
        #loss = mes(out,y_onehot) mse:均方误差
        loss = F.mse_loss(out,y_onehot)

        optimizer.zero_grad()#清零梯度
        loss.backward()       #梯度下降
        #w = w- lr*grad
        optimizer.step()
        #放到train_loss列表中,方便查看
        train_loss.append(loss.item())

        if batch_idx % 10 ==0:
            print(epoch,batch_idx,loss.item())
#查看loss下降曲线
plot_curve(train_loss)
#得到一个比较好的[w1,b1,w2,b2,w3,b3]
#loss并不是完全的衡量指标,要用准确度

#4.准确度测试
total_correct = 0
for x,y in test_loader:
    #降维
    x = x.view(x.size(0),28*28)
    #得到网络的输出
    out = net(x)
    #最大值所在的索引 =>pred:[b]
    pred = out.argmax(dim=1)
    #当前这个batch中图片预测对的数量
    #通过item()取出数值
    correct = pred.eq(y).sum().float().item()
    total_correct += correct
#求测试的数量
total_num = len(test_loader.dataset)
acc = total_correct / total_num   #正确数量/测试样本数量
print('test acc:',acc)

x,y = next(iter(test_loader))
out = net(x.view(x.size(0),28*28))
pred = out.argmax(dim=1)
plot_image(x,pred,'test')


 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值