You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib绘图中np.meshgrid的X/Y轴校准及梯度下降点显示问题

二元函数梯度下降可视化问题修正方案

问题根源分析

  1. 2D图轴范围异常:plt.imshow()默认以数组的行列索引作为坐标轴刻度,而非你定义的x = np.arange(-1.5,2,0.1)和y = np.arange(-1.5,2,0.1)真实范围,导致轴显示为0-40(数组长度)。
  2. 2D散点位置错误:梯度下降得到的(x,y)是真实坐标,但imshow的坐标系统未映射到真实范围,导致散点位置偏移。
  3. 3D图试验点遮挡:曲面绘制在试验点之前,且无半透明设置,导致点被遮挡;未添加3D等高线。

修正后完整代码

import numpy as np
import matplotlib.pyplot as plt

def func(x: float, y: float) -> float:
    return -( x * y * (1 - x - y) ) / 8

def partial_x_der(x: float, y: float) -> float:
    return (-y * (-2 * x - y + 1)) / 8

def partial_y_der(x: float, y: float) -> float:
    return (-x * (1 - x - 2 * y) ) / 8

def gradient(x: float, y: float):
    return (partial_x_der(x, y), partial_y_der(x, y))

def tuple_minus(my_tuple1: tuple, my_tuple2: tuple) -> tuple:
    return (my_tuple1[0] - my_tuple2[0], my_tuple1[1] - my_tuple2[1])

def tuple_multi_val(my_tuple: tuple, value: float) -> tuple:
    return (my_tuple[0] * value, my_tuple[1] * value)

def gradient_descent(start_point: tuple, learning_rate: float, epsilon: float) -> list:
    max_iterations = 1000
    cur_point = start_point
    result_points = list()
    # 先添加初始点
    result_points.append((cur_point[0], cur_point[1], func(cur_point[0], cur_point[1])))
    for iter in range(max_iterations):
        grad = gradient(cur_point[0], cur_point[1])
        next_point = tuple_multi_val(grad, learning_rate)
        if np.abs(next_point[0]) < epsilon and np.abs(next_point[1]) < epsilon:
            print(f"学习率{learning_rate},在({cur_point[0]:.4f};{cur_point[1]:.4f})找到最小值,函数值{func(cur_point[0], cur_point[1]):.4f},迭代次数{iter}")
            result_points.append((cur_point[0], cur_point[1], func(cur_point[0], cur_point[1])))
            return result_points
        cur_point = tuple_minus(cur_point, next_point)
        if iter % 10 == 0:
            result_points.append((cur_point[0], cur_point[1], func(cur_point[0], cur_point[1])))

    print(f"达到最大迭代次数{max_iterations},在({cur_point[0]:.4f};{cur_point[1]:.4f})找到最小值")
    result_points.append((cur_point[0], cur_point[1], func(cur_point[0], cur_point[1])))
    return result_points

def show_gradient_descend(points_to_show: list):
    x = np.arange(-1.5, 2, 0.1)
    y = np.arange(-1.5, 2, 0.1)
    X, Y = np.meshgrid(x, y)
    Z = func(X, Y)
    
    # 修正后的2D图
    plt.figure(figsize=(8,6))
    # 指定extent映射真实坐标范围:[x_min, x_max, y_min, y_max]
    im = plt.imshow(Z, 'GnBu', origin='lower', extent=[x.min(), x.max(), y.min(), y.max()])
    # 基于真实坐标绘制等高线
    cset = plt.contour(X, Y, Z, np.arange(-0.5, 1, 0.1), linewidths=1, cmap=plt.cm.Set2)
    plt.clabel(cset, inline=True, fmt='%1.1f', fontsize=8)
    plt.colorbar(im)
    # 提取试验点的x,y坐标绘制散点
    point_x = [p[0] for p in points_to_show]
    point_y = [p[1] for p in points_to_show]
    plt.scatter(point_x, point_y, color='r', marker='o', zorder=5)
    plt.title('二元函数2D等高线与梯度下降路径')
    plt.xlabel("X")
    plt.ylabel("Y")
    plt.xlim(-1.5, 2)
    plt.ylim(-1.5, 2)
    
    # 优化后的3D图
    fig = plt.figure(figsize=(10,8))
    ax = fig.add_subplot(projection='3d')
    # 曲面设置半透明,避免遮挡试验点
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='GnBu', linewidth=0, antialiased=False, alpha=0.7)
    # 添加3D等高线(投影到XY平面)
    ax.contour(X, Y, Z, zdir='z', offset=Z.min()-0.1, cmap='GnBu')
    # 绘制梯度下降试验点,设置zorder保证可见
    point_z = [p[2] for p in points_to_show]
    ax.scatter(point_x, point_y, point_z, color='r', marker='o', s=50, zorder=10)
    # 连接试验点,展示路径
    ax.plot(point_x, point_y, point_z, color='r', linestyle='--', zorder=8)
    ax.set_title('$z= -(x*y*(1-x-y)) / 8$ 3D可视化')
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_zlabel("Z")
    ax.set_xlim(-1.5, 2)
    ax.set_ylim(-1.5, 2)
    plt.show()

def main():
    x0 = (0, 0)
    x1 = (1, 1)
    xm = (5/10, 9/10)
    epsilon = 0.0001
    points = [x0, x1, xm]
    # 收集所有起始点的梯度下降路径
    all_points = []
    for point in points:
        all_points.extend(gradient_descent(point, 0.42, 0.0001))
    # 去重(可选,避免重复点)
    all_points = list(set(all_points))
    show_gradient_descend(all_points)

if __name__ == "__main__":
    main()

关键修改说明

2D图修正

  1. 轴范围映射:给imshow添加extent=[x.min(), x.max(), y.min(), y.max()],将数组索引映射到真实x/y坐标范围。
  2. 等高线与散点对齐:contour改为基于X,Y真实坐标绘制,散点直接使用梯度下降得到的(x,y)值,同时设置zorder=5保证散点在等高线之上。
  3. 显式设置轴范围:添加plt.xlim和plt.ylim确保显示范围符合预期。

3D图优化

  1. 试验点可见性:
    • 给曲面添加alpha=0.7设置半透明,让下方点可见;
    • 散点设置zorder=10,确保在曲面上层;
    • 添加路径连线,更清晰展示梯度下降过程。
  2. 添加3D等高线:使用ax.contour并指定zdir='z'和offset,将等高线投影到XY平面下方,避免遮挡曲面。
  3. 代码健壮性:main函数中收集所有起始点的路径,统一可视化;修正了梯度下降函数的拼写错误(gradiant_descent改为gradient_descent),并添加初始点记录。

内容的提问来源于stack exchange,提问作者Vytenis Kajackas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:05:58