w~深度学习~合集1

我自己的原文哦~     https://blog.51cto.com/whaosoft/12663254

#Motion Plan

代码  github.com/liangwq/robot_motion_planing

轨迹约束中的软硬约束

前面的几篇文章已经介绍了,轨迹约束的本质就是在做带约束的轨迹拟合。输入就是waypoint点list,约束条件有两种硬约束和软约束。所谓硬约束对应到数学形式就是代价函数,硬约束对应的就是最优化秋季的约束条件部分。对应到物理意义就是,为了获得机器人可行走的安全的轨迹有:

  1. 把轨迹通过代价函数推离障碍物的方式
  2. 给出障碍物之间的可行走凸包走廊,通过硬约束让机器人轨迹必须在凸包走廊行走

上图展示的是软硬约束下Bezier曲线拟合的求解的数学框架,以及如何把各种的约束条件转成数学求解的代价函数(软约束)或者是求解的约束条件(软约束)。image.png

上面是对常用的代价函数约束的几种表示方式的举例。image.png

Bezier曲线拟合轨迹

前面已经一篇文章介绍过贝赛尔曲线拟合的各种优点:

  • 端点插值。贝塞尔曲线始终从第一个控制点开始,结束于最后一个控制点,并且不会经过任何其他控制点。
  • 凸包。贝塞尔曲线 ( ) 由一组控制点 完全限制在由所有这些控制点定义的凸包内。
  • 速度曲线。贝塞尔曲线 ( ) 的导数曲线 ′( ) 被称为速度曲线,它也是一个由控制点定义的贝塞尔曲线,其中控制点为 ∙ ( +1− ),其中 是阶数。
  • 固定时间间隔。贝塞尔曲线始终在 [0,1] 上定义。

Fig1.一段轨迹用bezier曲线拟合image.png

上面的两个表达式对应的代码实现如下:

def bernstein_poly(n, i, t):
    """
    Bernstein polynom.
    :param n: (int) polynom degree
    :param i: (int)
    :param t: (float)
    :return: (float)
    """
    return scipy.special.comb(n, i) * t ** i * (1 - t) ** (n - i)

def bezier(t, control_points):
    """
    Return one point on the bezier curve.
    :param t: (float) number in [0, 1]
    :param control_points: (numpy array)
    :return: (numpy array) Coordinates of the point
    """
    n = len(control_points) - 1
    return np.sum([bernstein_poly(n, i, t) * control_points[i] for i in range(n + 1)], axis=0)

要用Bezier曲线来表示一段曲线,上面已经给出了表达式和代码实现,现在缺的就是给定控制点,把控制点带进来用Bezier曲线表达式来算出给定终点和结束点中需要画的点坐标。下面代码给出了4个控制点、6个控制点的Bezier曲线实现;其中为了画曲线需要算170个线上点。代码如下:

def calc_4points_bezier_path(sx, sy, syaw, ex, ey, eyaw, offset):
    """
    Compute control points and path given start and end position.
    :param sx: (float) x-coordinate of the starting point
    :param sy: (float) y-coordinate of the starting point
    :param syaw: (float) yaw angle at start
    :param ex: (float) x-coordinate of the ending point
    :param ey: (float) y-coordinate of the ending point
    :param eyaw: (float) yaw angle at the end
    :param offset: (float)
    :return: (numpy array, numpy array)
    """
    dist = np.hypot(sx - ex, sy - ey) / offset
    control_points = np.array(
        [[sx, sy],
         [sx + dist * np.cos(syaw), sy + dist * np.sin(syaw)],
         [ex - dist * np.cos(eyaw), ey - dist * np.sin(eyaw)],
         [ex, ey]])

    path = calc_bezier_path(control_points, n_points=170)

    return path, control_points

def calc_6points_bezier_path(sx, sy, syaw, ex, ey, eyaw, offset):
    """
    Compute control points and path given start and end position.
    :param sx: (float) x-coordinate of the starting point
    :param sy: (float) y-coordinate of the starting point
    :param syaw: (float) yaw angle at start
    :param ex: (float) x-coordinate of the ending point
    :param ey: (float) y-coordinate of the ending point
    :param eyaw: (float) yaw angle at the end
    :param offset: (float)
    :return: (numpy array, numpy array)
    """

    dist = np.hypot(sx - ex, sy - ey) * offset
    control_points = np.array(
        [[sx, sy],
         [sx + 0.25 * dist * np.cos(syaw), sy + 0.25 * dist * np.sin(syaw)],
         [sx + 0.40 * dist * np.cos(syaw), sy + 0.40 * dist * np.sin(syaw)],
         [ex - 0.40 * dist * np.cos(eyaw), ey - 0.40 * dist * np.sin(eyaw)],
         [ex - 0.25 * dist * np.cos(eyaw), ey - 0.25 * dist * np.sin(eyaw)],
         [ex, ey]])

    path = calc_bezier_path(control_points, n_points=170)

    return path, control_points

def calc_bezier_path(control_points, n_points=100):
    """
    Compute bezier path (trajectory) given control points.
    :param control_points: (numpy array)
    :param n_points: (int) number of points in the trajectory
    :return: (numpy array)
    """
    traj = []
    for t in np.linspace(0, 1, n_points):
        traj.append(bezier(t, control_points))

    return np.array(traj)

有了一段Bezier曲线的拟合方式,接下来要做的就是如何生成多段Bezier曲线合成一条轨迹;并且是需要可以通过代价函数方式(软约束)+必须经过指定点+制定点衔接要连续(硬约束)来生成一条光滑的轨迹曲线。

Fig2.无障碍物,带bondary轨迹做了smooth优化Figure_1.png

多段Bezier曲线生成代码如下,其实原理很简单,给定多个waypoint点,每相邻两个wayponit生成一段Bezizer曲线,代码如下:

# Bezier path one as per the approach suggested in
    # https://users.soe.ucsc.edu/~elkaim/Documents/camera_WCECS2008_IEEE_ICIAR_58.pdf
    def cubic_bezier_path(self, ax, ay):

        dyaw, _ = self.calc_yaw_curvature(ax, ay)

        cx = []
        cy = []
        ayaw = dyaw.copy()

        for n in range(1, len(ax)-1):
            yaw = 0.5*(dyaw[n] + dyaw[n-1])
            ayaw[n] = yaw

        last_ax = ax[0]
        last_ay = ay[0]
        last_ayaw = ayaw[0]

        # for n waypoints, there are n-1 bezier curves
        for i in range(len(ax)-1):

            path, ctr_points = calc_4points_bezier_path(last_ax, last_ay, ayaw[i], ax[i+1], ay[i+1], ayaw[i+1], 2.0)
            cx = np.concatenate((cx, path.T[0][:-2]))
            cy = np.concatenate((cy, path.T[1][:-2]))
            cyaw, k = self.calc_yaw_curvature(cx, cy)
            last_ax = path.T[0][-1]
            last_ay = path.T[1][-1]

        return cx, cy

代价函数计算包括:曲率代价 + 偏差代价 + 距离代价 + 连续性代价,同时还有边界条件,轨迹必须在tube内的不等式约束,以及问题优化求解。具体代码实现如下:

# Objective function of cost to be minimized
    def cubic_objective_func(self, deviation):

        ax = self.waypoints.x.copy()
        ay = self.waypoints.y.copy()

        for n in range(0, len(deviation)):
            ax[n+1] -= deviation[n]*np.sin(self.waypoints.yaw[n+1])
            ay[n+1] += deviation[n]*np.cos(self.waypoints.yaw[n+1])

        bx, by = self.cubic_bezier_path(ax, ay)
        yaw, k = self.calc_yaw_curvature(bx, by)

        # cost of curvature continuity
        t = np.zeros((len(k)))
        dk = self.calc_d(t, k)
        absolute_dk = np.absolute(dk)
        continuity_cost = 10.0 * np.mean(absolute_dk)

        # curvature cost
        absolute_k = np.absolute(k)
        curvature_cost = 14.0 * np.mean(absolute_k)

        # cost of deviation from input waypoints
        absolute_dev = np.absolute(deviation)
        deviation_cost = 1.0 * np.mean(absolute_dev)

        distance_cost = 0.5 * self.calc_path_dist(bx, by)

        return curvature_cost + deviation_cost + distance_cost + continuity_cost
# Minimize objective function using scipy optimize minimize
    def optimize_min_cubic(self):

        print("Attempting optimization minima")

        initial_guess = [0, 0, 0, 0, 0]
        bnds = ((-self.bound, self.bound), (-self.bound, self.bound), (-self.bound, self.bound), (-self.bound, self.bound), (-self.bound, self.bound))
        result = optimize.minimize(self.cubic_objective_func, initial_guess, bounds=bnds)

        ax = self.waypoints.x.copy()
        ay = self.waypoints.y.copy()

        if result.success:
            print("optimized true")
            deviation = result.x
            for n in range(0, len(deviation)):
                ax[n+1] -= deviation[n]*np.sin(self.waypoints.yaw[n+1])
                ay[n+1] += deviation[n]*np.cos(self.waypoints.yaw[n+1])

            x, y = self.cubic_bezier_path(ax, ay)
            yaw, k = self.calc_yaw_curvature(x, y)
            self.optimized_path = Path(x, y, yaw, k)

        else:
            print("optimization failure, defaulting")
            exit()

带障碍物的Bezier曲线轨迹生

image.png

带有障碍物的场景,通过代价函数让生成的曲线远离障碍物。从而得到一条可以安全行走的轨迹,下面是具体的代码实现。optimizer_k中lambda函数f就是在求解轨迹在经过障碍物附近时候的代价,penalty1、penalty2就是在求曲线经过障碍物附近的具体代价值;
b.arc_len(granuality=10)+B.arc_len(granuality=10)+m_k + penalty1 + penalty2就是轨迹的整体代价。for循环部分用scipy的optimize的minimize来求解轨迹。

def optimizer_k(cd, k, path, i, obs, curve_penalty_multiplier, curve_penalty_divider, curve_penalty_obst):
    """Bezier curve optimizer that optimizes the curvature and path length by changing the distance of p1 and p2 from
     points p0 and p3, respectively. """
    p_tmp = copy.deepcopy(path)
    if i+3 > len(path)-1:
        b = CubicBezier()
        b.p0 = p_tmp[i]
        x, y = calc_p1(p_tmp[i], p_tmp[i + 1], p_tmp[i - 1], i, cd[0])
        b.p1 = Point(x, y)
        x, y = calc_p2(p_tmp[i-1], p_tmp[i + 0], p_tmp[i + 1], i, cd[1])
        b.p2 = Point(x, y)
        b.p3 = p_tmp[i + 1]
        B = CubicBezier()
    else:
        b = CubicBezier()
        b.p0 = p_tmp[i]
        x, y = calc_p1(p_tmp[i],p_tmp[i+1],p_tmp[i-1], i, cd[0])
        b.p1 = Point(x, y)
        x, y = calc_p2(p_tmp[i],p_tmp[i+1],p_tmp[i+2], i, cd[1])
        b.p2 = Point(x, y)
        b.p3 = p_tmp[i + 1]
        B = CubicBezier()
        B.p0 = p_tmp[i]
        x, y = calc_p1(p_tmp[i+1], p_tmp[i + 2], p_tmp[i], i, 10)
        B.p1 = Point(x, y)
        x, y = calc_p2(p_tmp[i+1], p_tmp[i + 2], p_tmp[i + 3], i, 10)
        B.p2 = Point(x, y)
        B.p3 = p_tmp[i + 1]

    m_k = b.max_k()
    if m_k>k:
        m_k= m_k*curve_penalty_multiplier
    else:
        m_k = m_k/curve_penalty_divider

    f = lambda x, y: max(math.sqrt((x[0] - y[0].x) ** 2 + (x[1] - y[0].y) ** 2) * curve_penalty_obst, 10) if math.sqrt(
        (x[0] - y[0].x) ** 2 + (x[1] - y[0].y) ** 2) < y[1] else 0
    b_t = b.calc_curve(granuality=10)
    b_t = zip(b_t[0],b_t[1])
    B_t = B.calc_curve(granuality=10)
    B_t = zip(B_t[0], B_t[1])
    penalty1 = 0
    penalty2 = 0
    for o in obs:
        for t in b_t:
            penalty1 = max(penalty1,f(t,o))
        for t in B_t:
            penalty2 = max(penalty2,f(t,o))
    return b.arc_len(granuality=10)+B.arc_len(granuality=10)+m_k + penalty1 + penalty2

# Optimize the initial path for n_path_opt cycles
for m in range(n_path_opt):
    if m%2:
        for i in range(1,len(path)-1):
                x0 = [0.0, 0.0]
                bounds = Bounds([-1, -1], [1, 1])
                res = minimize(optimizer_p, x0, args=(path, i, obs, path_penalty), method='TNC', tol=1e-7, bounds=bounds)
                x, y = res.x
                path[i].x += x
                path[i].y += y
    else:
        for i in range(len(path)-1,1):
                x0 = [0.0, 0.0]
                bounds = Bounds([-1, -1], [1, 1])
                res = minimize(optimizer_p, x0, args=(path, i, obs, path_penalty), method='TNC', tol=1e-7, bounds=bounds)
                x, y = res.x
                path[i].x += x
                path[i].y += y

带飞行走廊的Bezier轨迹生成

得益于贝赛尔曲线拟合的优势,如果我们可以让机器人可行走的轨迹转成多个有重叠区域的凸多面体,那么轨迹完全位于飞行走廊内。   

image.png

  • 飞行走廊由凸多边形组成。
  • 每个立方体对应于一段贝塞尔曲线。
  • 此曲线的控制点被强制限制在多边形内部。
  • 轨迹完全位于所有点的凸包内。

如何通过把障碍物地图生成可行凸包走廊

生成凸包走廊的方法目前有以下三大类的方法:

平行凸簇膨胀方法

从栅格地图出发,利用最小凸集生成算法,完成凸多面体的生成。其算法的思想是首先获得一个凸集,再沿着凸集的表面进行扩张,扩张之后再进行凸集检测,判断新扩张的集合是否保持为凸。一直扩张到不能再扩张为止,再提取凸集的边缘点,利用快速凸集生成算法,生成凸多面体。该算法的好处在于可以利用这种扩张的思路,将安全的多面体的体积尽可能的充满整个空间,因此获得的安全通道更大。但其也具有一定的缺点,就是计算量比较大,计算所需要的时间比较长,为了解决这个问题,在该文章中,又提出了采用GPU加速的方法,来加速计算。

基于凸分解的安全通道生成

基于凸分解的安全通道生成方法由四个步骤完成安全通道的生成,分别为:找到椭球、找到多面体、边界框、收缩。

半定规划的迭代区域膨胀

为了获取多面体,这个方法首先构造一个初始椭球,由一个以选定点为中心的单位球组成。然后,遍历障碍物,为每个障碍物生成一个超平面,该超平面与障碍物相切并将其与椭球分开。再次,这些超平面定义了一组线性约束,它们的交集是一个多面体。然后,可以在那个多面体中找到一个最大的椭球,使用这个椭球来定义一组新的分离超平面,从而定义一个新的多面体。选择生成分离超平面的方法,这样椭圆体的体积在迭代之间永远不会减少。可以重复这个过程,直到椭圆体的增长率低于某个阈值,此时我们返回多面体和内接椭圆体。这个方法具有迭代的思想,并且具有收敛判断的标准,算法的收敛快慢和初始椭球具有很大的关系。

Fig3.半定规划的迭代区域膨胀。每一行即为一次迭代操作,直到椭圆体的增长率低于阈值。image.png

这篇文章介绍的是“半定规划的迭代区域膨胀”方法,具体代码实现如下:

# 根据输入路径对空间进行凸分解
    def decomp(self, line_points: list[np.array], obs_points: list[np.array], visualize=True):
        # 最终结果
        decomp_polygons = list()
        # 构建输入障碍物点的kdtree
        obs_kdtree = KDTree(obs_points)
        # 进行空间分解
        for i in range(len(line_points) - 1):
            # 得到当前线段
            pf, pr = line_points[i], line_points[i + 1]
            print(pf)
            print(pr)
            # 构建初始多面体
            init_polygon = self.initPolygon(pf, pr)
            print(init_polygon.getInterPoints())
            print(init_polygon.getVerticals())
            # 过滤障碍物点
            candidate_obs_point_indexes = obs_kdtree.query_ball_point((pf + pr) / 2, np.linalg.norm([np.linalg.norm(pr - pf) / 2 + self.consider_range_, self.consider_range_]))
            local_obs_points = list()
            for index in candidate_obs_point_indexes:
                if init_polygon.inside(obs_points[index]):
                    local_obs_points.append(obs_points[index])
            # 得到初始椭圆
            ellipse = self.findEllipse(pf, pr, local_obs_points)
            # 根据初始椭圆构建多面体
            polygon = self.findPolygon(ellipse, init_polygon, local_obs_points)
            # 进行保存
            decomp_polygons.append(polygon)

            if visualize:
                # 进行可视化
                plt.figure()
                # 绘制路径段
                plt.plot([pf[1], pr[1]], [pf[0], pr[0]], color="red")
                # 绘制初始多面体
                verticals = init_polygon.getVerticals()
                # 绘制多面体顶点
                plt.plot([v[1] for v in verticals] + [verticals[0][1]], [v[0] for v in verticals] + [verticals[0][0]], color="blue", linestyle="--")
                # 绘制障碍物点
                plt.scatter([p[1] for p in local_obs_points], [p[0] for p in local_obs_points], marker="o")
                # 绘制椭圆
                ellipse_x, ellipse_y = list(), list()
                for theta in np.linspace(-np.pi, np.pi, 1000):
                    raw_point = np.array([np.cos(theta), np.sin(theta)])
                    ellipse_point = np.dot(ellipse.C_, raw_point) + ellipse.d_
                    ellipse_x.append(ellipse_point[0])
                    ellipse_y.append(ellipse_point[1])
                plt.plot(ellipse_y, ellipse_x, color="orange")
                # 绘制最终多面体
                # 得到多面体顶点
                verticals = polygon.getVerticals()
                # 绘制多面体顶点
                plt.plot([v[1] for v in verticals] + [verticals[0][1]], [v[0] for v in verticals] + [verticals[0][0]], color="green")
                plt.show()

        return decomp_polygons

    # 构建初始多面体
    def initPolygon(self, pf: np.array, pr: np.array) -> Polygon:
        # 记录多面体的平面
        polygon_planes = list()
        # 得到线段方向向量
        dire = self.normalize(pr - pf)
        # 得到线段法向量
        dire_h = np.array([dire[1], -dire[0]])
        # 得到平行范围
        p_1 = pf + self.consider_range_ * dire_h
        p_2 = pf - self.consider_range_ * dire_h
        polygon_planes.append(Hyperplane(dire_h, p_1))
        polygon_planes.append(Hyperplane(-dire_h, p_2))
        # 得到垂直范围
        p_3 = pr + self.consider_range_ * dire
        p_4 = pf - self.consider_range_ * dire
        polygon_planes.append(Hyperplane(dire, p_3))
        polygon_planes.append(Hyperplane(-dire, p_4))
        # 构建多面体
        polygon = Polygon(polygon_planes)
        return polygon

    # 得到初始椭圆
    def findEllipse(self, pf: np.array, pr: np.array, obs_points: list[np.array]) -> Ellipse:
        # 计算长轴
        long_axis_value = np.linalg.norm(pr - pf) / 2
        axes = np.array([long_axis_value, long_axis_value])
        # 计算旋转
        rotation = self.vec2Rotation(pr - pf)
        # 计算初始椭圆
        C = np.dot(rotation, np.dot(np.array([[axes[0], 0], [0, axes[1]]]), np.transpose(rotation)))
        d = (pr + pf) / 2
        ellipse = Ellipse(C, d)
        # 得到椭圆内的障碍物点
        inside_obs_points = ellipse.insidePoints(obs_points)
        # 对椭圆进行调整,使得全部障碍物点都在椭圆外
        while inside_obs_points:
            # 得到与椭圆距离最近的点
            closest_obs_point = ellipse.closestPoint(inside_obs_points)
            # 将最近点转到椭圆坐标系下
            closest_obs_point = np.dot(np.transpose(rotation), closest_obs_point - ellipse.d_) 
            # 根据最近点,在椭圆长轴不变的情况下对短轴进行改变,使得,障碍物点在椭圆上
            if Compare.small(closest_obs_point[0], axes[0]):
                axes[1] = np.abs(closest_obs_point[1]) / np.sqrt(1 - (closest_obs_point[0] / axes[0]) ** 2)
            # 更新椭圆
            ellipse.C_ = np.dot(rotation, np.dot(np.array([[axes[0], 0], [0, axes[1]]]), np.transpose(rotation)))
            # 更新椭圆内部障碍物
            inside_obs_points = ellipse.insidePoints(inside_obs_points, include_bound=False)
        return ellipse

    # 进行多面体的构建
    def findPolygon(self, ellipse: Ellipse, init_polygon: Polygon, obs_points: list[np.array]) -> Polygon:
        # 多面体由多个超平面构成
        polygon_planes = copy.deepcopy(init_polygon.hyper_planes_)
        # 初始化范围超平面
        remain_obs_points = obs_points
        while remain_obs_points:
            # 得到与椭圆最近障碍物
            closest_point = ellipse.closestPoint(remain_obs_points)
            # 计算该处的切平面的法向量
            norm_vector = np.dot(np.linalg.inv(ellipse.C_), np.dot(np.linalg.inv(ellipse.C_), (closest_point - ellipse.d_)))
            norm_vector = self.normalize(norm_vector)
            # 构建平面
            hyper_plane = Hyperplane(norm_vector, closest_point)
            # 保存到多面体平面中
            polygon_planes.append(hyper_plane)
            # 去除切平面外部的障碍物
            new_remain_obs_points = list()
            for point in remain_obs_points:
                if Compare.small(hyper_plane.signDist(point), 0):
                    new_remain_obs_points.append(point)
            remain_obs_points = new_remain_obs_points
        polygon = Polygon(polygon_planes)
        return polygon

image.png

上面图是给定16个障碍物点,必经6个路径点后得到的凸包可行走廊,具体代码如下:

def main():
        # 路径点
    line_points = [np.array([-1.5, 0.0]), np.array([0.0, 0.8]), np.array([1.5, 0.3]), np.array([5, 0.6]), np.array([6, 1.2]), np.array([7.6, 2.2])]
    # 障碍物点
    obs_points = [
        np.array([4, 2.0]),
        np.array([6, 3.0]),
        np.array([2, 1.5]),
        np.array([0, 1]),
        np.array([1, 0]),
        np.array([1.8, 0]),
        np.array([3.8, 2]),
        np.array([0.5, 1.2]),
        np.array([4.3, 0]),
        np.array([8, 0.9]),
        np.array([2.8, -0.3]),
        np.array([6, -0.9]),
        np.array([-0.5, -0.5]),
        np.array([-0.75 ,-0.5]),
        np.array([-1, -0.5]),
        np.array([-1, 0.8])
    ]

    convex_decomp = ConvexDecomp(2)
    decomp_polygons = convex_decomp.decomp(line_points, obs_points, False)
    #convex_decomp.decomp(line_points, obs_points,False)
    plt.figure()
    # 绘制障碍物点
    plt.scatter([p[0] for p in obs_points], [p[1] for p in obs_points], marker="o")
    # 绘制边界
    for polygon in decomp_polygons:
        verticals = polygon.getVerticals()
        # 绘制多面体顶点
        plt.plot([v[0] for v in verticals] + [verticals[0][0]], [v[1] for v in verticals] + [verticals[0][1]], color="green")
    #plt.plot(x_samples, y_samples)
    plt.show()

带凸包走廊求解

带凸包走廊的光滑轨迹生成。前面已经求解得到了可行的凸包走廊,这部分可以做为硬约束作为最优化求解的不等式条件。要求的光滑路径和必须经过点的点,这部分可以把必须经过点作为等式约束,光滑路径可以通过代价函数来实现。这样就可以把带软硬约束的轨迹生成框架各种技能点都用上了。

image.png

下面看具体代码实现:

# 进行优化
    def optimize(self, start_state: np.array, end_state: np.array, line_points: list[np.array], polygons: list[Polygon]):
        assert(len(line_points) == len(polygons) + 1)
        # 得到分段数量
        segment_num = len(polygons)
        assert(segment_num >= 1)
        # 计算初始时间分配
        time_allocations = list()
        for i in range(segment_num):
            time_allocations.append(np.linalg.norm(line_points[i+1] - line_points[i]) / self.vel_max_)
        # 进行优化迭代
        max_inter = 10
        cur_iter = 0
        while cur_iter < max_inter:
            # 进行轨迹优化
            piece_wise_trajectory = self.optimizeIter(start_state, end_state, polygons, time_allocations, segment_num)
            # 对优化轨迹进行时间调整,以保证轨迹满足运动上限约束
            cur_iter += 1
            # 计算每一段轨迹的最大速度,最大加速度,最大jerk
            condition_fit = True
            for n in range(segment_num):
                # 得到最大速度,最大加速度,最大jerk
                t_samples = np.linspace(0, time_allocations[n], 100)
                v_max, a_max, j_max = self.vel_max_, self.acc_max_, self.jerk_max_
                for t_sample in t_samples:
                    v_max = max(v_max, np.abs(piece_wise_trajectory.trajectory_segments_[n][0].derivative(t_sample)), np.abs(piece_wise_trajectory.trajectory_segments_[n][1].derivative(t_sample)))
                    a_max = max(a_max, np.abs(piece_wise_trajectory.trajectory_segments_[n][0].secondOrderDerivative(t_sample)), np.abs(piece_wise_trajectory.trajectory_segments_[n][1].secondOrderDerivative(t_sample)))
                    j_max = max(j_max, np.abs(piece_wise_trajectory.trajectory_segments_[n][0].thirdOrderDerivative(t_sample)), np.abs(piece_wise_trajectory.trajectory_segments_[n][1].thirdOrderDerivative(t_sample)))
                # 判断是否满足约束条件
                if Compare.large(v_max, self.vel_max_) or Compare.large(a_max, self.acc_max_) or Compare.large(j_max, self.jerk_max_):
                    ratio = max(1, v_max / self.vel_max_, (a_max / self.acc_max_)**0.5, (j_max / self.jerk_max_)**(1/3))
                    time_allocations[n] = ratio * time_allocations[n]
                    condition_fit = False
            if condition_fit:
                break
        return piece_wise_trajectory

    # 优化迭代
    def optimizeIter(self, start_state: np.array, end_state: np.array, polygons: list[Polygon], time_allocations: list, segment_num):
        # 构建目标函数 inter (jerk)^2
        inte_jerk_square = np.array([
            [720.0, -1800.0, 1200.0, 0.0, 0.0, -120.0],
            [-1800.0, 4800.0, -3600.0, 0.0, 600.0, 0.0],
            [1200.0, -3600.0, 3600.0, -1200.0, 0.0, 0.0],
            [0.0, 0.0, -1200.0, 3600.0, -3600.0, 1200.0],
            [0.0, 600.0, 0.0, -3600.0, 4800.0, -1800.0],
            [-120.0, 0.0, 0.0, 1200.0, -1800.0, 720.0]
        ])
        # 二次项系数
        P = np.zeros((self.dim_ * segment_num * self.freedom_, self.dim_ * segment_num * self.freedom_))
        for sigma in range(self.dim_):
            for n in range(segment_num):
                for i in range(self.freedom_):
                    for j in range(self.freedom_):
                        index_i = sigma * segment_num * self.freedom_ + n * self.freedom_ + i
                        index_j = sigma * segment_num * self.freedom_ + n * self.freedom_ + j
                        P[index_i][index_j] = inte_jerk_square[i][j] / (time_allocations[n] ** 5)
        P = P * 2
        P = sparse.csc_matrix(P)
        # 一次项系数
        q = np.zeros((self.dim_ * segment_num * self.freedom_,))

        # 构建约束条件
        equality_constraints_num = 5 * self.dim_ + 3 * (segment_num - 1) * self.dim_
        inequality_constraints_num = 0
        for polygon in polygons:
            inequality_constraints_num += self.freedom_ * len(polygon.hyper_planes_)

        A = np.zeros((equality_constraints_num + inequality_constraints_num, self.dim_ * segment_num * self.freedom_))
        lb = -float("inf") * np.ones((equality_constraints_num + inequality_constraints_num,))
        ub = float("inf") * np.ones((equality_constraints_num + inequality_constraints_num,))

        # 构建等式约束条件(起点位置、速度、加速度;终点位置、速度;连接处的零、一、二阶导数)
        # 起点x位置
        A[0][0] = 1
        lb[0] = start_state[0]
        ub[0] = start_state[0]
        # 起点y位置
        A[1][segment_num * self.freedom_] = 1
        lb[1] = start_state[1]
        ub[1] = start_state[1]
        # 起点x速度
        A[2][0] = -5 / time_allocations[0]
        A[2][1] = 5 / time_allocations[0]
        lb[2] = start_state[2]
        ub[2] = start_state[2]
        # 起点y速度
        A[3][segment_num * self.freedom_] = -5 / time_allocations[0]
        A[3][segment_num * self.freedom_ + 1] = 5 / time_allocations[0]
        lb[3] = start_state[3]
        ub[3] = start_state[3]
        # 起点x加速度
        A[4][0] = 20 / time_allocations[0]**2
        A[4][1] = -40 / time_allocations[0]**2
        A[4][2] = 20 / time_allocations[0]**2
        lb[4] = start_state[4]
        ub[4] = start_state[4]
        # 起点y加速度
        A[5][segment_num * self.freedom_] = 20 / time_allocations[0]**2
        A[5][segment_num * self.freedom_ + 1] = -40 / time_allocations[0]**2
        A[5][segment_num * self.freedom_ + 2] = 20 / time_allocations[0]**2
        lb[5] = start_state[5]
        ub[5] = start_state[5]
        # 终点x位置
        A[6][segment_num * self.freedom_ - 1] = 1
        lb[6] = end_state[0]
        ub[6] = end_state[0]
        # 终点y位置
        A[7][self.dim_ * segment_num * self.freedom_ - 1] = 1
        lb[7] = end_state[1]
        ub[7] = end_state[1]
        # 终点x速度
        A[8][segment_num * self.freedom_ - 1] = 5 / time_allocations[-1]
        A[8][segment_num * self.freedom_ - 2] = -5 / time_allocations[-1]
        lb[8] = end_state[2]
        ub[8] = end_state[2]
        # 终点y速度
        A[9][self.dim_ * segment_num * self.freedom_ - 1] = 5 / time_allocations[-1]
        A[9][self.dim_ * segment_num * self.freedom_ - 2] = -5 / time_allocations[-1]
        lb[9] = end_state[3]
        ub[9] = end_state[3]

        # 连接处的零阶导数相等
        constraints_index = 10
        for sigma in range(self.dim_):
            for n in range(segment_num - 1):
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 1] = 1
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_] = -1
                lb[constraints_index] = 0
                ub[constraints_index] = 0
                constraints_index += 1
        # 连接处的一阶导数相等
        for sigma in range(self.dim_):
            for n in range(segment_num - 1):
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 1] = 5 / time_allocations[n]
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 2] = -5 / time_allocations[n]
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_] = 5 / time_allocations[n + 1]
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_ + 1] = -5 / time_allocations[n + 1]
                lb[constraints_index] = 0
                ub[constraints_index] = 0
                constraints_index += 1
        # 连接处的二阶导数相等
        for sigma in range(self.dim_):
            for n in range(segment_num - 1):
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 1] = 20 / time_allocations[n]**2
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 2] = -40 / time_allocations[n]**2
                A[constraints_index][sigma * segment_num * self.freedom_ + n * self.freedom_ + self.freedom_ - 3] = 20 / time_allocations[n]**2
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_] = -20 / time_allocations[n + 1]**2
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_ + 1] = 40 / time_allocations[n + 1]**2
                A[constraints_index][sigma * segment_num * self.freedom_ + (n+1) * self.freedom_ + 2] = -20 / time_allocations[n + 1]**2
                lb[constraints_index] = 0
                ub[constraints_index] = 0
                constraints_index += 1

        # 构建不等式约束条件
        for n in range(segment_num):
            for k in range(self.freedom_):
                for hyper_plane in polygons[n].hyper_planes_:
                    A[constraints_index][n * self.freedom_ + k] = hyper_plane.n_[0]
                    A[constraints_index][segment_num * self.freedom_ + n * self.freedom_ + k] = hyper_plane.n_[1]
                    ub[constraints_index] = np.dot(hyper_plane.n_, hyper_plane.d_)
                    constraints_index += 1
        assert(constraints_index == equality_constraints_num + inequality_constraints_num)
        A = sparse.csc_matrix(A)

        # 进行qp求解
        prob = osqp.OSQP()
        prob.setup(P, q, A, lb, ub, warm_start=True)
        res = prob.solve()
        if res.info.status != "solved":
            raise ValueError("OSQP did not solve the problem!")

        # 根据参数进行轨迹解析
        trajectory_x_params, trajectory_y_params = list(), list()
        for n in range(segment_num):
            trajectory_x_params.append(res.x[self.freedom_ * n: self.freedom_ * (n+1)])
            trajectory_y_params.append(res.x[segment_num * self.freedom_ + self.freedom_ * n: segment_num * self.freedom_ + self.freedom_ * (n+1)])
        piece_wise_trajectory = PieceWiseTrajectory(trajectory_x_params, trajectory_y_params, time_allocations)

        return piece_wise_trajectory

小结:

这篇文章介绍了带软硬约束的轨迹优化算法框架。第一部份介绍了软硬约束对应到最优求解问题数学上如何表示。第二部份介绍了贝赛尔曲线的代码实现,给出了具体的代码实现和讲解;并针对没有障碍物场景只给定waypoint点,生成光滑的Bezier轨迹的朴素求解代码实现。第三部份给出了带障碍物情况下如何做最优化求解,如何通过代价函数的方式来给轨迹施加推力让轨迹远离障碍物的代码实现。第四部分是一个综合性的例子,把软硬约束最优轨迹生成的求解框架做了一个综合呈现。详细的介绍了如何利用障碍物地图生成最大可行区域的凸包走廊,如何利用Bezier曲线的特性给定凸包两点生成路径一定在凸包中;以及如何利用代价行数来保证轨迹的光滑性、安全性,通过等式、不等式约束实现轨迹必须经过哪些点,某个点的运动状态如何。
这一系列的文章已经进入结尾的阶段,后面会简单介绍在碰到移动的物体时候单机器人如何处理;以及在多个机器人运行环境如何协同,最后会给出一个Motion Planning的综合实现例子讲解实际环境数据输入、前端规划、后端轨迹生成。至于定位和感知部分的内容后面可以根据情况而定是否在开一个新的系列来讲解介绍,对于更前沿的技术点会跟进论文做些文章分享。
最后本系列文章的代码在以下git链接,这部分代码相对零碎主要是配合文章理论来讲的,里面很多片段直接来源于网络整合。后面这可项目会持续维护,把项目代码(应该是c++实现,更体系)、整合进来,根据需要在看看有没必要整合出一个库。

#Bridging the Gap

作者研究了已经建立的 U-Net 肿瘤分割框架在训练来自低资源设置的 MRI 数据以及将其推广到较低分辨率和数据质量方面的能力,并探讨了在资源有限的情况下实现这些框架的可行性。作者的策略是复制一个 BraTS 挑战基准模型,以研究仅包含低分辨率数据的外部数据集的分割预测受到训练数据组成的影响。UNet在新年就又开始大展身手了!广泛接触+局部微调,让UNet无所畏惧!

肿瘤分割模型的一个关键挑战是能够适应各种临床环境,特别是在应用到 poor 质量的神经影像数据时。围绕这种适应性的不确定性源于缺乏代表性的数据集,导致在 Sub-Saharan Africa (SSA) 地区常见于 MRI 数据中的常见伪影的顶级性能模型没有暴露。

作者复制了一个在 2022 年 BraTS 竞赛中获得第二名的框架,以研究数据集组成对模型性能的影响,并通过使用 BraTS-Africa 数据只训练模型(train_SSA,N=60),仅使用 BraTS-成人胶质瘤数据(train_GLI,N=1251),将两者都在一起训练(train_ALL,N=1311),以及使用 BraTS-Africa 数据进一步训练 train_GLI 模型(train_ftSSA)。值得注意的是,仅在较小的低质量数据集上训练(train_SSA)得到的结果不佳,而在仅在较大的高质量数据集上训练(train_GLI)在低质量验证集上难以区分水肿组织。最具有前景的方法(train_ftSSA)是先在高质量神经影像上预训练模型,然后在较小的低质量数据集上进行微调。

这种方法超过了其他方法,在 MICCAI BraTS Africa 全球挑战外部测试阶段排名第二。这些发现强调了改进分割性能的重要性,即更大的样本量和广泛的数据接触。此外,证明了通过使用更广泛的数据进行局部微调,可以改善此类模型的性能。

Introduction

癌症的负担逐年上升,这主要影响低收入和中等收入国家(LMICs),因为这些国家在影像技术以及专家方面的限制,这对于早期诊断和成功治疗至关重要。准确的肿瘤分割为治疗决策提供了重要信息,从而影响了患者的生存率。在颅内肿瘤中,胶质瘤具有高度异质性,尽管在神经肿瘤领域取得了相当大的进展,但预后仍然较差。胶质瘤的形状、大小、边界、强度分布和体积波动都为使用磁共振成像(MRI)进行精确分割带来了挑战。MRI 是脑肿瘤的标准治疗和首选成像模式。

尽管它具有优势,但在低资源环境中仍需解决各种挑战,特别是在撒哈拉以南非洲(SSA)等地区,例如,缺乏高场磁共振扫描仪的可用性以及获取、分析和解释 MRI 数据的合格专家短缺,这导致肿瘤诊断的延迟。此外,由于 SSA 的相对较差的医疗保健系统、社会经济地位以及疾病通常在 SSA 中的晚发性,这进一步恶化了预后并维持了 SSA 的高死亡率。这些因素继续推动颅内肿瘤早期诊断和及时干预的需求。因此,开发能够在各种临床设置上表现良好的精确自动脑肿瘤分割模型在全球范围内具有重要意义。

近年来,脑肿瘤分割领域有了很大的发展,旨在克服依赖领域专业知识、主观性、对噪声和强度非均匀性的敏感性等限制。机器学习技术,特别是深度学习,在这个领域处于前沿,在肿瘤组织、周围水肿和正常组织之间的分割精度方面取得了显著的改进。卷积神经网络(CNNs)和自动编码器的结合是目前最好的方法,已经逐渐减少了依赖领域专业知识和复杂特征提取方法。

具体来说,U-Net模型在自动化脑肿瘤分割任务中已经确立了自己作为黄金标准的地位。为了进一步提高效率、准确性和普遍性,已经提出了几种对U-Net的改进。然而,由于医疗领域的伦理问题和数据隐私规定,用于深度学习模型泛化的神经影像数据集是有限的。

自从 BraTS 挑战赛成立以来,已经从多参数(mp-)MRI 扫描的全球贡献中观察到了显著的脑患者数据增长,其中包含约 4,500 例标注的公开可用脑肿瘤数据集。通过这种合作开发的标准化的自动脑肿瘤分割基准,已经显著推动了该领域的创新架构和训练程序的发展。然而,尽管表现出色,但仍然不确定这些顶级表现的方法是否可以有效地应用于来自撒哈拉以南非洲(SSA)人群的数据,因为这些人群的 MRI 图像质量仍然较差。这主要是由于缺乏代表性的数据集,再加上不同设置之间的图像获取参数的巨大差异,这使得泛化面临着挑战。当前的基准主要是基于高分辨率脑 MRI 在高收入国家的标准资源丰富的临床设置中获得的,并包括图像预处理步骤,这些步骤可能不会让模型暴露于 SSA 常见于常规临床扫描中的伪影。

当前最先进的框架之一是由 Isensee 等人开发的 nn-UNet,它提供了一个强大的肿瘤分割流水线,能够适应各种成像模式和结构 [28]。该框架通过将不同 U-Net 基于架构的预测进行集成,强调了建模决策的重要性,如预处理、数据增强流水线和超参数调优方法。Zeineldin 等人最近表明,对来自撒哈拉以南非洲(SSA)的较小外部测试数据集的期望-最大化集成的 DeepSeg、nn-UNet 和 Deep-SCAN U-Net  Pipeline 表现良好;对于整个肿瘤(WT)、肿瘤核心(TC)和增强肿瘤(ET),分别实现了 Dice 分数系数(DSC)0.9737、0.9593 和 0.9022,以及 Hausdorff 距离(95%)(HD95) 分数低于 3.32 的所有子区域。

然而,在具有与训练数据相似特性的外部数据集上的测试并未表现出色,它们的集成方法与 nn-UNet 基础模型的独立运行之间的验证结果差异微小(~0.005,U=6.0,p=0.7)。这可能进一步强调,在模型训练期间增加相关数据表示的简单框架,以及更激进的数据增强和精心选择的后处理方法,可能有助于在各种数据集上实现相似性能的模型开发,并可立即在低资源环境中应用。其中,增加模型训练期间相关数据表示尤为重要。

今年,首次将 BraTS 挑战扩展到包括来自低资源设置的多模态 MRI 训练数据。在这项工作中,作者研究了已经建立的 U-Net 肿瘤分割框架在训练来自低资源设置的 MRI 数据以及将其推广到较低分辨率和数据质量方面的能力,并探讨了在资源有限的情况下实现这些框架的可行性。鉴于挑战的目标是创建一个多功能的基准模型,作者优先考虑与顶级表现方法建立可比指标作为参考,而不是引入复杂的增强。作者的策略是复制一个 BraTS 挑战基准模型,以研究仅包含低分辨率数据的外部数据集的分割预测受到训练数据组成的影响。

Methods

Data Description

本研究中使用的数据集来源于 BraTS 2023 挑战赛的数据。训练、验证和测试数据集包括来自 1565 名术前成人胶质瘤患者的 mp-MRI 扫描,其中 1470 例来自现有的 BraTS 数据(BraTS-Adult Glioma),如前文所述,另外 95 例来自撒哈拉以南非洲(SSA)(BraTS-Africa) 。这些是作为标准护理的一部分在各种机构获得的典型临床扫描,导致成像质量存在显著差异。每个病例包括 T1 加权(T1)、术后钆对比 T1 加权(T1Gd)、T2 加权(T2)和 T2 液体衰减反转恢复(T2-FLAIR)。

图 1 显示了来自每个数据集的患者的样本切片, 强调 BraTS-Adult Glioma 和 BraTS-Africa 之间的数据质量的巨大差异。BraTS-Africa 数据集是通过一个非洲成像中心网络收集的, 得到了非洲 MRI 教育和研究推进联盟(CAMERA)的支持和 Lacuna 基金在健康公平性方面的资金。在每个病例中, 基于图像的肿瘤子区域的真实标注通过迭代过程生成和批准。

Selecting a Framework

自 nn-UNet  Pipeline 开发以来,它已经经历了几次修订,主要集中在训练参数上,而不是架构本身。表 1(行 1-3)显示了 2017 年原始 nn-UNet 模型以及 Isensee 等人随后的 BraTS 挑战中提交的修订模型,其中它在 2018 年获得第二名,在 2020 年获得第一名。nn-UNet 有效地解决了在设计更改和选择最佳表现集成时手动考虑相互依赖性的挑战。

然而,参加 2021 年 BraTS 挑战的一些团队表明,nn-UNet  Pipeline 中的基本 3D U-Net 组件可以优化以在脑肿瘤分割任务上获得良好性能,而不需要运行涵盖 nn-UNet  Pipeline 的整个网络集成。这些团队的比较结果(见表 1,第 4-7 行显示外部验证结果)主要表明,当样本数量保持不变时,整体模型性能存在轻微差异。与使用不同较小样本大小训练的三个 nn-UNet 提交结果的多样性能相比,这可能进一步强调了用于训练分割模型的样本大小的重要性以及其对模型性能的影响。

在选择时, 作者考虑了简单性和有效性, 因为在资源有限的环境中更容易进行复制, 对长期将模型本地化到资源受限的环境更有益。除了样本大小外, Futrega 等人表明, 改变网络架构对整体肿瘤分割性能的影响很小。具体来说, 他们表明, 改变网络层 (例如, 残差连接、多头自注意力)或集成不同的架构(例如, 具有自编码器或基本 U-Net 的残差 U-Net 与视觉 Transformer)与基本 3D U-Net 架构(子区域平均 Dice 分数约为 0.002 )相比仍然具有可比性。

Data Pre-Processing

所有数据都在挑战组织者的初始预处理后提供,以确保在公共数据共享之前删除所有受保护的健康信息。BraTS 标准化的流水线详细描述在 [3, 25] 中使用,预处理步骤包括将 DICOM 文件转换为 NifTI 格式,以删除所有个人患者元数据;去头骨,以毁损神经影像扫描;与 SRI24 解剖模板进行配准;

最后,重采样到统一的 1mm3 等向同性分辨率(见 [11] 中的内容)。然后,作者按照 OptiNet 流水线的描述执行了几个额外的预处理步骤。这些步骤包括:将所有模态的体积堆叠;裁剪冗余背景 Voxel ,以减少计算成本;对非零区域进行归一化;并添加一个前景的 one-hot 编码通道,以区分肿瘤和非肿瘤区域。这最终得到了一个形状为 (5, 240, 240, 155) 的输入张量,其中通道分别表示 4 个模态和 one-hot 编码层。

OptiNet Pipeline and Experiments

OptiNet 主要调整 nn-UNet 框架,涉及与数据预处理相关的建模选择,实现的数据增强,应用的损失函数(区域性,累加二进制交叉熵和 Dice 损失),以及几个后处理步骤。应用的数据增强包括空间变换(大小为 128x128x128 的随机裁剪和随机翻转)和与强度相关的变换(高斯噪声、高斯模糊、亮度变化),并在训练期间实现。

Yousef 等人 [38] 提供了关于基本 U-Net 架构的详细综述:简而言之,它由一个标准的 CNN(卷积神经网络)的收缩(编码器)路径和一个结合了卷积层特征图和三线性插值上采样器的解码器路径组成,用于降采样和上采样。在 OptiNet 版本中,编码器由一个标准的 CNN 组成,与一个结合了卷积层特征图和三线性插值上采样器的解码器相结合。裁剪后的体积大小为 128x128x128,同时保留上下文,通过跳过连接在编码器和解码器之间减少信息损失,帮助解码器恢复图像分辨率和空间结构。

图 2 显示了作者在实验中使用的模型架构,根据提供的公开笔记本 [4] 复制。Futrega 等人 [37] 对 nn-UNet 默认的 UNet 架构进行了轻微的修改(例如,通道大小,上采样技术等)。Futrega 和同事在 2021 年 [35] 和 2022 年 [37] 的论文中详细介绍了他们探索的所有架构和非架构调整。

值得注意的是,他们发现结合其中一些变化与附加的 one-hot 编码通道(约 0.0026,p=0.5;见 [35] 中的表 3)只会稍微增加平均 Dice 分数。

作者进行了四项实验,使用 OptiNet 流水线并改变训练数据集的组成。作者用 1)仅使用 BraTS-Africa 数据进行训练(_train_SSA_,N=60),2)仅使用 BraTS-成人胶质瘤数据进行训练(_train_GLI_,N=1251),3)同时使用两者进行训练(_train_ALL_,N=1311),4)进一步使用 BraTS-Africa 数据训练 train_GLI 模型(_train_figSSA_)。_train_figSSA_ 模型用于估计在非洲局部微调预训练基准模型的可行性。

所有训练和验证都在 Compute Canada 提供的高性能计算集群上使用 Pytorch 1.9 进行的,集群上有一台 NVIDIA T4 Turing(16GB GDDR6 内存)或 NVIDIA V100 Volta(16GB/32GB HBM2 内存)显卡,根据集群上的可用性而定。所有训练都使用内部验证程序,使用训练数据集的划分。由于时间和计算限制,作者将包含更大 BraTS-成人胶质瘤数据集的模型在每轮上分别训练 100 遍。对于仅包含较小 BraTS-Africa 数据集的模型(_train_SSA_ 和 _train_figSSA_),训练设置为最大 150 轮/轮,采用 5 倍交叉验证和当内部验证 Dice 分数在 100 轮内没有改善时采用的早期停止策略。表 2 显示了每轮训练中获得的平均 Dice 分数。每个实验的外部验证预测使用了每个轮内部验证集上的最佳 Dice 分数。

3 Results

以下是针对每个训练变体的性能指标描述,通过挑战在线评估系统计算的验证分数。系统提供的指标(见表 3)是病灶相关的 Dice 分数系数(DSC)和 Hausdorff 距离(95%)(HD95)平均值,跨 15 个用于 BraTS-Africa 2023 验证阶段的患者样本。没有提供真实分割;然而,数据集的较小尺寸允许对所有验证主题生成的分割掩膜进行更详细的审查。本文中呈现的图像是作者模型在选定验证案例上生成的分割。所有分割都由如前述描述的用于标注的非生物标签表示,其中 ED 是绿色,ET 是蓝色,NCR 是红色。

正如预期,仅用 60 个样本训练模型(train_SSA)是不够的,大多数验证分割都是在机会水平上获得的(50%)。为了在类似的数据上提供性能估计以及与其他训练集组成的比较,提交了仅用一次折叠训练 100 个 epoch 的低分辨率 Naive train_GLI 模型进行验证,该模型在包含 219 个胶质瘤患者的 Task 1(BraTS-成人胶质瘤)和 Task 2(BraTS-非洲)验证数据集上表现相对良好(平均 Dice 分数分别为 79.81、82.12、78.48 和 54.04、28.80、42.90,对应 WT、TC 和 ET 的 HD95)。

在 Task 2 验证数据上,肿瘤子区域平均性能指标也很好。由于计划将其用作使用 SSA 数据进一步训练的前训练基础,并检查内部验证损失表明其正在稳定,作者认为该模型足够用于后续使用 BraTS-Africa 数据进行微调。使用 BraTS-成人胶质瘤数据与 BraTS-非洲数据在 5 倍训练过程中进行微调,导致子区域上的平均 Dice 分数相似。

进一步研究子区域性能显示,尽管具有相同的平均 DSC,但 train_GLI 和 train_fISSA 模型在不同子区域上的表现有所不同。_train_GLI_ 模型在区分肿瘤组织和非肿瘤组织方面存在困难,40% 的案例实现了低于机会 DSC。相反,_train_fISSA_ 模型在这个区域表现良好,但在 ET 区域上存在困难,26% 的受试者得分低于机会。ET 子区域通常是最难精确分割的,因为其大小和与周围子区域的重叠。HD95 也提供了更清晰的指示,以评估模型在小型或低质量分割和轮廓重要时的性能。

查看这些分数的差异,作者看到 train_fISSA 模型平均能够比 train_GLI 模型更好地预测整个肿瘤边界(HD95 约 63 个单位较低)。相反,_train_GLI_ 模型在平均上比 train_fISSA 模型更好地区分 ET 子区域(HD95 约 40 个单位较低)。图 3 显示了这些差异明显的情况。

确定了一个异常案例,其中所有模型在准确分割 TC 子区域(平均 DSC 范围 22.33-49.04)方面存在困难,这可能是因为在脑水肿组织中存在类似于 ET 和 TC 的像素强度,这些像素强度存在于脑皮质的后部区域。这个案例对 train_fISSA 的影响大于其他模型:去除这个异常案例后,ET 和 TC 子区域的 DSC 分别增加了 4.13 和 3.43(相应的 HD95 分别降低了 13.04 和 8.04)。此外,这个异常案例还展示了 train_SSA 和 train_ALL 模型在 ET 和 TC 子区域性能的改善,尽管与 train_fISSA 相比较弱。

表 4 显示了平均 DSC 和 HD95 分数的完整差异比较。只有 train_GLI 模型在 TC 子区域受到了影响。此外,一个案例始终在所有模型上实现极其糟糕的分割结果,平均 DSC 跨子区域范围 35.40-37.02,HD95 229.37-229.89,如图 4 所示。 

图 5 显示了一个在 ET 和 TC 分割上获得了极好分数(平均 DSC > 89,HD95 < 2.00)但 WT 区域没有很好分割的受试者。传统上,ET 区域的准确分割更具挑战性,因为它通常是一个较小的区域。整个肿瘤本身应该更容易识别。图 5 中,从左到右,每个模型在所示面板的 ET 和 TC 分割上的平均 DSC(HD95)分别为:72.22(9.273)、0.125(285.335)、41.33(190.082)和 89.49(1.414)。从视觉上看,大多数模型主要在区分水肿组织(ED)方面存在困难,而水肿组织非常少。

在回顾所有模型性能时,作者还考虑到了整个肿瘤包含水肿组织,这在低分辨率扫描中更难区分。没有暴露于 SSA 的低质量数据,_train_GLI_ 模型可能很难精确识别伴有广泛水肿的肿瘤的边界。因此,作者将预训练了更大 BraTS-成人胶质瘤数据集并进一步在较小的 SSA 数据集(_train_ftsSA_)上训练的模型提交了外部测试数据集,该数据集包括来自 SSA 的 20 名患者的扫描。在这个未见过的外部测试数据集上,该模型表现良好,在全球范围内排名第二。在撰写本文时,测试阶段获得的最终 DSC 和 HD95 分数尚未公开。

4 Discussion

综上所述,作者的实验结果强调,当前最先进的模型不能直接应用于 SSA 数据,因为可用的训练数据有限,会导致模型过拟合。作者的最终模型在单预训练 100 个 epoch 和 5 倍交叉验证的微调上表现出色。然而,Futrega 等人表明,10 倍交叉验证允许实现更准确的分割性能。作者只验证了 train_SSA 和 train_ftsSA 的 5 倍交叉验证,并在 train_ALL 和 train_GLI 模型上未进行交叉验证。因此,更广泛的交叉验证可能产生更准确的模型比较。

然而,作者的最终模型的高排名性能重申了以前在模拟案例中表明的内容:通过联邦学习,最先进的模型可以通过使用来自不同区域的大量数据进行改进,这使得低资源设置的机构可以在不从外部来源获取数据的情况下,在较小的本地数据集上重新训练。然而,这些结果需要谨慎解释,因为训练和验证数据集的样本量有限。

此外,未来的工作应包括集成来自非洲不同区域的更广泛的数据集,并在使用高质量 MRI 扫描进行训练时,实施与扫描器伪影相关的更强大的数据增强。这些步骤对于开发能够跨各种临床设置看到的图像质量进行泛化的模型至关重要。

#Fus-MAE

一种基于Mask自编码器的自监督学习框架Fus-MAE,它使用交叉注意力在合成孔径雷达和多光谱光学数据之间进行早期和特征 Level 的数据融合。

自监督表示学习框架最近在遥感和传感器社区中引起了兴趣,因为它们有可能减轻制作大型卫星图像数据集的高昂标签成本。在多模态数据融合领域,虽然经常使用的对比学习方法可以帮助弥合不同传感器类型之间的域间隙,但它们依赖于需要专业知识和仔细设计的数据增强技术,尤其是对于多光谱遥感和数据。一种可能的但很少研究的绕过这些限制的方法是使用基于Mask图像建模的预训练策略。

在本文中介绍了一种基于Mask自编码器的自监督学习框架Fus-MAE,它使用交叉注意力在合成孔径雷达和多光谱光学数据之间进行早期和特征 Level 的数据融合,这两种模态具有显著的域差异。

实证结果表明,Fus-MAE可以有效地与针对SAR-光学数据融合的自定义对比学习策略相竞争,并在更大的语料库上训练的其它Mask自编码器框架之上表现出色。

1 Introduction

近年来,多模态学习越来越受到关注,因为有许多模态,如RGB-Depth或文本图像。值得注意的是,最近的研究已经为深度多模态学习相对于单模态的性能优势提供了理论依据。在遥感领域的数据融合领域,有两种模态被广泛研究:合成孔径雷达(SAR)和光学影像。确实,这些模态本质上是互补的:SAR数据具有全天候和穿透云的能力,但存在斑点噪声,使得其解释具有挑战性。另一方面,光学数据虽然受到天气和季节性约束,但具有自然感(例如RGB)和较少的噪声图像,有利于解释。因此,它们的结合对于土地覆盖分类等任务是相关的,并为云去除和SAR去斑等应用打开了大门。

自监督学习(SSL)在各个机器学习领域引起了广泛关注,如自然语言处理(NLP)和计算机视觉。其中一种关键特征是它能够在不需要 Token 数据的情况下学习强大的表示,这在遥感领域尤其有趣,因为数据标注可能代价高昂,通常需要特定领域的专业知识。

近年来,大规模的公共SAR-光学数据集(如SeCo,BigEarthNet-MM,SEN12MS和,最近,SSL4EO-12)的出现,推动了SAR-光学融合的SSL方法的研究。然而,现有的大多数研究倾向于对比学习,虽然有效,但存在一些局限性。这些包括依赖于数据增强,需要仔细设计以适应遥感图像(RSI)的特定性,以及需要负样本,这需要较大的批量大小。

近年来,在Mask图像建模(MIM)方面取得了某些视觉表示学习任务的新状态。尽管MIM避免了对比学习的上述缺陷,但据作者所知,使用MIM进行遥感图像(RSI)数据融合的文献仍然相对较少。在本文中,作者探索了这种替代的预训练方法,用于自监督学习数据融合,贡献可以总结如下:

1.提出了FusMAE,这是一种基于自监督和MAE的框架,能够实现早期级和特征级的数据融合。

2.通过实证方式证明了基于交叉注意力的早期融合策略是最适合预训练SAR-光学数据进行土地覆盖分类任务的策略。

3.展示了FusMAE模型可以在某些最先进的对比学习方法上与针对RSI数据融合的最近方法相竞争。

2 Related Works

在遥感领域中的自监督学习- 根据文献,自监督学习方法可以分为三类:

  1. 生成方法,其中预任务是在像素级重构被破坏的信号(例如降采样或Mask);
  2. 预测方法,其中目标是通过预任务(例如预测图像中两个块的相对位置或灰度到RGB着色)学习语义上下文特征;
  3. 对比学习方法,该方法传统上旨在创建一个嵌入空间,其中相同实例的视图被拉近(正视图),而不相关的视图被拉远(负视图)。

对于SAR-光学数据融合,大部分研究努力都倾向于后者:Chen和Bruzzone研究了SAR和光学图像的早期、中期和晚期融合,通过联合训练两个ResUnets和一个多视对比损失。Montanaro等人使用了SimCLR框架将不同模态的嵌入拉近。Wang等人适应了基于知识蒸馏的DINO框架,该框架不需要负样本,从而省去了需要大型批处理的需求。尽管这些对比方法都相当成功,但它们需要精心设计数据增强 Pipeline 来创建正视图,其质量很难评估。为了绕过这个挑战,作者选择专注于不需要数据增强的生成方法:Mask图像建模。

在遥感领域中的Mask图像建模- He等人[9]最近提出了一种去噪自动编码器(DAE)架构的变体,其中输入图像块以高 Mask 比例随机 Mask ,只留下少量输入块输入到Transformer编码器中。然后,浅层解码器使用获得的潜在和 Mask  Token 来重建图像。被称为 Mask 自动编码器(MAE)的框架在ImageNet-1K上设置了新的最先进状态,同时由于处理输入 Token 数量较少和轻量级解码器,训练时间大大缩短。Cong等人将该架构适应光学数据,通过添加多域编码(例如位置+时间或位置+光谱)。Sun等人在2M光学图像数据集上训练了一个基于MAE的模型,并声称在各种RS数据集上实现了最先进性能。Allen等人跟进了一项与SAR图像类似的工作。

然而,尽管在自然领域对Mask图像建模的数据融合方面进行了许多 recent advancements,但SAR-光学方面的文献较少,有些尝试通过在通道轴上堆叠SAR和光学数据来训练MAE,以及一些关于专业 Mask 策略的研究。在本文中提出了一些架构变化来研究早期、中期和晚期融合策略,为未来研究铺平道路。

3 Methodology

作者的工作受到了MultiMAE的启发,MultiMAE是一种基于Mask自动编码器的架构,在自然图像上具有已被证明的记录,其混合流式架构可以接受不同的模态作为输入。在本节中通过在第3.1节中提出需要多任务编码器在第3.2节中提出需要多任务解码器来描述Fus-MAE架构。考虑了两种 Mask 策略,其中详细内容在3.3节中提供。整体架构如图1所示。

Multi-modal encoder

Multi-task decoder

Masking strategies

作者提出研究两种 Mask 策略:独立 Mask 和一致 Mask 。遵循MAE的方法,应用了75%的 Mask 比例,并在各个模态上均匀地采样作者的块。

独立 Mask - 在RS领域中的MiM文献中,跨模态的独立 Mask 被广泛采用,因为它可以捕获模态之间的内相关性和跨相关性。遵循这种策略,作者在各个模态上以均匀的方式随机采样作者的 Mask 块。

一致 Mask  - 作者还研究了一种一致 Mask 策略,其中跨模态的 Mask 块相同。作者的假设是,由于SAR和光学数据的域间隙,捕获跨模态相关性比捕获模态内相关性更容易。通过确保作者向各个模态提供表示相同块的 Token ,作者可以减少注意力层捕获跨模态信息时的困难。

4 Experiments and Results

为了研究两种不同的融合策略,作者预训练了两个Fus-MAE实例:仅执行特征级融合的Fus-MAE w/ XAD,以及同时执行早期和特征级融合的Fus-MAE w/ XAE&D。在BigEarthNet训练分割的354,196张图像上训练Fus-MAE,使用AdamW优化器,批处理大小为200,共100个Epoch。在前10个Epoch中,学习率逐步升温到,然后使用余弦计划进行衰减。 

作者在2台NVIDIA RTX 3090Ti上训练Fus-MAE,大约需要60小时。将ImageNet初始化作为 Baseline ,并使用两个专门为SAR-光学数据融合设计的基于Transformer的预训练模型来完成作者的基准测试:分别代表最近对比学习研究的DINO-MM和SATVIT,以及分别代表Mask图像建模的近期研究。

多标签分类 - 为了评估预训练策略的有效性,在预训练的编码器顶部附加一个线性分类头。在10个Epoch中微调模型,使用PyTorch的MultiLabelSoftMargin Loss和AdamW优化器,并报告测试分割上的平均平均精度(mAP)得分。

表1总结了这些微调实验的结果,其中分类器在单模态数据(S1或S2)或多模态数据(S1+S2)上进行训练。值得注意的是,与其它架构相比,Fus-MAE展示了优越的性能,对于S2和S1+S2,mAP提高了大约2个百分点,而Fus-MAE w/XAE&D略有优势。

然而,值得注意的是,在所有架构中,使用仅SAR数据(S1)的mAP显著低于使用S2或S1+S2时的情况,这表明所有模型在S1+S2场景中主要依赖光学数据进行预测。

此外,为了评估在标签和资源稀缺条件下学习的表示的质量,在训练标签的1%上进行线性评估。在这种情况下,线性块投影和编码器权重被冻结,只允许学习线性分类器的权重。在AdamW优化器的支持下训练这个分类器20个Epoch,批量大小为128。结果也在表1中报告,与其它SSL架构相比,性能提高更大,突显了Fus-MAE学习的表示的质量。

迁移学习 - 为了研究泛化能力,作者在另一个下游任务上进行线性评估:在SEN12MS数据集上进行单模态土地覆盖分类。由于这个数据集的不平衡性质,使用加权平均方法计算精确度、召回率和F1-score。在AdamW优化器的支持下训练这个分类器10个Epoch,批量大小为256,使用Timm的LabelSmoothingCrossEntropy损失。与之前实验类似的实验设置下的基准测试结果报告在表2中。Fus-MAE在所有跟踪指标上均优于其他技术,尽管优势较小。

5 Conclusion

在本文中提出了Fus-MAE,这是一个新颖的用于SAR-光学数据融合的自监督学习框架。基于MAE架构,它使用在不同阶段两个数据流之间的交叉注意力来执行早期和特征级数据融合。

Fus-MAE在各种下游任务上超过了最近对比学习和基于MIM的工作,证明了使用交叉注意力描述具有较大域间隙的模态之间跨模态交互的有效性。可以进一步研究将作者的交叉注意力层扩展到超过2个模态,并使Fus-MAE在各个模态上的预测依赖更加均衡。

#Weight Selection

作者提出了一种称为权重选择 (Weight Selection) 的方法,这是一种从预训练好的大模型中选择权重来初始化较小模型的方法。Weight Selection 把知识从预训练好的权重迁移到更小的模型中。权重选择:用大神经网络的权重初始化小神经网络

权重初始化是神经网络训练中的一个古老而又永恒的话题。对于从头训练的神经网络而言,有很多权重初始化的方法。近年来大模型的出现,为这一经典的科研课题带来的新的机会。

在本文中,作者提出了一种称为权重选择 (Weight Selection) 的方法,这是一种从预训练好的大模型中选择权重来初始化较小模型的方法。Weight Selection 把知识从预训练好的权重迁移到更小的模型中。

本文的实验结果表明,Weight Selection 可以显着提高小模型的性能并减少它们的训练时间。而且,值得一提的是,它可以与知识蒸馏方法一起使用。Weight Selection 提供了一种在资源受限的环境中借助预训练模型强大力量的新方法,本文希望它可以使大模型时代训练小模型的有用工具。

1 用大神经网络的权重初始化小神经网络?

论文名称:Initializing Models with Larger Ones

论文地址:https//arxiv.org/pdf/2311.18823.pdf

1 Weight Selection 论文解读:

1.1 重新思考神经网络初始化

神经网络权重的初始化 (Weight Initialization) 对其后续的优化过程至关重要。合适的初始化权重可以有助于模型的收敛以及防止梯度消失的问题。当前有两种比较著名的初始化技术:Xavier 初始化[1]和 Kaiming 初始化[2],在神经网络的训练中发挥了重要作用。它们至今为止仍然是 PyTorch 等现代深度学习库的默认方法。

这些方法是为从随机初始化进行训练的神经网络研发的,在当时是很常见的做法。然而,在大模型时代,由于社区的集体努力,很容易获得各种预训练模型。一般而言,这些预训练模型背后的数据集包含 ImageNet-21K[3]和 LAION-5B[4] 等等。因此,从这些预训练模型进行微调,而不是从头开始训练模型,通常被认为是当今时代的首要选择,如下图1所示。

然而,这些预训练的大模型在资源需求上可能令人望而却步,严重阻碍了它们在资源受限设备 (比如移动设备) 上的使用。对于很多预训练模型族 (model zoo),即使是最小的模型在某些情况下也可以被认为非常大。比如MAE[5]和CLIP[6]模型,两者的最小预训练 Transformer 模型是 ViT-Base[7]模型,包含 80M 参数量。对于边缘设备的应用来说,这已经太大了,最小的 LLaMa[8]模型甚至大 100 倍,包含 7B 参数量。由于可以直接使用的预训练模型很少,开发人员必须在目标数据集上面从头开始训练模型,以适应他们的需求。这种方法错过了使用大型预训练模型的机会。这有点可惜,因为大模型的知识是从大数据集里面好不容易学到的,不加以合理利用就有点可惜了。

图1:大模型时代,预训练权重为小模型的学习带来新的生机

1.2 本文贡献

本文作者通过引入一种权重初始化 (Weight Selection) 技术来解决上面的问题,该方法使用预训练大模型来训练小模型。具体而言,本文提出一种 Weight Selection 技术,选择来自预训练大模型的权重子集来初始化较小的模型,也就是允许大模型学习到的知识通过其权重转移到小一点的模型里面。

而且,由于现代神经网络的模块化设计,权重选择只涉及3个简单的步骤:Layer Selection, Component Mapping, 和 Element Selection。该方法可以应用于与大模型相同的模型族中的任何小模型。使用权重选择来初始化小模型很简单,并且与从头开始训练相比没有任何额外的计算成本。即使对于大模型训练也很有用,比如使用来自 LLAMA-30B 的训练权重初始化 LLAMA-7B。

1.3 Weight Selection 方法介绍

给定一个预训练模型,Weight Selection 的目标是在同一个模型族 (model zoo) 中,为小一点的模型找到更高效的初始化,如下图2所示。将预训练的大模型称为 Teacher,小一点的模型称为 Student。

由于现代神经网络架构通常遵循模块化方法,即:堆叠很多相似的 layer 来构建最终的模型 (主要目的是为了方便模型的可扩展性)。因此,在选择 Teacher 中的权重来初始化 Student 模型时就可以借助这个特点节约很多力气。

在本文中,作者通过3步来实现权重选择:Layer Selection, Component Mapping, 和 Element Selection。

  • Layer Selection 就是选择 Teacher 中的哪一层来初始化 Student 模型。

对于学生模型的每一层,都要选择教师模型的一层来进行初始化。学生模型分为 Isotropic 和 Hierarchical 两种架构:

  1. Isotropic 就是直筒型架构,从头到尾都是相同的分辨率和特征维度。Isotropic 架构的典型代表有 ViT 和 MLP-Mixer。
  2. Hierarchical 就是金字塔式架构,从开始到结束分为多个 Stage,各个 Stage 之间特征分辨率逐渐降低,而特征的维度逐渐升高。Isotropic 架构的典型代表有 Swin Transformer 和 ConvNeXt。

图2:Weight Selection 的步骤

  • Component Mapping 就是选择 Teacher 中一层的哪个组件来初始化 Student 模型对应层的什么组件。

上一步获得了从教师到学生的 Layer 的映射。Component Mapping 就简化了为用一个 Teacher layer 初始化一个 Student layer。由于现代神经网络设计采用的模块化方法,相同 model zoo 里面不同大小的模型的 Component 一般都是一致的,只是特征的通道数不同,或者说宽度不同。因此,Component Mapping 就是一对一映射的关系。

  • Element Selection 就是选择 Teacher 中某个组件的哪部分权重来初始化 Student 中对应组件的权重。

均匀选择 (Uniform Selection)

本着简单的原则考虑,默认方法是均匀选择 (Uniform Selection),即从图2中教师模型的某个权重中拿出间隔均匀的权重元素来初始化学生模型。接下来介绍下 Uniform Selection 的具体做法。

图3:Uniform Selection 的伪代码

1.4 实验配置

数据集:9个图像分类数据集:ImageNet1K, CIFAR-10, CIFAR-100, Flowers, Pets, STL-10, Food-101, DTD, SVHN 和 EuroSAT。

模型:如下图4所示。

Student 模型:ViT-T/16 和 ConvNeXt-F。Teacher 模型:ImageNet-21K 预训练的 ViT-S/16 和 ConvNeXt-T。

图4:模型配置

训练策略:如下图5, 6, 7所示,本文作者遵循 ConvNeXt 的训练策略,并对不同数据集的 Batch Size、学习率和 stochastic depth rate 进行调整。为了确保公平的比较,作者将这套训练策略也应用于 Baseline 模型。

图5:训练策略

图6:ConvNeXt-F 的超参数设置

图7:ViT-T 的超参数设置

1.5 实验结果

实验结果如下图8所示。在所有 9 个图像分类数据集中,本文的 Weight Selection 方法都可以提高精度,尤其是对于小数据集而言更是如此。值得注意的是,Weight Selection 方法解决了在小数据集上训练 ViT 的难题,有助于 ViT 精度的显著提高。ImageNet-1K 的训练曲线如图9所示。两种模型都受益于早期的权重选择,在整个训练过程中保持这一优势。

图8:9个图像分类数据集实验结果

图9:ViT-T 和 ConvNeXt-F 在 ImageNet-1K 上的训练曲线

1.6 与其他方法的比较

作者在 CIFAR100 数据集上面对比了其他几种初始化方法的结果,如图10所示。

而且,还可以发现一致性是 Weight Selection 达到最佳性能的关键。对于这两种模型架构 ViT-T 和 ConvNeXt-F,均匀选择,连续选择,以及一致性随机选择的最终性能相似。在去除一致性时,性能急剧下降。

图10:与其他几种初始化方法的比较

1.7 与知识蒸馏的兼容性

权重选择 (Weight Selection) 通过参数从预训练模型转移知识。另一种流行的知识转移方法是知识蒸馏 (Knowledge Distillation),它利用了预训练模型的输出。在这里,作者也探讨了这2种技术的兼容性。

实验设置:作者尝试了2种知识蒸馏方案:logit-based distillation 和 feature-based distillation。

图11:与知识蒸馏的兼容性的实验结果

1.8 其他分析结果

权重选择可以减少训练时间。如下图12所示为作者使用权重选择方法训练不同 Epoch 数量,得到的曲线与随机初始化训练 300 Epoch 的结果对比。可以看到,权重选择与随机初始化训练相比,CIFAR-100 的相同性能只需 1/3 个 Epoch 即可获得。

图12:与随机初始化的比较

迁移学习结果对比。如下图13所示为作者希望看看先在 ImageNet-1K 上预训练多少 Epoch,再在 CIFAR-100 上做 fine-tune 的结果与权重选择的结果相当。可以发现,在 ImageNet-1K 上进行 60 个 epoch 的预训练之后微调,可以实现与权重选择相当的性能。在这种情况下,与预训练达到相同的性能相比,权重选择快 6.12 倍,且无需访问用于预训练的数据集。

图13:预训练与微调结果比较

层的选择方案。如下图14所示为作者以 ViT-A 和 ConvNeXt-F 为学生模型,ImageNet-21K 上预训练的 ViT-S 和 ConvNeXt-T 作为权重选择的教师模型。可以看到,使用 \text{First-N}\text{First-N} 选择的结果最佳。用 \text{First-N}\text{First-N} 选择做初始化的层自然是连续的层,而且更接近输入处理,因此它们为较小的模型提供了更有效的初始化。

图14:层选择方案对比

教师模型尺寸。如下图15所示为作者对比了不同尺寸教师模型的结果。可以看到,教师模型大小更接近时,权重选择会得到更好的结果。教师模型很大意味着将丢弃更高百分比的参数,这会在权重选择过程中导致更多的信息丢失。图15的结果中有趣的是,即使是使用 ViT-L 这样的模型初始化,从 301M 参数中选取 5M 参数,也很有效,精度提升了 4.5%。 

图15:不同尺寸教师模型结果对比

图16:与剪枝方法的对比

与模拟初始化 (Mimetic initialization[12]方案对比。如下图17所示为作者对比了权重选择方法与模拟初始化 (Mimetic initialization[12] 方法。权重选择方法大大优于模拟初始化。

图17:与模拟初始化方法对比

图18:注意力层可视化

#DeepDR

本项研究创新性提出了基于Weibull混合分布模型的疾病进展分析深度学习框架,创造性地将糖尿病视网膜病变的进展和发生时间视为筛查区间内的随机变量,通过生存分析与时序分布概率建模,成功实现了对糖尿病视网膜病变进展的风险预警和时间预测。

1月4日,上海交通大学电子信息与电气工程学院计算机科学与工程系/教育部人工智能重点实验室盛斌教授团队,上海交通大学医学院附属第六人民医院内分泌代谢科、上海市糖尿病重点实验室贾伟平教授和李华婷教授团队,清华大学副教务长、医学院主任黄天荫教授团队,在国际权威刊物《Nature Medicine》(《自然医学》)发表题为“A deep learning system for predicting time to progression of diabetic retinopathy”(用于预测糖尿病视网膜病变进展时间的深度学习系统)的科研成果。该成果是医工交叉团队继2021年成功完成糖尿病视网膜病变辅助智能诊断系统“DeepDR”的研发之后,进一步构建的基于时序影像序列深度学习的糖尿病视网膜并发症预警系统“DeepDR Plus"。该系统可基于眼底图像精准预测糖尿病视网膜病变进展,成果为推动全球糖尿病并发症的智能防控贡献了中国力量,有望为全球糖尿病视网膜病变的筛防新策略的制定提供指引。

研究介绍

糖尿病视网膜病变(diabetic retinopathy, DR)是糖尿病最常见的微血管并发症,也是全球可预防失明的主要原因。该病初期症状隐匿,病情严重时可能导致永久视力损伤甚至失明。由于不同患者病情进展存在较大差异,每位糖尿病病人患DR的风险和时间难以准确预测。目前,以深度学习为代表的人工智能技术已被用于DR筛查,然而基于眼底图像来预测DR发生风险仍是全球关注的重难点问题。在糖尿病等相关慢病诊疗和管理的临床实践流程中,糖尿病患者往往只会按照相对固定的时间间隔进行筛查或随访,并发症的确切发生或进展时间无法知晓,这也导致传统深度学习模型无法实现疾病进展时序轨迹的精准建模,进而无法预测个体的发病和进展时间点。针对这一困扰全球糖尿病管理的关键技术瓶颈与临床需求,本项研究首次基于大规模医学影像纵向队列,涵盖多国多种族的超20万名糖尿病患者的眼底图像和临床数据,创新性提出了基于Weibull混合分布模型的疾病进展分析深度学习框架,创造性地将糖尿病视网膜病变的进展和发生时间视为筛查区间内的随机变量,通过生存分析与时序分布概率建模,成功实现了对糖尿病视网膜病变进展的风险预警和时间预测。研究团队通过将该系统应用于中国和印度的真实临床流程,证实该系统可在大幅降低筛查频率和公共卫生成本的情况下仍保持极低的漏诊率,从而为将来的糖尿病并发症防控实践提供了个性化筛查和管理决策的依据。

DeepDR Plus系统概览和研究设计

早期筛查和干预对于DR的预防和管理至关重要。国内和国际组织大多建议无或轻度DR的糖尿病患者每年进行常规眼底摄片检查,以便及时发现视网膜病变并进行干预。然而,由于经济和医疗资源等因素的限制,尤其是在中、低收入国家,糖尿病患者常规眼底摄片检查的实施和普及困难重重。本研究首次实现了个体化糖尿病视网膜病变风险和时间预测,DeepDR Plus系统仅根据基线眼底图像,准确预测未来5年DR进展的个体化风险和时间,优于传统临床参数模型。此外,DeepDR Plus系统可以准确识别高、低风险人群,提供了人工智能驱动的个性化的推荐随访间隔(低风险患者给予相对更长时间的随访间隔建议而几乎不导致威胁视力DR的漏诊)和管理策略(高风险患者给予相对更严格的综合干预建议)。

人工智能驱动的个性化筛查间隔纳入糖尿病视网膜病变筛查系统,特别在发展中国家,可以极大地提高眼底摄片筛查的效率、公平性和可及性。该研究为糖尿病视网膜病变筛查、预防和诊疗指南提供了新的证据,有望对未来糖尿病视网膜病变的临床诊疗流程和医疗费用等产生重要影响,在世界地图上为糖尿病智能防控贡献了中国技术和亚洲力量,为一带一路及全球中低收入国家和地区的糖尿病管理模式的提质增效与改革创新开辟了新道路。

#DATM~

作者分析了生成数据的难易以及其对压缩效果的影响,发现应该根据压缩比率控制生成数据的难易。通过应用这一策略,作者提出了第一个可以在低压缩率保持有效的数据集蒸馏方法,并首次实现了无损数据集蒸馏。

论文题目:
Towards Lossless Dataset Distillation via Difficulty-Aligned Trajectory Matching
论文地址:https://arxiv.org/abs/2310.05773
代码地址: https://gzyaftermath.github.io/DATM/

一、背景

数据集蒸馏旨在以生成的方式将一个大的数据集压缩成一个小的数据集。得益于生成数据的高信息密度,在压缩率较高时,数据集蒸馏的效果远超数据集剪枝等其他数据压缩方法。

然而,随着压缩率的逐渐降低,现有数据集蒸馏方法的效果逐渐变差,甚至弱于从原数据集中随机选取等量数据。这导致现有数据集蒸馏方法局限于高压缩率场景,无法实现对原数据集的无损压缩。

在本文中,作者分析了生成数据的难易以及其对压缩效果的影响,发现应该根据压缩比率控制生成数据的难易。通过应用这一策略,作者提出了第一个可以在低压缩率保持有效的数据集蒸馏方法,并首次实现了无损数据集蒸馏。

二、动机

数据蒸馏可以看作是一个从目标数据集提取特征并将之添加到生成数据上的过程。

目前,主流的数据集蒸馏方法大多通过匹配模型在目标数据集和生成数据集上的某种指标来完成特征的提取与压缩。其中,基于匹配模型训练轨迹[1](Matching Training Trajectory)的方法在多个基准下达到了最优。由于该方法通过匹配模型在生成数据集和目标数据集上的训练轨迹(匹配模型参数)来进行蒸馏,因此其效果受模型在目标数据集上的训练轨迹影响。

根据文献[2]可知,对于分类任务而言,模型倾向于在训练前期学习目标物体的简单特征而在后期学习难特征。因此我们推测匹配模型的前期轨迹就会倾向于在生成数据上添加更多的简单特征而匹配后期轨迹则会倾向于添加难特征。意识到这一点,我们开始探索匹配不同阶段路径对于数据集蒸馏的影响。

图一、匹配不同阶段的轨迹的蒸馏效果

实验结果如图一所示,当IPC较低(即压缩率较高)时,匹配前期轨迹(即添加简单特征)是最有效的。而随着压缩率的降低,匹配后期轨迹则变成了最优选择,此时匹配前期路径甚至变得有害。基于这些实验现象,我们提出根据压缩比率控制生成特征的难易,并基于此提出了我们的方法。

三、方法

四、实验结果

3.1 效果比较

我们在CIFAR10,CIFAR100和TinyImageNet数据集下和多个有代表性的数据集蒸馏方法进行了对比,并进一步探索了数据集蒸馏在高IPC情境下的表现。主要的实验结果如下,更多的结果请参考我们的论文。

和多个蒸馏方法在不同数据集和不同IPC(image per class)设定下的比较

在高IPC情境下数据集蒸馏和数据集剪枝的表现比较   

3.2 分析

简单特征和难特征有什么特点?为什么压缩率较低时添加简单特征有害?我们对这些问题进行了探索。如下图所示,匹配前期轨迹(添加简单特征)会更大幅度的改变图片内容,将目标物体融入背景,使图片有更多关于目标物体的基本信息。这使得添加简单特征在压缩率较高时有效,因为此时蒸馏数据集太小以至于模型无法很好的学习到各个类别的基本特征。

匹配处于不同训练阶段的轨迹所得的蒸馏样本

此外,我们可以观察到添加简单特征会让图片损失关于目标物体的细节信息,而添加难特征(匹配后期轨迹)则会让目标物体具有更丰富的纹理细节。因此在压缩率较低时添加难特征的表现更好,因为此时蒸馏数据集本身就含有足够多的数据让模型学会基本的类别特征,添加更多的细节有利于模型识别离群样本。下图是蒸馏图片的可视化,更多分析请见论文。

不同IPC设定下蒸馏所得样本

五、总结

在这项工作中,作者发现应该根据压缩比率控制生成样本的难度。通过应用这一思想,作者提出了第一个可以在高/低压缩率皆能保持有效的数据集蒸馏算法,并首次实现了无损数据集蒸馏,将CIFAR-10,CIFAR-100压缩到了原数据集的1/5大小而不对训练ConvNet造成性能损失。

#MOSS-RLHF

RLHF中Reward model的trick, 作者们在报告中提出了一系列方法来解决如何增加RM的泛化能力的问题,从数据和算法角度,分别提出了两个问题核心问题和对应的解决方法,旨在提高奖励模型在处理错误偏好数据和泛化到新分布数据时的性能。 

引入

在大家搞RLHF中经常遇到的一个核心的问题是,RM的水平不够好没法训练得到想要的效果,其背后两大类基本的原因是:1.数据质量低。2.模型泛化能力差。复旦MOSS这篇技术报告,从这两个问题入手,提出了一系列方法优化和提升。也是Secrets of RLHF 系列的第二篇。干货十足,细节丰富,推荐阅读。

​https://arxiv.org/abs/2401.06080​

​https://github.com/OpenLMLab/MOSS-RLHF​

核心问题

展开来讲的话,关于1.数据质量低 2.模型泛化能力差这两个问题具体指的是:

一、数据质量低:数据集中的错误和模糊的偏好对(pairs),可能导致奖励模型(RM)无法准确捕捉人类的偏好。你通过数据透传给你的模型,一会儿向左,一会儿向右,模型也要学懵。

二、泛化能力差:奖励模型在特定分布上训练后,很难泛化到该分布之外的例子,且不适合迭代式的RLHF训练(提升RLHF的重要路径之一)。你的模型训练得到了一个二极管,对于自己相信的东西表现的非常极端,对于没见过的东西就傻眼了。

针对这两类问题,作者提出了两个视角的方法,分别从数据角度和算法角度出发。

一、数据角度:使用多个奖励模型的输出,增加数据度量的信息源,用这种方法来量化数据中偏好的强度信息,并通过这种方法来识别和纠正错误或模糊的偏好对。对于不同质量水平,模糊度水平的数据,采取了不一样的措施,有翻转,软标签,适应性margin等具体方法,后面具体展开讲解。

二、算法角度:借助对比学习和元学习的方法。增加对比学习的loss,对比学习通过增强模型区分能力,来增强RM的对好坏的区分水平。元学习则使奖励模型能够维持区分分布外样本的细微差异,这种方法可以用于迭代式的RLHF优化。

数据视角

可以看出数据的区分性比较强,并且随着的上升,和GPT4标注结果的一致性也在上升。

通过如上的方法就可以把数据大概分开,我们划分为3类进行分析。

1.低强度的偏好数据的负面影响:研究发现,数据集中偏好强度最低的20%的数据对模型在验证集上的性能有负面影响。这些数据的偏好强度平均值小于0,表明这些数据可能包含错误的偏好标签。

2.中等强度偏好数据的中立影响:偏好强度在20%到40%之间的数据,在训练后,模型在验证集上的预测准确率大约为0.5。这些数据的偏好强度平均值接近0,表明这些数据的偏好差异不大,模型在这些数据上的学习效果一般。

3.高强度的偏好数据的积极影响:剩余的数据(偏好强度最高的60%)显著提高了模型的性能。然而,仅使用偏好强度最高的10%的数据训练模型时,并没有达到最佳性能。这可能是因为这些数据过于强烈,导致模型可能过度拟合这些数据。

归纳出偏好强度信息后,我们可以根据偏好强度的测量结果,可以对数据集进行分类,并对不同类别的数据采取不同的处理策略。

对于低强度的偏好数据,隐含标签错误的可能性,通过翻转偏好对的标签可以有效地提高模型性能。对于中强度的,比较模糊的偏好数据,应用软标签和适应性边距可以避免模型过度拟合。对于高强度的偏好数据,使用软标签和适应性边距的组合特别有效。

adaptive margin

一种让同类聚集,异类区分度增大的经典方法,来自于人脸识别的经典方法。

作者给了这几种方法的详细实验过程:包含了reward,loss,ppl,输出len等角度的度量。

整体看起来,软标签适用在中上强度的偏好数据,margin方法在所有强度数据都适用。

算法视角

在论文的 "Preference Generalization and Iterated RLHF" (偏好泛化和迭代RLHF) 部分,作者们提出了两种主要的方法来提高奖励模型 (Reward Model, RM) 的泛化能力,使其能够在分布变化的情况下仍然能够有效地区分不同的响应。具体做法如下:

一、对比学习 (Contrastive Learning):

二、MetaRM(Meta Reward Model)

提出了一种名为MetaRM的方法,通过元学习来对齐原始偏好对与分布变化。MetaRM的关键思想是在训练阶段最小化原始偏好对的损失,同时最大化对从新分布中采样的响应的区分能力。

训练过程: MetaRM的训练过程包括四个步骤: 计算从新分布中采样的响应的差异损失,计算损失相对于RM参数的梯度并更新参数,计算原始偏好对的损失,以及计算损失相对于更新后的参数的梯度并优化原始参数。

具体,MetaRM 的算法包括以下步骤:

通过这些方法,奖励模型能够更好地捕捉数据中细微的偏好差异,从而在面对新分布的数据时保持其区分能力。这使得奖励模型能够在迭代的RLHF过程中更稳定地优化语言模型,即使在模型输出分布发生变化时也能保持其指导优化的能力。

主要实验结果如图所示:MetaRM 在分布内和分布外任务评估中都显示出了优越的性能。在分布内任务中,MetaRM 在多个回合的 PPO 训练后,其性能显著优于基线模型。

另外在OOD上的表现做了单独的分析,在分布外任务中,MetaRM 继续优于基线模型,表明其方法能够有效地在新领域实现对齐,而无需对一组query进行成本高昂的重新标注。

总结

总结来说,作者们在报告中提出了一系列方法来解决开头提到的核心问题,如何增加RM的泛化能力,从数据和算法角度,分别提出了两个问题核心问题和对应的解决方法,旨在提高奖励模型在处理错误偏好数据和泛化到新分布数据时的性能。

#后向传递の计算量

从前向传递、后向传递和优化器参数更新的浮点数计算次数入手,详解向传递的耗时为啥几乎是前向传递的两倍。后向传递的计算量大约是前向传递的两倍

1.

训练神经网络的一次迭代分为三步:(1)前向传递计算损失函数;(2)后向传递计算梯度;(3)优化器更新模型参数。在实验中,我们观察到一个现象:后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时几乎可以忽略。要解释这个现象,我们要从前向传递、后向传递和优化器参数更新的浮点数计算次数入手。

上图表示一次训练迭代中各个环节(前向传递、后向传递、通信环节、优化器更新)的耗时占比,来自于《PyTorch Distributed: Experiences on Accelerating Data Parallel Training》。上图中,纵轴表示耗时占比,FWD表示一次训练迭代中前向传递的耗时占比,BWD则表示一次训练迭代中后向传递的耗时占比,OPT表示一次训练迭代中优化器更新模型参数的耗时占比。从上图中可以看到,一次训练迭代中,后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时占比很小,几乎可以忽略。

上图表示GPipe流水线并行的调度策略,来自于《Efficient large-scale language model training on gpu clusters using megatron-lm》。上图中,横轴表示耗时,一个蓝色小块表示一个微批次的前向传递,一个绿色小块表示一个微批次的后向传递,黑色竖线表示一次流水线刷新,也就是优化器更新模型参数。从上图中可以看到,一个绿色小块的宽度大约是蓝色小块的二倍,一次训练迭代中,后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时占比很小,几乎可以忽略。

2.反向传播算法是怎么工作的

反向传播算法已经是训练神经网络模型不可缺少的一部分。训练神经网络模型时,用梯度下降算法来学习和更新模型参数(包含权重weights和偏置bias),问题是如何计算损失函数关于模型参数的梯度呢?这就要用到反向传播(backpropagation)算法。

2.1 前向传递:计算神经网络的输出

在讨论反向传播算法之前,我们先以多层前馈神经网络为例,用基于矩阵的方法来计算神经网络的输出。在此过程中,先定义一些数学符号。

2.2 反向传播的四个基本等式

2.2.2 误差与下一层误差的关联

带入上上式中,得到:

2.2.3 偏置的梯度

 2.2.4 权重的梯度

2.2.5 四个基本等式

综上,梯度反向传播的四个基本等式是:

有了这四个基本等式,我们就基本理解了梯度的计算过程。

3. 后向传递与前向传递的FLOPs比率

3.1 定义

FLOPS:全大写,floating point operations per second,每秒钟浮点数计算次数,理解为运算速度,是衡量硬件性能的指标。例如:A100的float32运算速度是9.7TFLOPS,V100的float32运算速度是7.8TFLOPS。

FLOPs:s为小写,floating point operations,表示浮点数运算次数,理解为计算量,衡量模型或算法的复杂度。

backward-forward FLOP ratio:后向传递与前向传递的FLOPs比率,表示一次后向传递的浮点数计算次数与一次前向传递的浮点数计算次数的比率。衡量了一次后向传递要比一次前向传递多进行的浮点数运算。

3.2 前向传递与后向传递的浮点数操作次数的理论分析

为了理解后向传递的浮点数运算为什么要比前向传递多?我们就要从反向传播算法的四个基本等式入手。

我们从一个有2层隐藏层的神经网络入手:

我们假设线性层采用ReLU激活函数,采用随机梯度下降优化器。下表中h1和h2分别表示第1层和第2层隐藏层的神经元个数。有2层隐藏层的神经网络一次训练迭代的计算过程如下表所示:

从上表中,我们可以观察到,对于多层前馈神经网络模型,有以下结论:

1. 相比于线性层,激活函数ReLU和损失函数的浮点数运算量可以忽略。

2. 对于第一层,后向传递-前向传递的FLOPs比率是1:1。

3. 对于其他层,后向传递-前向传递的FLOPs比率是2:1。

4. 采用随机梯度下降作为优化器,权重更新的FLOPs是模型参数规模的2倍。

3.2.1 第一层与其他层的区别

对于多层前馈神经网络模型,采用随机梯度下降作为优化器。

第一层的后向传递-前向传递的FLOPs比率是1:1,其他层的后向传递-前向传递的FLOPs比率是2:1。模型参数更新的FLOPs是模型参数规模的2倍。

3.2.2 batch_size的影响

前向传递和后向传递的计算量FLOPs与batch_size成正比,即随着batch_size增大而线性增长。

优化器更新模型参数的FLOPs与batch_size无关,只与模型参数规模和优化器类型有关。

随着batch_size增大,前向传递和后向传递的FLOPs线性增长,而权重更新的FLOPs保持不变,这使得权重更新的FLOPs变得逐渐可以忽略不计了。

3.2.3 网络深度的影响

神经网络层数对后向传递-前向传递FLOPs比率有着间接的影响。由于第一层的后向-前向FLOPs比率是1:1,而其他层后向-前向FLOPs比率是2:1。层数的影响实际上是第一层与其他层的比较。

定义一个CNN神经网络,中间层的数量由0到100,可以看到后向-前向FLOPs比率由1.5提高到了接近2的水平。当层数逐渐变深的时候,第一层对模型整体的FLOPs影响就变小了,模型整体的后向-前向FLOPs比率就很接近2。

4. 总结

随着batch_size的增大,前向传递和后向传递的FLOPs线性增长,而权重更新的FLOPs保持不变,参数更新的FLOPs变得可以忽略不计了。这体现为:当batch_size足够大时,在训练神经网络的一次迭代中,前向传递和后向传递是主要的耗时环节,而参数更新的耗时变得几乎可以忽略不计

由于第一层的后向-前向FLOPs比率是1:1,而其他层后向-前向FLOPs比率是2:1。随着网络层数的加深,第一层对整体FLOPs的影响变得可以忽略不计了。这体现为:当网络层数足够深时,后向传递的耗时几乎是前向传递耗时的2倍

总的来说,对于用大batch_size的深层神经网络来说,后向传递-前向传递的FLOPs比率接近于2:1,换句话说,后向传递的计算量大约是前向传递的两倍

#InternLM2-Math

上海人工智能实验室(上海AI实验室)开源发布新一代数学模型书生·浦语数学(InternLM2-Math)。基于书生·浦语2.0(InternLM2)强大的基础能力,InternLM2-Math仅以中轻量级参数规模,即在多项数学评测中刷新开源模型数学能力上限;此外,InternLM2-Math不仅会“解题”,更会“判题”,突破了传统数学大模型应用局限,将为数学基础研究和教学提供优质应用基座。

InternLM2-Math为首个同时支持形式化数学语言及解题过程评价的开源模型,以强大内生计算和推理能力,为技术社区提供强大数学工具和模型范式。秉持“以高质量开源赋能创新”的理念,InternLM2-Math代码和模型完全开源,并支持免费商用。

数学能力是大语言模型推理水平的重要体现。近日,谷歌 DeepMind 运用AI数学模型AlphaGeometry解几何题,其水平已接近人类奥林匹克金牌得主,引发广泛关注。当前,全球数学大模型领域研究取得了突出进展,但与顶尖人类水平相比仍然存在差距。上海AI实验室将继续以开源开放理念,与全球研究人员合作,共同探索提升语言模型数学推理能力的提升路径。

InternLM2-Math对MATH评测集中Level-5难度题目的解题过程

开源链接

GitHub:

​https://github.com/InternLM/InternLM-Math​

Huggingface:

​https://huggingface.co/internlm​

ModelScope:

​https://modelscope.cn/organization/Shanghai_AI_Laboratory​

四两拨千斤,轻量级选手刷新能力上限

本次开源的InternLM2-Math同时包含轻量级(7B)及中量级(20B)两个版本。

为测试InternLM2-Math的能力水平,研究人员采用GSM8K、MATH、匈牙利数学竞赛等四项数学评测集作为验证“考题”。评测结果显示,InternLM2-Math-7B以轻量级参数规模达到了与GPT-3.5同等的数学水平;中量级的InternLM2-Math-20B 则在没有借助任何外部工具的条件下,取得了目前开源模型的最佳成绩,达到与GPT-4接近的数学能力,刷新当前开源模型数学能力上限。

GSM8K:OpenAI提出的英文小学算数习题集,共1000余题;

MATH:UC Berkeley提出的英文初高中竞赛习题集,共5000题;

匈牙利数学竞赛评测集:用来衡量模型在非常见分布上的数学性能的测试集,共30余小问,通过专家校阅进行打分。

多个同类模型在GSM8K评测集上评测成绩对比,InternLM2-Math综合领先通用模型和数学专用模型,接近GPT-4数学能力

从下图中可见,InternLM2-Math-7B在GSM8K和MATH上的测试评分分别达到78.1和34.6,超越其他7B量级的通用模型和数学专用模型,与ChatGPT(GPT-3.5)不分伯仲。InternLM2-Math-20B 则超越了更大规模参数的数学专用模型MetaMath-Llemma-34B以及数理能力较强的 70B 级别通用开源模型Qwen-72B和DeepSeek-67B,并且在各个数据集上都达到了GPT-4性能约九成的评测成绩。

为了考察InternLM2-Math通用的数学能力,研究人员引入了“匈牙利数学竞赛评测集”作为指标参考。该评测集用于衡量语言模型OOD(分布外泛化)的数学性能,共设置30余道问题,通过专家人工校阅打分。评测结果显示,InternLM2-Math的7B与20B版本分别获得55分和66分,远超同类开源模型并整体接近GPT-4。这表明,InternLM2的数学性能并非针对特定评测集“突击”优化而来,而是具备了增强通用的数学能力。

为了保证InternLM2-Math在参与考试前没有被“泄题”,研究人员采用了MinHash和严格的数字匹配对模型训练中可能遇到的测试集数据进行去重,避免产生“数据污染”,研究人员在两组对照数据集上进行了损失函数计算,若不存在数据污染,损失函数应接近或大于0。验证结果显示,在InternLM2-Math7B/20B两个版本的损失函数值分别为0.14及0.11,表明训练过程中不存在“数据污染”。InternLM2-Math的数学考试成绩来源于自身“硬实力”,没有“考前泄题”。

数学课代表是怎样炼成的

上海AI实验室近期开源的InternLM2模型基座语言建模能力获得质的提升,综合性能达到同量级开源模型的领先水平,得益于此,InternLM2获得了 “天赋”。

研究人员利用InternLM2基座版模型,精选数学相关语料进行继续预训练,包括中英文数学相关的代码、网页、书籍等。其中,InternLM2-Math-7B/20B分别经过了120B和80B token的继续预训练。

微调阶段使用的指令数据覆盖中英文双语,共计200余万条,包含CoT、工具调用、奖励模型、数据推广等多种形式。

研究人员同时对数据量较少、模型性能交叉的数学知识点进行了数据增广,运用奖励建模对增广数据进行了过滤,删除不可靠的回复。对于数据中的复杂计算过程,研究人员将其扩写为更详细的步骤,使模型减少跳步推理产生的计算幻觉。

通过以上多任务学习,“天赋选手”逐步获取了多种数学能力,成为“优等生”。

经过多任务学习的InternLM2-Math在不借助任何工具(计算器、Python、Wolfram)的情况下,已表现出了高性能的内生计算能力。为探索其由“优等生”进步为“尖子生”的可能性,研究人员在训练时引入了数学语言Lean。

Lean是一种形式化数学语言,通过机器可检查的数学证明来数字化数学定理的证明,目前,许多本科数学阶段以下的数学定理都已经被用Lean表述。权威数学家曾通过Lean语言将学术论文转为形式化表达,表明Lean已经具有对现代数学的描述能力。

经过训练,InternLM2-Math可使用Lean的代码进行解答题计算,可将自然语言的证明题与Lean语言的证明状态互相翻译,或者根据给定的Lean证明状态进行证明步骤的搜索。表明InternLM2-Math在内生计算能力上,衍生出了强大的数学推理能力,已由“天赋选手”进步为名副其实的“数学尖子生”。

下图为InternLM2-Math使用Lean 3解应用题的例子,模型在注释会描述自己的计算思路。

下图为InternLM2-Math进行交互式证明,模型会根据当前Lean的证明状态搜索下一个证明步骤。模型用形式化语言严格证明了给定命题。

会解题也会判题的“AI名师”

InternLM2-Math创新性地具备了对解题过程与结果的评价能力,不仅会“解题”,更会“判题”,这使得其超越了传统数学大模型,拥有更广阔的应用空间,为数学基础研究、教学提供优质应用基座。

研究人员在模型微调阶段同时引入Outcome Reward Model (ORM)、Process Reward Model (PRM)、Lean as Reward Model (LRM)训练数据。通过PRM能力的获取,使InternLM2-Math可以认识到“自身错误”并指出错误过程。而LRM可使模型将自己产生的CoT 过程转变为Lean的形式,再通过Lean的计算结果判断过程的正确性,达到形式化过程监督的目的。

下图展示了模型PRM的能力,模型指出了错误的过程。

作为首个同时支持形式化数学语言及解题过程评价的开源模型,InternLM2-Math能够判断模型思维链过程的正确与否,使得模型具备数学能力持续改进的潜力。

#美杜莎~2

去年,在加速大语言模型推理层面,我们迎来了一个比推测解码更高效的解决方案 —— 普林斯顿、UIUC 等机构提出的 Medusa。如今,关于 Medusa 终于有了完整技术论文,还提供了新的版本。

如你我所知,在大型语言模型(LLM)的运行逻辑中,随着规模大小的增加,语言生成的质量会随着提高。不过,这也导致了推理延迟的增加,从而对实际应用构成了重大挑战。

从系统角度来看,LLM 推理主要受内存限制,主要延迟瓶颈源于加速器的内存带宽而非算术计算。这一瓶颈是自回归解码的顺序性所固有的,其中每次前向传递都需要将完整的模型参数从高带宽内存传输到加速器缓存。该过程仅生成了单个的 token,没有充分利用现代加速器的算术计算潜力,导致了效率低下。

为了解决这一问题,加速 LLM 推理的方法被提出,既可以增加解码过程的算术强度(FLOPs 与总数据移动的比率),也能减少解码步骤数量。这类方法以推测解码(speculative decoding)为代表,使用较小的草稿(draft) 模型在每一步生成 token 序列,然后通过较大的原始模型进行细化以获得可接受的延续。不过获得合适的草稿模型仍然具有挑战性,并且将草稿模型集成到分布式系统中更加困难。

在本文中,来自普林斯顿大学、Together.AI、伊利诺伊大学厄巴纳 - 香槟分校等机构的研究者没有使用单独的草稿模型来顺序生成候选输出,而是重新审视并完善了在主干模型之上使用多个解码头加速推理的概念。他们发现,如果该技术得到有效应用,可以克服推测解码的挑战,从而无缝地集成到现有 LLM 系统中。

具体来讲, 研究者提出了 MEDUSA,一种通过集成额外解码头(能够同时预测多个 tokens)来增强 LLM 推理的方法。这些头以参数高效的方式进行微调,并可以添加到任何现有模型中。至此,不需要任何新模型,MEDUSA 就可以轻松地集成地当前的 LLM 系统中(包括分布式环境),以确保友好用户体验。

值得关注的是,该论文作者之一 Tri Dao 是近来非常火爆的 Transformer 替代架构 Mamba 的两位作者之一。他是 Together.AI 首席科学家,并即将成为普林斯顿大学计算机科学助理教授。

  • 论文地址:https://arxiv.org/pdf/2401.10774.pdf
  • GitHub 地址:https://arxiv.org/pdf/2401.10774.pdf

在具体实现中,研究者通过两个关键见解进一步增强了 MEDUSA。首先,当前在每个解码步骤生成单个候选延续的方法导致了可接受长度受限和计算资源的低效使用。为了解决这个问题,他们建议使用 MEDUSA 头来生成多个候选延续,并通过对注意力掩码的简单调整来进行验证。其次可以使用类似于推测解码中的拒绝采样方案来生成与原始模型具有相同分布的响应,但对于很多 LLM 应用来说通常不必要。

因此,研究者考虑或许可以引入一种典型的可接受方案,即从 MEDUSA 输出中选择合理的候选者。他们使用温度作为阈值来管理原始模型预测的偏差,为拒绝采样提供了一种有效的替代方案。这种方法有效地解决了拒绝采样的局限性,比如在较高温度下速度降低。

此外,为了给 LLM 配备预测性的 MEDUSA 头,研究者提出了两种针对不同场景量身定制的微调程序。对于计算资源有限或者目标是将 MEDUSA 纳入现有模型而不影响其性能的情况,他们建议使用 MEDUSA-1。该方法需要的内存最少,并且可以使用类似于 QLoRA 中的量化技术来进一步优化,而不会因固定主干模型影响生成质量。

不过,对于 MEDUSA-1,主干模型的全部潜力无法得到充分利用。因此可以进一步进行微调,以提高 MEDUSA 头的预测精度,并直接带来更大加速。因此研究者提出了 MEDUSA - 2,它适用于计算资源充足或从基础模型进行直接监督微调的场景。MEDUSA-2 的关键是一个训练协议,它能够对 MEDUSA 头和主干模型进行联合训练,而不会影响模型下一个 token 的预测能力和输出质量。

在实验部分,研究者主要关注批大小为 1 的场景,这代表了 LLM 本地托管以供个人使用的用例。他们在不同大小和训练设置下测试了 MEDUSA,包括 Vicuna-7B 和 13B(使用公共数据集训练)、Vicuna -33B(使用私有数据集训练)、Zephyr-7B(使用监督微调和对齐训练)。 

结果表明,MEDUSA 在不影响生成质量的情况下,可以在不同的 promt 类型中实现 2.3 至 3.6 的推理加速。如下动图为 Vicuna-7b 上有无 Medusa-1 时推理速度比较。

论文共同一作 Tianle Cai 表示,自 Medusa 项目推出以来,它在 TensorRT、TGI 以及众多开源项目和公司中得到采用。在新的技术论文中,我们推出了用于全模型调优的 Medusa-2 方案、用于将 Medusa 集成到任何微调 LLM 的自蒸馏以及其他更多加速技术。

对于这项研究,Lepton AI 创始人贾扬清表示,Medusa 可能是他们见过的最优雅的加速推理解决方案之一,能够与 int8/fp8、编译等互补,在实践中实现 2 倍性能增益。

并且,他们已将 Medusa 与很多现有优化方法、混合加速方案进行集成,结果在合理的并发下,加速保持正值,并在 A100 和 H100 等卡中尤其有效。此外,他们还已经为 Llama 模型训练了通用 Medusa 头。

方法概览

MEDUSA 遵循推测解码框架,其中每个解码步骤主要由三个子步骤组成:(1) 生成候选者,(2) 处理候选者, (3) 接受候选者。对于 MEDUSA,(1) 是通过 MEDUSA 头(head)实现的,(2) 是通过树注意力(tree attention)实现的,并且由于 MEDUSA 头位于原始主干模型之上,因此 (2) 中计算的 logits 可以用于子步骤 (1) 的下一个解码步骤。最后一步 (3) 可以通过拒绝采样(rejection sampling)或典型接受(typical acceptance)来实现。MEDUSA 的整体流程如下图 1 所示。

关键组件

MEDUSA 的关键组件主要包括 MEDUSA 头和树注意力。

首先,MEDUSA 头与原始主干模型一起进行训练。其中,原始主干模型可以在训练期间保持冻结状态 (MEDUSA-1) 或一起训练 (MEDUSA-2)。这种方法甚至可以在单个 GPU 上微调大模型,利用强大的基础模型学得的表征。

此外,MEDUSA 头的分布确保与原始模型的分布一致,从而缓解了分布偏移问题,并且 MEDUSA 不会增加服务系统设计的复杂性,对分布式设置很友好。

由于候选者增加会提高计算需求,该研究采用树状结构的注意力机制来同时处理多个候选者。这种注意力机制不同于传统的因果注意力范式。在其框架内,只有来自同一 continuation 的 token 才被视为历史数据。受图神经网络领域提出的将图结构嵌入注意力的启发,研究团队还将树结构合并到注意力掩码中,如下图 2 所示。

训练策略

冻结主干模型来训练 MEDUSA 头的方法很简单,并且需要的计算资源很少,但是将主干网络与 MEDUSA 头结合训练可以显著提高 MEDUSA 头的准确性。因此,根据计算资源和用例的具体要求,研究团队为 MEDUSA 头提出了两个级别的训练策略,即 MEDUSA-1:冻结主干网络,MEDUSA-2:联合训练。

最后,该研究提出了 MEDUSA 的两个扩展,包括自蒸馏(self-distillation)和典型接受(typical acceptance),分别用于处理 MEDUSA 没有可用训练数据的情况和提高解码过程的效率。

实验

为了证明 MEDUSA 在不同设置下的有效性,该研究进行了两组实验:首先,在 Vicuna-7B/13B 模型上评估 MEDUSA,以展示 MEDUSA-1 和 MEDUSA-2 的性能;其次,在 Vicuna-33B 和 Zephyr-7B 模型上评估 MEDUSA,以研究自蒸馏的有效性,因为 Vicuna-33B 模型的训练数据集不公开,而 Zephyr-7B 模型使用 RLHF 进行训练。

用例研究 1:在 Vicuna-7B/13B 模型上评估 MEDUSA

在 Vicuna-7B/13B 模型上评估 MEDUSA-1、MEDUSA-2 的结果如下图 4 所示。

用例研究 2:在 Vicuna-33B 和 Zephyr-7B 使用自蒸馏训练

研究者关注了需要自蒸馏的情况,使用 Vicuna-33B 和 Zephyr-7B 作为示例。他们首先使用一些种子 prompt 来生成数据集,然后将 ShareGPT 和 UltraChat 作为种子数据集,并为以上两个示例收集了包含大约 100k 样本的数据集。

下表 1 展示了不同 MEDUSA-2 模型在 MT-Bench 基准下的加速比、开销和质量。

下图 5 为使用 MEDUSA-2 时不同模型的加速情况。

消融实验

下图 6a 比较了随机采样密集树设置(蓝点)和优化稀疏树设置(红星)的加速率。6b 比较了密集和稀疏树设置的速度。 

下图 7 展示了不同采样设置下,模型性能的比较分析。

两阶段微调的有效性。研究者针对 Vicuna-7B 模型,评估了两种微调策略下的性能差异。

#Uni-RLHF

RLHF 通过学习人类偏好,能够在难以手工设计奖励函数的复杂决策任务中学习到正确的奖励引导,得到了很高的关注,在不同环境中选择合适的人类反馈类型和不同的学习方法至关重要。

然而,当前研究社区缺乏能够支持这一需求的标准化标注平台和统一基准,量化和比较 RLHF 的最新进展是有挑战性的。

本文中,天津大学深度强化学习实验室的研究团队推出了面向现实决策场景的 Uni-RLHF 平台,这是一个专为 RLHF 量身定制的综合系统实施方案。它旨在根据真实的人类反馈提供完整的工作流程,一站式解决实际问题。

  • 论文题目:Uni-RLHF: Universal Platform and Benchmark Suite for Reinforcement Learning with Diverse Human Feedback
  • 项目主页:https://uni-rlhf.github.io/
  • 平台链接:https://github.com/pickxiguapi/Uni-RLHF-Platform
  • 算法代码库:https://github.com/pickxiguapi/Clean-Offline-RLHF
  • 论文链接:https://arxiv.org/abs/2402.02423
  • 作者主页:http://yifu-yuan.github.io/

Uni-RLHF 包含三个部分:1)通用多反馈标注平台,2)大规模众包反馈数据集,3)模块化离线 RLHF 基线代码库

具体流程来看,Uni-RLHF 首先针对各种反馈类型开发了用户友好的标注界面,与各种主流 RL 环境兼容。然后建立了一个系统的众包标注流水线,产生了包含 32 个任务、超过 1500 万个时间步的大规模标注数据集。最后,基于大规模反馈数据集,实现了最先进的 RLHF 算法的基线结果和模块化组件以供其他研究者使用。

Uni-RLHF 希望通过评估各种设计选择,深入了解它们的优势和潜在的改进领域,构建有价值的开源平台、数据集和基线,以促进基于真实人类反馈开发更强大、更可靠的 RLHF 解决方案。目前平台、数据集和基线代码库均已开源。

多反馈类型通用标注平台

Uni-RLHF 标注平台提供了众包标准标注工作流程:

  • 接口支持多种在线环境 (Online Mode) 和离线数据集 (Offline Mode),并且可以通过简单的接口扩展方式接入定制化的环境;
  • 查询采样器 (Query Sampler) 可决定哪些数据需要被标注,支持多种类型的采样策略;
  • 交互式用户界面 (User Interface) 可让众包查看可用轨迹片段并提供反馈响应,提供包含选择、拖动、框选和关键帧捕捉等一系列视频片段和图像标注方式;
  • 反馈翻译器 (Feedback Translator) 可将不同的反馈标签转换为标准化格式。

Uni-RLHF 包括平台、数据集和离线 RLHF 基线代码库三个部分

Uni-RLHF 能够支持大量主流的强化学习环境

适用于强化学习的标准反馈编码格式

为了更好地捕捉和利用来自标注者的各种不同类型的反馈标签,Uni-RLHF 对一系列相关研究进行了总结,提出一种标准化的反馈编码格式和对应的训练方法。使用者可以根据任务和标注成本需求,选择不同类型的标注方法。一般来说,信息密度越高,标注成本相应也会更大,但是反馈效率也会随之提升。

Uni-RLHF 支持以下五种反馈类型:

  • 比较反馈 (Comparative Feedback):对两段轨迹给出相对性的二元反馈比较
  • 属性反馈 (Attribute Feedback):对两段轨迹给出基于多属性的相对反馈比较
  • 评估反馈 (Evaluative Feedback):对一段轨迹给出多个级别的评估选项
  • 视觉反馈 (Visual Feedback):对一段轨迹中的视觉重点进行选择和标记
  • 关键帧反馈 (Keypoint Feedback):对一段轨迹中的关键帧进行捕捉和标记

大规模众包标注流水线

在 RLHF 训练过程中,数据标注是一项复杂的工程问题。研究人员围绕 Uni-RLHF 构建众包数据注释流水线,通过并行的众包数据注释和过滤,促进大规模注释数据集的创建。

为了验证 Uni-RLHF 平台各方面的易用性和对 RLHF 前沿算法性能进行验证,研究人员使用广受认可的离线 RL 数据集实现了大规模众包标注任务,以收集反馈标签。

在完成数据收集后,研究人员进行了两轮数据过滤,以尽量减少有噪声的众包数据量,最终建立了一个系统化的众包注释流水线,形成了大规模标注数据集,包括 32 个主流任务中的 1,500 多万个时间步。

标注流水线中每个组件的验证

为了证明数据过滤的有效性。研究人员首先在 SMARTS 中抽取了 300 个轨迹片段进行专家注释,称为「Oracle」。接下来,研究人员请了五位众包在三种不同的设置下分别标注 100 条轨迹。「Naive」意味着只能看到任务描述,「Example」允许查看专家提供的五个注释样本和详细分析,而「Filter」则添加了过滤器。

以上实验结果表明,每个组件都显著提高了标注的可靠性,最终实现了与专家注释 98% 的一致率。

离线 RLHF 基准实验

研究人员利用收集到的众包反馈数据集对下游决策任务进行了大量实验,以评估各种不同的设计选择及其对应的优势。

首先,Uni-RLHF 使用了三种不同的奖励模型设计结构,分别是 MLP、TFM (Transformer) 和 CNN,其中 MLP 结构便于处理向量输入,而 CNN 结构便于处理图像输入。TFM 奖励结构则能够更好地拟合 non-Markovian 奖励。同时Uni-RLHF 使用了三种广泛使用的离线强化学习算法作为底座,包括 IQL、CQL 和 TD3BC。

Oracle 代表使用手工设计的任务奖励训练的模型;CS (CrowdSource) 代表一种是通过 Uni-RLHF 系统众包获得的众包标签;而 ST (Script Teacher) 代表根据实际任务奖励生成的合成标签,可视为专家标签供比较。

实验结论表明:

  • 基于 IQL 基线效果最稳定,并且比较 IQL-CS 能够表现出和 IQL-Oracle 相当的优异性能,而 CQL 基线偶尔会出现策略崩溃的结果;
  • 总体看来,TFM 结构在稳定性和性能两方面均领先于 MLP 结构,尤其是在稀疏奖励设置的环境中;
  • 和合成标签 (ST) 相比,众包标签 (CS) 在大多数环境中能够达到相当甚至超越的效果,这也证明了 Uni-RLHF 具有高质量的数据标注。

在图像输入的环境中,众包标签 (CS) 则全面领先于合成标签 (ST),研究人员认为这种优异表现来源于人类能够更敏感的捕捉到游戏过程中的细节过程,这些细节则很难用简单的积分奖励来概括。

RLHF 方法是否能在真实的复杂任务上成功替代手工设计的奖励函数?研究人员使用了 NeurIPS 2022 中 SMARTS 自动驾驶竞赛的环境,该环境提供了相对真实和多样化的自动驾驶场景,并使用成功率,速度和舒适度等多个指标评估模型的性能。其中,冠军方案针对该任务设计奖励函数会经过多次试错,并在多次训练过程中不断调整完善各项奖励时间及系数,最终形成了以下极为复杂的奖励函数构成,设计成本极高:

自动驾驶场景奖励函数设计

而通过众包标注的简单反馈标签进行奖励函数训练,Uni-RLHF 就能够达到超越专家奖励的任务成功率,并且在舒适度指标上也有所领先。

针对 SMARTS 自动驾驶场景的多指标评测

Uni-RLHF 方法和 Oracle 奖励函数对比。(左:Oracle,右:Uni-RLHF)

Uni-RLHF 还针对其他多种类型的反馈形式进行了更多验证,这里以多属性反馈 (Attribute Feedback) 举一个简单的例子:用户希望训练一个 Walker 机器人,使其速度和躯干高度在运动的过程中进行自由的变化,而不是简单的最大化速度。此时简单的比较反馈就很难准确的表述用户的偏好,Uni-RLHF 则提供了针对多属性反馈的标注模式。在本实验中,Walker 会运行 1000 步,并每 200 步调整姿态,速度的属性值设定为 [慢,快,中,慢,快],高度的属性值设定为 [高,中,高,低,高]。从曲线和相应的视频中可以清楚地观察到经过 Uni-RLHF 标注后训练的模型能够灵活的进行姿态转换。 

Walker 遵循用户偏好进行灵活姿态转换

总结和未来展望

Uni-RLHF 展示了在决策任务中基于 RLHF 方法取代手工设计奖励函数的重要前景,研究人员希望通过建设平台、大规模数据集和代码库以促进更加可靠,基于真实人类反馈标注的 RLHF 解决方案。该领域仍存在一些挑战和可能的未来方向:

  • 评估人类的非理性和偏向性:众包提供反馈标签势必会带来反馈标签的噪音,即对任务认知不统一、标注错误、有偏向性等问题,如何在嘈杂的标签数据中进行学习是值得研究的方向。
  • 不完美奖励函数修正:反馈标签的噪音和数据分布狭窄等问题会导致学习到次优的奖励函数、如何基于奖励塑形、先验知识等进一步的基于该奖励函数进行修正也是重要的研究问题。
  • 多反馈类型的组合作用:尽管目前的研究已经证实,使用更细粒度的反馈方式会给学习效率带来巨大提升,但在同一个任务中聚合图像、评估、关键帧等各类型反馈方式依然值得进一步研究。

#MobileNetV4

作者介绍了最新一代的MobileNets,名为MobileNetV4(MNv4),其特点是针对移动设备设计的通用高效架构。作者的两阶段神经网络架构搜索(NAS)方法,将粗略搜索与细粒度搜索分开,显著提升了搜索效率,并促进了比先前最先进模型显著更大的模型的创建。

作者介绍了最新一代的MobileNets,名为MobileNetV4(MNv4),其特点是针对移动设备设计的通用高效架构。在其核心部分,引入了通用倒瓶颈(UIB)搜索块,这是一个统一且灵活的结构,它融合了倒瓶颈(IB)、ConvNext、前馈网络(FFN)以及一种新颖的额外深度可分(ExtraDW)变体。与UIB并行,我们提出了Mobile MQA,这是一个专为移动加速器设计的注意力块,能带来显著的39%速度提升。

同时,作者还介绍了一种优化的神经架构搜索(NAS)方法,它提高了MNv4搜索的有效性。UIB、Mobile MQA以及精细化的NAS方法的整合,使得MNv4模型系列在移动CPU、DSP、GPU以及像苹果神经引擎和谷歌Pixel EdgeTPU这样的专用加速器上几乎达到了帕累托最优——这是其他测试模型所不具备的特性。最后,为了进一步提升准确度,引入了一种新颖的蒸馏技术。借助这项技术,MNv4-Hybrid-Large模型在ImageNet-1K上的准确度达到了87%,在Pixel 8 EdgeTPU上的运行时间仅为3.8ms。

1 Introduction

作者的两阶段神经网络架构搜索(NAS)方法,将粗略搜索与细粒度搜索分开,显著提升了搜索效率,并促进了比先前最先进模型显著更大的模型的创建。此外,结合离线蒸馏数据集,减少了NAS奖励测量中的噪声,从而提升了模型质量。

通过整合UIB、MQA和改进的NAS配方,作者推出了MNv4模型系列,在包括CPU、DSP、GPU和专业加速器在内的多种硬件平台上,实现了大多为帕累托最优性能。作者的模型系列覆盖了从极其紧凑的MNv4-Conv-S设计(拥有3.8M参数和0.2GMACs),在Pixel6CPU上以2.4毫秒内达到73.8%的ImageNet-1Ktop-1准确率,到MNv4-Hybrid-L高端变体,在Pixel8EdgeTPU上以3.8毫秒的运算时间为移动模型准确率树立了新的基准。作者新颖的蒸馏配方混合了带有不同增强的数据集,并添加了平衡的同类数据,增强了泛化能力,进一步提高了准确率。借助这项技术,尽管MNv4-Hybrid-L的MACs减少了39倍,但其ImageNet-1Ktop-1准确率仍达到了令人印象深刻的87%:仅比其教师模型低0.5%。

2 RelatedWork

优化模型的准确性和效率是一个研究得很深入的问题。

移动卷积网络: 关键工作包括MobileNetV1 利用深度可分离卷积以提高效率,MobileNetV2 引入了线性瓶颈和倒置残差,MnasNet 在瓶颈中整合了轻量级注意力机制,以及MobileOne 在推理时在倒置瓶颈中添加并重新参数化线性分支。

高效混合网络:这一研究方向整合了卷积和注意力机制。MobileViT 通过全局注意力块将CNN的优势与ViT相结合。MobileFormer并行处理MobileNet和一个Transformer,并在两者之间建立双向桥梁进行特征融合。FastViT 在最后一个阶段加入注意力,并使用大的卷积核作为早期阶段自注意力机制的替代。

高效注意力: 研究工作一直集中在提高MHSA的效率。EfficientViT和MobileViTv2提出了自注意力近似方法,以达到线性复杂度,而对准确度的影响很小。EfficientFormer-V2为了提高效率而对Q、K、V进行下采样,而CMT和NextViT仅对K和V进行下采样。

硬件感知神经架构搜索(NAS):另一种常见的技术是使用硬件感知神经架构搜索(NAS)来自动化模型设计过程。NetAdapt 使用经验延迟表来在目标延迟约束下优化模型的准确性。MnasNet 同样使用延迟表,但它应用强化学习来进行硬件感知的NAS。FBNet 通过可微分的NAS加速了多任务硬件感知搜索。MobileNetV3 通过结合硬件感知NAS、NetAdapt算法和架构改进,针对手机CPU进行调优。MobileNetMultiHardware 为多个硬件目标优化单一模型。Once-for-all 为提高效率,将训练和搜索分离。

3 Hardware-IndependentParetoEfficiency

屋顶线模型: 为了使一个模型在普遍情况下都高效,它必须能够在其理论的计算复杂度与实际硬件性能之间找到平衡。

在硬件目标上表现出色,这些硬件目标的瓶颈极大地限制了模型性能,这些瓶颈主要由硬件的最高计算吞吐量和最高内存带宽决定。

脊点扫描分析:如图2和图3所示,屋顶线模型揭示了MobileNetV4模型如何与其他卷积MobileNets相比,实现硬件独立的几乎帕累托最优性能。在低脊点硬件(例如CPU)上,模型更可能受计算限制而非内存限制。因此,为了提高延迟,即使以增加内存复杂度为代价(如MobileNetV3Large-1.5x),也要最小化总的MAC数量。在高脊点硬件上,数据移动是瓶颈,所以MAC不会显著减慢模型速度,但可以增加模型容量(如MobileNetV1-1.5x)。因此,为低脊点优化的模型在高脊点上运行缓慢,因为内存密集和低MAC的全连接(FC)层受到内存带宽的限制,不能利用高可用的峰值MAC。

MobileNetV4设计:MobileNetV4在平衡MACs和内存带宽方面进行了投资,旨在以最低的成本获得最大的回报,特别关注网络的起始和结束部分。在网络的开头,MobileNetV4使用大而昂贵的前几层来显著提高模型的容量和下游准确性。这些初始层主要由大量的MACs组成,因此它们仅在低RP硬件上成本较高。在网络的末端,所有MobileNetV4变体使用相同大小的最终全连接(FC)层以最大化准确性,尽管这导致较小尺寸的MNV4变体在高RP硬件上遭受更高的FC延迟。由于大的初始卷积层在低RP硬件上成本高,但在高RP硬件上并不昂贵,而最终的全连接层在高RP硬件上成本高,在低RP硬件上却不贵,MobileNetV4模型不会同时遭受这两种减速。换句话说,MNV4模型能够使用提高准确性的昂贵层,但不会同时承受这些层的组合成本,从而在所有脊点上都实现了几乎是最优的Pareto性能。

4 UniversalInvertedBottlenecks

作者提出了通用逆瓶颈(UniversalInvertedBottleneck, UIB)模块,这是一个适用于高效网络设计的可适应构建块,它具有灵活地适应各种优化目标的能力,而不会使搜索复杂度爆炸性增长。

倒瓶颈(IB)模块,由MobileNetV2提出,已成为高效网络的标准化构建模块。

基于最成功的MobileNet要素——可分离的深度卷积(DW)和点式(PW)扩展及倒瓶颈结构,本文引入了一种新的构建块——通用倒瓶颈(UIB)块,如图4所示。其结构相当简单。作者在倒瓶颈块中引入了两个可选的DW,一个在扩展层之前,另一个在扩展层和投影层之间。这些DW的存在与否是神经网络架构搜索(NAS)优化过程的一部分,从而产生新的架构。尽管这种修改很简单,但作者的新构建块很好地统一了几个重要现有块,包括原始的IB块、ConvNext块以及ViT中的FFN块。此外,UIB还引入了一种新的变体:额外的深度卷积IB(ExtraDW)块。

除了在神经网络架构搜索(NAS)过程中允许灵活的中间层(IB)结构外,作者还避免了任何人为设计的缩放规则,比如在EfficientNet中使用的那种,而是为每个模型大小单独优化结构。为了防止NAS超级网络的大小爆炸性增长,作者共享了通用组件(逐点扩展和投影)并简单地将深度可分离卷积(DWs)作为额外的搜索选项添加进去。结合基于超级网络的网络架构搜索算法,这种方法使得大多数参数(大于95%)可以在不同的实例之间共享,使得NAS变得极其高效。

UIB实例化 UIB块中的两个可选深度卷积有四种可能的实例化方式(图4),这导致了不同的权衡。

倒瓶颈(IB)- 在扩展的特征激活上进行空间混合,以增加成本为代价提供更大的模型容量。

ConvNext 通过在扩展之前执行空间混合,实现了使用更大核尺寸进行更廉价的空间混合。

ExtraDW是本文提出的一种新变体,它允许廉价地增加网络的深度和感受野。它提供了以下几点优势:

结合ConvNext与IB.4的优势。

FFN 是由两个1x1的点状卷积(PW)堆叠而成,并在它们之间加入激活和标准化层。PW是最受加速器友好的操作之一,但最好与其他模块一起使用。

在网络的每个阶段,UIB提供了灵活性以:

  1. 达成一个即时的空间和通道混合的权衡。
  2. 按需扩大感受野。
  3. 最大化计算利用率。

5 MobileMQA

在本节中,作者介绍了MobileMQA,这是一个专门为加速器优化的新型注意力块,它能提供超过39%的推理速度提升。

操作强度的重要性:近期在视觉模型的研究中,人们大多致力于减少算术运算(MACs)以提高效率。然而,在移动加速器上性能的真正瓶颈往往不是计算而是内存访问。这是因为加速器提供的计算能力远大于内存带宽。因此,仅仅最小化MACs可能并不会导致更好的性能。相反,作者必须考虑操作强度,即算术运算与内存访问的比率。

MQA在混合模型中是高效的:MHSA 将Query、键和值投影到多个空间以捕捉信息的不同方面。多Query注意力(MQA)[37] 通过在所有头之间使用共享的键和值简化了这一点。尽管多个Query头是必要的,但大型语言模型可以有效共享单个键和值的头,而不会牺牲准确度[25]。对于键和值使用一个共享的头,当批处理的Token数量相对于特征维度较小时,可以大大减少内存访问需求,从而显著提高操作强度。这对于面向移动应用的混合视觉模型通常是这种情况,在这种情况下,仅在具有高特征维度的低分辨率后期阶段使用注意力,并且批大小通常为1。作者的实验证实了MQA在混合模型中的优势。如表1所示,与MHSA相比,MQA在EdgeTPUs和三星S23GPU上实现了超过39%的加速,而质量损失可以忽略不计(-0.03%)。MQA还将MACs和模型参数减少了25%以上。据作者所知,作者是第一个在移动视觉中使用MQA的。

采用非对称空间下采样: 受到MQA的启发,它在Query、键和值之间使用非对称计算,作者将空间缩减注意力(SRA)[45]融合到作者优化的MQA模块中,以降低键和值的分辨率,同时保持高分辨率Query。这一策略是由混合模型中空间相邻标记之间的观察到的相关性所启发的,这归因于早期层中的空间混合卷积滤波器。通过非对称空间下采样,作者在输入和输出之间保持了相同的标记数量,保持了注意力的高分辨率并显著提高了效率。与不同,作者的方法用步长为2的3x3深度卷积替换了AvgPooling,为提高模型容量提供了一种成本效益高的方式。

移动MQA 这里作者提出了作者的移动MQA模块:

6 DesignofMNv4Models

作者的设计理念:简约遇见高效。 在开发最新的MobileNets时,作者的核心目标是实现在各种移动平台上的帕累托最优。为了达到这个目标,作者首先对现有模型和硬件进行了广泛的相关性分析。通过实证检验,作者找到了一组既能确保在各种设备上成本模型(延迟成本的预测)之间的高度相关性,又能在性能上接近帕累托前沿的组件和参数。

作者的调查揭示了一些关键的见解:

多路径效率问题:组卷积和类似的多路径设计,尽管具有更低的浮点运算次数(FLOPcounts),但由于内存访问复杂度,可能效率较低。

硬件支持很重要:像SqueezeandExcite(SE)[21]这样的高级模块,

GELU、LayerNorm 在DSPs上的支持并不好,LayerNorm的速度也比BatchNorm慢,而SE在加速器上的表现也比较慢。

简洁的力量:传统组件——深度卷积和逐点卷积、ReLU、批量归一化以及简单的注意力机制(例如,MHSA)——展示了卓越的效率和硬件兼容性。

基于这些发现,作者建立了一套设计原则:

标准组件:作者优先考虑广泛支持的元素,以实现无缝部署和硬件效率。

灵活的UIB模块:作者新颖的可搜索UIB构建块支持可适应的空间和通道混合,接收场调整,以及最大化的计算利用率,通过网络架构搜索(NAS),促进了效率和准确性之间的平衡妥协。

采用直接注意力机制:作者的MobileMQA机制为了最佳性能而优先考虑简单性。

这些原则使得MobileNetV4在所有评估的硬件上大多数情况下都是帕累托最优的。以下,作者详细介绍了针对UIB模型搜索改进的NAS配方,概述了各种MNv4-Conv模型大小的特定搜索配置,并解释了混合模型的构建过程。

RefiningNASforEnhancedArchitectures

为了有效地实例化UIB块,作者采用了针对性能改进定制的TuNAS。

增强搜索策略:作者的方法通过实施两阶段搜索,减轻了TuNAS因参数共享而偏向于较小滤波器和扩展因子的偏见。这种策略解决了UIB的深度层与其他搜索选项之间参数数量方差的问题。

粗粒度搜索:起初,作者专注于确定最优的滤波器大小,同时保持参数固定:一个默认扩展因子为4的反向瓶颈块和一个3x3的深度可分核。

细粒度搜索:在初步搜索结果的基础上,作者搜索UIB的两个深度可分层的配置(包括它们的存在以及3x3或5x5的核大小),同时保持扩展因子恒定为4。

表3展示了与传统的单阶段搜索相比,通过作者的两阶段搜索所提高的效率和模型质量,在单次TuNAS传递中探索了一个统一的搜索空间。

增强TuNAS的鲁棒训练 TuNAS的成功取决于对架构质量的准确评估,这对于奖励计算和政策学习至关重要。最初,TuNAS利用ImageNet-1k来训练超级网络,以便进行架构评估。然而,这种做法忽略了实际应用中网络可能遇到的噪声和扰动。为了解决这个问题,作者建议在训练过程中加入鲁棒性训练。具体来说,作者在训练集中引入了多种数据增强和对抗样本,以此来增强模型的鲁棒性。通过这种方式,TuNAS可以更好地评估架构在嘈杂环境下的性能,从而提高最终学到的网络架构的质量。

网络,然而模型在ImageNet上的性能显著受到数据增强、正则化以及超参数选择的影响。鉴于TuNAS的架构样本在不断发展变化,找到一个稳定的超参数集合是具有挑战性的。

作者通过一个离线的蒸馏数据集来解决这一问题,这样就不需要额外的增强方法,并减少了对正则化和优化设置的敏感性。如第8节所述的JFT蒸馏数据集作为作者训练TuNAS的集合,在表4中展示了显著的改进。考虑到在扩展训练会话中,深度缩放模型超越了宽度缩放模型,作者将TuNAS的训练扩展到750个周期,产生了更深、质量更高的模型。

作者构建了基于NAS优化的UIB块的MNv4-Conv模型,并根据特定的资源限制对其进行定制。更多详细信息见附录0.A。与其他混合模型一致,作者发现将注意力机制添加到卷积模型的最后阶段最为有效。在MNv4-Hybrid模型中,作者交错使用MobileMQA块和UIB块以提升性能。有关全面的模型规格,请参考附录0.D。

7 Results

在本节中,作者将展示MobileNetV4(MNv4)模型在ImageNet-1K分类和COCO目标检测上的几乎是最优的帕累托性能。

ImageNetclassification

实验设置:为了评估模型结构的性能,作者遵循标准的协议,仅使用ImageNet-1k 训练分割进行训练,并在验证分割上测量Top-1准确度。作者的延迟分析涵盖了多种移动硬件的广泛和代表性选择,包括ARMCortexCPU(Pixel6, SamsungS23)、高通HexagonDSP(Pixel4)、ARMMaliGPU(Pixel7)、高通Snapdragon(S23GPU)、苹果神经引擎和谷歌EdgeTPU。作者完整的训练设置在附录0.C中详细说明。

在基准测试中,作者将自己的模型与领先的效率模型进行了比较,包括混合型(MiT-EfficientViT,FastViT,NextViT)和卷积型(MobileOne,ConvNext,以及先前的MobileNet)。

作者根据报告的Top-1准确率以及作者的延迟评估,选择了这些版本([19][36][18])。值得注意的是,作者采用现代训练方法改进了MobileNet系列(V1、V2、V3),从而显著提高了准确性:MobileNetV1提高了3.4%,达到74.0%;V2提高了1.4%,达到73.4%;V3提高了0.3%,达到75.5%。这些改进后的MobileNets基准线在本论文中被用于隔离架构的进步。

结果:

作者的结果,如图1所示,并在表5中详细说明,表明MNv4模型在一系列准确度目标和移动硬件上大多数情况下都达到了帕累托最优,包括CPU、DSP、GPU以及像苹果神经引擎和谷歌EdgeTPU这样的专用加速器。

在CPU上,MNv4模型显著优于其他模型,其速度大约是MobileNetV3的两倍,与同等准确度目标的其他模型相比,速度要快几倍。在EdgeTPU上,MNv4模型在相同准确度水平下的速度是MobileNetV3的两倍。特别是,MNv4-Conv-M模型比MobileOne-S4和FastViT-S12快了50%以上,同时在可比延迟下,比MobileNetV2的Top-1准确度提高了1.5%。在S23GPU和iPhone13CoreML(ANE)上,MNv4模型大多数都处于Pareto前沿。在S23GPU上,最接近的竞争对手MIT-EfficientViT,其速度超过了。

在相同的准确度下,MNv4在CoreML上的延迟是两倍。针对AppleNeuralEngine进行优化的FastViT在CoreML上排名第二,但在S23GPU上的延迟是MNv4的五倍以上。与许多混合模型一样,MNv4混合模型与DSP不兼容。尽管如此,MNv4-Conv模型在DSP上仍然表现最佳,突显了它们在多样化硬件平台上的领先兼容性和效率。MNv4-Conv模型提供了卓越的硬件兼容性和效率。这一成功凸显了作者的UIB块、增强的NAS配方以及精心设计的搜索空间的强大。MNv4-Hybrid在CPU和加速器上实现了优异的性能,展示了作者MobileMQA设计的跨平台效率。

普遍性对于移动模型至关重要,它要求这些模型能够在多样化的硬件平台上实现最佳性能。作者的评估突显出现有模型在实现这一目标时所面临的挑战。MobileNetV3在CPU上的表现不错,但在EdgeTPUs、DSPs和GPU上则有所不足。FastViT在苹果神经引擎上表现良好,但在CPU和GPU上则表现挣扎。EfficientViT在GPU上的性能较好,但在苹果神经引擎上的表现就不尽如人意。相比之下,MNv4-Conv模型展现出了异常好的兼容性,并在包括CPU、GPU、苹果神经引擎和谷歌EdgeTPUs在内的广泛硬件上实现了几乎普遍的帕累托最优性能。这种多用途性确保了MNv4-Conv模型可以在移动生态系统间无缝部署,无需进行任何平台特定的调整,为移动模型的普遍性树立了新的基准。

COCOObjectDetection

实验设置:作者在COCO17数据集上评估了MNv4Backbone网络在目标检测任务中的有效性。作者将M尺寸的MNv4Backbone网络与具有相似MACs数量的SOTA高效Backbone网络进行了比较。对于每个Backbone网络,作者使用RetinaNet框架构建了一个目标检测器。作者在P3-P7端点附加了一个256维FPN解码器和一个带有4个卷积层的 256 维预测头。像移动检测器一样,作者采用深度可分离卷积来降低FPN解码器和边界框预测头的计算复杂性。作者在COCO17训练集上对所有模型进行了600轮训练。

8 Enhanceddistillationrecipe

在补充架构创新的同时,蒸馏是一种提高机器学习效率的强大工具。其对移动模型的益处尤为显著,在严格的部署约束下,可能提供数倍的效率提升。基于稳固的 “PatientTeacher" 蒸馏基准,作者引入了两项新技术来进一步推动性能的提升。

动态数据集混合:数据增强对于提取性能至关重要。尽管先前的方法依赖于固定的增强序列,但作者发现动态地混合多个具有不同增强策略的数据集会导致更优的提取结果。作者对三个关键提取数据集进行了实验:

JFT数据增强:为了增加训练数据量,作者通过重新采样JFT-300M 数据集,以使每个类别包含13万张图片 (总计1.3亿张),加入领域内、类别平衡的数据。遵循NoisyStudent 协议,并使用在ImageNet-1K上训练的EfficientNet-BO。   

9 Conclusion

在本文中,作者提出了MobileNetV4,这是一系列通用的、高效的模型,旨在在整个移动生态系统内高效运行。作者利用了多项进展,使MobileNetV4几乎在所有的移动CPU、GPU、DSP以及专用加速器上达到帕累托最优,这是其他任何模型所不具备的特性。

作者测试了多种模型。作者引入了新的通用反转瓶颈和移动MQA层,并结合了改进的神经架构搜索(NAS)方法。将这些与一种新颖的、最先进的蒸馏方法相结合,作者在Pixel8EdgeTPU上以3.8毫秒的延迟达到了87%的ImageNet-1K准确度,推进了移动计算机视觉的最新技术水平。此外,作者还提出了一种理论框架和分析方法,以理解是什么让模型在异构设备上具有通用性,这为未来的设计指明了方向。作者希望这些新颖的贡献和分析框架能进一步推动移动计算机视觉的发展。

搜索空间构建:

固定初始层:作者首先在第一阶段使用了一个Conv2D层(3x3核,步长2)以便快速降低分辨率,随后在第二阶段采用了NAS优化的融合IB块(步长2),以平衡效率和准确性。

NAS驱动的优化:NAS过程精确地确定了在剩余四个阶段中UIB块的数量和参数实例化,确保了性能的最优结构。

固定Head层:作者使用了与MobileNetV3相同的Head层配置。

观察到在UIB块内的点式卷积在高分辨率下往往表现出较低的运算强度,作者优先在初始层中使用计算密度更高的操作,以平衡效率和准确度。

作者的优化目标:

MNv4-Conv-S:双重目标——285MMACs和0.2ms延迟(Pixel6EdgeTPU,224px输入)。

MNv4-Conv-M:0.6毫秒延迟(Pixel6EdgeTPU,256像素输入)。

MNv4-Conv-L:针对384px输入,双重延迟目标为2.3ms(Pixel6EdgeTPU)和2.0ms(Pixel7EdgeTPU)。

需要注意的是,通过将作者的搜索空间限制在跨设备具有良好相关成本模型的组件上,作者发现EdgeTPU延迟优化可以直接产生普遍高效的模型,这一点在后文中有详细演示。

Appendix0.BBenchmarkingmethodology

作者在各种移动平台上应用了一致的基准测试策略,对苹果神经引擎(AppleNeuralEngine)做了例外处理。为了提高效率,模型被转换为TensorFlowLite格式,并针对移动CPU、Hexagon和EdgeTPUs量化为INT8,而移动GPU则使用FP16。作者每个模型运行1000次,并取那些运行的平均延迟。然后,作者对每个模型重复该过程5次,并报告均值的中间值。为了优化性能,作者将CPU亲和性设置为最快的核心,并在CPU评估中使用XNNPACK后端。相比之下,对于苹果神经引擎的基准测试(在配备iOS16.6.1、CoreMLTools7.1和Xcode15.0.1的iPhone13上进行性能分析),PyTorch模型被转换为CoreML的MLProgram格式,以Float16精度,使用float16的MultiArray输入以最小化输入复制。

Appendix0.CTrainingsetupforImageNet-1kclassification

为了提升模型性能,作者的训练方法融合了广泛采用的数据增强技术和正则化方法。在数据增强方面,作者使用了Inception裁剪,水平翻转,RandAugment,Mixup,以及CutMix。在正则化方面,作者应用了L2规范化和随机深度丢弃。增强和正则化的强度根据模型大小进行调整,具体细节见表9。

Appendix0.DModeldetails

作者的MNv4模型的架构细节从表10到表14进行描述。

现在,让作者详细审视一下TuNAS优化后的MNv4-Conv模型。TuNAS优化的宏观架构策略性地结合了四种UIB实例:ExtraDW、ConvNext、IB和FFN。这种组合展示了UIB的灵活性以及在不同网络阶段使用不同实例化块的重要性。具体来说,在每一个可搜索阶段的开始,空间分辨率显著降低的地方,ExtraDW成为首选。ExtraDW中双深度分离层的设计有助于扩大感受野,增强空间混合,有效减轻分辨率损失。同样,由于类似的原因,ExtraDW也经常在MNv4-Conv模型的早期阶段被选择。对于最后的层,由于前面的层已经进行了大量的空间混合,选择了FFN和ConvNext,因为通道混合提供了更大的增益。

表12:* MNv4-Hybrid-M的架构规格。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值