计算思维项目中的优化技术:从线性回归到梯度下降
2025-07-10 07:36:00作者:廉皓灿Ida
引言
在计算思维项目中,优化技术是解决各类数学和工程问题的核心工具。本文将深入探讨如何使用Julia语言实现多种优化方法,从简单的线性回归到复杂的梯度下降算法。
数据准备与可视化
首先我们生成一些带有噪声的线性数据:
n = 100 # 数据点数量
x = sort(rand(-10:100, n))
y = 5/9 .* x .- 17.7777777 .+ 5 .* randn.() # 线性关系加噪声
通过绘图可以直观地看到数据的分布情况:
plot(x, y, m=:c, mc=:red, legend=false, ls=:dash)
xlabel!("°F")
ylabel!("°C")
最小二乘法线性回归
统计学方法
最直接的线性回归方法是使用统计学公式计算斜率和截距:
m = cov(x,y)/var(x)
b = mean(y) - m * mean(x)
这种方法计算高效,结果准确。
线性代数方法
对于熟悉线性代数的用户,可以使用更简洁的矩阵运算:
[one.(x) x]\y
这种方法不仅代码简洁,而且可以推广到更高维的回归问题。
优化方法
使用Optim.jl包
Optim.jl是一个纯Julia编写的优化包,我们可以用它来最小化损失函数:
loss((b, m)) = sum((b + m*x[i] - y[i])^2 for i=1:n)
result = optimize(loss, [0.0,0.0])
result.minimizer
使用JuMP.jl建模语言
JuMP(Julia for Mathematical Programming)提供了更高级的建模接口:
model = Model(Ipopt.Optimizer)
@variable(model, b)
@variable(model, m)
@objective(model, Min, sum((b + m*x[i] - y[i])^2 for i in 1:n))
optimize!(model)
(value(b), value(m))
梯度计算与分析
手动计算梯度
对于简单问题,我们可以手动推导梯度公式:
∇loss(b,m,i) = 2*(b+m*x[i]-y[i]) .* [1,x[i]] # 第i项的梯度
∇loss(b,m) = sum(∇loss(b,m,i) for i=1:n) # 整体梯度
有限差分法
当手动计算梯度困难时,可以使用有限差分法近似:
ϵ = .000000001
([loss([.1+ϵ ,.3]);loss([.1 ,.3+ϵ])] .- loss([.1 ,.3])) ./ ϵ
自动微分
Julia的ForwardDiff包提供了精确的自动微分功能:
ForwardDiff.gradient(loss, [.1,.3])
自动微分既避免了手动推导的繁琐,又比有限差分法更精确稳定。
梯度下降算法
基本梯度下降
b, m = 0, 0 # 初始猜测
for i=1:25
db, dm = ∇loss(b,m)
η = sum((b+m*x[i]-y[i])*(db+dm*x[i]) for i=1:n)/sum((db+dm*x[i])^2 for i=1:n)
b, m = (b, m) .- η .* (db, dm)
end
随机梯度下降(SGD)
在大规模问题中,随机梯度下降更为高效:
b, m = 0.0, 0.0
for t=1:10_000_000
η = .00002
b, m = (b, m) .- η *∇loss(b,m, rand(1:n))
end
优化算法比较
Optim.jl提供了多种优化算法选择:
optimize(loss, [0.0,0.0], BFGS(), autodiff=:forward) # BFGS算法
optimize(loss, [0.0,0.0], GradientDescent()) # 梯度下降
不同算法在收敛速度和内存使用上有各自的特点,需要根据问题规模和要求选择。
总结
本文通过温度转换的线性回归问题,展示了计算思维项目中多种优化技术的实现方法。从直接的统计公式到复杂的优化算法,Julia语言提供了丰富而高效的工具链。理解这些方法的原理和实现,对于解决更复杂的科学计算和机器学习问题至关重要。
在实际应用中,建议:
- 对于简单线性问题,优先使用统计或线性代数方法
- 中等规模问题可尝试Optim.jl
- 大规模或复杂问题考虑JuMP建模
- 深度学习等超大规模问题使用随机梯度下降