使用Scipy优化梯度下降问题

目    录

问题重述

附加问题

步骤实施

1.查看Scipy官网SciPy,找到优化有关的模块(Optimize)

2.研究多种优化策略,选择最符合代码的方案进行优化

3.minimize函数参数及其返回值

4.代码展示

5.结果展示

6.进一步优化

6.1对如下函数方法进行优化

6.2基准测试

6.3 发现

测试文件附录

任务清单


问题重述

在二维平面有n个点,如何画一条直线,使得所有点到该直线距离之和最短

如果能找到,请给出其损失函数

附加问题

1.使用Scipy优化上述问题

2.主代码中不得出现任何循环语法,出现一个扣10分

步骤实施

1.查看Scipy官网SciPy,找到优化有关的模块(Optimize)

2.研究多种优化策略,选择最符合代码的方案进行优化

优化方法
名称特点应用场景
Scalar Functions Optimization用于最小化或最大化单个标量函数的,通常用于解决一维问题目标函数只返回一个标量(单个值)
Local (Multivariate) Optimization适用于多变量问题,需要梯度函数,不过会自动寻找梯度更新目标值在参数空间中找到局部最小值或最大值
Global Optimization寻找函数的全局最小值或最大值,包含多个局部最值在计算条件允许的条件下可以得到全局最优解

优化方法
序号名称使用方法适用条件
1Nelder-MeadNelder-Mead单纯形法适用于一般的非线性问题
2PowellPowell方法适合多维非约束优化的方法
3CG共轭梯度法(Conjugate Gradient)适用于二次优化问题或大规模问题
4BFGS拟牛顿BFGS算法适用于大多数非线性优化问题的常用方法,尤其是当梯度信息可用时
5Newton-CG牛顿共轭梯度法适用于大多数非线性优化问题,但相对于BFGS需要更多的内存
6L-BFGS-B限制内存BFGS算法适用于大规模问题,因为它限制了内存使用
7TNC截断牛顿法适用于大多数非线性优化问题,并且能够处理约束条件
8COBYLA约束优化适用于具有约束条件的问题
9SLSQP顺序最小二乘法适用于具有约束条件的问题,并且能够处理线性和非线性约束
10trust-constr信任区域约束优化方法适用于有约束条件的问题,并且可以处理线性和非线性约束
11dogleg信任域Dogleg方法适用于具有约束条件的问题
12trust-ncg信任区域牛顿共轭梯度法适用于约束优化问题
13trust-krylov信任区域Krylov子空间法适用于约束优化问题
14trust-exact精确信任区域方法适用于约束优化问题

 此问题我们需要求最小值,所以我们采用minimize函数,并选择常用的BFGS策略

3.minimize函数参数及其返回值

原型如下:

scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)

挑五个主要的参数讲

1.fun:需要最小化的目标函数

这个函数应该接受一个输入向量,返回一个标量(单个值),表示损失函数的值。

2.x0:起始参数的初始猜测值

通常是一个数组或列表,表示参数的初始估计。

3.args:传递给目标函数的额外参数的元组

如果目标函数需要额外的参数,可以将它们作为元组传递给args参数。

4.method:选择优化方法的字符串

这是一个可选参数,如果未指定,默认使用'Nelder-Mead'方法。可以选择其他方法,

5.jac:表示目标函数的梯度(导数)的函数

如果提供了梯度函数,通常可以加速优化过程。如果不提供,优化算法会尝试数值估计梯度。

所以我们在优化代码的时候,

可以将 calcLoseFunction函数作为fun,

而k,b两个参数打成列表作为x0,

将XData,YData组成元组传递给arg

method选择BFGS

最后jac选择不写,便于对比两者速度差异

其返回值说明如下

1.x:优化的参数值。这是一个数组,包含找到的最优参数。

2.fun:最小化目标函数的最小值(损失函数的最小值)。

3.success:一个布尔值,表示优化是否成功收敛到最小值。

4.message:一个字符串,描述优化的终止消息。

5.nit:迭代次数,表示优化算法运行的迭代次数。

6.nfev:函数调用次数,表示评估目标函数的次数。

7.njev:梯度计算次数,表示计算目标函数梯度的次数(如果提供了梯度函数)。

8.hess_inv:Hessian矩阵的逆矩阵(如果提供了Hessian信息)。

9.jac:目标函数的梯度值。

4.代码展示

import numpy #发现直接用List就行了
import random
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from commonTools import *
# random.random()
# random.randint(start,stop)
#################全局数据定义区
# 数组大小
listSize=10
# 定义学习率 取尽量小0.001
learningRate=0.0001
#定义初始直线的 斜率k 和 截距b 45° 1单位距离
# 现在设置 k=0.5 检验程序
k,b=0.5,1
initialParams=[k,b]
#定义迭代次数
bfsNums=9999
#################全局数据定义区END
# 生成随机数
def generateRandomInteger(start, end):# [1-100]return random.randint(start, end)# 打印本次随机生成的X,Y 便于快速粘贴复现
def printXYArray(XData,YData):# 打印Xprint("[", ",".join([str(i) for i in XData]), "]")# 打印Yprint("[", ",".join([str(i) for i in YData]), "]")#调用公共模块进行打印 便于快速查看粘贴
def printXYData(XData,YData):loc=locals()printArray(XData,loc)printArray(YData,loc)
# 最小二乘法定义损失函数 并计算
#参考链接:https://blog.csdn.net/zy_505775013/article/details/88683460
# 求最小二乘法的最小值 最终结果应当是在learningRate一定情况下  这个最小的sum
def calcLoseFunction(params,XData,YData):k, b = paramssum=0for i in range(0,listSize):# 使用偏离值的平方进行累和sum+=(YData[i]-(k*XData[i]+b))**2return sum#梯度下降法
def calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums):for i in range(0, bfsNums):sumk, sumb = 0, 0for j in range(0, listSize):# 定义预测值Y'normalNum = k * XData[j] + b# 计算逆梯度累和sumk += -(2 / listSize) * (normalNum - YData[j]) * XData[j]sumb += -(2 / listSize) * (normalNum - YData[j])# 在逆梯度的方向上进行下一步搜索k += learningRate * sumkb += learningRate * sumbreturn k, b# 随机生成横坐标
XData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 随机生成纵坐标
YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]
# 纯随机生成 但是可视化效果不直观
# YData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 死值替换区
# XData=testArrayX
# YData=testArrayYprint("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k,b,calcLoseFunction(initialParams,XData,YData)))
# 对k,b进行梯度修正
# k,b=calcGradientCorrection(b,k,XData,YData,learningRate,bfsNums)
#使用Scipy进行求解
result = minimize(calcLoseFunction, initialParams, args=(XData, YData), method='BFGS')
resultk,resultb=result.x
print("修正后:k={},b={},最小损失sum={},最小二乘法损失sums={}".format(resultk,resultb,result.fun,calcLoseFunction([resultk,resultb],XData,YData)))
print("调试数组")
printXYArray(XData,YData)#画图
plt.plot(XData, YData, 'b.')
plt.plot(XData, resultk*numpy.array(XData)+resultb, 'r')
plt.show()
print("END")

5.结果展示

6.进一步优化

两个目标

1.优化损失函数中的for循环

2.对使用Scipy优化前后的代码进行基准测试,比较运行速度

6.1对如下函数方法进行优化
def calcLoseFunction(params,XData,YData):k, b = paramssum=0for i in range(0,listSize):# 使用偏离值的平方进行累和sum+=(YData[i]-(k*XData[i]+b))**2return sum

使用numpy,优化后如下:

def calcLoseFunction(params,XData,YData):XData,YData=np.array(XData),np.array(YData)k, b = paramssum=np.sum((YData - (k * XData + b))**2)return sum

无for优化后代码如下:

import numpy as np
import random
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from commonTools import *#################全局数据定义区
# 数组大小
listSize=10
#定义初始直线的 斜率k 和 截距b 45° 1单位距离
# 现在设置 k=0.5 检验程序
k,b=0.5,1
initialParams=[k,b]
#################全局数据定义区END
# 生成随机数
def generateRandomInteger(start, end):return random.randint(start, end)#调用公共模块进行打印 便于快速查看粘贴
def printXYData(XData,YData):loc=locals()printArray(XData,loc)printArray(YData,loc)# 最小二乘法定义损失函数 并计算
def calcLoseFunction(params,XData,YData):XData,YData=np.array(XData),np.array(YData)k, b = paramssum=np.sum((YData - (k * XData + b))**2)return sum# 随机生成横坐标
XData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 随机生成纵坐标
YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]
# 纯随机生成 但是可视化效果不直观
# YData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 死值替换区
# XData=[ 49,74,62,54,20,14,27,74,23,50 ]
# YData=[ 47,65,56,57,21,21,32,81,27,46 ]print("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k,b,calcLoseFunction(initialParams,XData,YData)))#使用Scipy进行求解
result = minimize(calcLoseFunction, initialParams, args=(XData, YData), method='BFGS')
resultk,resultb=result.x
print("修正后:k={},b={},最小损失sum={},最小二乘法损失sums={}".format(resultk,resultb,result.fun,calcLoseFunction([resultk,resultb],XData,YData)))
print("调试数组")
printXYData(XData,YData)#画图
plt.plot(XData, YData, 'b.')
plt.plot(XData, resultk*np.array(XData)+resultb, 'r')
plt.show()
print("END")

其中公共模块commonTools.py 代码如下:

#########导包区#########说明
#1.想要在公共模块区域使用变量列表 必须传进来 因为彼此的变量作用域不同#########公共变量定义区
#这个locals应该是被引入的界面传进来,而不是从这拿
# loc=locals()#########函数书写区
#1.获取变量名称
def getVariableName(variable,loc):for k,v in loc.items():if loc[k] is variable:return k#附带的打印变量名
def printValue(object,loc):print("变量{}的值是{}".format(getVariableName(object,loc),object))# 2.组装列表为字符串
def mergeInSign(dataList,sign):# print(str(sign).join([str(i) for i in dataList]))return str(sign).join([str(i) for i in dataList])# 3.打印一个列表
def printArray(dataArray,loc):print("列表{}的内容是:".format(getVariableName(dataArray,loc)),\"[", ",".join([str(i) for i in dataArray]), "]"\)

原先的代码如下:

import numpy #发现直接用List就行了
import random
import matplotlib.pyplot as plt
# random.random()
# random.randint(start,stop)
#################全局数据定义区
# 数组大小
listSize=10
# 定义学习率 取尽量小0.001
learningRate=0.0001
#定义初始直线的 斜率k 和 截距b 45° 1单位距离
# 现在设置 k=0.5 检验程序
k,b=0.5,1
#定义迭代次数
bfsNums=9999
#################全局数据定义区END
# 生成随机数
def generateRandomInteger(start, end):# [1-100]return random.randint(start, end)# 打印本次随机生成的X,Y 便于快速粘贴复现
def printXYArray(XData,YData):# 打印Xprint("[", ",".join([str(i) for i in XData]), "]")# 打印Yprint("[", ",".join([str(i) for i in YData]), "]")# 最小二乘法定义损失函数 并计算
#参考链接:https://blog.csdn.net/zy_505775013/article/details/88683460
# 求最小二乘法的最小值 最终结果应当是在learningRate一定情况下  这个最小的sum
def calcLoseFunction(k,b,XData,YData):sum=0for i in range(0,listSize):# 使用偏离值的平方进行累和sum+=(YData[i]-(k*XData[i]+b))**2return sum#梯度下降法
def calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums):for i in range(0, bfsNums):sumk, sumb = 0, 0for j in range(0, listSize):# 定义预测值Y'normalNum = k * XData[j] + b# 计算逆梯度累和  注意这里求偏导应当是两倍 不知道为什么写成1了# 求MSE的偏导sumk += -(2 / listSize) * (normalNum - YData[j]) * XData[j]sumb += -(2 / listSize) * (normalNum - YData[j])# 在逆梯度的方向上进行下一步搜索k += learningRate * sumkb += learningRate * sumbreturn k, b# 随机生成横坐标
XData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 随机生成纵坐标
YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]
# 纯随机生成 但是可视化效果不直观
# YData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 死值替换区
# XData=testArrayX
# YData=testArrayYprint("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k,b,calcLoseFunction(k,b,XData,YData)))
# 对k,b进行梯度修正
k,b=calcGradientCorrection(b,k,XData,YData,learningRate,bfsNums)
print("修正后:k={},b={},最小损失sum={}".format(k,b,calcLoseFunction(k,b, XData, YData)))
print("调试数组")
printXYArray(XData,YData)#画图
plt.plot(XData, YData, 'b.')
plt.plot(XData, k*numpy.array(XData)+b, 'r')
plt.show()
print("END")

 到此,使用scipy并对for循环进行优化已经完成,下面我们使用程序对比优化后时间效率上有没有改进。

6.2基准测试

我们将先后代码的画图部分都注释

目录结构如下:

 test.py代码如下:

import os       #执行调用
import time     #记录时间
DEBUG=False
execFileName="old.py" if DEBUG else "new.py"if __name__=="__main__":startTime = time.time()os.system("python {}".format(execFileName))endTime = time.time()print("文件:{}执行耗时:{}ms".format(execFileName,endTime-startTime))

DEBUG为False

DEBUG为True

额,调用minimize函数在时间上不如自己写的梯度下降。。。。。

多次随机测试后发现结果依旧如此,可能是因为scipy引入了其他策略,导致了执行时间变长

6.3 发现

使用scipy在某种程度上可能能优化执行效率,但是在部分情况下可能耗时会略长于基本实现

测试文件附录

commonTools.py

#########导包区#########说明
#1.想要在公共模块区域使用变量列表 必须传进来 因为彼此的变量作用域不同#########公共变量定义区
#这个locals应该是被引入的界面传进来,而不是从这拿
# loc=locals()#########函数书写区
#1.获取变量名称
def getVariableName(variable,loc):for k,v in loc.items():if loc[k] is variable:return k#附带的打印变量名
def printValue(object,loc):print("变量{}的值是{}".format(getVariableName(object,loc),object))# 2.组装列表为字符串
def mergeInSign(dataList,sign):# print(str(sign).join([str(i) for i in dataList]))return str(sign).join([str(i) for i in dataList])# 3.打印一个列表
def printArray(dataArray,loc):print("列表{}的内容是:".format(getVariableName(dataArray,loc)),\"[", ",".join([str(i) for i in dataArray]), "]"\)

test.py

import os       #执行调用
import time     #记录时间
DEBUG=True
execFileName="old.py" if DEBUG else "new.py"if __name__=="__main__":startTime = time.time()os.system("python {}".format(execFileName))endTime = time.time()print("文件:{}执行耗时:{}ms".format(execFileName,endTime-startTime))

new.py

import numpy as np
import random
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from commonTools import *#################全局数据定义区
# 数组大小
listSize=10
#定义初始直线的 斜率k 和 截距b 45° 1单位距离
# 现在设置 k=0.5 检验程序
k,b=0.5,1
initialParams=[k,b]
#################全局数据定义区END
# 生成随机数
def generateRandomInteger(start, end):return random.randint(start, end)#调用公共模块进行打印 便于快速查看粘贴
def printXYData(XData,YData):loc=locals()printArray(XData,loc)printArray(YData,loc)# 最小二乘法定义损失函数 并计算
def calcLoseFunction(params,XData,YData):XData,YData=np.array(XData),np.array(YData)k, b = paramssum=np.sum((YData - (k * XData + b))**2)return sum# # 随机生成横坐标
# XData=[generateRandomInteger(1,100) for i in range(listSize) ]
# # 随机生成纵坐标
# YData=[XData[i]+generateRandomInteger(-10,10) for i in range(listSize) ]
# 纯随机生成 但是可视化效果不直观
# YData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 死值替换区
XData=[ 49,74,62,54,20,14,27,74,23,50 ]
YData=[ 47,65,56,57,21,21,32,81,27,46 ]print("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k,b,calcLoseFunction(initialParams,XData,YData)))#使用Scipy进行求解
result = minimize(calcLoseFunction, initialParams, args=(XData, YData), method='BFGS')
resultk,resultb=result.x
print("修正后:k={},b={},最小损失sum={},最小二乘法损失sums={}".format(resultk,resultb,result.fun,calcLoseFunction([resultk,resultb],XData,YData)))
print("调试数组")
printXYData(XData,YData)#画图
# plt.plot(XData, YData, 'b.')
# plt.plot(XData, resultk*np.array(XData)+resultb, 'r')
# plt.show()
print("END")

old.py 

import numpy  # 发现直接用List就行了
import random
import matplotlib.pyplot as plt
from commonTools import *
# random.random()
# random.randint(start,stop)
#################全局数据定义区
# 数组大小
listSize = 10
# 定义学习率 取尽量小0.001
learningRate = 0.0001
# 定义初始直线的 斜率k 和 截距b 45° 1单位距离
# 现在设置 k=0.5 检验程序
k, b = 0.5, 1
# 定义迭代次数
bfsNums = 9999#################全局数据定义区END
# 生成随机数
def generateRandomInteger(start, end):# [1-100]return random.randint(start, end)# 打印本次随机生成的X,Y 便于快速粘贴复现
def printXYArray(XData, YData):# 打印Xprint("[", ",".join([str(i) for i in XData]), "]")# 打印Yprint("[", ",".join([str(i) for i in YData]), "]")# 最小二乘法定义损失函数 并计算
# 参考链接:https://blog.csdn.net/zy_505775013/article/details/88683460
# 求最小二乘法的最小值 最终结果应当是在learningRate一定情况下  这个最小的sum
def calcLoseFunction(k, b, XData, YData):sum = 0for i in range(0, listSize):# 使用偏离值的平方进行累和sum += (YData[i] - (k * XData[i] + b)) ** 2return sum# 梯度下降法
def calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums):for i in range(0, bfsNums):sumk, sumb = 0, 0for j in range(0, listSize):# 定义预测值Y'normalNum = k * XData[j] + b# 计算逆梯度累和  注意这里求偏导应当是两倍 不知道为什么写成1了# 求MSE的偏导sumk += -(2 / listSize) * (normalNum - YData[j]) * XData[j]sumb += -(2 / listSize) * (normalNum - YData[j])# 在逆梯度的方向上进行下一步搜索k += learningRate * sumkb += learningRate * sumbreturn k, b# 随机生成横坐标
XData = [generateRandomInteger(1, 100) for i in range(listSize)]
# 随机生成纵坐标
YData = [XData[i] + generateRandomInteger(-10, 10) for i in range(listSize)]
# 纯随机生成 但是可视化效果不直观
# YData=[generateRandomInteger(1,100) for i in range(listSize) ]
# 死值替换区
# XData=[ 49,74,62,54,20,14,27,74,23,50 ]
# YData=[ 47,65,56,57,21,21,32,81,27,46 ]print("初始选取k={},b={}的情况下的损失函数值为sum={}".format(k, b, calcLoseFunction(k, b, XData, YData)))
# 对k,b进行梯度修正
k, b = calcGradientCorrection(b, k, XData, YData, learningRate, bfsNums)
print("修正后:k={},b={},最小损失sum={}".format(k, b, calcLoseFunction(k, b, XData, YData)))
print("调试数组")
printXYArray(XData, YData)# 画图
# plt.plot(XData, YData, 'b.')
# plt.plot(XData, k * numpy.array(XData) + b, 'r')
# plt.show()
print("END")

任务清单

1.算法程序不使用任何for循环(已完成)

2.使用scipy对原先的代码进行优化(已完成)

3.对优化前后代码进行基准测试(已完成)

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

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

相关文章

CDN网络基础入门:CDN原理及架构

背景 互联网业务的繁荣让各类门户网站、短视频、剧集观看、在线教育等内容生态快速发展,互联网流量呈现爆发式增长,自然也面临着海量内容分发效率上的挑战,那么作为终端用户,我们获取资源的体验是否有提升呢? 答案是…

一文了解硬盘AFR年化故障率评估方式和预测方案

目前常用评价硬盘(或者其他硬件产品)有一个关键的指标就是年化故障率(AFR)。年化故障率(AFR)是一种衡量产品可靠性的指标,表示在一年内产品发生故障的概率。 除了年化故障率(AFR&…

Netron可视化深度学习网络结构

有时候,我们构建网络模型想要直观的查看网络详细结构图,但是苦于没有办法。但是有了Netron以后,我们就可以将对应的onnx模型直接可视化,这样不仅可以观察网络的详细结构图,还可以查看网络每一层的具体参数,…

【数据结构】排序算法(二)—>冒泡排序、快速排序、归并排序、计数排序

👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.冒泡排序 2.快速排序 2.1Hoare版 2.2占…

C++入门

一、C关键字 C总计63个关键字,C语言32个关键字。 二、命名空间 在C/C中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存 在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称…

谁“动”了我的信息?

通信公司“内鬼” 批量提供手机卡 超6万张手机卡用来发涉赌短信 2023年10月2日,据报道2022年12月,湖北省公安厅“雷火”打击整治治安突出问题专项行动指挥部研判发现,有人在湖北随州利用虚拟拨号设备GOIP发出大量赌博短信。随州市公安局研判…

【最新】如何在CSDN个人主页左侧栏添加二维码?侧边推广怎么弄?

目录 引言 效果展示 步骤讲解 引言 当你决定在CSDN上展示自己的技术才能和项目时,💡 将你的个人主页变得更炫酷和引人注目是必不可少的!在这篇博客中,我们将向你揭开神秘的面纱,教你如何在CSDN个人主页的左侧栏上添…

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型 1. 准备工作1.1 安装RabbitMQ1.2 简单部署搭建设计1.3 参考官网 2. RabbitMQ 形成集群的方法3. 搭建RabbitMQ集群3.1 部署架构3.2 rabbitmq集群基础知识3.2.1 关于节点名称(标识符)3.2.…

Java常见API---split()

package daysreplace;public class SplitTest {public static void main(String[] args) {String str"武汉市|孝感市|长沙市|北京市|上海市";String[] array str.split("\\|");System.out.println(array[0]);System.out.println(array[1]);System.out.pri…

【C++】一文带你走入vector

文章目录 一、vector的介绍二、vector的常用接口说明2.1 vector的使用2.2 vector iterator的使用2.3 vector空间增长问题2.4 vector 增删查改 三、总结 ヾ(๑╹◡╹)ノ" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)ノ" 一、vector的介绍 vector…

golang gin——文件上传(单文件,多文件)

文件上传 单文件上传 从form-data获取文件 package uploadimport ("github.com/gin-gonic/gin""net/http" ) // 单文件上传,多文件上传 func Upload(c *gin.Context) {file, _ : c.FormFile("file") // file为字段名dst : "…

nodejs开发环境搭建

Nodejs是一个开源的、跨平台JavaScript运行时环境,其使用V8引擎对JavaScript脚本执行解释,在前后端分离的应用架构设计中,其既能支持web页面服务应用的开发、也能支持后端接口服务应用的开发,类似于Java语言的J2EE运行时环境&…

安装matplotlib__pygame,以pycharm调入模块

安装pip 安装matplotlib 安装完毕,终端输入pip list检查 导入模块出现bug,发现不是matplotlib包的问题,pycharm版本貌似不兼容,用python编辑器可正常绘图,pygame也可正常导入。 ​​​​​​​ pycharm版本问题解决 终…

【Spring笔记02】Spring中的IOC容器和DI依赖注入介绍

这篇文章,主要介绍一下Spring中的IOC容器和DI依赖注入两个概念。 目录 一、IOC控制反转 1.1、什么是IOC 1.2、两种IOC容器 (1)基于BeanFactory的IOC容器 (2)基于ApplicationContext的IOC容器 二、DI依赖注入 2.…

stm32-SPI协议

SPI协议详解(图文并茂超详细) SPI通讯协议 于是我们想有没有更好一点的串行通讯方式;相比较于UART,SPI的工作方式略有不同。 SPI是一个同步的数据总线,也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和…

MySQL中的 增 删 查 改(CRUD)

目录 新增 insert into 表名 value(数据,数据),.......; insert into 表名(列1,列2.....) value(数据,数据),.......; datatime 类型的数据如何插入? 查询 select * from 表名…

动态调整系统主题色(4): CssVar 与 Variant 方案的探索

动态调整系统主题色(4): CssVar 与 Variant 方案的探索 动态调整系统主题色(4): CssVar 与 Variant 方案的探索 前言方案的介绍与比较 CssVar (CSS 变量方案)CSS 变量方案与 tailwindcss 的结合Variant 方案 2种方案在小程序上的示例之前的几篇 前言 这篇已经是动态调整系统…

Docker 的数据管理与Docker 镜像的创建

------------------Docker 的数据管理--------------------- 管理 Docker 容器中数据主要有两种方式:数据卷(Data Volumes)和数据卷容器(DataVolumes Containers)。 1.数据卷 数据卷是一个供容器使用的特殊…

什么是Vue的JSX语法?如何使用JSX语法

Vue的JSX语法:更接近JavaScript的模板语言 Vue.js是一个流行的JavaScript框架,用于构建交互式的Web应用程序。虽然Vue通常使用模板语法来构建用户界面,但它也提供了JSX语法的支持,使开发人员能够更接近JavaScript的表达方式来构建…

分享几个优秀开源免费管理后台模版,建议收藏!

大家好,我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面,帮助大家快速搭建前端页面。为什么要用模板?道理很简单,原因是方便我们快速开发。我们不应该花太多的时间在页面调整上,而应该把精力放在核心逻辑和…