CV计算机视觉核心03-初步认识机器学习(线性回归模型、梯度下降法、线性回归模型解决数字识别问题(没用auto grad)、逻辑回归模型sigmoid、作业:线性回归解决数字识别auto grad)

2023-11-01

CV计算机视觉核心03-初步认识机器学习(线性回归模型、梯度下降法、区分一下回归模型和分类模型、线性回归模型解决数字识别问题(没有使用auto grad)、逻辑回归模型(sigmoid函数)、如何使用自动梯度计算、auto grad使用的注意事项、作业:线性回归模型解决数字图像分类问题(使用auto grad))

本节内容:
一、第一个可训练的模型,线性回归模型。
二、线性回归模型解决数字识别问题。
三、逻辑回归模型。

基本概念监督学习、非监督学习、模型参数

如何用经验来学习解决问题?
两种思路:
1、监督学习:凡是需要标注数据的方法。(分类、分割…)
2、非监督学习(是未来):凡是不需要人工标注数据的学习方法。(数据量太大,人工无法完成标注,用一定规则作为“监督”,不需要人打标签。)

模型参数:指的是完成该模型所必须要的已知量。

计算机视觉问题:
image => get feature(各种特征:Hog、LBP、直方图,投影特征等) => model判断(欧式距离、直接做差、线性回归模型) => 结果。

以案例来引出我们需要完成的内容:

我们还是以10张图片识别问题,特征投影特征,V[ v1,v2,v3,…,v6]的6维向量。我们用以下方程式来判别类别:
y = W * V = w1v1 + w2v2 + w3v3 + … + w6v6
此时:若要y输出正确的类别,需要求出特征的W权值。

该如何求解W呢?

一共有4种方法(列方程组(消元法)、最小二乘法(最小平方函数)、极大似然估计、算法法(只有前面几种方法实在不能使用的时候使用算法法,因此算法法是最终的方法,前几种方法是可以求得确切的结果的。)),我们先来看最直观的一种:列方程组。

列方程组:

这里V特征是可以提前获得的,比如投影特征。
下图的方程是一个6元1次方程组,可以使用消元法求解。
w1v11 + w2v12 + w3v13 + … + w6v16 = y0预测值 = 我们希望是0(理想值)


w1v101 + w2v102 + w3v103 + … + w6v106 = y9预测值 = 我们希望是9(理想值)
在这里插入图片描述
在这里插入图片描述
这里会存在一个问题,我们有多少个样本,就需要列出多少个方程,因此这种手动求解的方式不太适用。

最小二乘法

怎么办呢?
这里我们构造一个二次函数,然后求这个函数的最小值,二次函数总会有一个最小值的。
在这里插入图片描述
求这个最小值,跟我们解上面的那多个方程有什么关系呢?
我们的目标是让y的输出和v特征对应起来,即y要符合我们的理想值。

因此y预测值减去y理想值(下图的方差),这样会形成一个2次函数。
在这里插入图片描述
这个二次函数总会有一个最小值。求到了最小值,那么就是说明求到了最近似的值。如果最小值求出来是0(理想状态下求出来应该是0),则y预测值就是y理想值。因此我们可以求出理想状态下对应的W。因此我们只需求导数即可。
在这里插入图片描述
我们可以注意到下面的公式,每一项都是大于等于0的,那我们如何求最小值呢?
在这里插入图片描述
通过对W求偏导数,让这个偏导数 = 0,解出这个偏导值。
在这里插入图片描述
有几个wj就是几个方程,把1000,10000个方程组,转成了6个方程(不管样本是10000又或是1000000也好,我就将原来的消元法的10000个方程,转化为6个方程了),我们只需解决这6个方程即可,因为有6个特征V对应6个权值W,对权值求导,有6个权值,就求6个方程即可。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面这种方法就是最小二乘法(也就是最小平方函数)。

极大似然估计法MLE(Maximum Likelihood Estimate)

估计出当前事件发生概率最大时,对应的概率密度函数中的参数是多少?概率密度函数中的参数是与我们模型中的参数是一致的。

当前事件指的是:y预测值与理想值y之间误差为0的时候。通常我们希望误差符合一个正太分布(均值为0,方差为σ)。正太分布的方程怎么写,正太分布的概率密度函数P如何写?
在这里插入图片描述
什么时候正太分布方程取到最大值呢?就是上图中的y预测值减y真实值为0的时候,L正太分布方程可以取到最大值。

对L概率密度函数取log:
也就是log(a*b) = loga + logb
在这里插入图片描述
我们要求的是Max(logL),即最大值logL,按照上图的公式,如果要求logL最大值,那么就需要下图红括号那部分求最小值,因为后半部分是二次函数,肯定有最小值。因为前半部分是单调递增的,因此只有减后半部为最小值,这个logL才能取到最大值。
在这里插入图片描述
在这里插入图片描述
极大似然估计有几个参数就有几个方程。有六个参数(特征)就有六个方程,因为求导是针对特征的权值w。

上面提到的极大似然估计MLE、最小二乘法和消元法都需要求解方程组,那么有没有不需要求解方程组的方法呢?
答:有,算法求解w。
但是在工业界,尽量能用上面的三种方法就用这三种,因为这三种方法是可以求得解析解(即确切的值),解析解永远是最准确的。只有样本量过多,特征过多的时候,实在不得已用算法的方法。因此算法方法就是终极方法。

一、第一个可训练的模型,线性回归模型。

算法求解W,线性回归模型

线性模型指的是y = w * v^T,其中y与v特征向量存在线性关系。
回归的过程:此外通过给定参数,求解方程的过程就是回归的过程,最终这些参数点都会回归到这个方程上,这个方程是一个连续的方程,这种回归模型多用于预测。

步骤:

1、先令w = w0
2、把w0带入到model输出,即y0 = model(w0,v) = w0 * v
3、观察模型输出与期望值差,即设立一个Loss函数,这里希望模型参数的更新,这个差值越来越小,这样我们的更新w才有意义。
4、如果输出值与期望值相同,求解完成。
5、如果不同,以一定规则R更新w,w1 = R(w0) = w0 - σL/σw0 *lr。
6、把w1带入model,得到模型输出。
7、转到第3步。
在这里插入图片描述
上面的步骤有两个关键:
1、如何观察输出与期望差?定义目标函数(损失函数)Loss Function:(y预测-y真实)^2 。
2、更新w的规则如何定义?梯度下降。

为什么梯度下降能使得Loss减小?

梯度下降法:

梯度定义:
因变量随着自变量变化的速度,y随x的变化的速度。
自变量朝着负梯度方向改变的时候,y值会减小,x会朝着-dy/dx反方向减小。
在这里插入图片描述

梯度计算:

y = f(x)
y0 = f(x0)
当:x1 = x0 + △x
y1 = y0 + g * △x 其中g为梯度。
要使y1 < y0,即函数值y下降,梯度下降。
则 g △x < 0
则 △x = -g *a (a>0,a就是lr学习率)。
此时,g △x = g (-g *a) = -ag^2 < 0
结论,若要使y的值减小(下降),只需要让x朝着-g的方向变化。
即:x1 = x0 - g *a
在这里插入图片描述
在这里插入图片描述
则算法中的更新公式可以写为:
在这里插入图片描述
例子:
先是解析方法:
在这里插入图片描述
算法:
lr学习率为0.1。
先令x0 = 5,则y0 = 25
x1 = 4,则y1 = 16
在这里插入图片描述
x2 = 3.2,则y2 = 10.24
在这里插入图片描述
x3 …
x4

发现y最后不在下降了,就开始震荡了。

该模型总结:
在这里插入图片描述

这里需要区分一下回归模型和分类模型:

回归模型:
通过给定参数,求解方程的过程就是回归的过程,最终这些参数点都会回归到这个方程上,这个方程是一个连续的方程,这种回归模型多用于预测。
在这里插入图片描述
分类模型:
线性回归做分类:将回归求解的方程,按照不同区间进行分段,不同区间为不同类型。
在这里插入图片描述

二、线性回归模型解决数字识别问题(没有使用auto grad)。

这里基本是原始的写法进行编写代码:

#coding:utf-8
# code for week2,recognize_computer_vision.py
# houchangligong,zhaomingming,20200520,
import torch
from itertools import product

def generate_data():
    # 本函数生成0-9,10个数字的图片矩阵
    image_data=[]
    num_0 = torch.tensor(
    [[0,0,1,1,0,0],
    [0,1,0,0,1,0],
    [0,1,0,0,1,0],
    [0,1,0,0,1,0],
    [0,0,1,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_0)
    num_1 = torch.tensor(
    [[0,0,0,1,0,0],
    [0,0,1,1,0,0],
    [0,0,0,1,0,0],
    [0,0,0,1,0,0],
    [0,0,1,1,1,0],
    [0,0,0,0,0,0]])
    image_data.append(num_1)
    num_2 = torch.tensor(
    [[0,0,1,1,0,0],
    [0,1,0,0,1,0],
    [0,0,0,1,0,0],
    [0,0,1,0,0,0],
    [0,1,1,1,1,0],
    [0,0,0,0,0,0]])
    image_data.append(num_2)
    num_3 = torch.tensor(
    [[0,0,1,1,0,0],
    [0,0,0,0,1,0],
    [0,0,1,1,0,0],
    [0,0,0,0,1,0],
    [0,0,1,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_3)
    num_4 = torch.tensor(
    [
    [0,0,0,0,1,0],
    [0,0,0,1,1,0],
    [0,0,1,0,1,0],
    [0,1,1,1,1,1],
    [0,0,0,0,1,0],
    [0,0,0,0,0,0]])
    image_data.append(num_4)
    num_5 = torch.tensor(
    [
    [0,1,1,1,0,0],
    [0,1,0,0,0,0],
    [0,1,1,1,0,0],
    [0,0,0,0,1,0],
    [0,1,1,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_5)
    num_6 = torch.tensor(
    [[0,0,1,1,0,0],
    [0,1,0,0,0,0],
    [0,1,1,1,0,0],
    [0,1,0,0,1,0],
    [0,0,1,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_6)
    num_7 = torch.tensor(
    [
    [0,1,1,1,1,0],
    [0,0,0,0,1,0],
    [0,0,0,1,0,0],
    [0,0,0,1,0,0],
    [0,0,0,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_7)
    num_8 = torch.tensor(
    [[0,0,1,1,0,0],
    [0,1,0,0,1,0],
    [0,0,1,1,0,0],
    [0,1,0,0,1,0],
    [0,0,1,1,0,0],
    [0,0,0,0,0,0]])
    image_data.append(num_8)
    num_9 = torch.tensor(
    [[0,0,1,1,1,0],
    [0,1,0,0,1,0],
    [0,0,1,1,1,0],
    [0,1,0,0,1,0],
    [0,0,0,0,1,0],
    [0,0,0,0,0,0]])
    image_data.append(num_9)
    image_label=[0,1,2,3,4,5,6,7,8,9]
    return image_data,image_label
    
def get_feature(x):
    feature = [0,0,0,0]

    # 下面添加提取图像x的特征feature的函数代码,这里只是定义函数:
    def get_shadow(x,dim):
        feature  =torch.sum(x,dim)
        feature = feature.float()

        # 归一化,使得区间在0-1之间
        for i in range(0,feature.shape[0]):
            feature[i]=feature[i]/sum(feature)

        #将feature结构调整为[1,6]
        feature = feature.view(1,6)
        return feature

    #这里dim=0,是垂直投影:
    feature  = get_shadow(x,0)
    # import pdb
    # pdb.set_trace()
    # print(feature)
    return feature

#model函数:需要传入参数feature和weights
def model(feature,weights):
    y=-1

    # 下面添加对feature进行决策的代码,判定出feature 属于[0,1,2,3,...9]哪个类别
    #import pdb
    #pdb.set_trace()

    # feature是[1,6]的,因此需要在feature末尾增加一个tensor[1,1],使得其达到[7,7]
    # 通过[1,6]和[1,1]的进行拼接处理,使得达到[1,7]
    # 其中最后一个是bias偏置的意思
    feature = torch.cat((feature,torch.tensor(1.0).view(1,1)),1)

    #.mm表示的是矩阵的乘法:feature[1,7]乘以weights[7,1],就得到y[1,1]
    # y = w1*x1 + w2*x2 + w3*x3 + w4*x4 + w5*x5 + w6*x6 + w7
    # y = W * X + b
    y = feature.mm(weights)
    return y

def train_model(image_data,image_label,weights):
   
    for epoch in range(0,3000):
        loss = 0 
        #for i in range(0,len(image_data)):
        for i in range(0,5):
            #print(image_label[i])
            #y = model(get_feature(image_data[i]),weights)
            feature = get_feature(image_data[i])
            y = model(feature,weights)

            # 定义loss
            # 观察模型输出y 与 期望值image_label的差距
            # mse:
            loss += 0.5*(y.item()-image_label[i])**2
   
            #print("loss=%s"%(loss))
            #weights =
            # 更新公式
            # w  = w - (y-y1)*x*lr
            # w1 = w1 - (y^ - y*)*x1*lr
            # w2 = w2 - (y^ - y*)*x2*lr
            #...
            feature=feature.view(6)

            # 这里表示负梯度
            lr = 0.05
            #w为[7,1]
            #w1:
            weights[0,0] = weights[0,0]- (y.item()-image_label[i])*feature[0]*lr
            weights[1,0] = weights[1,0]- (y.item()-image_label[i])*feature[1]*lr
            weights[2,0] = weights[2,0]- (y.item()-image_label[i])*feature[2]*lr
            weights[3,0] = weights[3,0]- (y.item()-image_label[i])*feature[3]*lr
            weights[4,0] = weights[4,0]- (y.item()-image_label[i])*feature[4]*lr
            weights[5,0] = weights[5,0]- (y.item()-image_label[i])*feature[5]*lr
            #w7:这里w7前没有x项,w7是偏置项
            weights[6,0] = weights[6,0]- (y.item()-image_label[i])*lr
        # import pdb
        # pdb.set_trace()
        #epoch表示训练一代,一代是训练了5个数据集:
        print("epoch=%s,loss=%s,weights=%s"%(epoch,loss,weights.view(7)))

        loss=0
        #import pdb
        #pdb.set_trace()
    return weights

if __name__=="__main__":
    # generate w_0
    # 随机生成7个w,结构是[7,1]
    weights = torch.rand(7,1)

    # 这个是用于打断点:
    # import pdb
    # pdb.set_trace()

    #调用generate_data()生成数据集和标签:
    image_data,image_label = generate_data()

    # 打印出0的图像
    print("数字0对应的图片是:")
    print(image_data[0])
    print("-"*20)
    
    # 打印出8的图像
    print("数字8对应的图片是:")
    print(image_data[8])
    print("-"*20)

    # 对模型进行训练:
    weights=train_model(image_data,image_label,weights)

    #训练后获得weight,对每张图片进行识别
    print("对每张图片进行识别")
    for i in range(0,5):
        #获得5张图片
        x=image_data[i]
    #import pdb
    #pdb.set_trace()
    #对当前图片提取特征
        feature=get_feature(x)
        # 对提取到得特征进行分类,使用训练好的权值。
        y = model(feature,weights)
    #打印出分类结果
        print("图像[%s]得分类结果是:[%s],它得特征是[%s]"%(i,y,feature))

在这里插入图片描述

三、逻辑回归模型(sigmoid函数)。

如何学习一个新模型:(三方面)
1、先看使用模型的方法:模型公式。y=wx+b。
2、再看模型的参数。w,b,要对模型中的x进行回归,预测y,就必须依赖w和b。
3、看模型求解方法。梯度下降。

Logistic regression:
1、先看使用模型的方法:模型公式。

下图中逻辑回归公式中的 wv = wx+b。
逻辑回归公式中就包含一个线性模型。
其中就是1/(1+e^-x) = sigmoid函数,将x替换成wx+b,就成为了逻辑回归公式了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、再看模型的参数。
逻辑回归模型有哪些参数呢?
其参数与线性回归模型参数是一样的。
在这里插入图片描述
3、看模型求解方法。
(1)定义Loss Function。
交叉熵 p(1-p),p代表的就是输出y。
(2)算法思维更新参数。

how to use auto grad如何使用自动梯度计算

案例:

#coding:utf-8
import torch


# 当x 是一个维度的时候
print("%s%s"%("-"*20,"当x是1x1的时候"))
x = torch.ones(1,1,requires_grad = True)
y = (x+2)*(x+2)*3
y.backward()
print('x.grad:',x.grad)

print("%s%s"%("-"*20,"当x是1x2的时候"))
x = torch.ones(1,2,requires_grad = True)
y = (x+2)*(x+2)*3
z = y.sum()
z.backward()
print('x.grad:',x.grad)

import pdb
# continue c 继续执行程序,直到下一个断点或调用点
# next n 执行下一行
# 回车 重复上一条命令
pdb.set_trace()


# 如何把autograd用到我们线性模型中
x = torch.rand(10,1)
print("%s%s"%("-"*20,"把autograd用到我们线性模型中"))
w = torch.ones(1,10,requires_grad = True)
w_init= w.data
label=100
for i in range(1,50):
    y = (w.mm(x))**2
    loss = (y-label)*(y-label)
    loss.backward()
    #w.data = w.data - w.grad.data*0.1
    #print("loss=%s,w.requires_grad:[%s],w=[%s]"%(loss.data,w.requires_grad,w.grad))
    print("y=%s,loss=%s"%(y,loss.data))
    
    # 梯度更新写法一,use tensor.data
    #w.data = w.data - w.grad.data*0.1
    #w.grad.data = torch.zeros(1,10)
    # 梯度更新写法二,use torch.no_grad()
    with torch.no_grad():
        w -= w.grad*0.0001
        print('w:',w)
        w.grad.zero_()
        #pdb.set_trace()
        #w.data = w.data - w.grad.data*0.1
        #w.grad.data = torch.zeros(1,10)
    
print("*"*20)
print("model:y= wx")
print("w_init =%s"%(w_init)) 
print("y_init =%s"%(w_init.mm(x)))
print("y的目标值是%s"%(label))
print("经过梯度下降算法训练后:")
print("w=%s"%(w.data))
print("y=wx=%s"%(y.data))

在这里插入图片描述
在这里插入图片描述

auto grad使用的注意事项

import torch
a = torch.tensor(2.0,requires_grad=True)
b = a.exp() #b = e^2
b.backward()
print('b:',b)
print(b.is_leaf)

# 叶子节点,是需要将导数保存下来的。梯度计算过程中的继承图将梯度保存在a.grad中。
print('a:',a)
print(a.is_leaf)
print('a.grad:',a.grad) #这里y=e^x的导数y′=e^x

在这里插入图片描述

input = torch.ones([3,3],requires_grad=False)
w1 = torch.tensor(2.0,requires_grad = True)
w2 = torch.tensor(3.0,requires_grad = False)
w3 = torch.tensor(3.0,requires_grad = True)

l1 = input * w1
l2 = l1+w2
l3 = l1*w3
l4 = l2*l3
#w为了求出loss,l4矩阵求一个均值,获得一个数值
loss = l4.mean() 
print(w1)

#发现.data后打印,是不带requires_grad=True
print(w1.data) 
#这里是只取数据。这样好处是只对数据做操作,对继承图中的requires_grad不受影响。

在这里插入图片描述

print(w1.data,w1.grad,w1.grad_fn)

在这里插入图片描述

print(l1.data)

print(l1.is_leaf)

print(l2.is_leaf)

print(w1.is_leaf)

在这里插入图片描述

print(l1.grad)

在这里插入图片描述

print(l1.grad_fn)
#这的grad_fn中的fn表示function的意思。
#l1 = input * w1
#因此下面打印出来的是MulBackward0...
#可以看到是乘法。

在这里插入图片描述

#是一个MeanBackward,继承图都有记录。
print(loss) 

在这里插入图片描述

print(loss.data,loss.grad,loss.grad_fn)

在这里插入图片描述

loss.backward()
#这里w2.grad之所以为none,是因为我们设置了requires_grad = False
print(w1.grad,w2.grad,w3.grad)

在这里插入图片描述

使用auto grad注意事项:

1、叶子张量 leaf tensor:反向传播时,只保留属性requires_grad和is_leaf为真的张量得导数。

2、requires_grad为真,is_leaf为假时,此张量得导数作为中间结果用于计算叶子张量得导师。

3、requires_grad is False,is_leaf is False,次张量参与导数计算

a = torch.ones([2,2],requires_grad=True)
print(a.is_leaf)

在这里插入图片描述

b = a+2 
print(b.is_leaf)

在这里插入图片描述

4、因为b不是用户创建的,是通过计算生成的

5、叶子张量的作用:节省内存或者显存

6、叶子节点的grad_fn都为空

7、非叶子节点点grad_fn都不为空

8、果我们想保留中间变量的导数,该怎么操作?

8.0.1、通过使用tensor.retain_grad()
loss = l4.mean()
#设置一下,保存一下中间节点的梯度信息
l1.retain_grad()
l4.retain_grad()
loss.retain_grad()

#这里还需注意的是继承图建立好后只能backward()一次,不能backward两次。
loss.backward()
print(loss.grad)
print(l4.grad)
print(l1.grad)

在这里插入图片描述

9、如果我们只想进行debug,只需要输出中间变量的导数信息,而不需要保存他们,我们还可以使用tensor.register_hook,如下

loss2 = l4.mean()
l1.register_hook(lambda grad:print("l1 grad:",grad))
l4.register_hook(lambda grad:print("l4 grad",grad))
loss2.register_hook(lambda grad:print("loss grad:",grad))

#在backward的过程中,就通过register_hook,获取到梯度,我们通过lambda表达式直接打印出来梯度信息。
loss2.backward()

#这我们在打印一下loss2.grad,发现这里又是none,register_hook是不保存梯度信息的,只是在backward过程中获得到这个梯度信息而已,结束backward,梯度信息也就释放掉了。
print(loss2.grad)

在这里插入图片描述

10、可以看到,是先打印loss的grade,后打印l4,l1的grade。

11、并且在最后print(loss2.grad)得时候打印出了none

12、这说明loss.grad在print完之后,就被清除掉了

13、pytorch 中,Hook的作用非常大

14、inplace 操作:inplace operation

15、在不更改变量的内存地址的情况下,直接修改变量的值。就叫inplace操作

a  = torch.tensor([3.0,1.0])
print(id(a))
#这里需要注意的是在继承图中是不允许这样赋值的。
#exp是高等数学里以自然常数e为底的指数函数
a = a.exp() # 不是inplace,可以通过id查看是否内存地址一致。
print(id(a))

b=[1,2]
print(id(b))
b[0]=10# 是inplace
print(id(b))

在这里插入图片描述

16、以上id有变化的不属于inplace操作,id没有变化的,才是inplace操作

17、pytorch 怎么监测tensor发生了inplace操作?通过tensor._version

a = torch.tensor([1.0,3.0],requires_grad=True)
b = a+2
print(b._version)

loss = (b * b).mean()
b[0] = 1000.0
print(b._version)

# loss.backward()
# print(loss._version)

在这里插入图片描述
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]], which is output 0 of AddBackward0, is at version 1; expected version 0 instead.

18、每次tensor进行inplace时,_version的值就会加1,在正向传播过程中,求导系统记录的b的version是0,但是反向传播过程中,求导系统发现b的version变成了

19、对于requires_grad=True的叶子节点的值,在求梯度之前,是不允许修改的。

20、类似一下应用:

RuntimeError: leaf variable has been moved into the graph interior
a = 0
a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
print(a,a.is_leaf)
print(a,id(a))

在这里插入图片描述

# a[:]=0
# a.add_(10.)
print(a,a.is_leaf,a.requires_grad)
print(a,id(a))

在这里插入图片描述

loss3 = (a*a).mean()
loss3.backward()

21、在使用a[:]=0时,实际上是用inplace操作把一个叶子节点变成了非叶子节点了,这样的话,导数就不会被保存了,就变成none了。

22、也就是说,在backward之前,我们要想修改叶子节点,必须按照一定的规则

23、方法一

a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
print(a,a.is_leaf,id(a))

#方法1:操作a的data
a.data.fill_(5.)
print(a,a.is_leaf,id(a))

loss5 = (a*a).mean()
loss5.backward()
print(a.grad)

在这里插入图片描述

24、方法二

a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
print(a,a.is_leaf)

#方法2:这里是设置不需要grad:
with torch.no_grad():
    a[:]=10.
print(a,a.is_leaf)
loss = (a*a).mean()
loss.backward()
print(a.grad)

在这里插入图片描述

25、这里,第一种方法用fill来修改,第二种方法用with torch.no_grad()来修改,其实都是找到了一个变量,这个变量与a共享了内存,但这个变量得requires_grad是False

26、比如,a.data.fill_(5.)时,a.data就是这个中间变量,不但与a共享了内存,而且这个变量是不需要requires_grad的

27、with torch.no_grad() 是不进行grad相关操作。

作业:线性回归模型解决数字图像分类问题(使用auto grad)

手动实现线性回归模型解决数字图像分类问题:
这里我们使用auto grad

# coding:utf-8
# code for week3

import torch
from torch.autograd import Variable as V

def generate_data():
    # 本函数生成0-9,10个数字的图片矩阵
    image_data = []
    num_0 = torch.tensor(
        [[0, 0, 1, 1, 0, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_0)
    num_1 = torch.tensor(
        [[0, 0, 0, 1, 0, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 1, 0, 0],
         [0, 0, 0, 1, 0, 0],
         [0, 0, 1, 1, 1, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_1)
    num_2 = torch.tensor(
        [[0, 0, 1, 1, 0, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 0, 1, 0, 0],
         [0, 0, 1, 0, 0, 0],
         [0, 1, 1, 1, 1, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_2)
    num_3 = torch.tensor(
        [[0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_3)
    num_4 = torch.tensor(
        [
            [0, 0, 0, 0, 1, 0],
            [0, 0, 0, 1, 1, 0],
            [0, 0, 1, 0, 1, 0],
            [0, 1, 1, 1, 1, 1],
            [0, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 0, 0]])
    image_data.append(num_4)
    num_5 = torch.tensor(
        [
            [0, 1, 1, 1, 0, 0],
            [0, 1, 0, 0, 0, 0],
            [0, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 1, 0],
            [0, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0]])
    image_data.append(num_5)
    num_6 = torch.tensor(
        [[0, 0, 1, 1, 0, 0],
         [0, 1, 0, 0, 0, 0],
         [0, 1, 1, 1, 0, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_6)
    num_7 = torch.tensor(
        [
            [0, 1, 1, 1, 1, 0],
            [0, 0, 0, 0, 1, 0],
            [0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0]])
    image_data.append(num_7)
    num_8 = torch.tensor(
        [[0, 0, 1, 1, 0, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_8)
    num_9 = torch.tensor(
        [[0, 0, 1, 1, 1, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 1, 1, 1, 0],
         [0, 1, 0, 0, 1, 0],
         [0, 0, 0, 0, 1, 0],
         [0, 0, 0, 0, 0, 0]])
    image_data.append(num_9)
    image_label = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    return image_data, image_label

def get_feature(x, dim):
    # 下面添加提取图像x的特征feature的代码
    Heigh = x.shape[0]
    feature = torch.sum(x, dim)
    feature = feature.float()
    feat_dim = feature.shape[0]
    #  归一化
    for i in range(0, feat_dim):
        feature[i] = feature[i] / sum(feature)
    feature = feature.view(1, Heigh)
    return feature

def train_model(weights, learning_rate, iters, num_data, image_data, image_label):

    for epoch in range(iters):
        loss = 0
        for i in range(0, num_data):
            feature = get_feature(image_data[i], 1)
            y_pred = linear_model(feature, weights)
            loss += 0.5 * (y_pred - image_label[i])**2
        # 自动计算梯度
        loss.backward()
        # 更新参数,原来的weight的data值减去训练后weight.grad.data*lr。
        weights.data.sub_(learning_rate * weights.grad.data)
        # 梯度清零,不清零梯度会累加
        weights.grad.data.zero_()
        print('each epoch loss is {}'.format(loss.item()))
    return weights

def linear_model(feature, weights):
    y = -1
    # y = w1*x1 + w2*x2 +...+ w6*x6
    feature = torch.cat((feature, torch.tensor(1.0).view(1,1)), 1)
    y = feature.mm(weights)
    return y


if __name__ == "__main__":
    #1、生成数据集和标签
    image_data, image_label = generate_data()
    num_sample = len(image_data) #样本数据的长度,样本个数。
    num_feat = 6 #特征数为5

    #2、随机的初始化参数
    #生成7行1列的weight。初始化的weight
    weights = torch.rand(num_feat + 1, 1, requires_grad=True)
    # 学习率
    learning_rate = 0.0005
    iters = 5000
    num_data = 6
    # 训练好的weight
    new_weights = train_model(weights, learning_rate, iters, num_data, image_data, image_label)

    print("对每张图片进行识别")
    for i in range(0, num_sample):
        x = image_data[i]

        # 对当前图片提取特征
        dim = 0
        feature = get_feature(x, dim)

        # 对提取到得特征进行分类
        y = linear_model(feature, weights)

        # 打印出分类结果
        print("图像[%s]得分类结果是:[%s]" % (i, y))

发现分类效果不好:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CV计算机视觉核心03-初步认识机器学习(线性回归模型、梯度下降法、线性回归模型解决数字识别问题(没用auto grad)、逻辑回归模型sigmoid、作业:线性回归解决数字识别auto grad) 的相关文章

  • ES6 let 与 const 命令 以及箭头函数初步学习

    ES6 let 与 const 命令 以及箭头函数初步学习 ES6 let 与 const 命令 以及箭头函数初步学习 let 与 const let 块级作用于 const 本质 ES6 声明变量的六种方法 ES6箭头函数 箭头函数与普通
  • CRM常用功能代码

    文章目录 前言 学习任务 一 常用框架 BS入口 方法体 二 常用功能 1 动态Pick 2 简单查询 3 通过值列表Code获取值 获取系统参数 模板 内置参数 4 开关管理员模式 遇到问题及其解决方案 心得总结 前言 学习情况总结 学习
  • ARMv8之arm64架构汇编知识

    1 寄存器 1 1 通用寄存器 31 个R0 R30 每一个寄存器能够存取一个64位大小的数 当使用 x0 x30访问时 是一个 64位的数 当使用 w0 w30访问时 是一个 32 位的数 访问的是寄存器的低32位 如下图所示 1 2 向
  • 线性表的顺序存储实现(数组)

    数据对象集 线性表是个元素构成的有序序列 操作集 线性表 整数i表示位置 元素 线性表主要操作如下 List MakeEmpty 初始化一个空线性表 ElementType FinKth int K List PtrL 根据位序K 返回相应

随机推荐