パワポ - 3ヶ月カレンダー

PowerPointスライドの左3分の1に3ヶ月カレンダーを作成するマクロを紹介します。ユーザーに開始年と月を入力させ、指定された月から3ヶ月分のカレンダーを生成します。各月は曜日ヘッダーと日付セルを含み、日曜日と土曜日は色分けされています。

Option Explicit

' --- DESIGN & LAYOUT PARAMETERS ---
Const FONT_SIZE As Single = 8
Const HEADER_FONT_SIZE As Single = 9
Const MONTH_FONT_SIZE As Single = 16
Const BOX_HEIGHT As Single = 30          ' Height of month title box
Const MARGIN_TOP As Single = 20         ' Bottom margin below calendars
Const MARGIN_LEFT As Single = 20
Const SPACING_VERTICAL As Single = 20    ' Space between calendars
Const CAL_WIDTH As Single = 300         ' Fixed calendar width
Const TOP_OFFSET As Single = 100        ' Space above calendars for title/lead text
Const TABLE_COLS As Integer = 7         ' Days of week

Public Sub CreateThreeMonthCalendar()

    Dim ppApp As PowerPoint.Application
    Dim ppPres As PowerPoint.Presentation
    Dim ppSld As PowerPoint.Slide
    Dim ppShpBox As PowerPoint.Shape
    Dim ppShpTable As PowerPoint.Shape
    Dim ppTbl As PowerPoint.Table

    ' --- COLOR VARIABLES ---
    Dim SUNDAY_COLOR As Long, SATURDAY_COLOR As Long
    Dim BORDER_COLOR_HORZ As Long, BORDER_COLOR_VERT As Long
    Dim BACKGROUND_COLOR As Long, TEXT_COLOR As Long
    Dim HEADER_TEXT_COLOR As Long, BOX_BACKGROUND_COLOR As Long

    ' --- COLOR CONSTANTS ---
    SUNDAY_COLOR = RGB(255, 100, 100)
    SATURDAY_COLOR = RGB(100, 100, 255)
    BORDER_COLOR_HORZ = RGB(192, 192, 192)
    BORDER_COLOR_VERT = RGB(220, 220, 220)
    BACKGROUND_COLOR = RGB(255, 255, 255)
    TEXT_COLOR = RGB(0, 0, 0)
    HEADER_TEXT_COLOR = RGB(0, 0, 0)
    BOX_BACKGROUND_COLOR = RGB(230, 230, 230)

    ' --- INPUTS ---
    Dim inputYearStr As String, inputMonthStr As String
    Dim currentYear As Integer, currentMonth As Integer

    On Error GoTo ErrorHandler

    Set ppApp = PowerPoint.Application
    Set ppPres = ppApp.ActivePresentation
    Set ppSld = ppPres.Slides.Add(ppPres.Slides.Count + 1, ppLayoutBlank)

    ' Get starting year and month
    inputYearStr = InputBox("Enter the starting year (e.g., 2025):", "Calendar Year")
    If Not IsNumeric(inputYearStr) Or Len(inputYearStr) <> 4 Then MsgBox "Invalid year.", vbCritical: Exit Sub
    currentYear = CInt(inputYearStr)

    inputMonthStr = InputBox("Enter the starting month (1-12):", "Calendar Month")
    If Not IsNumeric(inputMonthStr) Or CInt(inputMonthStr) < 1 Or CInt(inputMonthStr) > 12 Then MsgBox "Invalid month.", vbCritical: Exit Sub
    currentMonth = CInt(inputMonthStr)

    ' --- Compute dynamic sizes ---
    Dim sldWidth As Single, sldHeight As Single
    Dim availableHeight As Single, blockHeight As Single
    Dim tableHeight As Single, cellHeight As Single
    Dim totalWeeks As Integer, rowsCount As Integer

    sldWidth = ppPres.PageSetup.SlideWidth
    sldHeight = ppPres.PageSetup.SlideHeight

    ' Available vertical space: subtract top offset, top & bottom margins, and inter-calendar spacing
    availableHeight = sldHeight - TOP_OFFSET - 2 * MARGIN_TOP - 2 * SPACING_VERTICAL
    blockHeight = availableHeight / 3

    ' Starting position
    Dim currentLeft As Single: currentLeft = MARGIN_LEFT
    Dim currentTop As Single: currentTop = TOP_OFFSET + MARGIN_TOP

    Dim i As Integer
    For i = 1 To 3
        Dim currentDate As Date, daysInMonth As Integer, firstDay As Integer
        Dim dayCounter As Integer, r As Integer, c As Integer
        Dim daysOfWeek As Variant: daysOfWeek = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")

        currentDate = DateSerial(currentYear, currentMonth, 1)
        daysInMonth = Day(DateSerial(currentYear, currentMonth + 1, 0))
        firstDay = Weekday(currentDate, vbSunday)

        ' Calculate weeks needed for this month
        totalWeeks = Int((daysInMonth + firstDay - 2) / 7) + 1
        rowsCount = totalWeeks

        ' Compute table height & cell height
        tableHeight = blockHeight - BOX_HEIGHT - 5
        cellHeight = tableHeight / (rowsCount + 1)   ' +1 for header row

        ' --- MONTH NAME BOX ---
        Set ppShpBox = ppSld.Shapes.AddTextbox(msoTextOrientationHorizontal, _
                                              currentLeft, currentTop, CAL_WIDTH, BOX_HEIGHT)
        With ppShpBox
            .Fill.ForeColor.RGB = BOX_BACKGROUND_COLOR
            With .TextFrame
                .TextRange.Text = Format(currentDate, "MMMM YYYY")
                With .TextRange.Font
                    .Name = "Arial"
                    .Size = MONTH_FONT_SIZE
                    .Bold = msoTrue
                    .Color.RGB = TEXT_COLOR
                End With
                .TextRange.ParagraphFormat.Alignment = ppAlignCenter
                .VerticalAnchor = msoAnchorMiddle
                .MarginLeft = 0: .MarginRight = 0: .MarginTop = 0: .MarginBottom = 0
            End With
        End With

        ' --- CALENDAR TABLE ---
        currentTop = currentTop + BOX_HEIGHT - 5
        Set ppShpTable = ppSld.Shapes.AddTable(rowsCount + 1, TABLE_COLS, _
                                              currentLeft, currentTop, CAL_WIDTH, tableHeight)
        Set ppTbl = ppShpTable.Table

        ' Set column widths and row heights
        For c = 1 To TABLE_COLS: ppTbl.Columns(c).Width = CAL_WIDTH / TABLE_COLS: Next c
        For r = 1 To rowsCount + 1: ppTbl.Rows(r).Height = cellHeight: Next r

        ' --- HEADER ROW ---
        For c = 1 To TABLE_COLS
            With ppTbl.Cell(1, c).Shape.TextFrame
                .TextRange.Text = daysOfWeek(c - 1)
                With .TextRange.Font
                    .Name = "Arial"
                    .Size = HEADER_FONT_SIZE
                    .Bold = msoTrue
                    .Color.RGB = IIf(c = 1, SUNDAY_COLOR, IIf(c = 7, SATURDAY_COLOR, HEADER_TEXT_COLOR))
                End With
                .TextRange.ParagraphFormat.Alignment = ppAlignCenter
                .VerticalAnchor = msoAnchorMiddle
                .MarginRight = 1
                .MarginLeft = 1
            End With
        Next c

        ' --- DATE CELLS ---
        dayCounter = 1
        For r = 2 To rowsCount + 1
            For c = 1 To TABLE_COLS
                With ppTbl.Cell(r, c).Shape.TextFrame
                    .VerticalAnchor = msoAnchorMiddle
                    .MarginRight = 2
                    .MarginLeft = 2
                    .TextRange.ParagraphFormat.Alignment = ppAlignRight
                    If (r = 2 And c >= firstDay) Or (r > 2 And dayCounter <= daysInMonth) Then
                        .TextRange.Text = dayCounter
                        With .TextRange.Font
                            .Name = "Arial"
                            .Size = FONT_SIZE
                            .Color.RGB = IIf(c = 1, SUNDAY_COLOR, IIf(c = 7, SATURDAY_COLOR, TEXT_COLOR))
                        End With
                        dayCounter = dayCounter + 1
                    Else
                        .TextRange.Text = ""
                        With .TextRange.Font
                            .Name = "Arial"
                            .Size = FONT_SIZE
                        End With
                    End If
                End With
            Next c
        Next r

        ' --- BORDER STYLING ---
        For r = 1 To rowsCount + 1
            For c = 1 To TABLE_COLS
                With ppTbl.Cell(r, c)
                    .Shape.Fill.ForeColor.RGB = BACKGROUND_COLOR
                    .Shape.Fill.Visible = msoTrue
                    ' Transparent outer borders
                    If r = 1 Then
                        .Borders(ppBorderTop).Transparency = 1: .Borders(ppBorderTop).Weight = 0
                    End If
                    If r = rowsCount + 1 Then
                        .Borders(ppBorderBottom).Transparency = 1: .Borders(ppBorderBottom).Weight = 0
                    End If
                    If c = 1 Then
                        .Borders(ppBorderLeft).Transparency = 1: .Borders(ppBorderLeft).Weight = 0
                    End If
                    If c = TABLE_COLS Then
                        .Borders(ppBorderRight).Transparency = 1: .Borders(ppBorderRight).Weight = 0
                    End If
                    ' Horizontal borders
                    .Borders(ppBorderTop).Weight = 0.1
                    .Borders(ppBorderTop).ForeColor.RGB = BORDER_COLOR_HORZ
                    .Borders(ppBorderBottom).Weight = 0.1
                    .Borders(ppBorderBottom).ForeColor.RGB = BORDER_COLOR_HORZ
                    ' Vertical borders
                    .Borders(ppBorderLeft).Weight = 0.3
                    .Borders(ppBorderLeft).ForeColor.RGB = BORDER_COLOR_VERT
                    .Borders(ppBorderRight).Weight = 0.3
                    .Borders(ppBorderRight).ForeColor.RGB = BORDER_COLOR_VERT
                End With
            Next c
        Next r

        ' --- Next Month Positioning ---
        currentMonth = currentMonth + 1
        If currentMonth > 12 Then currentMonth = 1: currentYear = currentYear + 1
        currentTop = currentTop + tableHeight + SPACING_VERTICAL
    Next i

    MsgBox "Three-month calendar created successfully!", vbInformation
    Exit Sub

ErrorHandler:
    MsgBox "Error: " & Err.Description, vbCritical
End Sub

物理シミュレーションと数値積分

最近、グランツーリスモ7のプレイヤーから、物理シミュレーションが破綻する現象が報告されています。特にサンババスで極端な破綻が起きるとのことで、空中に60万km/h以上で打ち出される事例の報告までされています。 報告を見る限り、リアにバラストを積み、車高を下げることで発生するようです。

一般に物理エンジンは数値積分を内部的に使っています。物理エンジンでシミュレーションする系に固いレートのバネが入っていると計算が発散しやすく、 GT7で報告されているような車が宙に突如放り出されるような挙動に陥りやすくなります。 GT7でも同じことが起きているとまでは断言できませんが、簡単なモデルを使って「再現」をしてみましょう。

サスペンションモデル

車両のサスペンションを含む最も単純な物理運動表現として、車体をタイヤとサスペンションに単純化したモデルを導入します。

サスペンションモデル

このモデルでは、タイヤのバネ定数 $ k_1 \text{\(N/m\)} $ や、ハブを起点に評価したホイールレート $ k_2 \text{\(N/m\)} $ を代表的なパラメータとして取り扱います。

システム方程式は

$$ \frac{d}{dt} \begin{pmatrix} x_1 \\ x_2 \\ \dot{x}_1 \\ \dot{x}_2 \end{pmatrix} = \begin{pmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ -\frac{k_1 + k_2}{m_t} & \frac{k_2}{m_t} & -\frac{c_2}{m_t} & \frac{c_2}{m_t} \\ \frac{k_2}{m_b} & -\frac{k_2}{m_b} & \frac{c_2}{m_b} & -\frac{c_2}{m_b} \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \\ \dot{x}_1 \\ \dot{x}_2 \end{pmatrix} $$

GT7で発散が報告されているパラメータを元に下記の式からシミュレーションで使う仮の値を概算で設定します。

  • 車体重量 $ m_b $ : 1,000 kg
  • タイヤ総重量 $ m_t $ : 100 kg
  • サスの固有振動数 $ f_2 $ : 1.5 Hz
  • サスの減衰比 $ \zeta_2 $ : 0.25

このほか、タイヤのバネ定数 $ k_1 $ をおよそ $ 2.0 \cdot 10^6 \text{N/m} $ とします。

システム方程式で使うパラメータはバネマスダンパー系の特性値の公式を使って概算値として求めます。

$$ \begin{aligned} k_2 &= m_b (2 \pi f_2)^2 \\ c_2 &= 2 m_b \zeta_2 (2 \pi f_2) \end{aligned} $$

物理シミュレーション

物理シミュレーションでは、現実世界の物理現象を数値的に再現するために、微分方程式を解く必要があります。これに数値積分法が使用されます。原理が簡単な前進オイラー法と、物理シミュレーションエンジンでポピュラーな半陰オイラー法を試します。

物理モデルが行列 $ A \in \mathrm{GL}_{2n}(\mathbb{R}) $ を使って、微分方程式

$$ \dot{x} = \frac{d}{dt} \begin{pmatrix} X \\ V \end{pmatrix} = A x $$

で与えられたとき、数値積分で逐次的にステップ $ n $ の $ x_n $ を求めます。

本件のモデルに対しては

$$ A = \begin{pmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ -2 \cdot 10^4 & 8.9 \cdot 10^2 & -4.7 \cdot 10 & 4.7 \cdot 10 \\ 8.9 \cdot 10 & -8.9 \cdot 10 & 4.7 & -4.7 \\ \end{pmatrix} $$

です。

前進オイラー法

前進オイラー法は、次の状態を現在の状態からタイムステップを使って計算するシンプルな数値積分法です。数式で表すと次のようになります。

$$ x_{n+1} = x_n + \Delta t A x_n $$

先程のサスペンションモデルをこの数値積分で解いてみましょう。

通常、ゲーム向けのシミュレーションではシミュレーションのタイムステップと画面のリフレッシュレートを一致させますから、GT7のリフレッシュレート120 Hzをひとつの水準にします。また、対比のため、1kHzでのシミュレーションもしてみましょう。

初期値として車両が加速トルクをうけて、準静的に1 cmスクワットし、これが開放された瞬間を取ります ($ x_0^\intercal= [0,-0.01,0,0] $ )。

前進オイラー法によるシミュレーション結果

120Hzの水準では車体の振幅が次第に拡大していき、ほんの3秒の間にはね飛ぶようになります(グラフ上段)。1kHzの水準ではダンパーの効果もあり、振幅がゼロに収束します。厳密解(実車体の動き)はこちらに近いはずです。

グラフ下段に示した通り、120Hzのシミュレーション条件ではシステムへ仕事の供給がないのに系のエネルギーが指数的に増えていきます。

半陰オイラー法

半陰オイラー法は、前進オイラー法の安定性を改善するため、速度の更新結果に基づいて位置を更新します。

$$ \begin{aligned} V_{n+1} &= V_n + \Delta t \dot{V_n} \\ X_{n+1} &= X_n + \Delta t V_{n+1} \\ &= X_n + \Delta t V_n + (\Delta t)^2 \dot{V_n} \end{aligned} $$

これを折り込み、前進オイラー法と同様に1ステップで計算するには…

$$ x_{n+1} = x_n + \Delta t (I + \Delta t \begin{pmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \end{pmatrix} ) A x_n $$

この式で下のように $ \tilde{A} $ を取れば実装上は前進オイラー法と同じです。

$$ \tilde{A} = (I + \Delta t \begin{pmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \end{pmatrix} ) A $$

これを使って修正した行列で同様にサスペンションモデルをシミュレーションすると120Hzでも発散しないことがわかります。

半陰(semi-implicit)オイラー法の結果(緑)

本シミュレーションの条件では発生しませんでしたが、より厳しいパラメータを与えると、この半陰オイラー法を採用しても発散します。GT7も、一般の物理シミュレーション同様に、この数値積分法を使っていると考えられますので、 剛体同士の接触などが起きていたのだろうと思います。

数値積分の安定域

シンプルな常微分方程式

$$ \begin{aligned} \dot{y} &= \lambda y \\ y(0) &= 1 \\ \lambda & \in \{ \text{Re}(x)<0 | x \in \mathbb{C}\} \end{aligned} $$

を考えます。この常微分方程式の解は、$ y = exp(\lambda t) $ です。この方程式を前進オイラー法で解くことを考えると、タイムステップ $ \Delta t $ に対して、数値解は

$$ \begin{aligned} y_{n+1} &= y_n + \Delta t \lambda y_n \\ &= (1+\Delta t \lambda) y_n \\ &= (1+\Delta t \lambda)^n y_0. \end{aligned} $$

このとき、$ \lambda $ の定義から $ t \rightarrow \infty $ で $ y = 0 $ ですから、数値解の収束条件は $ | 1 + \Delta t \lambda | < 1 $ とわかります。

同様に

$$ B = \begin{pmatrix} \lambda_{1} & & \\ & \ddots & \\ & & \lambda_{2n} \end{pmatrix} $$

を考え、$ \dot{y} = By $ について考察すると、すべての $ \lambda_k $ が前記の収束条件を満たしている必要性があります。

また、仮に$ A $ が $ B = P^{-1}AP $ と対角化可能であれば、$ B $ の対角に並ぶ要素は $ A $ の固有値です。数値積分の収束について議論する場合は、Aの固有値に注目すれば良さそうです。

本ケースの考察

サスペンションモデルの $ A $ の固有値を求めると $ -23.7±141.8i, -2.2±9.0i $であることから、120Hz ($ \Delta t = \frac{1}{120} $) の条件で、(絶対値が大きい方の固有値で) $ | 1+ \frac{-23.7+141.8i}{120}| > 1 $ となり、収束条件を満たしません。

前進オイラー法では、収束条件を満たすには $ \Delta t < \frac{1}{433} $ (433 Hz以上)である必要があります。実際、1kHzの条件では収束していました。

次に半陰オイラー法について $ \tilde{A} $ の固有値を求めると $ -110.8±91.7i, -2.5±9.0i $です。収束条件は $ \tilde{A} $ について、前進オイラー法と同じ議論は成り立つことから、収束条件を確認すると、 $ | 1+ \frac{-110.8+91.7i}{120}| \approx 0.77 < 1 $ で、120Hzの数値積分でも収束条件を満たすことがわかります。

参考

JAXとPyTorchの速度検証

JAXとPyTorchの性能差を検証します。今回、ベンチマークはpytestのbenchmarkモジュールを使って行いました。

今回のコードはここに置いてあります。python_bench/neural_network at master · Chachay/python_bench

環境

  • python 3.10
  • numpy 1.24.3
  • pytorch 2.0.0
  • jax
  • CUDA 11.7 + cudnn 8.5.0
  • NVIDIA Driver Version: 531.14
  • NVIDIA RTX3060

あいにくWindowsではPyTorch2.0のJIT機能は使えません。

ライブラリの性能

AlexNetおよびGoogleNetで比較し、JAXはPyTorchの1.4~2.0倍の性能とわかりました。Whisper-jaxでPyTorchからJAXに書き換えた性能向上分2倍と同等です。また、JAXのチュートリアルでも、2.5~3.4倍の性能と紹介されており、妥当な結果と思われます。

性能差はAlexNetやVGGのような単純な2次元畳み込みよりも、GoogleNetやResNetのようなモデルのほうがつきやすいようです。

両ライブラリ推論性能(ms)
Network
Flax PyTorch
AlexNet 2.7 (1.0) 3.8 (1.4)
GoogleNet 37.0 (1.0) 81.1 (2.2)

AlexNetの実装

推論(Inference)での性能差を計測するため、全結合層や学習に関する層を省略したAlexNetモデルを定義した。

import torch
from torch import nn

class AlexNetPyTorch(nn.Module):
    def __init__(self):
        super(AlexNetPyTorch, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=11, stride=4),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),

            nn.Conv2d(96, 256, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),

            nn.Conv2d(256, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),

            nn.Conv2d(384, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),

            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2)
        )

    def forward(self,x):
        x = self.features(x)
        return x
from flax import linen as nn

class AlexNetFlax(nn.Module):
    @nn.compact
    def __call__(self, x):
        x = nn.Conv(96, (11, 11), strides=(4, 4), name='conv1')(x)
        x = nn.relu(x)
        x = nn.max_pool(x, (3, 3), strides=(2, 2))

        x = nn.Conv(256, (5, 5), padding=((2, 2),(2, 2)), name='conv2')(x)
        x = nn.relu(x)
        x = nn.max_pool(x, (3, 3), strides=(2 ,2))

        x = nn.Conv(384, (3, 3), padding=((1, 1),(1, 1)), name='conv3')(x)
        x = nn.relu(x)

        x = nn.Conv(384, (3, 3), padding=((1, 1),(1 ,1)), name='conv4')(x)
        x = nn.relu(x)

        x = nn.Conv(256, (3, 3), padding=((1, 1),(1, 1)), name='conv5')(x)
        x = nn.relu(x)
        x = nn.max_pool(x, (3, 3), strides=(2, 2))

        return x

GoogleNet

こちらはGitHubのレポジトリをご参照ください。

ベンチのコード

ベンチはpytest-benchmarkを使って準備しました。イメージを共有するため簡略化したものを紹介します。 ベンチはrun(x)を20回繰り返し実行(iterations)する計測を3セット(rounds)した結果を返します。 各測定の前に2回のwarmupを行います。

import pytest
import numpy as np

import torch
import jax
import jax.numpy as jnp

from models_flax import AlexNetFlax
from models_pytorch import AlexNetPyTorch

@pytest.mark.benchmark(
    group="AlexNet",
    warmup=True
)
def test_AlexNetPytorch(benchmark):
    model = AlexNetPyTorch()
    model.to('cuda')
    model.eval()

    # FlaxとPyTorchでデータの並び順が異なることに注意
    # バッチ数、チャネル数、画像高さ、画像幅 [N, C, H, W]
    x = np.random.rand(16, 3, 224, 224).astype(np.float32)
    x = torch.from_numpy(x).to('cuda')

    def run(_x):
        with torch.no_grad():
            return model(_x)

    benchmark.pedantic(run, args=(x,), warmup_rounds=2, iterations=20, rounds=3)

@pytest.mark.benchmark(
    group="AlexNet",
    warmup=True
)
def test_AlexNetFlax(benchmark):
    model = AlexNetFlax()

    key1, key2 = jax.random.split(jax.random.PRNGKey(0))

    # FlaxとPyTorchでデータの並び順が異なることに注意
    # バッチ数、画像高さ、画像幅、チャネル数 [N, H, W, C]
    x = jax.random.normal(key1, (16, 224, 224, 3))
    weight = model.init(key2, x) # Initialization cal

    @jax.jit
    def run(_x):
        y = model.apply(weight, _x)
        # JAXは非同期実行するのでベンチのため結果がでるのを待ちます。
        jax.block_until_ready(y)
        return y

    # warm_upラウンドを2回いれることで、jitの時間を除外する
    benchmark.pedantic(run, args=(x,), warmup_rounds=2, iterations=20, rounds=3)

if __name__ == "__main__":
    pytest.main(['-v', __file__])

実行

全部の条件のベンチを行うコマンドはこちらです。

pytest benchmark_main.py --benchmark-compare

結果はこのようにグループで出力されます。

--------------------------------------------------------------------------- benchmark 'AlexNet': 2 tests ---------------------------------------------------------------------------
Name (time in ms)          Min               Max              Mean            StdDev            Median               IQR            Outliers       OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_AlexNetFlax        2.7234 (1.0)      2.7352 (1.0)      2.7289 (1.0)      0.0059 (1.0)      2.7283 (1.0)      0.0088 (1.0)           1;0  366.4413 (1.0)           3          20
test_AlexNetPytorch     3.7357 (1.37)     3.9136 (1.43)     3.8180 (1.40)     0.0897 (15.15)    3.8047 (1.39)     0.1335 (15.09)         1;0  261.9172 (0.71)          3          20
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------- benchmark 'GoogleNet': 2 tests ----------------------------------------------------------------------------
Name (time in ms)             Min                Max               Mean            StdDev             Median               IQR            Outliers      OPS            Rounds  Iterations
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_GoogleNetFlax        36.6693 (1.0)      37.2125 (1.0)      36.9712 (1.0)      0.2766 (1.17)     37.0316 (1.0)      0.4074 (1.15)          1;0  27.0481 (1.0)           3          20
test_GoogleNetPytorch     80.8444 (2.20)     81.3176 (2.19)     81.0850 (2.19)     0.2367 (1.0)      81.0931 (2.19)     0.3549 (1.0)           1;0  12.3327 (0.46)          3          20
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

個別に実行する場合

# ひとつだけ
pytest .\benchmark_main.py::test_AlexNetPytorch
# 複数
pytest .\benchmark_main.py -k "test_GoogleNetPytorch or test_GoogleNetFlax"

参考