用梯度下降的方式来拟合曲线

news2024/9/20 0:55:25

文章目录

    • 1. 简述
    • 2. 理论原理
      • 以二次函数为例
      • 整体的梯度下降步骤:
    • 3. 编码实现
      • 初始化权重矩阵
      • 计算损失和梯度
      • 更新权重
    • 4. 结果
      • 首先对上一篇文章中的真实数据拟合。
      • 测试拟合高次曲线方程
        • 数据是2阶的,拟合方程是2阶的
        • 数据是4阶的,拟合方程也是4阶的。
        • 方程是4阶的,拟合方程是3阶的,(测试欠拟合)
        • 方程式4阶的,拟合方程是5阶的,(测试过拟合)
        • 数据是2阶的,方程是4阶的 (测试过拟合)
    • 5. 总结
    • 6. 还有可做的可视化方向
    • 完整源码

1. 简述

在之前的一篇文章opencv C++ 曲线拟合中为了拟合一条二次曲线,用超定方程的理论转为求最小二乘的方式来做,这是一个解析的方式求的解,也是全局最优的解。在深度学习中学到的函数是非常复杂的,不能保证是凸的,也没办法从解析的角度来计算一个最优解,这时最有效常用的方法就是梯度下降,为了加深对梯度下降的理解,所以这里以梯度下降来拟合多项式函数来探索一下。

2. 理论原理

以二次函数为例

设函数为 f ( x ) = a 0 + a 1 x + a 2 x 2 f(x)=a_0+a_1x+a_2x^2 f(x)=a0+a1x+a2x2,确定一组 a 0 , a 1 , a 2 a_0,a_1,a_2 a0,a1,a2的值,也就确定了二次函数,所以可以认为一组 a 0 , a 1 , a 2 a_0,a_1,a_2 a0,a1,a2值就是一个模型了。

样本为 ( x , y ) (x,y) (x,y) y ^ \hat{y} y^为模型的预测值,要评价一个模型好不好,我们可以用残差总和(loss)来表示,残差总和越小,模型越好。那我们的目标就是找一组 a 0 , a 1 , a 2 a_0,a_1,a_2 a0,a1,a2的值,使得下面的式子:
l o s s = Σ i = 1 N ∥ y i − y i ^ ∥ 2 2 loss = \Sigma_{i=1}^{N}\|y_i - \hat{y_i} \|_2^2 loss=Σi=1Nyiyi^22
最小即可。虽然在很多场合都会用MSE均方误差来做损失函数,但是为了方便手动计算梯度,就不用MSE了,两者回归出来的最优值是一样的。


W = [ a 0 a 1 a 2 ] W = \begin{bmatrix} a_0 \\ a_1 \\ a_2 \end{bmatrix} W= a0a1a2 , Z = [ 1 x x 2 ] Z = \begin{bmatrix} 1 \\ x \\ x^2 \end{bmatrix} Z= 1xx2 ,则 f ( x ) f(x) f(x)可以写为 f ( x ) = W T Z f(x)=W^TZ f(x)=WTZ

整体的梯度下降步骤:

  1. 初始化权重W
    直接随机初始化
  2. 计算拟合损失

    对每一组数据 z i z_i zi, y i y_i yi in (Z,Y), l o s s i = ( y i − y i ^ ) 2 = ( y i − W T z i ) 2 = ( y i − ( w 1 z i 1 + w 2 z i 2 + w 3 z i 3 ) ) 2 loss_i =(y_i-\hat {y_i})^2 = (y_i - W^T z_i)^2 = (y_i - (w_1z_{i1} + w_2z_{i2} + w_3z_{i3}))^2 lossi=(yiyi^)2=(yiWTzi)2=(yi(w1zi1+w2zi2+w3zi3))2

l o s s i loss_i lossi W W W的梯度就是 ∇ = [ − 2 ( y i − ( w 1 z i 1 + w 2 z i 2 + w 3 z i 3 ) z i 1 − 2 ( y i − ( w 1 z i 1 + w 2 z i 2 + w 3 z i 3 ) z i 2 − 2 ( y i − ( w 1 z i 1 + w 2 z i 2 + w 3 z i 3 ) z i 3 ] \nabla = \begin{bmatrix} -2(y_i - (w_1z_{i1} + w_2z_{i2} + w_3z_{i3})z_{i1} \\ -2(y_i - (w_1z_{i1} + w_2z_{i2} + w_3z_{i3})z_{i2} \\ -2(y_i - (w_1z_{i1} + w_2z_{i2} + w_3z_{i3})z_{i3} \end{bmatrix} = 2(yi(w1zi1+w2zi2+w3zi3)zi12(yi(w1zi1+w2zi2+w3zi3)zi22(yi(w1zi1+w2zi2+w3zi3)zi3
4. 更新权重W
W t + 1 = W t − η ∇ W_{t+1}=W_t -\eta \nabla Wt+1=Wtη η \eta η为学习率;
5. 输入下一个数据,重复步骤2,直到误差小于一定值或者迭代次数达到设定上限。

3. 编码实现

初始化权重矩阵

  
    def init_weights(self, order_of_polynomial):
        """init_weights 按照多项式阶数生成一个 阶数行1列的权重矩阵
        例如;order_of_polynomial为3,则生成的W为

        [[random1],
         [random2],
         [random3]]

        Args:
            order_of_polynomial (_type_): _description_

        Returns:
            weights: 阶数行1列的权重矩阵
        """
        W = np.random.randn(order_of_polynomial, 1)
        W = np.array(W,dtype=np.float)
        return W

计算损失和梯度

loss_i = (yi-y_pred)**2

gradient_i = (-2*(yi-y_pred)*zi).T # 和zi维度一样,(n,) 后一个维度为空

更新权重


    def update(self, W, gradient, learning_rate):
        """update 更新权重

        Args:
            W (np array): nx1的array
            gradient (np array): nx1的array
            learning_rate (float): 学习率

        Returns:
            weights: 更新后的权重
        """
        W = W - learning_rate*gradient
        return W

4. 结果

首先对上一篇文章中的真实数据拟合。

opencvC++曲线拟合
在epoches = 10000
learning_rate = 0.0001的条件下获得的结果。
在这里插入图片描述
权重矩阵:

W_best:[[ 0.97192164 -0.00196608 -0.00102088]]

在上一篇文章中用解析的方式球的的结果是
拟合方程:f(x) = [0.97301156] + ([-0.00231144]*x) + ([-0.00109041]*x^2)

从图像的拟合结果和对比最小二乘解的权重矩阵,可以发现最后的误差是很小的。
Wonderful!!!

测试拟合高次曲线方程

测试的样本我们可以先随机生成一个系数矩阵A,然后在x的某个区间内随机采样一些点X,用A和X来生成Y,这样的话我们用X,Y来拟合得到一个系数矩阵,和真实的A对比就知道误差怎么样了。

数据是2阶的,拟合方程是2阶的

8100/10000,loss: [3.51305315], min loss [3.51305315],learning rate : 1e-05
weights : [[-4.66950745  1.85807499]], W_best:[[-4.66950745  1.85807499]]
8200/10000,loss: [3.42047123], min loss [3.42047123],learning rate : 1e-05
weights : [[-4.67867211  1.8609997 ]], W_best:[[-4.67867211  1.8609997 ]]
8300/10000,loss: [3.33339115], min loss [3.33339115],learning rate : 1e-05
weights : [[-4.68756034  1.863836  ]], W_best:[[-4.68756034  1.863836  ]]
8400/10000,loss: [3.25148594], min loss [3.25148594],learning rate : 1e-05
weights : [[-4.69618048  1.86658659]], W_best:[[-4.69618048  1.86658659]]
8500/10000,loss: [3.17444808], min loss [3.17444808],learning rate : 1e-05
weights : [[-4.70454061  1.86925406]], W_best:[[-4.70454061  1.86925406]]
8600/10000,loss: [3.10198832], min loss [3.10198832],learning rate : 1e-05
weights : [[-4.71264857  1.87184095]], W_best:[[-4.71264857  1.87184095]]
8700/10000,loss: [3.0338346], min loss [3.0338346],learning rate : 1e-05
weights : [[-4.72051196  1.87434969]], W_best:[[-4.72051196  1.87434969]]
8800/10000,loss: [2.96973104], min loss [2.96973104],learning rate : 1e-05
weights : [[-4.72813815  1.87678267]], W_best:[[-4.72813815  1.87678267]]
8900/10000,loss: [2.90943694], min loss [2.90943694],learning rate : 1e-05
weights : [[-4.7355343   1.87914216]], W_best:[[-4.7355343   1.87914216]]
9000/10000,loss: [2.85272592], min loss [2.85272592],learning rate : 1e-05
weights : [[-4.74270734  1.88143041]], W_best:[[-4.74270734  1.88143041]]
9100/10000,loss: [2.79938505], min loss [2.79938505],learning rate : 1e-05
weights : [[-4.74966401  1.88364956]], W_best:[[-4.74966401  1.88364956]]
9200/10000,loss: [2.74921405], min loss [2.74921405],learning rate : 1e-05
weights : [[-4.75641082  1.88580172]], W_best:[[-4.75641082  1.88580172]]
9300/10000,loss: [2.70202456], min loss [2.70202456],learning rate : 1e-05
weights : [[-4.76295412  1.8878889 ]], W_best:[[-4.76295412  1.8878889 ]]
9400/10000,loss: [2.65763939], min loss [2.65763939],learning rate : 1e-05
weights : [[-4.76930002  1.88991308]], W_best:[[-4.76930002  1.88991308]]
9500/10000,loss: [2.61589189], min loss [2.61589189],learning rate : 1e-05
weights : [[-4.77545449  1.89187616]], W_best:[[-4.77545449  1.89187616]]
9600/10000,loss: [2.57662531], min loss [2.57662531],learning rate : 1e-05
weights : [[-4.78142331  1.89377998]], W_best:[[-4.78142331  1.89377998]]
9700/10000,loss: [2.53969223], min loss [2.53969223],learning rate : 1e-05
weights : [[-4.78721206  1.89562634]], W_best:[[-4.78721206  1.89562634]]
9800/10000,loss: [2.50495396], min loss [2.50495396],learning rate : 1e-05
weights : [[-4.79282619  1.89741698]], W_best:[[-4.79282619  1.89741698]]
9900/10000,loss: [2.47228008], min loss [2.47228008],learning rate : 1e-05
weights : [[-4.79827095  1.89915358]], W_best:[[-4.79827095  1.89915358]]
true weights:[-5  2],predicted weights:[[-4.80349946  1.90082118]]

在这里插入图片描述

数据是4阶的,拟合方程也是4阶的。

true weights:[-10  -9   6  -5],predicted weights:[[-9.94695159 -9.02171446  5.97634426 -5.00084477]]

在这里插入图片描述

方程是4阶的,拟合方程是3阶的,(测试欠拟合)

true weights:[-10  -6   9  10],predicted weights:[[-8.23658869 49.58531876 10.11229995]]

在这里插入图片描述

方程式4阶的,拟合方程是5阶的,(测试过拟合)

true weights:[ 1 -9 -2 10],predicted weights:[[ 0.96926572 -7.09732105 -1.80982351  9.71279898 -0.03855437]]

在这里插入图片描述

数据是2阶的,方程是4阶的 (测试过拟合)

true weights:[10 -5],predicted weights:[[ 8.15489344 -3.46121244  0.75647929 -0.39215996]]

在这里插入图片描述

5. 总结

对于欠拟合的系统,模型的容量无法完整的表示数据,对于过拟合的系统,模型容量比较富余,当增加增加样本后模型的泛化能力就可以提高。在上面的过拟合的例子中增加样本数就可以更好的拟合真实的多项式。
在阶次较高的数据中,当x比较大时,计算中容易产生nan,所以这里的梯度下降并不能完全解决多项式拟合的问题,主要是在数值计算上,初始化在某些地方模型不收敛。但是这个项目对于理解梯度下降是一个非常好的角度,手动计算梯度,手动更新权重…。

6. 还有可做的可视化方向

查看权重的走向:
以2阶的方程为例,设权重为w1,w2, 以w1和w2为平面坐标的两个轴,对平面上的每一点(每一个都表示一个权重矩阵)都计算一次模型对数据的拟合损失,这样可以得到一个loss(w1,w2)的函数,用mesh可视化这个二维函数就可以知道在不同地方的损失,标记best weights的移动位置就可以更形象的看到梯度下降导致的权重矩阵的走向了。

完整源码


import numpy as np
import matplotlib.pyplot as plt
import random


class MyModule():
    def __init__(self) -> None:
        pass
        
    def init_weights(self, order_of_polynomial):
        """init_weights 按照多项式阶数生成一个 阶数行1列的权重矩阵
        例如;order_of_polynomial为3,则生成的W为

        [[random1],
         [random2],
         [random3]]

        Args:
            order_of_polynomial (_type_): _description_

        Returns:
            weights: 阶数行1列的权重矩阵
        """
        W = np.random.randn(order_of_polynomial, 1)
        W = np.array(W,dtype=np.float)
        return W

    def update(self, W, gradient, learning_rate):
        """update 更新权重

        Args:
            W (np array): nx1的array
            gradient (np array): nx1的array
            learning_rate (float): 学习率

        Returns:
            weights: 更新后的权重
        """
        W = W - learning_rate*gradient
        return W

    def trans_to_struct_data(self, X, order_of_polynomial):
        """_trans_to_struct_data 把x转为范德蒙德矩阵形式的变量

        Args:
            X (np array): nx1
            order_of_polynomial (int): 多项式的阶数

        Returns:
            Z: np array,[[1,x,x^2,x^3,...,x^order_of_polynomial],...]
        """
        sample_num = X.shape[0] 
        Z = np.zeros((sample_num, order_of_polynomial),dtype=np.float32)
        mul_item = np.ones((sample_num,))
        for i in range(order_of_polynomial):
            Z[:,i] = mul_item
            mul_item *= X
        return Z

    def fit(self,X, Y, order_of_polynomial, epoches=30, learning_rate=0.001):
        """fit 根据指定的阶数拟合曲线

        Args:
            X (_type_): _description_
            Y (_type_): _description_
            order_of_polynomial (): 拟合多项式的阶数,至少是一阶的
        """
        if order_of_polynomial < 1:
            raise ValueError("拟合多项式的阶数,至少是一阶的")
              
        W = self.init_weights(order_of_polynomial)
        W_best = W
        min_loss = 99999999999999
        Z = self.trans_to_struct_data(X, order_of_polynomial)
        for epoch in range(epoches):
            gradient = np.zeros((order_of_polynomial, 1)) # nx1的矩阵
            loss = 0.0
            for zi,yi in zip(Z,Y):
                # yi 是标量,一个数
                # zi 是一个样本,长为n的向量,numpy中没有像矩阵一样有两个维度
                # W 权重,nx1矩阵
                y_pred = np.dot(W.T, zi) # 预测值
                loss_i = (yi-y_pred)**2
                # gradient_i = np.array([2*zi]).T # 一维向量-2*zi转为矩阵后的转置,nx1
                
                gradient_i = (-2*(yi-y_pred)*zi).T # 和zi维度一样,(n,) 后一个维度为空
                gradient_i = np.array([gradient_i]).T # 增加一个维度,和gradient一致
                W = self.update(W,gradient_i,learning_rate)
                loss += loss_i
                gradient += gradient_i
            # W = self.update(W,gradient,learning_rate)
            if loss < min_loss:
                min_loss = loss
                W_best = W
            if epoch % 100 ==0:
                print(f"{epoch}/{epoches},loss: {loss}, min loss {min_loss},learning rate : {learning_rate}")
                print(f"weights : {W.T}, W_best:{W_best.T}")
        return W_best


def dataset_pool_n(n, sample_num=100, max_abs_x=1, if_rand=False):
    """生成随机多项式分布的样本

    Args:
        n (int): 阶数
        sample_num (int, optional): 生成的样本数量. Defaults to 100.
        max_abs_x (int, optional): x的最大值. Defaults to 1.
        if_rand (bool, optional): 为True时,在标准的数据上加随机波动,. Defaults to False.

    Returns:
        _type_: _description_
    """
    # 系数矩阵,标准的多项式系数
    A = [] # a0+a1x+a2x+...
    for i in range(n):
        A.append(random.randint(-10,10)) # 系数的绝对值在10以内,太大了的话次数高的数值太大
    A = np.array(A)
    
    # 随机生成一些x
    X = []
    for i in range(sample_num):
        x = 1 - 2*random.random()
        x *= max_abs_x
        X.append(x)
    Z = np.zeros((sample_num, n))
    mul_item = np.ones((sample_num,))
    for i in range(n):
        Z[:,i] = mul_item
        mul_item *= X
    
    # 用A和Z计算Y
    Y = []
    for zi in Z:
        y = np.dot(A,zi) 
        if if_rand:
            y += + (0.5 - random.random())
        Y.append(y)
    return A,np.array(X),np.array(Y)



def dataset_pool_two():
    X = np.array([-10.,  -9.,  -8.,  -7.,  -6.,  -5.,  -4.,  -3.,  -2.,  -1.,   0.,
         1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.], np.float)
    Y = np.array([0.890928, 0.904723, 0.921421, 0.935007, 0.94281 , 0.949828,
        0.966265, 0.975411, 0.978693, 0.97662 , 0.974468, 0.967101,
        0.957691, 0.958369, 0.949841, 0.932791, 0.9213  , 0.901874,
        0.879374, 0.868257], np.float)
    return X,Y



def main():
    
    order_of_polynomial_for_data_generation = 4 # 生成数据时用的阶数
    sample_num = 100 # 样本数量
    max_abs_x = 3 # x的最大值,当方程次数较高时,x值太大容易导致计算中产生nan
    if_rand = True # 为True时,在标准的数据上加随机波动,

    # X, Y = dataset_pool_linear()
    # X, Y = dataset_pool_two()
    A, X, Y = dataset_pool_n(order_of_polynomial_for_data_generation, sample_num, max_abs_x, if_rand)
    
    epoches = 10000
    learning_rate = 0.00001
    
    model = MyModule()
    order_of_polynomial_for_fit = 4 # 拟合数据时用的阶数
    W = model.fit(X,Y,order_of_polynomial_for_fit,epoches,learning_rate)

    print(f"true weights:{A},predicted weights:{W.T}")

    # 可视化
    X_axis = np.arange(-max_abs_x, max_abs_x,2*max_abs_x/sample_num)
    Z = model.trans_to_struct_data(X_axis,order_of_polynomial_for_fit)
    Y_pred = [np.dot(W.T,zi) for zi in Z]
    Y_pred = np.array(Y_pred)
    plt.scatter(X,Y,label="true sample")
    plt.plot(X_axis,Y_pred,c='red',label="predicted curve")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.title("fit curve")
    plt.legend()
    plt.grid(True)
    plt.show()
    
    

if __name__ == '__main__':

    main()

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/448472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3年自动化测试(心路历程),从月薪10k到30k我经历了什么?

前言 2018年的时候&#xff0c;由于项目的原因&#xff0c;开始使用Robot Framework测试框架&#xff0c;正因为有Python的基础所以很快就理解了Robot Framework框架的工作原理&#xff0c;并可以根据项目的需要开发系统关键字。2019年随着移动App越来越流行&#xff0c;乘着换…

HTML5超链接和图片基础用法

一、HTML5 超链接&#xff08;链接&#xff09; 超链接可以是一个文本&#xff0c;也可以是一幅图像&#xff0c;您可以点击这些内容来跳转到新的页面或新的文档或者当前文档中的某个部分。 当您把鼠标指针移动到网页中的某个链接上时&#xff0c;箭头会变为一只小手。 1.我…

MATLAB | MATLAB配色不够用,近2000款配色来啦

MATLAB绘图配色不够多&#xff1f;很多python\R语言绘图包都会带着好几套配色方案&#xff0c;比如很常见的ggsci绘图包就自带45套离散配色&#xff0c;于是本工具收集了常见55个绘图包中的离散配色&#xff0c;制作出了这个包含了1967套配色的离散配色包slanCL。 基本使用 以…

机器学习(二):线性回归之梯度下降法

文章目录 专栏导读1、梯度下降法原理2、梯度下降法原理代码实现3、sklearn内置模块实现专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知识。 ✍ 本文录入于《机器学习案例》,本专栏精选了经典的机器学习算法进行讲解,针对大学生、初级数据分…

CleanMyMac4.13最新免费mac电脑系统优化软件

CleanMyMac免费mac下载版是一款简单实用的PC清洁管理工具&#xff0c;电脑刚装完系统的时候运行速度超级快&#xff0c;随着时间的推移&#xff0c;你会发现越来越慢&#xff0c;经常会反应卡顿&#xff0c;越来越多的垃圾文件占用了你的磁盘空间&#xff0c;各种过时的日志&am…

数组题目总结 -- 前缀和数组

目录 一. 区域和检索 - 数组不可变1. 思路和代码I. 博主的做法&#xff1a;II. 东哥的做法&#xff1a; 2. 总结 二. 二维区域和检索 - 矩阵不可变1. 思路和代码I. 博主的做法&#xff1a;II. 东哥的做法&#xff1a; 2. 总结 一. 区域和检索 - 数组不可变 题目链接&#xff1…

【方法一:二分+字符串哈希 优化】【dp——取不取问题-背包】最长公共子串【上海交通大学考研机试题】

最长公共子串 二分方法字符串哈希的复习字符串哈希 如何理解 二分代码 dp方法字符串str1中以第i个字符为结尾的子串 与字符串str2中以第i个字符为结尾的子串的连续公共子串 二维一维优化 二分方法 由于这个题是要求求子串&#xff0c;而子串是连续的一段&#xff0c;所以用二分…

在微信小程序中怎么使用vant框架?

目录标题 首先介绍什么是vant一、第一步&#xff0c;打开我们小程序项目目录&#xff0c;找到所在的位置&#xff0c;打开终端二、对项目进行初始化三、进行安装依赖1、通过npm安装vant/weapp2、安装miniprogram 四、修改app.json五、修改project.config.json六、然后构建npm 需…

使用Word的一些技巧记录

本文主要用于记录书写毕业论文时&#xff0c;遇到的Word的使用技巧。 设置样式及多级列表 每个学校必然会对论文中的字体、字号、行间距提出要求&#xff0c;设置Word中样式解决此问题。 例如&#xff0c;本校的格式要求为&#xff1a; 正文中的一级标题&#xff08;章目&a…

【C#】GridControl动态更换DataSource,查询数据异常处理

系列文章 【C#】单号生成器&#xff08;编号规则、固定字符、流水号、产生业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…

适应大、中、小型医院的手术麻醉临床信息管理系统源码

手术麻醉管理系统是一款专门用于医院手术麻醉管理的软件系统&#xff0c;它可以帮助医院和医生更好地管理手术麻醉过程&#xff0c;提高手术麻醉的质量和安全性。本文将介绍手术麻醉管理系统的实现、功能概述、主要功能、系统设置、麻醉管理、术中记录、苏醒室记录、PCA实施及管…

【微服务笔记20】微服务组件之Nacos配置中心基础环境搭建、配置持久化、动态刷新配置

这篇文章&#xff0c;主要介绍微服务组件之Nacos配置中心基础环境搭建、配置持久化、动态刷新配置。 目录 一、搭建Nacos配置中心环境 1.1、Nacos配置中心介绍 1.2、搭建Nacos配置中心客户端 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;添加配置信息 &…

图书管理系统的开发与设计(论文+源码)_kaic

摘 要 随着科学技术的快速发展&#xff0c;尤其是计算机技术的突飞猛进&#xff0c;计算机技术普及到日常生活、学习生活的方方面面。由此想到学校的相对于传统的图书管理系统&#xff0c;帮助到学校的读者和学校的图书管理员的系统。提升图书管工作人员的效率&#xff0c;满足…

【C++类和对象】类和对象(中):构造函数 {六个默认成员函数;构造函数的概念及特性;编译器自动生成的构造函数;默认构造函数}

一、类的六个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器…

Pytorch深度学习笔记(六)用pytorch实现线性回归

目录 1.数据准备 2.设计模型 3.构造损失函数和优化器 4.训练周期&#xff08;前馈—>反馈—>更新&#xff09; 课程推荐&#xff1a;05.用PyTorch实现线性回归_哔哩哔哩_bilibili 线性通常是指变量之间保持等比例的关系&#xff0c;从图形上来看&#xff0c;变量之间…

为什么要学习微服务?

文章目录 1.认识微服务1.1微服务由来1.2为什么需要微服务&#xff1f; 2.两种架构2.1.单体架构2.2.分布式架构 3.微服务的特点4.SpringCloud5.总结最后说一句 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为…

类和对象(上篇)

类和对象----上篇 &#x1f506;面向过程和面向对象的初步认识&#x1f506;类的引入&#x1f506;类的定义&#x1f506;类的访问限定符及封装访问限定符封装 &#x1f506;类的作用域&#x1f506;类的实例化&#x1f506;类的对象大小的计算如何计算一个类的大小结构体内存对…

15天学习MySQL计划(多表联查)第四天

15天学习MySQL计划&#xff08;多表联查&#xff09;第四天 1.多表查询 1.1概述 ​ 指从多张表中查询数据 ​ 在项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互…

【HCIP】Huawei设备下IPV4IPV6共存实验

目录 方法一、普通的GRE将V6基于V4通讯 方法二、6to4的tunnel 方法三、双栈 方法一、普通的GRE将V6基于V4通讯 //方法一和方法二的前提&#xff0c;搭个简单的V4网络就行 [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip address 12.1.1.1 24 [r1]router id 1.1.1.1 [r1-Gigabi…

Spring Security 05 密码加密

目录 DelegatingPasswordEncoder 使用 PasswordEncoder 密码加密实战 密码自动升级 实际密码比较是由PasswordEncoder完成的&#xff0c;因此只需要使用PasswordEncoder 不同实现就可以实现不同方式加密。 public interface PasswordEncoder {// 进行明文加密String encod…