利用NsightSystem分析动转静性能

利用NsightSystem分析动转静性能

前置知识

NsightSystem 是一个集终端 CUDA Profile 日志生成和 前端可视化 timeline 分析的强大工具。安装 nsys 需要分别下载适合 Unix 的 Installer 和 Mac/Windows 的可视化终端。

背景

在部分场景下,开启SOT后的性能劣于动态图,主要的可行优化点在于:

  1. 减少子图打断

支持动态shape,numpy()等

  1. 热启动优化

Guard等机制会随着模型的变大而越来越大,越来越慢

  1. 冷启动优化

提高cache命中率、减少编译时间(前者可以促成后者)

Windows端安装NSystem

在GUI当中查看profile,在前置知识提到的链接中进行下载。
下载带GUI的Full Version
用.msi文件直接安装

Linux端安装NSystem

安装不带GUI的版本,我们只会在Windows或者mac端进行可视化分析。
下载.deb包后,用命令安装

(py310) λ yq01-sys-hic-k8s-v100-qm-a223-0007 /workspace  dpkg -i NsightSystems-linux-cli-public-2025.1.1.103-3542797.deb 

输出如下,则安装成功

(py310) λ yq01-sys-hic-k8s-v100-qm-a223-0007 /workspace  dpkg -i NsightSystems-linux-cli-public-2025.1.1.103-3542797.deb 
Selecting previously unselected package nsight-systems-cli-2025.1.1.
(Reading database ... 32179 files and directories currently installed.)
Preparing to unpack NsightSystems-linux-cli-public-2025.1.1.103-3542797.deb ...
Unpacking nsight-systems-cli-2025.1.1 (2025.1.1.103-251135427971v0) ...
Setting up nsight-systems-cli-2025.1.1 (2025.1.1.103-251135427971v0) ...
update-alternatives: using /opt/nvidia/nsight-systems-cli/2025.1.1/target-linux-x64/nsys to provide /usr/local/bin/nsys (nsys) in auto mode

最后update-alternatives: ...信息的意思是(来自GPT):
这条消息是 update-alternatives 机制的输出,表示系统已经自动为 nsys 命令设置了一个全局可用的路径。

解析这条消息

update-alternatives: using /opt/nvidia/nsight-systems-cli/2025.1.1/target-linux-x64/nsys 
to provide /usr/local/bin/nsys (nsys) in auto mode

意思是:

  • update-alternatives 是一个 Linux 系统管理多个软件版本的工具,它用于在不同的可执行文件之间创建符号链接(symlink)。
  • 这里,它把 /opt/nvidia/nsight-systems-cli/2025.1.1/target-linux-x64/nsys 设置为 /usr/local/bin/nsys 的默认执行文件。
  • auto mode 表示系统自动选择了这个 nsys 作为默认选项(而不是用户手动指定)。

如何查看和管理 nsys 的 alternatives

你可以用以下命令检查 nsys 的 alternatives 设置:

update-alternatives --display nsys

如果你想手动选择不同的 nsys 版本(如果你安装了多个版本),可以运行:

sudo update-alternatives --config nsys

它会列出所有可用的 nsys 版本,你可以选择一个。

这对你意味着什么?

  • 你现在可以直接在终端输入 nsys 来使用 Nsight Systems CLI,无需手动指定完整路径。
  • nsys 实际上指向 /opt/nvidia/nsight-systems-cli/2025.1.1/target-linux-x64/nsys,但系统已经帮你自动处理了路径问题。

如果 nsys --version 能正确返回信息,那说明安装已经完成,你可以正常使用 nsys 了!🚀

NSys试运行

实验代码

用一个简单的伪推理程序来检查nsys是否能够正常执行:

import os
import unittest
import numpy

# os.environ["FLAGS_prim_all"] = "true"
# os.environ["FLAGS_prim_enable_dynamic"] = "true"
# os.environ["FLAGS_use_cinn"] = "1"

import paddle

build_strategy = paddle.static.BuildStrategy()
# build_strategy.build_cinn_pass = True

S2 = 32


def init():
    var_kwarg_middle_1 = paddle.rand([64, 26, 512, S2, 40])
    var_kwarg_middle_1 = paddle.cast(var_kwarg_middle_1, "float16")
    var_kwarg_middle_2 = paddle.rand([64, 1, 512, 1, 40])
    var_kwarg_middle_2 = paddle.cast(var_kwarg_middle_2, "float16")
    var_23 = paddle.rand([64, 26, 512])
    var_kwarg_middle_3 = paddle.rand([64, 26, 512, S2, 40])
    var_kwarg_middle_3 = paddle.cast(var_kwarg_middle_3, "float16")
    return var_kwarg_middle_1, var_kwarg_middle_2, var_23, var_kwarg_middle_3


def func(var_kwarg_middle_1, var_kwarg_middle_2, var_23, var_kwarg_middle_3):
    var_28 = paddle.cast(var_23, dtype="float16")
    # var_29 = paddle.to_tensor([64, 26, 512, 1, 1])
    # var_30 = paddle.reshape(var_28, var_29)
    var_30 = paddle.reshape(var_28, [64, 26, 512, 1, 1])
    # var_31 = paddle.to_tensor([64, 26, 512, 32, 40])
    # var_32 = paddle.expand(var_30, var_31)
    # var_33 = paddle.to_tensor([64, 26, 512, 32, 40])
    # var_34 = paddle.expand(var_kwarg_middle_1, var_33)
    # var_35 = var_32 * var_34
    var_35 = var_30 * var_kwarg_middle_1
    var_36 = paddle.sum(var_35, keepdim=True, axis=[1, 3])
    # var_37 = paddle.to_tensor([64, 26, 512, 32, 40])
    # var_38 = paddle.expand(var_kwarg_middle_2, var_37)
    # var_39 = var_32 * var_38
    var_39 = var_30 * var_kwarg_middle_2
    var_40 = var_39
    var_41 = paddle.reshape(var_36, [64, 512, 1, 40])
    var_42 = var_41
    return var_40, var_42


# x.reshape([64, 26, 512, paddle.shape(kwarg_middle_3)[3], 40])


def input_spec():
    return [
        paddle.static.InputSpec(
            # shape=[None, None, None, None, None],
            shape=[64, 26, 512, None, 40],
            dtype="float16",
            name="var_kwarg_middle_1",
        ),
        paddle.static.InputSpec(
            shape=[64, 1, 512, 1, 40],
            dtype="float16",
            name="var_kwarg_middle_2",
        ),
        paddle.static.InputSpec(
            shape=[64, None, 512], dtype="float32", name="var_23"
        ),
        paddle.static.InputSpec(
            shape=[64, 26, 512, None, 40],
            dtype="float16",
            name="var_kwarg_middle_3",
        ),
    ]


class TestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def compare_result(self, dy_compute, data_init):
        static_compute = paddle.jit.to_static(
            full_graph=True,
            build_strategy=build_strategy,
            input_spec=input_spec(),
        )(dy_compute)
        inputs = data_init()
        dy_out = dy_compute(*inputs)
        for step in range(100):
            with paddle.profiler.utils._nvprof_range(step, 50, 60):
                st_out = static_compute(*inputs)
        if isinstance(dy_out, paddle.Tensor):
            numpy.testing.assert_allclose(dy_out, st_out, atol=1e-3, rtol=1e-3)
            return
        for d, s in zip(dy_out, st_out):
            numpy.testing.assert_allclose(d, s, atol=1e-3, rtol=1e-3)

    def test_case(self):
        self.compare_result(func, init)


if __name__ == "__main__":
    unittest.main()

实验结果

运行如下命令

(py310) λ yq01-sys-hic-k8s-v100-qm-a223-0007 /workspace/Paddle/xym/py_dir CUDA_VISIBLE_DEVICES=3 nsys profile -t cuda,nvtx --cpuctxsw=process-tree -o nsys-test --capture-range=cudaProfilerApi --force-overwrite true python nsys_test.py

输出信息如下:

WARNING: Device-side CUDA Event completion trace is currently enabled.
         This may increase runtime overhead and the likelihood of false
         dependencies across CUDA Streams. If you wish to avoid this, please
         disable the feature with --cuda-event-trace=false.
grep: warning: GREP_OPTIONS is deprecated; please use an alias or script
W0208 08:40:24.016208 20209 gpu_resources.cc:119] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 12.0, Runtime API Version: 12.3
W0208 08:40:24.017017 20209 gpu_resources.cc:164] device: 0, cuDNN Version: 9.0.
W0208 08:40:24.017033 20209 gpu_resources.cc:196] WARNING: device: 0. The installed Paddle is compiled with CUDA 12.3, but CUDA runtime version in your machine is 12.0, which may cause serious incompatible bug. Please recompile or reinstall Paddle with compatible CUDA version.
I0208 08:40:24.116797 20209 pir_interpreter.cc:1604] New Executor is Running ...
I0208 08:40:24.117646 20209 pir_interpreter.cc:1628] pir interpreter is running by multi-thread mode ...
Capture range started in the application.
Capture range ended in the application.
Generating '/tmp/nsys-report-756f.qdstrm'


--------------------------------------
C++ Traceback (most recent call last):
--------------------------------------
0   paddle::platform::CudaProfilerStop()

----------------------
Error Message Summary:
----------------------
FatalError: `Termination signal` is detected by the operating system.
  [TimeInfo: *** Aborted at 1739004027 (unix time) try "date -d @1739004027" if you are using GNU date ***]
  [SignalInfo: *** SIGTERM (@0x4ee5) received by PID 20209 (TID 0x7f8272f17780) from PID 20197 ***]

[1/1] [0%                          ] nsys-test.nsys-repProcessing events...
[1/1] [========================100%] nsys-test.nsys-rep
Generated:
        /workspace/Paddle/xym/py_dir/nsys-test.nsys-rep

虽然输出了Fatal Error,但是可以看到这里并不是段错误❌,而是SIGTERM,这个信号是在监控装饰器的结尾程序主动发出的,我们这里只监控50-60个循环,超出60个循环,就发出结束信号了。

学习NSys GUI的使用

找到了Nvidia官方的视频教程

准备工作

发现了一个一直没有注意的warning,但好像问题不大

W0210 10:28:10.189069 10936 gpu_resources.cc:196] WARNING: device: 0. The installed Paddle is compiled with CUDA 12.3, but CUDA runtime version in your machine is 12.0, which may cause serious incompatible bug. Please recompile or reinstall Paddle with compatible CUDA version.

但是为了控制变量,保证不是其他地方出错,把这个问题也解决了。

(base) λ yq01-sys-hic-k8s-v100-qm-a223-0007 /workspace/performance-analysis/PaddleYOLO ls /usr/local/ | grep cuda
grep: warning: GREP_OPTIONS is deprecated; please use an alias or script
cuda
cuda-12
cuda-12.3/

检查发现,这个机子上,既有12.0的run time,也有12.3的,那么我们只要把12.3加到LD_LIBRARY_PATH的前面,就能保证优先使用12.3的了。

export LD_LIBRARY_PATH=/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH

subgraph_relation读法

image

这里箭头上写的-1表示这个函数输出的是动态shape,而因为此处输入已经确定了,所以输出也是确定的,因此输出向量不是-1,而是一个具体的shape

模型1:PaddleYOLO_yolov5_l_300e_coco_bs16_fp32_DP

在不改变配置文件的情况下,动态图可以跑到结束,但是动态图跑到20多轮就会出问题,一个是:

Traceback (most recent call last):
  File "/workspace/performance-analysis/PaddleYOLO/tools/train.py", line 202, in <module>
    main()
  File "/workspace/performance-analysis/PaddleYOLO/tools/train.py", line 198, in main
    run(FLAGS, cfg)
  File "/workspace/performance-analysis/PaddleYOLO/tools/train.py", line 151, in run
    trainer.train(FLAGS.eval)
  File "/workspace/performance-analysis/PaddleYOLO/ppdet/engine/trainer.py", line 513, in train
    profiler.add_profiler_step(profiler_options)
  File "/workspace/performance-analysis/PaddleYOLO/ppdet/utils/profiler.py", line 103, in add_profiler_step
    paddle.utils.profiler.start_profiler(_profiler_options['state'],
AttributeError: module 'paddle.utils' has no attribute 'profiler'

虽然这个不是直接导致程序崩溃的问题,但还是把相应的代码注释了。

此处代码不影响正确性,是用来监控的,所以可以放心去掉。

另一处是跟dataloader相关的一个报错,是致命问题,会导致程序退出,在配置文件configs/yolov5/_base_/yolov5_reader_high_aug.yml中,把这一行

use_shared_memory: True

更改为false后,程序不再崩溃,但是ips非常低;动态图亦是如此,原因有待进一步分析。

模型2:PaddleYOLO_yolov5_l_300e_coco_bs16_fp32_DP

估计所有模型都存在profiler相关的问题,因为那部分代码已经注释,所以不会再产生影响,故不再赘述。

插曲

测的过程中遇到了一个小插曲:

一直在爆显存

Out of memory error on GPU 0. Cannot allocate 92.250000MB memory on GPU 0, 15.716553GB memory has been allocated and available memory is only 57.125000MB.

Please check whether there is any other process using GPU 0.
1. If yes, please stop them, or start PaddlePaddle on another GPU.
2. If no, please decrease the batch size of your model. 
 (at /workspace/Paddle/paddle/phi/core/memory/allocation/cuda_allocator.cc:71)

这里显示的是device 0,我还以为是这个进程跑到GPU 0上去了,看了半天,每次跑都是0,最后才发现这里的0意思是,该进程可见的显卡里面的0号,因为我设置了CUDA_VISIBLE_DEVICES=7,所以它只能看见7号卡,这里只会输出0;

要验证进程跑到了哪个卡上,可以watch一下nvidia-smi,看看哪张卡的显存占用一直在往上涨。

至此解决办法也就出来了:减少batch_size.

插曲2

注意,我们直接运行的命令是

bash test_tipc/benchmark_train.sh test_tipc/configs/yolov5/yolov5_l_300e_coco_train_infer_python.txt benchmark_train dynamicTostatic_bs16_fp32_DP_N1C1

但真正影响训练中batch_size的配置不在这个txt文件里,而是在这里:

# run test_train_inference_python.sh
                cmd="bash test_tipc/test_train_inference_python.sh ${FILENAME} benchmark_train > ${log_path}/${log_name} 2>&1 "
                echo $cmd
                eval $cmd
                eval "cat ${log_path}/${log_name}"

这个bash文件也会引用一个txt配置文件,那里面的batch_size才是训练过程中实际生效的。

真正生效的配置如下(部分节选):

===========================train_params===========================
model_name:yolov5_l_300e_coco
python:python
gpu_list:7
use_gpu:True
auto_cast:fp32
epoch:benchmark_train=1
save_dir:null
TrainReader.batch_size:benchmark_train=16
pretrain_weights:https://paddledet.bj.bcebos.com/models/yolov5_l_300e_coco.pdparams 
trained_model_name:model_final.pdparams
train_infer_img_dir:./dataset/coco/test2017/
--profiler_options:null

有效的部分就是这个TrainReader.batch_size:benchmark_train,尝试修改为8,但是一运行bash脚本,又立刻被修改为8了,通过二分法定位到是在test_tipc/benchmark_train.sh文件中发生的修改操作,定位到原因如下:

我们默认使用的命令是

bash test_tipc/benchmark_train.sh test_tipc/configs/yolov5/yolov5_l_300e_coco_train_infer_python.txt benchmark_train dynamicTostatic_bs16_fp32_DP_N1C1

benchmark_train.sh会分析我们的参数,然后把bs16填入到配置文件,所以我们只要在这里修改就行,不用修改配置文件本身。


问题1

NSys打出来的日志十分抽象;在SOT执行期,负载莫名其妙地从一个线程转移到了另一个线程;而且在前向和后向之间有比较大的一块空白没有任何event被记录,非常的玄学。

可行的解决办法:

  • 进一步降低batch_size,看看是不是显存导致的问题。
  • 在代码中增加更多的日志输出(即在Nsys报告中,空白前的那些函数,看看他们后续都执行了什么)。
  • 看看Allacator后面都执行了什么。
  • 可以开GLOG_v=7,这里的GLOGGoogleLogging
  • 看看FallbackWrapper后面都执行了什么。

问题2

有一个规模比较大的子图,一直在重新编译,总共输出了30张subgraph_relation,后来发现是一个Guard Error导致的,已经有相应的修复PR,可以后续观察一下合入后的效果,说不定能顺带解决问题1。

修复手段1

逐步降低batch_size发现,在这个过程中动态图和动转静的ips都会提升,但是动转静性能始终不及动态图,ips差了10左右.

修复手段2

合入了修复numpy相关问题的PR之后,再次进行测试,发现ips指标如下:

BS4
动态图:
24.6234
动转静:
Average ips: 19.9879
BS8
动态图:
Avg: 27.645 images/s
动转静:
Avg: 17.862 images/s

可以看到,依然比动态图慢,而且诡异的是,在动转静模式下,提高batch_size之后,ips反而下降了。

小进展

subgraph的数量从原来的30个下降到了2个,原来重复编译的问题确实被成功解决了。

观察此时的新nsys-repo发现:
image

在动转静执行流程中,有一个set_value_dygraph方法被大量重复调用,它的位置处在一个FallbackWrapper的后面,而这个FallbackWrapper正是我们封装之后的SIR执行器,因此,我们能够推断出:

这个重复的函数调用,发生在动态图的执行路径上。

因为问题出在动态图执行路径,所以我们肯定要在日志中找FallbackError出现的位置。

修复手段3

因为根据修复手段2当中的信息,我们能够确认问题出在动态图执行路径上,因此我们在日志中搜索FallbackError,发现两处均来自同一段模型源代码yolo_v5.py

def yolov5_loss(self, pi, t_cls, t_box, t_indices, t_anchor, balance):
        loss = dict()
        b, a, gj, gi = t_indices  # image, anchor, gridy, gridx
        n = b.shape[0]  # number of targets
        tobj = paddle.zeros_like(pi[:, :, :, :, 4])
        loss_box = paddle.to_tensor([0.])
        loss_cls = paddle.to_tensor([0.])
        if n:
            mask = paddle.stack([b, a, gj, gi], 1)
            ps = pi.gather_nd(mask)
            # Regression
            pxy = F.sigmoid(ps[:, :2]) * 2 - 0.5
            pwh = (F.sigmoid(ps[:, 2:4]) * 2)**2 * t_anchor
            pbox = paddle.concat((pxy, pwh), 1)
            iou = bbox_iou(pbox.T, t_box.T, x1y1x2y2=False, ciou=True)
            loss_box = (1.0 - iou).mean()

            # Objectness
            score_iou = paddle.cast(iou.detach().clip(0), tobj.dtype)
            # with paddle.no_grad():
            #     x = paddle.gather_nd(tobj, mask)
            #     tobj = paddle.scatter_nd_add(
            #         tobj, mask, (1.0 - self.gr) + self.gr * score_iou - x)
            with paddle.no_grad():
                tobj[b, a, gj, gi] = (1.0 - self.gr
                                      ) + self.gr * score_iou  # iou ratio

            # Classification
            if self.num_classes > 1:  # cls loss (only if multiple classes)
                # t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                # t[range(n), t_cls] = self.cls_pos_label
                # loss_cls = self.BCEcls(ps[:, 5:], t)

                t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                if not self.to_static:
                    t = paddle.put_along_axis(
                        t,
                        t_cls.unsqueeze(-1),
                        values=self.cls_pos_label,
                        axis=1)
                else:
                    for i in range(n):
                        t[i, t_cls[i]] = self.cls_pos_label

                loss_cls = self.BCEcls(ps[:, 5:], t)

        obji = self.BCEobj(pi[:, :, :, :, 4], tobj)  # [bs, 3, h, w]

        loss_obj = obji * balance

        loss['loss_box'] = loss_box * self.loss_weights['box']
        loss['loss_obj'] = loss_obj * self.loss_weights['obj']
        loss['loss_cls'] = loss_cls * self.loss_weights['cls']
        return loss

这里用到了装饰器paddle.no_grad(),导致整个函数都被Fallback掉了,因此我们可以把被装饰器的部分单独拿出来,封装成一个函数,这样的话就只有被装饰的部分代码会引起Fallback

手段3效果

修改过后,从subgraph_relation当中能够看出,子图数量确实变多了,说明这里从Fallback变成了打断,但是性能依然没有赶上动态图,对比之前的SOT表现,ips只提升了不到1,几乎可以当做是误差。

另一方面,原来修改前只有一种FallbackError,全都是不支持字节码SETUP_WITH导致的,现在因为进入静态图执行流程的代码变多,出现了另一种新的FallbackError:

paddle.jit.sot.utils.exceptions.FallbackError: Currently don't support predicate SymbolicVariable

重新观察Nsys的报告,发现性能瓶颈在SIR_19的后面:
image

image

SIR_19对应的函数是bbox_utils.poy当中的bbox_iou

修复手段4

发现这些性能瓶颈是大量重复的小event,可以确认他们来自于一个循环,再检查一下update_tobj后面的代码

self.update_tobj(tobj, score_iou, b, a, gj, gi)

            # Classification
            if self.num_classes > 1:  # cls loss (only if multiple classes)
                # t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                # t[range(n), t_cls] = self.cls_pos_label
                # loss_cls = self.BCEcls(ps[:, 5:], t)

                t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                if not self.to_static:
                    t = paddle.put_along_axis(
                        t,
                        t_cls.unsqueeze(-1),
                        values=self.cls_pos_label,
                        axis=1)
                else:
                    for i in range(n):
                        t[i, t_cls[i]] = self.cls_pos_label

这里已经完美符合条件了,动静执行路径不同,且在SOT的执行路径上有一个循环,直接把SOT的执行路径替换为和动态图一致:

# Classification
            if self.num_classes > 1:  # cls loss (only if multiple classes)
                # t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                # t[range(n), t_cls] = self.cls_pos_label
                # loss_cls = self.BCEcls(ps[:, 5:], t)

                t = paddle.full_like(ps[:, 5:], self.cls_neg_label)
                # if not self.to_static:
                if True:
                    t = paddle.put_along_axis(
                        t,
                        t_cls.unsqueeze(-1),
                        values=self.cls_pos_label,
                        axis=1)
                # else:
                #     for i in range(n):
                #         t[i, t_cls[i]] = self.cls_pos_label
                #         print(f"n: {n} i: {i}, t_cls: {t_cls[i]}, cls_pos_lable: {self.cls_pos_label}\n")

接下来只要确认精度没问题就行了。

修复成果

修改后重新进行测试,数据如下(已固定随机数种子):

动转静:

Extract 1500 records: separator=None; position=None
average ips of 1500 steps, skip 0 step:
Avg: 27.021 images/s
FPS: 27.021 images/s
average ips of 1500 steps, skip 4 steps, valid steps 1348 :
var: 1.085
Avg: 27.276 images/s
Min: 23.668 images/s
Max: 28.070 images/s
diff_min_max: -15.682 %
FPS: 27.276 images/s
Loss: 0.251002

动态图:

Extract 1695 records: separator=None; position=None
average ips of 1695 steps, skip 0 step:
Avg: 27.817 images/s
FPS: 27.817 images/s
average ips of 1695 steps, skip 4 steps, valid steps 1523 :
var: 2.692
Avg: 28.109 images/s
Min: 22.525 images/s
Max: 29.142 images/s
diff_min_max: -22.707 %
FPS: 28.109 images/s
Loss: 0.174485

ips和loss还是存在一定差距,但是已经非常接近了。

经过努力后,loss还是没有和动态图对齐,现在暂定目标如下:

只要这处修改不影响loss,即SOT本身在修改前后的loss能够对齐,那么我们就认为问题解决,可以提PR了。

模型2:PaddleVideo_VideoSwin_bs1_fp32_DP

本文作者:Gold_stein

本文链接:https://www.cnblogs.com/smartljy/p/18703086

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Gold_stein  阅读(32)  评论(0编辑  收藏  举报
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
点击右上角即可分享
微信分享提示
  1. 1 逃离地面 RAD & 三浦透子
逃离地面 - RAD & 三浦透子
00:00 / 00:00
An audio error has occurred.

作词 : 野田洋次郎

作曲 : 野田洋次郎

空飛ぶ羽根と引き換えに 繋ぎ合う手を選んだ僕ら

それでも空に魅せられて 夢を重ねるのは罪か

夏は秋の背中を見て その顔を思い浮かべる

憧れなのか、恋なのか 叶わぬと知っていながら

重力が眠りにつく 1000年に一度の今日

太陽の死角に立ち 僕らこの星を出よう

彼が眼を覚ました時 連れ戻せない場所へ

「せーの」で大地を蹴って ここではない星へ

行こう

もう少しで運命の向こう もう少しで文明の向こう

もう少しで運命の向こう もう少しで

夢に僕らで帆を張って 来たるべき日のために夜を超え

いざ期待だけ満タンで あとはどうにかなるさと 肩を組んだ

怖くないわけない でも止まんない

ピンチの先回りしたって 僕らじゃしょうがない

僕らの恋が言う 声が言う

「行け」と言う