2025/07/17

tf2onnx

先日もちらっと書きました。現行tf2onnx(1.16.1)はnumpy 1.26.4までにしないとダメです。

 python -m tf2onnx.convert --saved-model .\saved_model_multi_output\ --output Shinba.onnx

自分はAnacondaの仮想環境使ってるので、Anaconda PowerShell Prompt使って仮想環境をアクティブにして上記コマンドでSavedModel形式の

# TensorSpec を生成(shapeは共通なので固定)
input_signature = [
    tf.TensorSpec([None, 1], dtype, name=name)
    for name, dtype in feature_info
]

@tf.function(input_signature=input_signature)
def serve_fn(*features):
    return {"output": model(list(features))}

saved_model_path = "saved_model_multi_output"
tf.saved_model.save(model, saved_model_path, signatures={"serving_default": serve_fn})

とした方を指定して変換。出来上がるShiba.onnxは1.53GBってデカイ! Netron使って開いてみると

って感じです。まあ、こんなのはどうでもいいですが、Graph Properties開くと

と表示されるのが重要で、これを元に

internal class TFShinbaOnnxInput
{
    [ColumnName("baba")]
    [VectorType(1)]
    public int[] baba { get; set; }
    [ColumnName("course")]
    [VectorType(1)]
    public int[] course { get; set; }
    [ColumnName("joucd")]
    [VectorType(1)]
    public int[] joucd { get; set; }
    [ColumnName("kaisaikai")]
    [VectorType(1)]
    public float[] kaisaikai { get; set; }
    [ColumnName("kaisainichi")]
    [VectorType(1)]
    public float[] kaisainichi { get; set; }
    [ColumnName("kaisaituki")]
    [VectorType(1)]
    public int[] kaisaituki { get; set; }
    [ColumnName("kyori")]
    [VectorType(1)]
    public float[] kyori { get; set; }
    [ColumnName("tenko")]
    [VectorType(1)]
    public int[] tenko { get; set; }
    [ColumnName("tousu")]
    [VectorType(1)]
    public float[] tousu { get; set; }
    [ColumnName("trackcd")]
    [VectorType(1)]
    public int[] trackcd { get; set; }

    // uma10
    [ColumnName("uma10bareidays")]
    [VectorType(1)]
    public float[] uma10bareidays { get; set; }
...

って感じの入力クラスを準備して、先程のGraph Propertiesの最後まで行くと確認出来る出力部分も確認して

internal class TFShinbaOnnxOutput
{
    [ColumnName("output")]
    public float[] output { get; set; }
}

てな感じの出力クラスも用意。

            MLContext mLContext = new MLContext();

            var inputType = typeof(TFShinbaOnnxInput);

            // int[]のColumnName一覧
            var intColumnNames = inputType.GetProperties()
                .Where(p => p.PropertyType == typeof(int[]) &&
                            p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute)))
                .Select(p => p.GetCustomAttributesData()
                    .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute))
                    ?.ConstructorArguments[0].Value?.ToString() ?? p.Name)
                .ToList();

            // float[]のColumnName一覧
            var floatColumnNames = inputType.GetProperties()
                .Where(p => p.PropertyType == typeof(float[]) &&
                            p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute)))
                .Select(p => p.GetCustomAttributesData()
                    .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute))
                    ?.ConstructorArguments[0].Value?.ToString() ?? p.Name)
                .ToList();
            var allInputColumns = intColumnNames.Concat(floatColumnNames).ToArray();

            var pipeline = mLContext.Transforms.ApplyOnnxModel(
                modelFile: Properties.Settings.Default.TF_Shinba_Onnx,
                outputColumnNames: new[] { "output" },  // Netronで確認した出力名
                inputColumnNames: allInputColumns       // 入力名と一致させる
            );

            var emptyData = mLContext.Data.LoadFromEnumerable(new List<TFShinbaOnnxInput>());
            var model = pipeline.Fit(emptyData);
            var predictionEngine = mLContext.Model.CreatePredictionEngine<TFShinbaOnnxInput, TFShinbaOnnxOutput>(model);

            var input = new TFShinbaOnnxInput();
            input.SetValue(_baba, _courseKB, byte.Parse(_jouCD), _kai, _nichi, _tuki, _kyori, _tenko, _tousu, _trackCD, raceDetails);
            var prediction = predictionEngine.Predict(input);

って感じにC#でモデルロードして予測が出来ますね😁

2025/07/13

TensorFlow→ML.NET

もうどの位の期間取り組んできたのか忘れた。相当時間掛かってます。Netronでモデルの情報確認してあれこれ試し、

model.export(save_path)

として保存してたのを

tf.saved_model.save(model, saved_model_path, signatures={"serving_default": serve_fn})

にしても結局何かがダメって言われる。この何かが理解不能でCopilotやGeminiで解決図ったが行き詰った。

public class TFShinbaModelInput
{
    [VectorType(1)]
    [ColumnName("serving_default_Baba")]
    public int[] Baba { get; set; }
    [VectorType(1)]
    [ColumnName("serving_default_Course")]
    public int[] Course { get; set; }
    [VectorType(1)]
    [ColumnName("serving_default_JouCD")]
    public int[] JouCD { get; set; }
...

新馬戦用でも1,018個の特徴量があったりで

var mlContext = new MLContext();

var inputType = typeof(TFShinbaModelInput);

var intColumns = inputType.GetProperties()
    .Where(p => p.PropertyType == typeof(int[]) &&
                p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute)))
    .Select(p =>
    {
        var attr = p.GetCustomAttributesData()
            .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute));
        return attr?.ConstructorArguments[0].Value?.ToString() ?? p.Name;
    })
    .ToArray();

var floatColumns = inputType.GetProperties()
    .Where(p => p.PropertyType == typeof(float[]) &&
                p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute)))
    .Select(p =>
    {
        var attr = p.GetCustomAttributesData()
            .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute));
        return attr?.ConstructorArguments[0].Value?.ToString() ?? p.Name;
    })
    .ToArray();

var allFeatureColumns = intColumns.Concat(floatColumns).ToArray();

var pipeline = mlContext.Model.LoadTensorFlowModel(Properties.Settings.Default.TF_Shinba)
    .ScoreTensorFlowModel(
        outputColumnNames: new[] { "StatefulPartitionedCall" },
        inputColumnNames: allFeatureColumns,
        addBatchDimensionInput: true);

こんな感じでしっかり準備したうえでロードしてるんですが結局ダメでした。

以前確か試した記憶があるんですが、TensorFlowモデルをonnx形式で保存してML.NETでonnx形式を利用する方法を試すべく新たな仮想環境を準備。ってのもtf2onnxはnumpy 2.0以降で削られたnp.castとかの部分がNGでnumpy 1.26.4にダウングレードして試す必要があるようなので、今その環境で新馬戦用モデルの学習してます。それが済んだらonnx形式で保存してML.NETでロードしてまた苦戦する予定😣

2025.7.14 23:02
ひゃ~! onnx形式で行けた😂 これでちょっと先が見えたので、一気に進めます😉

2025/07/12

今回の芋焼酎

3カ月ぶりに新たな芋焼酎探しの買い物をしました。

楽天の買い回り利用しての購入でしたが

  • 甕伊佐錦三年貯蔵 2,800円
  • 伊佐舞 2,120円
  • 小鹿本にごり 2,050円
  • 黒伊佐錦 2,050円
それと島乙女 1,896円で2本と合わせて12,812円で送料無料に。このショップは1万円以上なら送料無料だったので選択しましたが、P箱での発送は処理に困るのでもう利用しない。送料無料がなかなか少ないので今回も島乙女が本来の値段ではないけど我慢して購入。今回の買い回りは14倍程度まで行ったので単純計算なら12,812×0.86だとすると実質11,018円程度。普段は先月辺りに購入した米焼酎が2ケースで13,530円なのでちょっと贅沢だ(笑)

取敢えず甕から試しましたが、まあ、値段的にもですが、美味い。表現難しいけど、角が無くまろやかな甘みがある芋ですね。ただ、値段的にもリピートは微妙。お気に入りのだいやめは12,650円/ケースの送料無料だから。

2025/07/03

VMware Workstation Pro Version 17.6.3

久しぶりにWMware入れてみようとダウンロードしました。ここ最近はPlayerが個人が無料で利用出来るって事で使ってたんですが、今はProも個人は無料😁 ちょっとビックリでしたが、まあ、ダウンロードしてインストール。

いきなり見た目が全く違うものになっていて驚きました。取敢えずUbuntu 24.04を入れてみました。
なんか随分スムーズになった感じがします。ちょっと遊んでみようかと思いますが、やる事もあるので程々に😉

2025/07/01

Microsoft Rewards 21回目

先日からちょいょいやらかしてます。夜勤明けに忘れたり、先週末はひたすらコーディングが気になり、すっかり忘れました。そんな訳で今のストリークが3だったりします😓 それでも継続は力? 本日Amazonギフト600円分頂きました。前回5月14日から49日での達成です。前回が40日での達成だったので大幅に伸びたのはやらかしてるからですね。でも、継続します。ああっ、楽天はもっと貯めないと交換出来ないので今回は諦めた。でも、今後は検討してみようかと思います。しかし、現時点で確認しても楽天は無くなってる。どうも不安定ですね。

2025/06/29

WinUI3での進捗

頑張って書いてるんですが時間掛かってます。やる事が多過ぎて時短は厳しい😓

見た目的には大分復元出来てきた。それと、これは確信はなかったんですが、学習モデルが大きくなるとロード時にエラーになる問題ですが、32bitではエラーになった196MBのモデルも64bitでは普通に使えました😁 これはなかなか嬉しい副産物です。RMSEが最適なのに大き過ぎて使えなかった過去があるので期待したい。

今後この画面にLightGBMやTensorFlow使った予測も入れ込めれば64bit化した恩恵が更に深まる。この辺りは優先的に進めたいと思ってます。特にTensorFlowの予測に期待しているので早い段階で使える事が確認出来れば学習も同時に進められるので効率も良いかも。

2025/06/26

BIG初ヒット!

BIGって発売当初からほぼ買ってます。まあ、色々とね。これまで末等の数百円とかはありました。普通のBIGは確か末等の次は千円程度の当りもあったかとおもいますが、それなんかも当りって感じではなく、まあ、宝くじの下1桁的な感覚のものですよね。だって開始当初は今の数百円の末等は無く、千円程度が末等だった記憶です。でまあ、今回当たったのは、高額ではないのですが、

BIG1000での当りでした。こんな小物に運を使ってちゃダメだけど、まあ、買い続けます😁

開発もしてますよ。

こんなのは既に上げてたかと思いますが、
こんなのも進めてます。まあ、この辺りは実は機械学習使うのに過去走データ取得も必要なのでデータ取得ついでに表示もさせてみたって感じで、装飾は後回しで機械学習させてその表示を今週末には完成させたいかなぁ。

2025/06/20

データグリッドの派生クラス

WinUI3のデータグリッドでは基本的にDataGridTextColumnを使いますが、文字の色や背景、ツールチップを追加等は派生クラスをいちいち定義するのが結局一番効率が良いのかな?例えばタイム型データマイニングだと

internal class DataGridTextColumnTimeDM : DataGridTextColumn
{
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        Border border = new Border
        {
            HorizontalAlignment = HorizontalAlignment.Stretch, // セル内で均等に広がる
            VerticalAlignment = VerticalAlignment.Stretch, // 上下も均等に広がる
            Padding = new Thickness(5) // 適度な余白
        };
        TextBlock textBlock = new TextBlock
        {
            TextAlignment = TextAlignment.Center, // テキストを中央揃え
            HorizontalAlignment = HorizontalAlignment.Center, // 左右中央揃え
            VerticalAlignment = VerticalAlignment.Center // 上下中央揃え
        };
        if (dataItem is RaceDetailInfo item)
        {
            textBlock.Text = item.TimeDM;

            // 現在のテーマを取得
            var theme = Application.Current.RequestedTheme;

            // 文字色を変更
            switch (item.TimeDMRank)
            {
                case 1:
                    border.Background = new Microsoft.UI.Xaml.Media.SolidColorBrush(SaraD64Constants.BackColor1);
                    textBlock.Foreground = new SolidColorBrush(Colors.Black);
                    break;
                case 2:
                    border.Background = new Microsoft.UI.Xaml.Media.SolidColorBrush(SaraD64Constants.BackColor2);
                    textBlock.Foreground = new SolidColorBrush(Colors.Black);
                    break;
                case 3:
                    border.Background = new Microsoft.UI.Xaml.Media.SolidColorBrush(SaraD64Constants.BackColor3);
                    textBlock.Foreground = new SolidColorBrush(Colors.Black);
                    break;
                default: // その他
                    textBlock.Foreground = new SolidColorBrush(theme == ApplicationTheme.Dark ? Colors.White : Colors.Black);
                    break;
            }
            // ツールチップ追加
            ToolTipService.SetToolTip(textBlock, item.TimeDMToolTip);
        }

        border.Child = textBlock; // Border に TextBlock を含める
        return border;
    }
}

ああ、現在のテーマチェックして一応ダークモードとライトモードで切り替えは自分でやる必要があるっぽい。まっ、テーマ的に全て色を統一してれば自動にって方法があるのかもですが、これまで色にあくまでも近い形にしたいので深く考えずに少しだけ考慮しておこうかと。ただ、実際自分はダークモードしか使わないので、一通り形になった時に念のためにライトモードは試してからリリースしなきゃだなぁっと。

まだまだ全然途中ですが、

こんな感じにしていく予定です。

ここ最近、プライベートで色々とあり、まあ、気分転換的に少しプログラミングから一旦離れ、余暇は「ダイヤのエース」を一気見しました。気晴らしのつもりがちょっと長かったorz ただ、最後まで観ないと気になるので最後は惰性で😅 75+51+52=178話で20分/話だとしても60時間弱 ちょっとしばらくはアニメはやめて映画に戻ろうかと思います。

2025/06/15

第66回宝塚記念

滅茶苦茶堅そうだけど、まあ、グランプリだしちょっとだけ参戦😉

今回のオッズマスターズも登録はしてますが、開発が途中なのでフル参戦は見送り。開発は地味に進めてますが、本当に地味です。Win UI3はめんどくさい😓

ああ、13年程度使ってきた三菱の冷蔵庫が...製氷機能がダメだ。まあ、この冷蔵庫は問題多過ぎで、買った時から気になってたけど、氷庫の裏側に氷が頻繁に落ちる。オフシーズンに氷をあまり使わないとカビが発生する。現在の三菱の冷蔵庫もこの氷が裏側に落ちるらしいので選択肢から排除。うちは元々パナで3台程度ハズレ引いたのでパナも除外してます。残るは日立か東芝か?悩む所ですが、東芝が気になるのは問い合わせ先。フリーダイヤルがあるんですが、携帯電話はナビダイヤル。以前もここに書いた気がするけど、このナビダイヤルに掛けさせる企業の姿勢が本当に疑問。こちらがかけ放題や無料通話アプリでもナビダイヤルは課金されます。なら、普通の固定電話番号を用意してくれた方がどうとでもなる。フリーダイヤルは携帯番号認識して撥ねられる。固定電話なんて既に解約済みです。時代にマッチしない企業にはあまり関わり持ちたくないんですよねぇ。

2025/06/12

Win UI3でのDataGrid定義

Windowsフォームアプリでは

var columnNames = new string[]
{
    "umaban", "bamei", "kishu", "choukyosi", "tansho", "fukusho", "bataijyu", "mark", "chaku"
};
var columnHeader = new string[]
{
    "馬番", "馬名", "騎手", "調教師", "単勝", "複勝", "馬体重", "印", "着順"
};
var columnWidth = new int[]
{
    30, 201, 88, 88, 60, 130, 60, 30, 30
};

for (int i = 0; i < columnNames.Length; i++)
{
    DataGridViewColumn tbCol = new DataGridViewTextBoxColumn();
    tbCol.Name = columnNames[i];
    tbCol.HeaderText = columnHeader[i];
    tbCol.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
    tbCol.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
    tbCol.ReadOnly = true;
    tbCol.SortMode = DataGridViewColumnSortMode.NotSortable;

    dgv.Columns.Add(tbCol);
    dgv.Columns[columnNames[i]].Width = columnWidth[i];
}

って感じでC#で定義してたりしました。素人的にWin UI3でデータグリッド使うにはxamlで

<Grid Grid.Row="1">
    <controls:DataGrid x:Name="RaceDetailGrid"
                    AutoGenerateColumns="False" HeadersVisibility="Column"
                    CanUserResizeColumns="False" SelectionMode="Single" RowHeight="30" CanUserSortColumns="False"
                    >
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Header="馬番" Binding="{Binding Umaban}" Width="60"/>
        <controls:DataGridTextColumn Header="馬名" Binding="{Binding Bamei}" Width="200"/>
        <controls:DataGridTextColumn Header="服" Binding="{Binding Fuku}" Width="80"/>
        <controls:DataGridTextColumn Header="騎手" Binding="{Binding Kishu}" Width="120"/>
        <controls:DataGridTextColumn Header="調教師" Binding="{Binding Chokyosi}" Width="120"/>
        <controls:DataGridTextColumn Header="単勝" Binding="{Binding Tansho}" Width="80"/>
        <controls:DataGridTextColumn Header="複勝" Binding="{Binding Fukusho}" Width="140"/>
        <controls:DataGridTextColumn Header="馬体重" Binding="{Binding Bataiju}" Width="100"/>
        <controls:DataGridTextColumn Header="印" Binding="{Binding Mark}" Width="60"/>
        <controls:DataGridTextColumn Header="着順" Binding="{Binding Chaku}" Width="80"/>
    </controls:DataGrid.Columns>
    </controls:DataGrid>
</Grid>

としてみてたのですが、今後こんなの増えてくるとってのと今回カスタム列タイプも試したのでその為にもスマートに定義が出来ればと思い、Copilotに質問ぶつけて得た方法は

public class DataGridColumnDefinition
{
    public string Header { get; set; }
    public string BindingPath { get; set; }
    public int Width { get; set; }
    public string ColumnType { get; set; } // 列の種類を文字列で管理
}

として定義用クラスを用意し、

private void DesignRaceDetailGrid(DataGrid dataGrid)
{
    var columnDefinitions = new List<DataGridColumnDefinition>
    {
        new DataGridColumnDefinition { Header = "馬番", BindingPath = "Umaban", Width = 60, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "馬名", BindingPath = "Bamei", Width = 200, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "服", BindingPath = "Fuku", Width = 80, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "騎手", BindingPath = "Kishu", Width = 120, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "調教師", BindingPath = "Chokyosi", Width = 120, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "単勝", BindingPath = "Tansho", Width = 80, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "複勝", BindingPath = "Fukusho", Width = 140, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "馬体重", BindingPath = "Bataiju", Width = 100, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "印", BindingPath = "Mark", Width = 60, ColumnType = "Text" },
        new DataGridColumnDefinition { Header = "着順", BindingPath = "Chaku", Width = 60, ColumnType = "Text" },
    };

    foreach (var column in columnDefinitions)
    {
        DataGridColumn dataGridColumn;
        switch (column.ColumnType)
        {
            case "Text":
                dataGridColumn = new DataGridTextColumn
                {
                    Header = column.Header,
                    Binding = new Binding { Path = new PropertyPath(column.BindingPath) },
                    Width = new DataGridLength(column.Width, DataGridLengthUnitType.Pixel)
                };
                break;

            default:
                    throw new InvalidOperationException($"未対応の列タイプ: {column.ColumnType}");
        }

        dataGrid.Columns.Add(dataGridColumn);
    }
}

定義しやすさとメンテしやすさと思ってしてみました。

2025/06/08

第75回安田記念

軽く狙ってみました。

山積するWin UI3版の開発ですが、面倒な部分は後から考えるとしてちょっと出来る事を
こんな感じをたたき台に進めようかと取り組んでます。

2025/06/05

Win UI3の苦悩

自分自身も期待している部分もあるのでちょっとだけ頑張ってはいるんですが、例えば、アプリの終了です。こんなのこれまでWindowsアプリだろうと、言っちゃえばDOSや他のOSなんかでも普通に終了的にすれば問題無いのに、Win UI3だと違うっぽいです。これで昨晩かなり時間を費やしました。

基本的にWin UI3なら

Application.Current.Exit(); // アプリケーションを終了

とすれば良いってCopilotとかに言われてしても、終了時にエラーが出るしまつorz まあ、そんなのはいつもの事なので、更に突っ込んだ質問ぶつけてもなかなか良い回答は得られずでしたが、結局の所

Process.GetCurrentProcess().Kill(); // アプリを強制終了

とすれば、一応エラー無しで終われる事を確認しました。が、なんでそんな事に時間費やすんだろうって疑問はねぇ^^; まあ、なにやらリソースが解放されてないのがって事ではって話だが、そんなの勝手に処理しろよってね。でまあ、

こんな感じには進んでます。ただ、こんなのは本来サクッとな部分で、この後のレース情報の表示をどんなに再現出来るかなんかがカギですね😔

2025/06/01

第92回東京優駿(日本ダービー)

 あまり荒れる事がないレースって印象ではありますが

先週かすったので今週はかすりもしない予感😓