肉そば屋 喰海の『かつ丼』

昼休みに、天神ビル地下1階にある『肉そば屋 喰海』に行ってみた。 ここは蕎麦屋なのかな。 グルメ本によってはつけ麺のカテゴリに載ってたりするけど、きっと蕎麦屋だろう。

初めて来たというのに、店名にもなっている肉そばではなく、かつ丼を注文してしまった。 かつ丼も密かに人気を集めているらしいし、実際、客の半数近く注文していた気がする。

かつ丼のトンカツは予想よりも肉厚で食べ応えあった。 卵はちょうど良いふわとろ具合。 つゆは甘めで、卵とご飯によくマッチしていると思う。 値段も 650 円と、コスパは悪くない。 友楽みたいに値段同じでご飯大盛りにできたら嬉しいんだけど、 さすがに無茶な注文だな。

肉そばも気になるので、次回は肉そばを食べることにしよう。

肉そば屋喰海
〒810-0001 福岡県福岡市中央区天神2-12-1 天神ビルB1F飲食街

Xamarin Forms でナビゲーションバーの左側にアイテムを配置する方法メモ

最近、Xamarin Forms で iOS アプリを開発している。 Xamarin Forms は XAML で記述できるので、WPF に慣れている身としては、 Storyboard よりも UI を作成しやすくて良いね。 Grid や StackLayout といったレイアウトが超便利だ。

一方で、「こんなこともできないの?」と思うことも度々ある。 例えば、ナビゲーションバーの左側にアイテムを配置する方法すら提供されていない、とかね。 今回は iOS プロジェクトでカスタムレンダラーを書いて実現できたけど。 こんなやつ。

using System.Collections.Generic;
using System.Linq;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ContentPage), typeof(XamarinFormsSample.iOS.ContentPageRenderer))]

namespace XamarinFormsSample.iOS
{
    public class ContentPageRenderer : PageRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            var toolbarItems = ((ContentPage)Element).ToolbarItems.OrderBy(w => w.Priority);
            var navigationItem = NavigationController.TopViewController.NavigationItem;
            var rightItems = new List<UIBarButtonItem>();
            var leftItems =  new List<UIBarButtonItem>();

            foreach (var item in toolbarItems)
            {
                // Priority がマイナスだったらナビゲーションバーの左側に配置する
                if (item.Priority < 0)
                {
                    leftItems.Add(item.ToUIBarButtonItem());
                }
                else
                {
                    rightItems.Add(item.ToUIBarButtonItem());
                }
            }

            navigationItem.SetRightBarButtonItems(rightItems.ToArray(), animated);
            navigationItem.SetLeftBarButtonItems(leftItems.ToArray(), animated);
        }
    }
}

シンプルな UI のアプリなので Xamarin Forms ですんなり実装できると思っていたけど、 結構つまづいている。UIKit 使って実装した方が早かったかも。 今のところ iOS だけが対象だし。

『かぐや様は告らせたい(4)』を読んだ

かぐや様は告らせたい〜天才たちの恋愛頭脳戦〜』の 4 巻がようやく Kindle で発売されたので、 購入して読んだ。

4 巻のお気に入りは藤原書記による特訓回だな。やっぱり。 今回は自分の得意分野だからと侮っていたために、 再び地獄の門を開いてしまうところが、藤原書記らしい。 この回では校歌が出てくるけど、 最後に校歌を使ってオチをつけたのが上手い。 それにしても、白金はこうも欠点が多くてよく会長になれたな。 努力でその場を凌いできたとあるから、 努力で克服していく姿勢が生徒の模範に相応しいと言えなくもないか。

会長の妹・圭が初登場する回も良かった。 圭がどんなキャラクターなのかは、 今回の話だけではまだ掴めなかったけど。 兄を嫌っているフシがあるが、 同属嫌悪的なヤツなのかな。 次回の登場に期待しよう。 この話の見所は妹よりも、黒いかぐや様だな。 もちろん、藤原書記が原因。 主人公(かぐやはヒロインではないみたい)の黒い一面が魅力になっているのが、 このマンガの凄いところだ。

今回も面白かった。既に 5 巻が待ち遠しい。 Kindle 版も紙の本と同時に発売して欲しいけど、 「電子書籍の購入は作家の応援にならない」という記事が記憶に新しいし、 出版業界を変革しないと難しいだろうな。

ニューラルネットワークに対する勾配を実装してみた

C# でゼロから Deep Learning を実装する挑戦の続き。 4 章もようやく終盤で、いよいよ機械学習に入る。 今回はニューラルネットワークに対する勾配を実装してみた。

using System;
using System.Linq;
using MathNet.Numerics.LinearAlgebra;

namespace GradientSimpleNet
{
    class Program
    {
        static void Main(string[] args)
        {
            var net = new SimpleNet();

            // 予測
            var x = Vector<double>.Build.DenseOfArray(new[] { 0.6, 0.9 });
            var p = net.Predict(x);
            Console.WriteLine("予測");
            Console.WriteLine(p);

            // 損失関数の値
            var t = Vector<double>.Build.DenseOfArray(new[] { 0, 0, 1.0 });
            var loss = net.Loss(x, t);
            Console.WriteLine("損失関数の値");
            Console.WriteLine(loss);

            // 勾配
            Func<Matrix<double>, double> f = W => net.Loss(x, t);
            var dW = Gradient.NumericalGradient(f, net.W);
            Console.WriteLine("勾配");
            Console.WriteLine(dW);

            Console.ReadLine();
        }
    }

    static class Functions
    {
        /// <summary>
        /// ソフトマックス
        /// </summary>
        public static Vector<double> Softmax(Vector<double> a)
        {
            var c = a.Max();

            // ベクトルの要素ごとの演算にも Map を使う
            var exp_a = a.Map(x => Math.Exp(x - c));
            var sum_exp_a = exp_a.Sum();
            var y = exp_a.Map(x => x / sum_exp_a);
            return y;
        }

        /// <summary>
        /// 交差エントロピー誤差
        /// </summary>
        public static double CrossEntropyError(Vector<double> y, Vector<double> t)
        {
            var delta = 1e-7;
            return -(y + delta).PointwiseLog().PointwiseMultiply(t).Sum();
        }
    }

    static class Gradient
    {
        /// <summary>
        /// 数値微分
        /// </summary>
        public static Matrix<double> NumericalGradient(Func<Matrix<double>, double> f, Matrix<double> x)
        {
            var h = 1e-4;
            var grad = Matrix<double>.Build.Dense(x.RowCount, x.ColumnCount);

            for (int row = 0; row < x.RowCount; row++)
            {
                for (int column = 0; column < x.ColumnCount; column++)
                {
                    var tmpVal = x[row, column];

                    x[row, column] = tmpVal + h;
                    var fxh1 = f(x);

                    x[row, column] = tmpVal - h;
                    var fxh2 = f(x);

                    grad[row, column] = (fxh1 - fxh2) / (2.0 * h);

                    // 値を元に戻す
                    x[row, column] = tmpVal;
                }
            }

            return grad;
        }
    }

    class SimpleNet
    {
        /// <summary>
        /// 重みパラメーター
        /// </summary>
        public Matrix<double> W { get; }

        public SimpleNet()
        {
            // ゼロから作る Deep Learning と同じ重みパラメーターを指定する
            W = Matrix<double>.Build.DenseOfArray(new double[,]
            {
                { 0.47355232, 0.9977393, 0.84668094 },
                { 0.85557411, 0.03563661, 0.69422093 }
            });
        }

        public Vector<double> Predict(Vector<double> x)
        {
            return x * W;
        }

        public double Loss(Vector<double> x, Vector<double> t)
        {
            var z = Predict(x);
            var y = Functions.Softmax(z);
            var loss = Functions.CrossEntropyError(y, t);
            return loss;
        }
    }
}

実行結果は次の通り。

『ゼロから作る Deep Learning』と同じような傾向になっている。 完全に一致しないのは、自分の実装が間違っているんだろうか。

ア・ラ・カンパーニュ

会社帰りに、福岡三越地下2階にある『ア・ラ・カンパーニュ』でタルトを買って帰った。 まだバレンタインセール中で、タルトとはいえチョコが使われているものを買うのは、 心理的ハードルが高めだ。

チョコレートのタルトは予想していたよりもかなりビターテイスト。 これバレンタイン限定商品っぽいけど、 かなりビターなチョコレートを貰った人は素直に喜べているんだろうか。 まぁ爆発して欲しいことには変わりない。

イチゴのタルトはこちらも生地がガトーショコラみたいになっていて、 イチゴの酸味とクリームの甘さと生地のほろ苦さが絶妙。 こっちの方が好みだったけど、こいつも限定商品なんだよな。 定番にすればいいのに。

www.alacampagne.jp

『まつもとゆきひろ 言語のしくみ』を読んだ

本書は、Matz こと『まつもとゆきひろ』氏が Streem という新しいプログラミング言語を開発するという、 日経 Linux で連載した記事をまとめて書籍にしたもの。

Streem のプログラミングモデルや文法を考え、 ガベージコレクションを含めた言語処理系だけでなくライブラリまで実装する、 という一部始終が詳細に書かれていた。 Streem の開発を通して、プロの言語デザイナーである Matz の頭の中を覗くことができる。

やはり、プログラミング言語のデザインについて書ける日本人は Matz しかいない。 いや、書くだけなら他にもいるだろうけど、 Ruby のパパである Matz が書くと説得力がケタ違いだ。

あと、タイムマシンコラムというのは面白い試みだった。 連載を書籍化したから生まれた発明かもしれない。 今後、同じようにタイムマシンコラムを載せる書籍が増えたら面白いだろうな。

自分にもプログラミング言語が作れそうな気がしてくる。作ってみたくなる。 そんな魅力が凝縮された一冊だった。

勾配降下法を実装してみた

C# でゼロから Deep Learning を実装する挑戦はまだ 4 章。 機械学習で使う勾配降下法を実装してみた。 勾配を計算するメソッドは前回記事を流用している。

using MathNet.Numerics.LinearAlgebra;
using System;
using System.Linq;

namespace GradientDescentSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // f(x0, x1) = x0^2 + x1^2
            Func<Vector<double>, double> function2 =
                (x) => Math.Pow(x[0], 2) + Math.Pow(x[1], 2);

            var initX = Vector<double>.Build.DenseOfArray(new double[]
            {
                -3.0,
                4.0
            });
            var result = GradientDescent(
                f: function2,
                initX: initX,
                learningRate: 0.1,
                stepNum: 100
                );

            Console.WriteLine(result);
            Console.ReadLine();
        }

        /// <summary>
        /// 勾配降下法を使って最小値を計算します。
        /// </summary>
        /// <param name="f">最適化したい関数</param>
        /// <param name="initX">初期値</param>
        /// <param name="learningRate">学習率</param>
        /// <param name="stepNum">勾配法による繰り返しの数</param>
        /// <returns>最小値</returns>
        static Vector<double> GradientDescent(
            Func<Vector<double>, double> f,
            Vector<double> initX,
            double learningRate,
            int stepNum = 100
            )
        {
            var x = initX;

            foreach (var i in Enumerable.Range(0, stepNum))
            {
                var grad = NumericalGradient(f, x);

                x = x - learningRate * grad;
            }

            return x;
        }

        /// <summary>
        /// 勾配を計算します。
        /// </summary>
        /// <param name="f">関数</param>
        /// <param name="x">関数に渡す引数</param>
        /// <returns>
        /// <paramref name="x"/> の各要素に対しての数値微分。
        /// </returns>
        static Vector<double> NumericalGradient(Func<Vector<double>, double> f, Vector<double> x)
        {
            var h = 0.0001;
            var grad = Vector<double>.Build.Dense(x.Count);

            foreach (var idx in Enumerable.Range(0, x.Count))
            {
                var tmpVal = x[idx];

                // f(x+h) の計算
                x[idx] = tmpVal + h;
                var fxh1 = f(x);

                // f(x-h) の計算
                x[idx] = tmpVal - h;
                var fxh2 = f(x);

                grad[idx] = (fxh1 - fxh2) / (2 * h);

                // 値を元に戻す
                x[idx] = tmpVal;
            }

            return grad;
        }
    }
}

実行結果。

数式だと難しく見えるが、コードにすると非常にシンプルだ。