STM32 FreeRTOS 非阻塞延时实战:用 APP_Time_IsElapsed 让多任务和平共处
2026/5/8 2:13:51
学习目标:理解多变量函数的导数,掌握梯度的概念和性质
预计时间:15-20分钟
前置知识:导数基础(3.1)
偏导数概念 → 偏导数计算 → 梯度定义 → 梯度性质 → 实际应用生活类比:房价受面积和楼层影响,偏导数告诉我们"只改变一个因素"时的变化
场景:你在看房
- 100平米,10楼,价格210万
问题1:如果面积增加到101平米(楼层不变),价格变多少?
- 答案:增加2万 → 这就是"对面积的偏导数" = 2
问题2:如果楼层升到11楼(面积不变),价格变多少?
- 答案:增加0.5万 → 这就是"对楼层的偏导数" = 0.5
偏导数 = 只改变一个变量,看结果变化多少
importnumpyasnpimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3D# 解决中文显示问题plt.rcParams['font.sans-serif']=['Arial Unicode MS','SimHei','Microsoft YaHei','STHeiti']plt.rcParams['axes.unicode_minus']=False# 例子:房价函数# price = 2 * area + 0.5 * floordefhouse_price(area,floor):return2*area+0.5*floor# 偏导数# ∂price/∂area = 2 (面积每增加1平米,价格增加2万)# ∂price/∂floor = 0.5(楼层每增加1层,价格增加0.5万)area=100floor=10price=house_price(area,floor)print(f"📊 房价分析:")print(f"当前房价:{price}万元({area}平米,{floor}楼)")print(f"\n💡 偏导数的含义:")print(f"∂price/∂area = 2 → 面积增加1平米,价格增加2万")print(f"∂price/∂floor = 0.5 → 楼层增加1层,价格增加0.5万")print(f"\n🔮 实际应用:")print(f"如果换成101平米(楼层不变):{house_price(101,floor)}万元(+2万)")print(f"如果换成11楼(面积不变):{house_price(area,11)}万元(+0.5万)")# 3D可视化fig=plt.figure(figsize=(10,6))ax=fig.add_subplot(111,projection='3d')area_range=np.linspace(50,150,30)floor_range=np.linspace(1,20,30)A,F=np.meshgrid(area_range,floor_range)P=house_price(A,F)ax.plot_surface(A,F,P,cmap='viridis',alpha=0.8)ax.set_xlabel('面积(平米)')ax.set_ylabel('楼层')ax.set_zlabel('价格(万元)')ax.set_title('房价函数')plt.show()📊 3D图解读:
关键观察:
斜面形状
沿着"面积"方向看(固定楼层)
沿着"楼层"方向看(固定面积)
颜色含义
💡 偏导数就是这个斜面在不同方向上的倾斜程度!
importnumpyasnp# 数值方法计算偏导数defpartial_derivative_x(f,x,y,h=1e-5):"""对x的偏导数"""return(f(x+h,y)-f(x,y))/hdefpartial_derivative_y(f,x,y,h=1e-5):"""对y的偏导数"""return(f(x,y+h)-f(x,y))/h# 例子:f(x, y) = x² + 2xy + y²deff(x,y):returnx**2+2*x*y+y**2x,y=3,4# 计算偏导数df_dx=partial_derivative_x(f,x,y)df_dy=partial_derivative_y(f,x,y)print(f"f({x},{y}) ={f(x,y)}")print(f"∂f/∂x ={df_dx:.4f}(理论值: 2x + 2y ={2*x+2*y})")print(f"∂f/∂y ={df_dy:.4f}(理论值: 2x + 2y ={2*x+2*y})")生活类比:爬山时,梯度指向最陡的上坡方向
场景:你在山上迷路了,想快速下山
方法1:随便走 → 可能走到平地,甚至上坡
方法2:每次都朝最陡的下坡方向走 → 最快下山!梯度就是告诉你"最陡的方向":
- 梯度方向 = 最陡的上坡方向(函数增长最快)
- 负梯度方向 = 最陡的下坡方向(函数下降最快)
AI训练就是"下山":
- 山顶 = 损失大(模型很差)
- 山谷 = 损失小(模型很好)
- 梯度下降 = 沿着最陡的路下山(优化模型)
importnumpyasnpimportmatplotlib.pyplotasplt# 解决中文显示问题plt.rcParams['font.sans-serif']=['Arial Unicode MS','SimHei','Microsoft YaHei','STHeiti']plt.rcParams['axes.unicode_minus']=False# 例子:损失函数 L(w, b) = (w-3)² + (b-2)²# 最小值在 (3, 2)defloss(w,b):return(w-3)**2+(b-2)**2# 梯度 = [∂L/∂w, ∂L/∂b]defgradient(w,b):dL_dw=2*(w-3)dL_db=2*(b-2)returnnp.array([dL_dw,dL_db])# 在不同点计算梯度points=[(0,0),(1,1),(2,2),(3,2),# 最小值点]print("📊 不同位置的梯度:")forw,binpoints:L=loss(w,b)grad=gradient(w,b)grad_magnitude=np.linalg.norm(grad)print(f"点({w},{b}): 损失={L:.2f}, 梯度={grad}, 梯度大小={grad_magnitude:.2f}")print("\n💡 观察:")print("- 离最优点越远,梯度越大(下山越陡)")print("- 在最优点(3, 2),梯度=[0, 0](到达山谷底部)")# 可视化w_range=np.linspace(-1,7,100)b_range=np.linspace(-1,5,100)W,B=np.meshgrid(w_range,b_range)L=loss(W,B)plt.figure(figsize=(10,6))contour=plt.contour(W,B,L,levels=20,cmap='viridis')plt.colorbar(contour,label='损失值')# 绘制梯度箭头forw,bin[(0,0),(1,1),(4,3)]:grad=gradient(w,b)plt.arrow(w,b,-grad[0]*0.3,-grad[1]*0.3,head_width=0.2,head_length=0.2,fc='red',ec='red')plt.plot(3,2,'r*',markersize=20,label='最小值点')plt.xlabel('w')plt.ylabel('b')plt.title('损失函数等高线图(红色箭头=负梯度方向)')plt.legend()plt.grid(True,alpha=0.3)plt.show()print("\n💡 梯度指向函数增长最快的方向")print("💡 负梯度指向函数下降最快的方向(优化方向)")📊 等高线图解读:
1. 等高线(圆圈)
2. 红色箭头(负梯度方向)
3. 实际意义
为什么梯度垂直于等高线?
想象你在山上:
- 等高线:海拔相同的点连成的线(水平的路)
- 梯度:最陡的上坡方向
- 问题:如果你沿着等高线走,海拔变化吗?
- 答案:不变!因为等高线上所有点海拔相同
- 结论:最陡的方向(梯度)一定垂直于水平的路(等高线)
数学表达:
实际应用:
importnumpyasnpdeff(x,y):returnx**2+y**2defgrad_f(x,y):returnnp.array([2*x,2*y])point1=(1,1)point2=(3,3)grad1=grad_f(*point1)grad2=grad_f(*point2)print(f"📊 梯度模长对比:")print(f"点{point1}的梯度:{grad1}, 模长:{np.linalg.norm(grad1):.2f}")print(f"点{point2}的梯度:{grad2}, 模长:{np.linalg.norm(grad2):.2f}")print("\n💡 离原点越远,梯度模长越大,变化越快")梯度模长的含义:
| 梯度模长 | 含义 | 实际意义 |
|---|---|---|
| 大 | 变化快 | 山坡很陡,需要小心走(小学习率) |
| 小 | 变化慢 | 山坡平缓,可以大步走(大学习率) |
| 0 | 不变化 | 到达极值点,停止优化 |
AI训练中的应用:
梯度是AI优化的指南针!🧭✨